Fix two encoding issues
[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 by Bundesamt für Sicherheit in der Informationstechnik
5  * Software engineering by Intevation GmbH
6  *
7  * This file is part of GpgOL.
8  *
9  * GpgOL is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * GpgOL is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 #ifndef MAIL_H
23 #define MAIL_H
24
25 #include "oomhelp.h"
26 #include "mapihelp.h"
27 #include "gpgme++/verificationresult.h"
28 #include "gpgme++/decryptionresult.h"
29 #include "gpgme++/key.h"
30
31 #include <string>
32 #include <future>
33
34 class ParseController;
35 class CryptController;
36
37 /** @brief Data wrapper around a mailitem.
38  *
39  * This class is intended to bundle all that we know about
40  * a Mail. Due to the restrictions in Outlook we sometimes may
41  * need additional information that is not available at the time
42  * like the sender address of an exchange account in the afterWrite
43  * event.
44  *
45  * This class bundles such information and also provides a way to
46  * access the event handler of a mail.
47  *
48  * Naming conventions of the suffixes:
49  *  _o functions that work on OOM and possibly also MAPI.
50  *  _m functions that work on MAPI.
51  *  _s functions that only work on internal data and are safe to call
52  *     from any thread.
53  *
54  * O and M functions _must_ only be called from the main thread. Use
55  * a WindowMessage to signal the Main thread. But be wary. A WindowMessage
56  * might be handled while an OOM call in the main thread waits for completion.
57  *
58  * An example for this is how update_oom_data can work:
59  *
60  * Main Thread:
61  *   call update_oom_data
62  *    └> internally invokes an OOM function that might do network access e.g.
63  *       to connect to the exchange server to fetch the address.
64  *
65  *   Counterintutively the Main thread does not return from that function or
66  *   blocks for it's completion but handles windowmessages.
67  *
68  *   After a windowmessage was handled and if the OOM invocation is
69  *   completed the invocation returns and normal execution continues.
70  *
71  *   So if the window message handler's includes for example
72  *   also a call to lookup recipients we crash. Note that it's usually
73  *   safe to do OOM / MAPI calls from a window message.
74  *
75  *
76  * While this seems impossible, remember that we do not work directly
77  * with functions but everything is handled through COM. Without this
78  * logic Outlook would probably become unusable because as any long running
79  * call to the OOM would block it completely and freeze the UI.
80  * (no windowmessages handled).
81  *
82  * So be wary when accessing the OOM from a Window Message.
83  */
84 class Mail
85 {
86 public:
87   enum CryptState
88     {
89       NoCryptMail,
90       NeedsFirstAfterWrite,
91       NeedsActualCrypt,
92       NeedsUpdateInOOM,
93       NeedsSecondAfterWrite,
94       NeedsUpdateInMAPI,
95       WantsSendInline,
96       WantsSendMIME,
97     };
98
99   /** @brief Construct a mail object for the item.
100     *
101     * This also installs the event sink for this item.
102     *
103     * The mail object takes ownership of the mailitem
104     * reference. Do not Release it! */
105   Mail (LPDISPATCH mailitem);
106
107   ~Mail ();
108
109   /** @brief looks for existing Mail objects for the OOM mailitem.
110
111     @returns A reference to an existing mailitem or NULL in case none
112     could be found.
113   */
114   static Mail* getMailForItem (LPDISPATCH mailitem);
115
116   /** @brief looks for existing Mail objects in the uuid map.
117     Only objects for which set_uid has been called can be found
118     in the uid map. Get the Unique ID of a mailitem thorugh get_unique_id
119
120     @returns A reference to an existing mailitem or NULL in case none
121     could be found.
122   */
123   static Mail* getMailForUUID (const char *uuid);
124
125   /** @brief Get the last created mail.
126
127     @returns A reference to the last created mail or null.
128   */
129   static Mail* getLastMail ();
130
131   /** @brief voids the last mail variable. */
132   static void clearLastMail ();
133
134   /** @brief Lock mail deletion.
135
136     Mails are heavily accessed multi threaded. E.g. when locating
137     keys. Due to bad timing it would be possible that between
138     a check for "is_valid_ptr" to see if a map is still valid
139     and the usage of the mail a delete would happen.
140
141     This lock can be used to prevent that. Changes made to the
142     mail will of course have no effect as the mail is already in
143     the process of beeing unloaded. And calls that access MAPI
144     or OOM still might crash. But this at least gurantees that
145     the member variables of the mail exist while the lock is taken.
146
147     Use it in your thread like:
148
149       Mail::lockDelete ();
150       Mail::isValidPtr (mail);
151       mail->set_or_check_something ();
152       Mail::unlockDelete ();
153
154       Still be carefull when it is a mapi or oom function.
155   */
156   static void lockDelete ();
157   static void unlockDelete ();
158
159   /** @brief looks for existing Mail objects.
160
161     @returns A reference to an existing mailitem or NULL in case none
162     could be found. Can be used to check if a mail object was destroyed.
163   */
164   static bool isValidPtr (const Mail *mail);
165
166   /** @brief wipe the plaintext from all known Mail objects.
167     *
168     * This is intended as a "cleanup" call to be done on unload
169     * to avoid leaking plaintext in case we are deactivated while
170     * some mails still have their plaintext inserted.
171     *
172     * @returns the number of errors that occured.
173     */
174   static int wipeAllMails_o ();
175
176   /** @brief revert all known Mail objects.
177     *
178     * Similar to wipe but works on MAPI to revert our attachment
179     * dance and restore an original MIME mail.
180     *
181     * @returns the number of errors that occured.
182     */
183   static int revertAllMails_o ();
184
185   /** @brief close all known Mail objects.
186     *
187     * Close our mail with discard changes set to true.
188     * This discards the plaintext / attachments. Afterwards
189     * it calls save if neccessary to sync back the collected
190     * property changes.
191     *
192     * This is the nicest of our three "Clean plaintext"
193     * functions. Will fallback to revert if closing fails.
194     * Closed mails are deleted.
195     *
196     * @returns the number of errors that occured.
197     */
198   static int closeAllMails_o ();
199
200   /** @brief closes the inspector for a mail
201     *
202     * @returns true on success.
203   */
204   static int closeInspector_o (Mail *mail);
205
206   /** Call close with discard changes to discard
207       plaintext. returns the value of the oom close
208       call. This may have delete the mail if the close
209       triggers an unload.
210   */
211   static int close (Mail *mail);
212
213   /** @brief locate recipients for all crypto mails
214     *
215     * To avoid lookups of recipients for non crypto mails we only
216     * locate keys when a crypto action is already selected.
217     *
218     * As the user can do this after recipients were added but
219     * we don't know for which mail the crypt button was triggered.
220     * we march over all mails and if they are crypto mails we check
221     * that the recipents were located.
222     */
223   static void locateAllCryptoRecipients_o ();
224
225   /** @brief Reference to the mailitem. Do not Release! */
226   LPDISPATCH item () { return m_mailitem; }
227
228   /** @brief Pre process the message. Ususally to be called from BeforeRead.
229    *
230    * This function assumes that the base message interface can be accessed
231    * and calles the MAPI Message handling which changes the message class
232    * to enable our own handling.
233    *
234    * @returns 0 on success.
235    */
236   int preProcessMessage_m ();
237
238   /** @brief Decrypt / Verify the mail.
239    *
240    * Sets the needs_wipe and was_encrypted variable.
241    *
242    * @returns 0 on success. */
243   int decryptVerify_o ();
244
245   /** @brief start crypto operations as selected by the user.
246    *
247    * Initiates the crypto operations according to the gpgol
248    * draft info flags.
249    *
250    * @returns 0 on success. */
251   int encryptSignStart_o ();
252
253   /** @brief Necessary crypto operations were completed successfully. */
254   bool wasCryptoSuccessful_m () { return m_crypt_successful || !needs_crypto_m (); }
255
256   /** @brief Message should be encrypted and or signed.
257     0: No
258     1: Encrypt
259     2: Sign
260     3: Encrypt & Sign
261   */
262   int needs_crypto_m () const;
263
264   /** @brief wipe the plaintext from the message and encrypt attachments.
265    *
266    * @returns 0 on success; */
267   int wipe_o (bool force = false);
268
269   /** @brief revert the message to the original mail before our changes.
270    *
271    * @returns 0 on success; */
272   int revert_o ();
273
274   /** @brief update some data collected from the oom
275    *
276    * This updates cached values from the OOM that are not available
277    * in MAPI events like after Write.
278    *
279    * For Exchange 2013 at least we don't have any other way to get the
280    * senders SMTP address then through the object model. So we have to
281    * store the sender address for later events that do not allow us to
282    * access the OOM but enable us to work with the underlying MAPI structure.
283    *
284    * It also updated the is_html_alternative value.
285    *
286    * @returns 0 on success */
287   int updateOOMData_o ();
288
289   /** @brief get sender SMTP address (UTF-8 encoded).
290    *
291    * If the sender address has not been set through update_sender this
292    * calls update_sender before returning the sender.
293    *
294    * @returns A reference to the utf8 sender address. Or an empty string. */
295   std::string getSender_o ();
296
297   /** @brief get sender SMTP address (UTF-8 encoded).
298    *
299    * Like get_sender but ensures not to touch oom or mapi
300    *
301    * @returns A reference to the utf8 sender address. Or an empty string. */
302   std::string getSender () const;
303
304   /** @brief get the subject string (UTF-8 encoded).
305     *
306     * @returns the subject or an empty string. */
307   std::string getSubject_o () const;
308
309   /** @brief Is this a crypto mail handled by gpgol.
310   *
311   * Calling this is only valid after a message has been processed.
312   *
313   * @returns true if the mail was either signed or encrypted and we processed
314   * it.
315   */
316   bool isCryptoMail () const;
317
318   /** @brief This mail needs to be actually written.
319   *
320   * @returns true if the next write event should not be canceled.
321   */
322   bool needsSave () { return m_needs_save; }
323
324   /** @brief set the needs save state.
325   */
326   void setNeedsSave (bool val) { m_needs_save = val; }
327
328   /** @brief is this mail an S/MIME mail.
329     *
330     * @returns true for smime messages.
331     */
332   bool isSMIME_m ();
333
334   /** @brief get the associated parser.
335     only valid while the actual parsing happens. */
336   std::shared_ptr<ParseController> parser () { return m_parser; }
337
338   /** @brief get the associated cryptcontroller.
339     only valid while the crypting happens. */
340   std::shared_ptr<CryptController> cryper () { return m_crypter; }
341
342   /** To be called from outside once the paser was done.
343    In Qt this would be a slot that is called once it is finished
344    we hack around that a bit by calling it from our windowmessages
345    handler.
346   */
347   void parsing_done ();
348
349   /** Returns true if the mail was verified and has at least one
350     signature. Regardless of the validity of the mail */
351   bool isSigned () const;
352
353   /** Returns true if the mail is encrypted to at least one
354     recipient. Regardless if it could be decrypted. */
355   bool isEncrypted () const;
356
357   /** Are we "green" */
358   bool isValidSig () const;
359
360   /** Get UID gets UniqueID property of this mail. Returns
361     an empty string if the uid was not set with set uid.*/
362   const std::string & getUUID () const { return m_uuid; }
363
364   /** Returns 0 on success if the mail has a uid alrady or sets
365     the uid. Setting only succeeds if the OOM is currently
366     accessible. Returns -1 on error. */
367   int setUUID_o ();
368
369   /** Returns a localized string describing in one or two
370     words the crypto status of this mail. */
371   std::string getCryptoSummary () const;
372
373   /** Returns a localized string describing the detailed
374     crypto state of this mail. */
375   std::string getCryptoDetails_o ();
376
377   /** Returns a localized string describing a one line
378     summary of the crypto state. */
379   std::string getCryptoOneLine () const;
380
381   /** Get the icon id of the appropiate icon for this mail */
382   int getCryptoIconID () const;
383
384   /** Get the fingerprint of an associated signature or null
385       if it is not signed. */
386   const char *getSigFpr () const;
387
388   /** Remove all categories of this mail */
389   void removeCategories_o ();
390
391   /** Get the body of the mail */
392   std::string getBody_o () const;
393
394   /** Get the recipients. */
395   std::vector<std::string> getRecipients_o () const;
396
397   /** Try to locate the keys for all recipients.
398       This also triggers the Addressbook integration, which we
399       treat as locate jobs. */
400   void locateKeys_o ();
401
402   /** State variable to check if a close was triggerd by us. */
403   void setCloseTriggered (bool value);
404   bool getCloseTriggered () const;
405
406   /** Check if the mail should be sent as html alternative mail.
407     Only valid if update_oom_data was called before. */
408   bool isHTMLAlternative () const;
409
410   /** Get the html body. It is updated in update_oom_data.
411       Caller takes ownership of the string and has to free it.
412   */
413   char *takeCachedHTMLBody ();
414
415   /** Get the plain body. It is updated in update_oom_data.
416       Caller takes ownership of the string and has to free it.
417   */
418   char *takeCachedPlainBody ();
419
420   /** Get the cached recipients. It is updated in update_oom_data.*/
421   std::vector<std::string> getCachedRecipients ();
422
423   /** Returns 1 if the mail was encrypted, 2 if signed, 3 if both.
424       Only valid after decrypt_verify.
425   */
426   int getCryptoFlags () const;
427
428   /** Returns true if the mail should be encrypted in the
429       after write event. */
430   bool getNeedsEncrypt () const;
431   void setNeedsEncrypt (bool val);
432
433   /** Gets the level of the signature. See:
434     https://wiki.gnupg.org/EasyGpg2016/AutomatedEncryption for
435     a definition of the levels. */
436   int get_signature_level () const;
437
438   /** Check if all attachments are hidden and show a warning
439     message appropiate to the crypto state if necessary. */
440   int checkAttachments_o () const;
441
442   /** Check if the mail should be encrypted "inline" */
443   bool getDoPGPInline () const {return m_do_inline;}
444
445   /** Check if the mail should be encrypted "inline" */
446   void setDoPGPInline (bool value) {m_do_inline = value;}
447
448   /** Append data to a cached inline body. Helper to do this
449      on MAPI level and later add it through OOM */
450   void appendToInlineBody (const std::string &data);
451
452   /** Set the inline body as OOM body property. */
453   int inlineBodyToBody_o ();
454
455   /** Get the crypt state */
456   CryptState cryptState () const {return m_crypt_state;}
457
458   /** Set the crypt state */
459   void setCryptState (CryptState state) {m_crypt_state = state;}
460
461   /** Update MAPI data after encryption. */
462   void updateCryptMAPI_m ();
463
464   /** Update OOM data after encryption.
465
466     Checks for plain text leaks and
467     does not advance crypt state if body can't be cleaned.
468   */
469   void updateCryptOOM_o ();
470
471   /** Enable / Disable the window of this mail.
472
473     When value is false the active window will
474     be disabled and the handle stored for a later
475     enable. */
476   void setWindowEnabled_o (bool value);
477
478   /** Determine if the mail is an inline response.
479
480     Call check_inline_response first to update the state
481     from the OOM.
482
483     We need synchronous encryption for inline responses. */
484   bool isAsyncCryptDisabled () { return m_async_crypt_disabled; }
485
486   /** Check through OOM if the current mail is an inline
487     response.
488
489     Caches the state which can then be queried through
490     async_crypt_disabled
491   */
492   bool check_inline_response ();
493
494   /** Get the window for the mail. Caution! This is only
495     really valid in the time that the window is disabled.
496     Use with care and can be null or invalid.
497   */
498   HWND getWindow () { return m_window; }
499
500   /** Cleanup any attached crypter object. Useful
501     on error. */
502   void resetCrypter () { m_crypter = nullptr; }
503
504   /** Set special crypto mime data that should be used as the
505     mime structure when sending. */
506   void setOverrideMIMEData (const std::string &data) {m_mime_data = data;}
507
508   /** Get the mime data that should be used when sending. */
509   std::string get_override_mime_data () const { return m_mime_data; }
510   bool hasOverrideMimeData() const { return !m_mime_data.empty(); }
511
512   /** Set if this is a forward of a crypto mail. */
513   void setIsForwardedCryptoMail (bool value) { m_is_forwarded_crypto_mail = value; }
514   bool is_forwarded_crypto_mail () { return m_is_forwarded_crypto_mail; }
515
516   /** Set if this is a reply of a crypto mail. */
517   void setIsReplyCryptoMail (bool value) { m_is_reply_crypto_mail = value; }
518   bool is_reply_crypto_mail () { return m_is_reply_crypto_mail; }
519
520   /** Remove the hidden GpgOL attachments. This is needed when forwarding
521     without encryption so that our attachments are not included in the forward.
522     Returns 0 on success. Works in OOM. */
523   int removeOurAttachments_o ();
524
525   /** Remove all attachments. Including our own. This is needed for
526     forwarding of unsigned S/MIME mails (Efail).
527     Returns 0 on success. Works in OOM. */
528   int removeAllAttachments_o ();
529
530   /** Check both OOM and MAPI if the body is either empty or
531     encrypted. Won't abort on OOM or MAPI errors, so it can be
532     used in both states. But will return false if a body
533     was detected or in the OOM the MAPI Base Message. This
534     is intended as a saveguard before sending a mail.
535
536     This function should not be used to detected the necessity
537     of encryption and is only an extra check to catch unexpected
538     errors.
539     */
540   bool hasCryptedOrEmptyBody_o ();
541
542   void updateBody_o ();
543
544   /** Set if this mail looks like the send again of a crypto mail.
545       This will mean that after it is decrypted it is treated
546       like an unencrypted mail so that it can be encrypted again
547       or sent unencrypted.
548       */
549   void setIsSendAgain (bool value) { m_is_send_again = value; }
550
551
552   /* Attachment removal state variables. */
553   bool attachmentRemoveWarningDisabled () { return m_disable_att_remove_warning; }
554
555   /* Gets the string dump of the verification result. */
556   std::string getVerificationResultDump ();
557
558   /* Block loading HTML content */
559   void setBlockHTML (bool value);
560   bool isBlockHTML () const { return m_block_html; }
561
562   /* Remove automatic loading of HTML references setting. */
563   void setBlockStatus_m ();
564
565   /* Crypto options (sign/encrypt) have been set manually. */
566   void setCryptoSelectedManually (bool v) { m_manual_crypto_opts = v; }
567   // bool is_crypto_selected_manually () const { return m_manual_crypto_opts; }
568
569   /* Reference that a resolver thread is running for this mail. */
570   void incrementLocateCount ();
571
572   /* To be called when a resolver thread is done. If there are no running
573      resolver threads we can check the recipients to see if we should
574      toggle / untoggle the secure state.
575      */
576   void decrementLocateCount ();
577
578   /* Check if the keys can be resolved automatically and trigger
579    * setting the crypto flags accordingly.
580    */
581   void autosecureCheck ();
582
583   /* Set if a mail should be secured (encrypted and signed)
584    *
585    * Only save to call from a place that may access mapi.
586    */
587   void setDoAutosecure_m (bool value);
588
589   /* Install an event handler for the folder of this mail. */
590   void installFolderEventHandler_o ();
591
592   /* Marker for a "Move" of this mail */
593   bool isAboutToBeMoved () { return m_is_about_to_be_moved; }
594   void setIsAboutToBeMoved (bool value) { m_is_about_to_be_moved = value; }
595
596   /* Releases the current item ref obtained in update oom data */
597   void releaseCurrentItem ();
598   /* Gets an additional reference for GetInspector.CurrentItem */
599   void refCurrentItem ();
600
601   /* Check if a flag change was triggered and can be ignored. */
602   bool flagChangeTriggered () const { return m_flag_change_triggered; }
603
604 private:
605   void updateSigFlag_o ();
606   void updateCategories_o ();
607   void updateSigstate ();
608
609   LPDISPATCH m_mailitem;
610   LPDISPATCH m_event_sink;
611   LPDISPATCH m_currentItemRef;
612   bool m_processed,    /* The message has been porcessed by us.  */
613        m_needs_wipe,   /* We have added plaintext to the mesage. */
614        m_needs_save,   /* A property was changed but not by us. */
615        m_crypt_successful, /* We successfuly performed crypto on the item. */
616        m_is_smime, /* This is an smime mail. */
617        m_is_smime_checked, /* it was checked if this is an smime mail */
618        m_is_signed, /* Mail is signed */
619        m_is_valid, /* Mail is valid signed. */
620        m_close_triggered, /* We have programtically triggered a close */
621        m_is_html_alternative, /* Body Format is not plain text */
622        m_needs_encrypt; /* Send was triggered we want to encrypt. */
623   int m_moss_position; /* The number of the original message attachment. */
624   int m_crypto_flags;
625   std::string m_sender;
626   std::string m_sent_on_behalf;
627   char *m_cached_html_body; /* Cached html body. */
628   char *m_cached_plain_body; /* Cached plain body. */
629   std::vector<std::string> m_cached_recipients;
630   msgtype_t m_type; /* Our messagetype as set in mapi */
631   std::shared_ptr <ParseController> m_parser;
632   std::shared_ptr <CryptController> m_crypter;
633   GpgME::VerificationResult m_verify_result;
634   GpgME::DecryptionResult m_decrypt_result;
635   GpgME::Signature m_sig;
636   GpgME::UserID m_uid;
637   std::string m_uuid;
638   std::string m_orig_body;
639   bool m_do_inline;
640   bool m_is_gsuite; /* Are we on a gsuite account */
641   std::string m_inline_body;
642   CryptState m_crypt_state;
643   HWND m_window;
644   bool m_async_crypt_disabled;
645   std::string m_mime_data;
646   bool m_is_forwarded_crypto_mail; /* Is this a forward of a crypto mail */
647   bool m_is_reply_crypto_mail; /* Is this a reply to a crypto mail */
648   bool m_is_send_again; /* Is this a send again of a crypto mail */
649   bool m_disable_att_remove_warning; /* Should not warn about attachment removal. */
650   bool m_block_html; /* Force blocking of html content. e.g for unsigned S/MIME mails. */
651   bool m_manual_crypto_opts; /* Crypto options (sign/encrypt) have been set manually. */
652   bool m_first_autosecure_check; /* This is the first autoresolve check */
653   int m_locate_count; /* The number of key locates pending for this mail. */
654   bool m_is_about_to_be_moved;
655   bool m_locate_in_progress; /* Simplified state variable for locate */
656   bool m_flag_change_triggered; /* We trigger a flagrequest change */
657 };
658 #endif // MAIL_H