a87209554d73c703d38327f6c3c7ac876a22f8f9
[gpgol.git] / src / mail.cpp
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
22 #include "config.h"
23 #include "dialogs.h"
24 #include "common.h"
25 #include "mail.h"
26 #include "eventsinks.h"
27 #include "attachment.h"
28 #include "mapihelp.h"
29 #include "message.h"
30 #include "revert.h"
31 #include "gpgoladdin.h"
32 #include "mymapitags.h"
33 #include "parsecontroller.h"
34 #include "gpgolstr.h"
35 #include "windowmessages.h"
36 #include "mlang-charset.h"
37
38 #include <gpgme++/tofuinfo.h>
39 #include <gpgme++/verificationresult.h>
40 #include <gpgme++/decryptionresult.h>
41 #include <gpgme++/key.h>
42 #include <gpgme++/context.h>
43 #include <gpgme++/keylistresult.h>
44 #include <gpg-error.h>
45
46 #include <map>
47 #include <set>
48 #include <vector>
49 #include <memory>
50
51
52 #undef _
53 #define _(a) utf8_gettext (a)
54
55 using namespace GpgME;
56
57 static std::map<LPDISPATCH, Mail*> g_mail_map;
58 static std::map<std::string, Mail*> g_uid_map;
59 static std::set<std::string> uids_searched;
60
61 #define COPYBUFSIZE (8 * 1024)
62
63 Mail::Mail (LPDISPATCH mailitem) :
64     m_mailitem(mailitem),
65     m_processed(false),
66     m_needs_wipe(false),
67     m_needs_save(false),
68     m_crypt_successful(false),
69     m_is_smime(false),
70     m_is_smime_checked(false),
71     m_is_signed(false),
72     m_is_valid(false),
73     m_close_triggered(false),
74     m_is_html_alternative(false),
75     m_needs_encrypt(false),
76     m_moss_position(0),
77     m_crypto_flags(0),
78     m_type(MSGTYPE_UNKNOWN)
79 {
80   if (get_mail_for_item (mailitem))
81     {
82       log_error ("Mail object for item: %p already exists. Bug.",
83                  mailitem);
84       return;
85     }
86
87   m_event_sink = install_MailItemEvents_sink (mailitem);
88   if (!m_event_sink)
89     {
90       /* Should not happen but in that case we don't add us to the list
91          and just release the Mail item. */
92       log_error ("%s:%s: Failed to install MailItemEvents sink.",
93                  SRCNAME, __func__);
94       gpgol_release(mailitem);
95       return;
96     }
97   g_mail_map.insert (std::pair<LPDISPATCH, Mail *> (mailitem, this));
98 }
99
100 GPGRT_LOCK_DEFINE(dtor_lock);
101
102 Mail::~Mail()
103 {
104   /* This should fix a race condition where the mail is
105      deleted before the parser is accessed in the decrypt
106      thread. The shared_ptr of the parser then ensures
107      that the parser is alive even if the mail is deleted
108      while parsing. */
109   gpgrt_lock_lock (&dtor_lock);
110   std::map<LPDISPATCH, Mail *>::iterator it;
111
112   detach_MailItemEvents_sink (m_event_sink);
113   gpgol_release(m_event_sink);
114
115   it = g_mail_map.find(m_mailitem);
116   if (it != g_mail_map.end())
117     {
118       g_mail_map.erase (it);
119     }
120
121   if (!m_uuid.empty())
122     {
123       auto it2 = g_uid_map.find(m_uuid);
124       if (it2 != g_uid_map.end())
125         {
126           g_uid_map.erase (it2);
127         }
128     }
129
130   gpgol_release(m_mailitem);
131   if (!m_uuid.empty())
132     {
133       log_oom_extra ("%s:%s: destroyed: %p uuid: %s",
134                      SRCNAME, __func__, this, m_uuid.c_str());
135     }
136   else
137     {
138       log_oom_extra ("%s:%s: non crypto mail: %p destroyed",
139                      SRCNAME, __func__, this);
140     }
141   gpgrt_lock_unlock (&dtor_lock);
142 }
143
144 Mail *
145 Mail::get_mail_for_item (LPDISPATCH mailitem)
146 {
147   if (!mailitem)
148     {
149       return NULL;
150     }
151   std::map<LPDISPATCH, Mail *>::iterator it;
152   it = g_mail_map.find(mailitem);
153   if (it == g_mail_map.end())
154     {
155       return NULL;
156     }
157   return it->second;
158 }
159
160 Mail *
161 Mail::get_mail_for_uuid (const char *uuid)
162 {
163   if (!uuid)
164     {
165       return NULL;
166     }
167   auto it = g_uid_map.find(std::string(uuid));
168   if (it == g_uid_map.end())
169     {
170       return NULL;
171     }
172   return it->second;
173 }
174
175 bool
176 Mail::is_valid_ptr (const Mail *mail)
177 {
178   auto it = g_mail_map.begin();
179   while (it != g_mail_map.end())
180     {
181       if (it->second == mail)
182         return true;
183       ++it;
184     }
185   return false;
186 }
187
188 int
189 Mail::pre_process_message ()
190 {
191   LPMESSAGE message = get_oom_base_message (m_mailitem);
192   if (!message)
193     {
194       log_error ("%s:%s: Failed to get base message.",
195                  SRCNAME, __func__);
196       return 0;
197     }
198   log_oom_extra ("%s:%s: GetBaseMessage OK.",
199                  SRCNAME, __func__);
200   /* Change the message class here. It is important that
201      we change the message class in the before read event
202      regardless if it is already set to one of GpgOL's message
203      classes. Changing the message class (even if we set it
204      to the same value again that it already has) causes
205      Outlook to reconsider what it "knows" about a message
206      and reread data from the underlying base message. */
207   mapi_change_message_class (message, 1);
208   /* TODO: Unify this so mapi_change_message_class returns
209      a useful value already. */
210   m_type = mapi_get_message_type (message);
211
212   /* Create moss attachments here so that they are properly
213      hidden when the item is read into the model. */
214   m_moss_position = mapi_mark_or_create_moss_attach (message, m_type);
215   if (!m_moss_position)
216     {
217       log_error ("%s:%s: Failed to find moss attachment.",
218                  SRCNAME, __func__);
219       m_type = MSGTYPE_UNKNOWN;
220     }
221
222   gpgol_release (message);
223   return 0;
224 }
225
226 static LPDISPATCH
227 get_attachment (LPDISPATCH mailitem, int pos)
228 {
229   LPDISPATCH attachment;
230   LPDISPATCH attachments = get_oom_object (mailitem, "Attachments");
231   if (!attachments)
232     {
233       log_debug ("%s:%s: Failed to get attachments.",
234                  SRCNAME, __func__);
235       return NULL;
236     }
237
238   std::string item_str;
239   int count = get_oom_int (attachments, "Count");
240   if (pos > 0)
241     {
242       item_str = std::string("Item(") + std::to_string(pos) + ")";
243     }
244   else
245     {
246       item_str = std::string("Item(") + std::to_string(count) + ")";
247     }
248   if (count < 1)
249     {
250       log_debug ("%s:%s: Invalid attachment count: %i.",
251                  SRCNAME, __func__, count);
252       gpgol_release (attachments);
253       return NULL;
254     }
255   attachment = get_oom_object (attachments, item_str.c_str());
256   gpgol_release (attachments);
257
258   return attachment;
259 }
260
261 /** Get the cipherstream of the mailitem. */
262 static LPSTREAM
263 get_attachment_stream (LPDISPATCH mailitem, int pos)
264 {
265   if (!pos)
266     {
267       log_debug ("%s:%s: Called with zero pos.",
268                  SRCNAME, __func__);
269       return NULL;
270     }
271   LPDISPATCH attachment = get_attachment (mailitem, pos);
272   LPATTACH mapi_attachment = NULL;
273   LPSTREAM stream = NULL;
274
275   mapi_attachment = (LPATTACH) get_oom_iunknown (attachment,
276                                                  "MapiObject");
277   gpgol_release (attachment);
278   if (!mapi_attachment)
279     {
280       log_debug ("%s:%s: Failed to get MapiObject of attachment: %p",
281                  SRCNAME, __func__, attachment);
282       return NULL;
283     }
284   if (FAILED (mapi_attachment->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream,
285                                              0, MAPI_MODIFY, (LPUNKNOWN*) &stream)))
286     {
287       log_debug ("%s:%s: Failed to open stream for mapi_attachment: %p",
288                  SRCNAME, __func__, mapi_attachment);
289       gpgol_release (mapi_attachment);
290     }
291   return stream;
292 }
293
294 #if 0
295
296 This should work. But Outlook says no. See the comment in set_pa_variant
297 about this. I left the code here as an example how to work with
298 safearrays and how this probably should work.
299
300 static int
301 copy_data_property(LPDISPATCH target, std::shared_ptr<Attachment> attach)
302 {
303   VARIANT var;
304   VariantInit (&var);
305
306   /* Get the size */
307   off_t size = attach->get_data ().seek (0, SEEK_END);
308   attach->get_data ().seek (0, SEEK_SET);
309
310   if (!size)
311     {
312       TRACEPOINT;
313       return 1;
314     }
315
316   if (!get_pa_variant (target, PR_ATTACH_DATA_BIN_DASL, &var))
317     {
318       log_debug("Have variant. type: %x", var.vt);
319     }
320   else
321     {
322       log_debug("failed to get variant.");
323     }
324
325   /* Set the type to an array of unsigned chars (OLE SAFEARRAY) */
326   var.vt = VT_ARRAY | VT_UI1;
327
328   /* Set up the bounds structure */
329   SAFEARRAYBOUND rgsabound[1];
330   rgsabound[0].cElements = static_cast<unsigned long> (size);
331   rgsabound[0].lLbound = 0;
332
333   /* Create an OLE SAFEARRAY */
334   var.parray = SafeArrayCreate (VT_UI1, 1, rgsabound);
335   if (var.parray == NULL)
336     {
337       TRACEPOINT;
338       VariantClear(&var);
339       return 1;
340     }
341
342   void *buffer = NULL;
343   /* Get a safe pointer to the array */
344   if (SafeArrayAccessData(var.parray, &buffer) != S_OK)
345     {
346       TRACEPOINT;
347       VariantClear(&var);
348       return 1;
349     }
350
351   /* Copy data to it */
352   size_t nread = attach->get_data ().read (buffer, static_cast<size_t> (size));
353
354   if (nread != static_cast<size_t> (size))
355     {
356       TRACEPOINT;
357       VariantClear(&var);
358       return 1;
359     }
360
361   /*/ Unlock the variant data */
362   if (SafeArrayUnaccessData(var.parray) != S_OK)
363     {
364       TRACEPOINT;
365       VariantClear(&var);
366       return 1;
367     }
368
369   if (set_pa_variant (target, PR_ATTACH_DATA_BIN_DASL, &var))
370     {
371       TRACEPOINT;
372       VariantClear(&var);
373       return 1;
374     }
375
376   VariantClear(&var);
377   return 0;
378 }
379 #endif
380
381 static int
382 copy_attachment_to_file (std::shared_ptr<Attachment> att, HANDLE hFile)
383 {
384   char copybuf[COPYBUFSIZE];
385   size_t nread;
386
387   /* Security considerations: Writing the data to a temporary
388      file is necessary as neither MAPI manipulation works in the
389      read event to transmit the data nor Property Accessor
390      works (see above). From a security standpoint there is a
391      short time where the temporary files are on disk. Tempdir
392      should be protected so that only the user can read it. Thus
393      we have a local attack that could also take the data out
394      of Outlook. FILE_SHARE_READ is necessary so that outlook
395      can read the file.
396
397      A bigger concern is that the file is manipulated
398      by another software to fake the signature state. So
399      we keep the write exlusive to us.
400
401      We delete the file before closing the write file handle.
402   */
403
404   /* Make sure we start at the beginning */
405   att->get_data ().seek (0, SEEK_SET);
406   while ((nread = att->get_data ().read (copybuf, COPYBUFSIZE)))
407     {
408       DWORD nwritten;
409       if (!WriteFile (hFile, copybuf, nread, &nwritten, NULL))
410         {
411           log_error ("%s:%s: Failed to write in tmp attachment.",
412                      SRCNAME, __func__);
413           return 1;
414         }
415       if (nread != nwritten)
416         {
417           log_error ("%s:%s: Write truncated.",
418                      SRCNAME, __func__);
419           return 1;
420         }
421     }
422   return 0;
423 }
424
425 /** Sets some meta data on the last attachment atted. The meta
426   data is taken from the attachment object. */
427 static int
428 fixup_last_attachment (LPDISPATCH mail, std::shared_ptr<Attachment> attachment)
429 {
430   /* Currently we only set content id */
431   if (attachment->get_content_id ().empty())
432     {
433       log_debug ("%s:%s: Content id not found.",
434                  SRCNAME, __func__);
435       return 0;
436     }
437
438   LPDISPATCH attach = get_attachment (mail, -1);
439   if (!attach)
440     {
441       log_error ("%s:%s: No attachment.",
442                  SRCNAME, __func__);
443       return 1;
444     }
445   int ret = put_pa_string (attach,
446                            PR_ATTACH_CONTENT_ID_DASL,
447                            attachment->get_content_id ().c_str());
448   gpgol_release (attach);
449   return ret;
450 }
451
452 /** Helper to update the attachments of a mail object in oom.
453   does not modify the underlying mapi structure. */
454 static int
455 add_attachments(LPDISPATCH mail,
456                 std::vector<std::shared_ptr<Attachment> > attachments)
457 {
458   int err = 0;
459   for (auto att: attachments)
460     {
461       if (att->get_display_name().empty())
462         {
463           log_error ("%s:%s: Ignoring attachment without display name.",
464                      SRCNAME, __func__);
465           continue;
466         }
467       wchar_t* wchar_name = utf8_to_wchar (att->get_display_name().c_str());
468       HANDLE hFile;
469       wchar_t* wchar_file = get_tmp_outfile (GpgOLStr (att->get_display_name().c_str()),
470                                              &hFile);
471       if (copy_attachment_to_file (att, hFile))
472         {
473           log_error ("%s:%s: Failed to copy attachment %s to temp file",
474                      SRCNAME, __func__, att->get_display_name().c_str());
475           err = 1;
476         }
477       if (add_oom_attachment (mail, wchar_file, wchar_name))
478         {
479           log_error ("%s:%s: Failed to add attachment: %s",
480                      SRCNAME, __func__, att->get_display_name().c_str());
481           err = 1;
482         }
483       if (!DeleteFileW (wchar_file))
484         {
485           log_error ("%s:%s: Failed to delete tmp attachment for: %s",
486                      SRCNAME, __func__, att->get_display_name().c_str());
487           err = 1;
488         }
489       xfree (wchar_file);
490       xfree (wchar_name);
491
492       err = fixup_last_attachment (mail, att);
493     }
494   return err;
495 }
496
497 GPGRT_LOCK_DEFINE(parser_lock);
498
499 static DWORD WINAPI
500 do_parsing (LPVOID arg)
501 {
502   gpgrt_lock_lock (&dtor_lock);
503   /* We lock with mail dtors so we can be sure the mail->parser
504      call is valid. */
505   Mail *mail = (Mail *)arg;
506   if (!Mail::is_valid_ptr (mail))
507     {
508       log_debug ("%s:%s: canceling parsing for: %p already deleted",
509                  SRCNAME, __func__, arg);
510       gpgrt_lock_unlock (&dtor_lock);
511       return 0;
512     }
513   /* This takes a shared ptr of parser. So the parser is
514      still valid when the mail is deleted. */
515   auto parser = mail->parser();
516   gpgrt_lock_unlock (&dtor_lock);
517
518   gpgrt_lock_lock (&parser_lock);
519   /* We lock the parser here to avoid too many
520      decryption attempts if there are
521      multiple mailobjects which might have already
522      been deleted (e.g. by quick switches of the mailview.)
523      Let's rather be a bit slower.
524      */
525   log_debug ("%s:%s: preparing the parser for: %p",
526              SRCNAME, __func__, arg);
527
528   if (!parser)
529     {
530       log_error ("%s:%s: no parser found for mail: %p",
531                  SRCNAME, __func__, arg);
532       gpgrt_lock_unlock (&parser_lock);
533       return -1;
534     }
535   parser->parse();
536   do_in_ui_thread (PARSING_DONE, arg);
537   gpgrt_lock_unlock (&parser_lock);
538   return 0;
539 }
540
541 bool
542 Mail::is_crypto_mail() const
543 {
544   if (m_type == MSGTYPE_UNKNOWN || m_type == MSGTYPE_GPGOL ||
545       m_type == MSGTYPE_SMIME)
546     {
547       /* Not a message for us. */
548       return false;
549     }
550   return true;
551 }
552
553 int
554 Mail::decrypt_verify()
555 {
556   if (!is_crypto_mail())
557     {
558       return 0;
559     }
560   if (m_needs_wipe)
561     {
562       log_error ("%s:%s: Decrypt verify called for msg that needs wipe: %p",
563                  SRCNAME, __func__, m_mailitem);
564       return 1;
565     }
566   set_uuid ();
567   m_processed = true;
568   /* Insert placeholder */
569   char *placeholder_buf;
570   if (gpgrt_asprintf (&placeholder_buf, opt.prefer_html ? decrypt_template_html :
571                       decrypt_template,
572                       is_smime() ? "S/MIME" : "OpenPGP",
573                       _("Encrypted message"),
574                       _("Please wait while the message is being decrypted / verified...")) == -1)
575     {
576       log_error ("%s:%s: Failed to format placeholder.",
577                  SRCNAME, __func__);
578       return 1;
579     }
580
581   if (opt.prefer_html)
582     {
583       if (put_oom_string (m_mailitem, "HTMLBody", placeholder_buf))
584         {
585           log_error ("%s:%s: Failed to modify html body of item.",
586                      SRCNAME, __func__);
587         }
588     }
589   else
590     {
591       if (put_oom_string (m_mailitem, "Body", placeholder_buf))
592         {
593           log_error ("%s:%s: Failed to modify body of item.",
594                      SRCNAME, __func__);
595         }
596     }
597   xfree (placeholder_buf);
598
599   /* Do the actual parsing */
600   auto cipherstream = get_attachment_stream (m_mailitem, m_moss_position);
601
602   if (!cipherstream)
603     {
604       log_debug ("%s:%s: Failed to get cipherstream.",
605                  SRCNAME, __func__);
606       return 1;
607     }
608
609   m_parser = std::shared_ptr <ParseController> (new ParseController (cipherstream, m_type));
610   gpgol_release (cipherstream);
611
612   HANDLE parser_thread = CreateThread (NULL, 0, do_parsing, (LPVOID) this, 0,
613                                        NULL);
614
615   if (!parser_thread)
616     {
617       log_error ("%s:%s: Failed to create decrypt / verify thread.",
618                  SRCNAME, __func__);
619     }
620   CloseHandle (parser_thread);
621
622   return 0;
623 }
624
625 void
626 Mail::update_body()
627 {
628   const auto error = m_parser->get_formatted_error ();
629   if (!error.empty())
630     {
631       if (opt.prefer_html)
632         {
633           if (put_oom_string (m_mailitem, "HTMLBody",
634                               error.c_str ()))
635             {
636               log_error ("%s:%s: Failed to modify html body of item.",
637                          SRCNAME, __func__);
638             }
639         }
640       else
641         {
642           if (put_oom_string (m_mailitem, "Body",
643                               error.c_str ()))
644             {
645               log_error ("%s:%s: Failed to modify html body of item.",
646                          SRCNAME, __func__);
647             }
648         }
649       return;
650     }
651   const auto html = m_parser->get_html_body();
652   if (opt.prefer_html && !html.empty())
653     {
654       char *converted = ansi_charset_to_utf8 (m_parser->get_html_charset().c_str(),
655                                               html.c_str(), html.size());
656       int ret = put_oom_string (m_mailitem, "HTMLBody", converted ? converted : "");
657       xfree (converted);
658       if (ret)
659         {
660           log_error ("%s:%s: Failed to modify html body of item.",
661                      SRCNAME, __func__);
662         }
663       return;
664     }
665   const auto body = m_parser->get_body();
666   char *converted = ansi_charset_to_utf8 (m_parser->get_body_charset().c_str(),
667                                           body.c_str(), body.size());
668   int ret = put_oom_string (m_mailitem, "Body", converted ? converted : "");
669   xfree (converted);
670   if (ret)
671     {
672       log_error ("%s:%s: Failed to modify body of item.",
673                  SRCNAME, __func__);
674     }
675   return;
676 }
677
678 void
679 Mail::parsing_done()
680 {
681   TRACEPOINT;
682   log_oom_extra ("Mail %p Parsing done for parser: %p",
683                  this, m_parser.get());
684   if (!m_parser)
685     {
686       /* This should not happen but it happens when outlook
687          sends multiple ItemLoad events for the same Mail
688          Object. In that case it could happen that one
689          parser was already done while a second is now
690          returning for the wrong mail (as it's looked up
691          by uuid.)
692
693          We have a check in get_uuid that the uuid was
694          not in the map before (and the parser is replaced).
695          So this really really should not happen. We
696          handle it anyway as we crash otherwise.
697
698          It should not happen because the parser is only
699          created in decrypt_verify which is called in the
700          read event. And even in there we check if the parser
701          was set.
702          */
703       log_error ("%s:%s: No parser obj. For mail: %p",
704                  SRCNAME, __func__, this);
705       return;
706     }
707   /* Store the results. */
708   m_decrypt_result = m_parser->decrypt_result ();
709   m_verify_result = m_parser->verify_result ();
710
711   m_crypto_flags = 0;
712   if (m_decrypt_result.numRecipients())
713     {
714       m_crypto_flags |= 1;
715     }
716   if (m_verify_result.numSignatures())
717     {
718       m_crypto_flags |= 2;
719     }
720
721   update_sigstate ();
722   m_needs_wipe = true;
723
724   TRACEPOINT;
725   /* Set categories according to the result. */
726   update_categories();
727
728   TRACEPOINT;
729   /* Update the body */
730   update_body();
731   TRACEPOINT;
732
733   /* Update attachments */
734   if (add_attachments (m_mailitem, m_parser->get_attachments()))
735     {
736       log_error ("%s:%s: Failed to update attachments.",
737                  SRCNAME, __func__);
738     }
739
740   /* Invalidate UI to set the correct sig status. */
741   m_parser = nullptr;
742   gpgoladdin_invalidate_ui ();
743   TRACEPOINT;
744   return;
745 }
746
747 int
748 Mail::encrypt_sign ()
749 {
750   int err = -1,
751       flags = 0;
752   protocol_t proto = opt.enable_smime ? PROTOCOL_UNKNOWN : PROTOCOL_OPENPGP;
753   if (!needs_crypto())
754     {
755       return 0;
756     }
757   LPMESSAGE message = get_oom_base_message (m_mailitem);
758   if (!message)
759     {
760       log_error ("%s:%s: Failed to get base message.",
761                  SRCNAME, __func__);
762       return err;
763     }
764   flags = get_gpgol_draft_info_flags (message);
765   if (flags == 3)
766     {
767       log_debug ("%s:%s: Sign / Encrypting message",
768                  SRCNAME, __func__);
769       err = message_sign_encrypt (message, proto,
770                                   NULL, get_sender ().c_str (), this);
771     }
772   else if (flags == 2)
773     {
774       err = message_sign (message, proto,
775                           NULL, get_sender ().c_str (), this);
776     }
777   else if (flags == 1)
778     {
779       err = message_encrypt (message, proto,
780                              NULL, get_sender ().c_str (), this);
781     }
782   else
783     {
784       log_debug ("%s:%s: Unknown flags for crypto: %i",
785                  SRCNAME, __func__, flags);
786     }
787   log_debug ("%s:%s: Status: %i",
788              SRCNAME, __func__, err);
789   gpgol_release (message);
790   m_crypt_successful = !err;
791   return err;
792 }
793
794 int
795 Mail::needs_crypto ()
796 {
797   LPMESSAGE message = get_oom_message (m_mailitem);
798   bool ret;
799   if (!message)
800     {
801       log_error ("%s:%s: Failed to get message.",
802                  SRCNAME, __func__);
803       return false;
804     }
805   ret = get_gpgol_draft_info_flags (message);
806   gpgol_release(message);
807   return ret;
808 }
809
810 int
811 Mail::wipe ()
812 {
813   if (!m_needs_wipe)
814     {
815       return 0;
816     }
817   log_debug ("%s:%s: Removing plaintext from mailitem: %p.",
818              SRCNAME, __func__, m_mailitem);
819   if (put_oom_string (m_mailitem, "HTMLBody",
820                       ""))
821     {
822       if (put_oom_string (m_mailitem, "Body",
823                           ""))
824         {
825           log_debug ("%s:%s: Failed to wipe mailitem: %p.",
826                      SRCNAME, __func__, m_mailitem);
827           return -1;
828         }
829       return -1;
830     }
831   m_needs_wipe = false;
832   return 0;
833 }
834
835 int
836 Mail::update_oom_data ()
837 {
838   LPDISPATCH sender = NULL;
839   log_debug ("%s:%s", SRCNAME, __func__);
840
841   /* Update the body format. */
842   m_is_html_alternative = get_oom_int (m_mailitem, "BodyFormat") > 1;
843
844   /* Store the body. It was not obvious for me (aheinecke) how
845      to access this through MAPI. */
846   m_html_body = get_oom_string (m_mailitem, "HTMLBody");
847
848   /* For some reason outlook may store the recipient address
849      in the send using account field. If we have SMTP we prefer
850      the SenderEmailAddress string. */
851
852   if (is_crypto_mail ())
853     {
854       /* This is the case where we are reading a mail and not composing.
855          When composing we need to use the SendUsingAccount because if
856          you send from the folder of userA but change the from to userB
857          outlook will keep the SenderEmailAddress of UserA. This is all
858          so horrible. */
859       char *type = get_oom_string (m_mailitem, "SenderEmailType");
860       if (type && !strcmp ("SMTP", type))
861         {
862           char *senderMail = get_oom_string (m_mailitem, "SenderEmailAddress");
863           if (senderMail)
864             {
865               m_sender = senderMail;
866               xfree (senderMail);
867               xfree (type);
868               return 0;
869             }
870         }
871       xfree (type);
872     }
873   sender = get_oom_object (m_mailitem, "SendUsingAccount");
874   if (sender)
875     {
876       char *buf = get_oom_string (sender, "SmtpAddress");
877       m_sender = buf;
878       xfree (buf);
879       gpgol_release (sender);
880       return 0;
881     }
882   /* Fallback to Sender object */
883   sender = get_oom_object (m_mailitem, "Sender");
884   if (sender)
885     {
886       char *buf = get_pa_string (sender, PR_SMTP_ADDRESS_DASL);
887       m_sender = buf;
888       xfree (buf);
889       gpgol_release (sender);
890       return 0;
891     }
892   /* We don't have s sender object or SendUsingAccount,
893      well, in that case fall back to the current user. */
894   sender = get_oom_object (m_mailitem, "Session.CurrentUser");
895   if (sender)
896     {
897       char *buf = get_pa_string (sender, PR_SMTP_ADDRESS_DASL);
898       m_sender = buf;
899       xfree (buf);
900       gpgol_release (sender);
901       return 0;
902     }
903
904   log_debug ("%s:%s: All fallbacks failed.",
905              SRCNAME, __func__);
906   return -1;
907 }
908
909 std::string
910 Mail::get_sender ()
911 {
912   if (m_sender.empty())
913     update_oom_data();
914   return m_sender;
915 }
916
917 int
918 Mail::close_all_mails ()
919 {
920   int err = 0;
921   std::map<LPDISPATCH, Mail *>::iterator it;
922   TRACEPOINT;
923   std::map<LPDISPATCH, Mail *> mail_map_copy = g_mail_map;
924   for (it = mail_map_copy.begin(); it != mail_map_copy.end(); ++it)
925     {
926       if (!it->second->is_crypto_mail())
927         {
928           continue;
929         }
930       if (close_inspector (it->second) || close (it->second))
931         {
932           log_error ("Failed to close mail: %p ", it->first);
933           /* Should not happen */
934           if (is_valid_ptr (it->second) && it->second->revert())
935             {
936               err++;
937             }
938         }
939     }
940   return err;
941 }
942 int
943 Mail::revert_all_mails ()
944 {
945   int err = 0;
946   std::map<LPDISPATCH, Mail *>::iterator it;
947   for (it = g_mail_map.begin(); it != g_mail_map.end(); ++it)
948     {
949       if (it->second->revert ())
950         {
951           log_error ("Failed to revert mail: %p ", it->first);
952           err++;
953           continue;
954         }
955
956       it->second->set_needs_save (true);
957       if (!invoke_oom_method (it->first, "Save", NULL))
958         {
959           log_error ("Failed to save reverted mail: %p ", it->second);
960           err++;
961           continue;
962         }
963     }
964   return err;
965 }
966
967 int
968 Mail::wipe_all_mails ()
969 {
970   int err = 0;
971   std::map<LPDISPATCH, Mail *>::iterator it;
972   for (it = g_mail_map.begin(); it != g_mail_map.end(); ++it)
973     {
974       if (it->second->wipe ())
975         {
976           log_error ("Failed to wipe mail: %p ", it->first);
977           err++;
978         }
979     }
980   return err;
981 }
982
983 int
984 Mail::revert ()
985 {
986   int err = 0;
987   if (!m_processed)
988     {
989       return 0;
990     }
991
992   err = gpgol_mailitem_revert (m_mailitem);
993   if (err == -1)
994     {
995       log_error ("%s:%s: Message revert failed falling back to wipe.",
996                  SRCNAME, __func__);
997       return wipe ();
998     }
999   /* We need to reprocess the mail next time around. */
1000   m_processed = false;
1001   m_needs_wipe = false;
1002   return 0;
1003 }
1004
1005 bool
1006 Mail::is_smime ()
1007 {
1008   msgtype_t msgtype;
1009   LPMESSAGE message;
1010
1011   if (m_is_smime_checked)
1012     {
1013       return m_is_smime;
1014     }
1015
1016   message = get_oom_message (m_mailitem);
1017
1018   if (!message)
1019     {
1020       log_error ("%s:%s: No message?",
1021                  SRCNAME, __func__);
1022       return false;
1023     }
1024
1025   msgtype = mapi_get_message_type (message);
1026   m_is_smime = msgtype == MSGTYPE_GPGOL_OPAQUE_ENCRYPTED ||
1027                msgtype == MSGTYPE_GPGOL_OPAQUE_SIGNED;
1028
1029   /* Check if it is an smime mail. Multipart signed can
1030      also be true. */
1031   if (!m_is_smime && msgtype == MSGTYPE_GPGOL_MULTIPART_SIGNED)
1032     {
1033       char *proto;
1034       char *ct = mapi_get_message_content_type (message, &proto, NULL);
1035       if (ct && proto)
1036         {
1037           m_is_smime = (!strcmp (proto, "application/pkcs7-signature") ||
1038                         !strcmp (proto, "application/x-pkcs7-signature"));
1039         }
1040       else
1041         {
1042           log_error ("Protocol in multipart signed mail.");
1043         }
1044       xfree (proto);
1045       xfree (ct);
1046     }
1047   gpgol_release (message);
1048   m_is_smime_checked  = true;
1049   return m_is_smime;
1050 }
1051
1052 static std::string
1053 get_string (LPDISPATCH item, const char *str)
1054 {
1055   char *buf = get_oom_string (item, str);
1056   if (!buf)
1057     return std::string();
1058   std::string ret = buf;
1059   xfree (buf);
1060   return ret;
1061 }
1062
1063 std::string
1064 Mail::get_subject() const
1065 {
1066   return get_string (m_mailitem, "Subject");
1067 }
1068
1069 std::string
1070 Mail::get_body() const
1071 {
1072   return get_string (m_mailitem, "Body");
1073 }
1074
1075 std::string
1076 Mail::get_html_body() const
1077 {
1078   return get_string (m_mailitem, "HTMLBody");
1079 }
1080
1081 char **
1082 Mail::get_recipients() const
1083 {
1084   LPDISPATCH recipients = get_oom_object (m_mailitem, "Recipients");
1085   if (!recipients)
1086     {
1087       TRACEPOINT;
1088       return nullptr;
1089     }
1090   return get_oom_recipients (recipients);
1091 }
1092
1093 int
1094 Mail::close_inspector (Mail *mail)
1095 {
1096   LPDISPATCH inspector = get_oom_object (mail->item(), "GetInspector");
1097   HRESULT hr;
1098   DISPID dispid;
1099   if (!inspector)
1100     {
1101       log_debug ("%s:%s: No inspector.",
1102                  SRCNAME, __func__);
1103       return -1;
1104     }
1105
1106   dispid = lookup_oom_dispid (inspector, "Close");
1107   if (dispid != DISPID_UNKNOWN)
1108     {
1109       VARIANT aVariant[1];
1110       DISPPARAMS dispparams;
1111
1112       dispparams.rgvarg = aVariant;
1113       dispparams.rgvarg[0].vt = VT_INT;
1114       dispparams.rgvarg[0].intVal = 1;
1115       dispparams.cArgs = 1;
1116       dispparams.cNamedArgs = 0;
1117
1118       hr = inspector->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
1119                               DISPATCH_METHOD, &dispparams,
1120                               NULL, NULL, NULL);
1121       if (hr != S_OK)
1122         {
1123           log_debug ("%s:%s: Failed to close inspector: %#lx",
1124                      SRCNAME, __func__, hr);
1125           return -1;
1126         }
1127     }
1128   return 0;
1129 }
1130
1131 /* static */
1132 int
1133 Mail::close (Mail *mail)
1134 {
1135   VARIANT aVariant[1];
1136   DISPPARAMS dispparams;
1137
1138   dispparams.rgvarg = aVariant;
1139   dispparams.rgvarg[0].vt = VT_INT;
1140   dispparams.rgvarg[0].intVal = 1;
1141   dispparams.cArgs = 1;
1142   dispparams.cNamedArgs = 0;
1143
1144   log_oom_extra ("%s:%s: Invoking close for: %p",
1145                  SRCNAME, __func__, mail->item());
1146   mail->set_close_triggered (true);
1147   int rc = invoke_oom_method_with_parms (mail->item(), "Close",
1148                                        NULL, &dispparams);
1149
1150   log_debug ("returned from invoke");
1151   return rc;
1152 }
1153
1154 void
1155 Mail::set_close_triggered (bool value)
1156 {
1157   m_close_triggered = value;
1158 }
1159
1160 bool
1161 Mail::get_close_triggered () const
1162 {
1163   return m_close_triggered;
1164 }
1165
1166 static const UserID
1167 get_uid_for_sender (const Key k, const char *sender)
1168 {
1169   UserID ret;
1170
1171   if (!sender)
1172     {
1173       return ret;
1174     }
1175
1176   if (!k.numUserIDs())
1177     {
1178       log_debug ("%s:%s: Key without uids",
1179                  SRCNAME, __func__);
1180       return ret;
1181     }
1182
1183   for (const auto uid: k.userIDs())
1184     {
1185       if (!uid.email())
1186         {
1187           log_error ("%s:%s: skipping uid without email.",
1188                      SRCNAME, __func__);
1189           continue;
1190         }
1191       auto normalized_uid = uid.addrSpec();
1192       auto normalized_sender = UserID::addrSpecFromString(sender);
1193
1194       if (normalized_sender.empty() || normalized_uid.empty())
1195         {
1196           log_error ("%s:%s: normalizing '%s' or '%s' failed.",
1197                      SRCNAME, __func__, uid.email(), sender);
1198           continue;
1199         }
1200       if (normalized_sender == normalized_uid)
1201         {
1202           ret = uid;
1203         }
1204     }
1205   return ret;
1206 }
1207
1208 void
1209 Mail::update_sigstate ()
1210 {
1211   std::string sender = get_sender();
1212
1213   if (sender.empty())
1214     {
1215       log_error ("%s:%s:%i", SRCNAME, __func__, __LINE__);
1216       return;
1217     }
1218
1219   if (m_verify_result.isNull())
1220     {
1221       log_debug ("%s:%s: No verify result.",
1222                  SRCNAME, __func__);
1223       return;
1224     }
1225
1226   if (m_verify_result.error())
1227     {
1228       log_debug ("%s:%s: verify error.",
1229                  SRCNAME, __func__);
1230       return;
1231     }
1232
1233   for (const auto sig: m_verify_result.signatures())
1234     {
1235       m_is_signed = true;
1236       m_uid = get_uid_for_sender (sig.key(), sender.c_str());
1237       if (!m_uid.isNull() && sig.validity() != Signature::Validity::Marginal &&
1238           sig.validity() != Signature::Validity::Full &&
1239           sig.validity() != Signature::Validity::Ultimate)
1240         {
1241           /* For our category we only care about trusted sigs. And
1242           the UID needs to match.*/
1243           continue;
1244         }
1245       if (sig.validity() == Signature::Validity::Marginal)
1246         {
1247           const auto tofu = m_uid.tofuInfo();
1248           if (tofu.isNull() ||
1249               (tofu.validity() != TofuInfo::Validity::BasicHistory &&
1250                tofu.validity() != TofuInfo::Validity::LargeHistory))
1251             {
1252               /* Marginal is not good enough without tofu.
1253                  We also wait for basic trust. */
1254               log_debug ("%s:%s: Discarding marginal signature."
1255                          "With too little history.",
1256                          SRCNAME, __func__);
1257               continue;
1258             }
1259         }
1260       log_debug ("%s:%s: Classified sender as verified",
1261                  SRCNAME, __func__);
1262       m_sig = sig;
1263       m_is_valid = true;
1264       return;
1265     }
1266
1267   log_debug ("%s:%s: No signature with enough trust. Using first",
1268              SRCNAME, __func__);
1269   m_sig = m_verify_result.signature(0);
1270   return;
1271 }
1272
1273 bool
1274 Mail::is_valid_sig ()
1275 {
1276    return m_is_valid;
1277 }
1278
1279 void
1280 Mail::remove_categories ()
1281 {
1282   const char *decCategory = _("GpgOL: Encrypted Message");
1283   const char *verifyCategory = _("GpgOL: Trusted Sender Address");
1284   remove_category (m_mailitem, decCategory);
1285   remove_category (m_mailitem, verifyCategory);
1286 }
1287
1288 void
1289 Mail::update_categories ()
1290 {
1291   const char *decCategory = _("GpgOL: Encrypted Message");
1292   const char *verifyCategory = _("GpgOL: Trusted Sender Address");
1293   if (m_decrypt_result.numRecipients())
1294     {
1295       /* We use the number of recipients as we don't care
1296          if decryption was successful or not for this category */
1297       add_category (m_mailitem, decCategory);
1298     }
1299   else
1300     {
1301       /* As a small safeguard against fakes we remove our
1302          categories */
1303       remove_category (m_mailitem, decCategory);
1304     }
1305
1306   if (is_valid_sig())
1307     {
1308       add_category (m_mailitem, verifyCategory);
1309     }
1310   else
1311     {
1312       remove_category (m_mailitem, verifyCategory);
1313     }
1314   return;
1315 }
1316
1317 bool
1318 Mail::is_signed() const
1319 {
1320   return m_verify_result.numSignatures() > 0;
1321 }
1322
1323 bool
1324 Mail::is_encrypted() const
1325 {
1326   return m_decrypt_result.numRecipients() > 0;
1327 }
1328
1329 int
1330 Mail::set_uuid()
1331 {
1332   char *uuid;
1333   if (!m_uuid.empty())
1334     {
1335       /* This codepath is reached by decrypt again after a
1336          close with discard changes. The close discarded
1337          the uuid on the OOM object so we have to set
1338          it again. */
1339       log_debug ("%s:%s: Resetting uuid for %p to %s",
1340                  SRCNAME, __func__, this,
1341                  m_uuid.c_str());
1342       uuid = get_unique_id (m_mailitem, 1, m_uuid.c_str());
1343     }
1344   else
1345     {
1346       uuid = get_unique_id (m_mailitem, 1, nullptr);
1347       log_debug ("%s:%s: uuid for %p set to %s",
1348                  SRCNAME, __func__, this, uuid);
1349     }
1350
1351   if (!uuid)
1352     {
1353       log_debug ("%s:%s: Failed to get/set uuid for %p",
1354                  SRCNAME, __func__, m_mailitem);
1355       return -1;
1356     }
1357   if (m_uuid.empty())
1358     {
1359       m_uuid = uuid;
1360       Mail *other = get_mail_for_uuid (uuid);
1361       if (other)
1362         {
1363           /* According to documentation this should not
1364              happen as this means that multiple ItemLoad
1365              events occured for the same mailobject without
1366              unload / destruction of the mail.
1367
1368              But it happens. If you invalidate the UI
1369              in the selection change event Outlook loads a
1370              new mailobject for the mail. Might happen in
1371              other surprising cases. We replace in that
1372              case as experiments have shown that the last
1373              mailobject is the one that is visible.
1374
1375              Still troubling state so we log this as an error.
1376              */
1377           log_error ("%s:%s: There is another mail for %p "
1378                      "with uuid: %s replacing it.",
1379                      SRCNAME, __func__, m_mailitem, uuid);
1380           delete other;
1381         }
1382       g_uid_map.insert (std::pair<std::string, Mail *> (m_uuid, this));
1383       log_debug ("%s:%s: uuid for %p is now %s",
1384                  SRCNAME, __func__, this,
1385                  m_uuid.c_str());
1386     }
1387   xfree (uuid);
1388   return 0;
1389 }
1390
1391 /* Returns -1 if the mail was signed by a uid with ownertrust
1392    ultimate and to which we have the secret key.
1393    This basically means "mail was signed by yourself"
1394
1395    Returns the number of the signature fromt the uid that belongs
1396    made it ultimately or fully trusted if the mail was signed by some
1397    ultimate key for which we don't have the secret key.
1398    This is direct trust or CA Style PGP.
1399
1400    0 otherwise */
1401 static int
1402 level_4_check (const UserID &uid)
1403 {
1404   if (uid.validity() == UserID::Validity::Ultimate)
1405     {
1406       /* TODO look for the signature that caused this
1407          to be ultimate. And check if it is our own. */
1408       return -1;
1409     }
1410   else if (uid.validity() == UserID::Validity::Full)
1411     {
1412       return 1;
1413     }
1414   return 0;
1415 }
1416
1417 std::string
1418 Mail::get_crypto_summary ()
1419 {
1420   const int level = get_signature_level ();
1421
1422   bool enc = is_encrypted ();
1423   if (level > 3 && enc)
1424     {
1425       return _("Highly Secure");
1426     }
1427   if (level > 3)
1428     {
1429       return _("Highly Trustworthy");
1430     }
1431   if (level >= 2 && enc)
1432     {
1433       return _("Secure");
1434     }
1435   if (level >= 2)
1436     {
1437       return _("Trustworthy");
1438     }
1439   if (enc)
1440     {
1441       return _("Encrypted");
1442     }
1443   if (is_signed ())
1444     {
1445       return _("Signed");
1446     }
1447   return _("Insecure");
1448 }
1449
1450 std::string
1451 Mail::get_crypto_details()
1452 {
1453   /* Handle encrypt only */
1454   if (!is_encrypted () && !is_signed ())
1455     {
1456       return _("You cannot be sure who sent, "
1457                "modified and read the message in transit.");
1458     }
1459   else if (is_encrypted() && !is_signed ())
1460     {
1461       return _("You cannot be sure who sent the message as "
1462                "it is not signed.");
1463     }
1464
1465   std::string message;
1466
1467   bool keyFound = true;
1468   bool isOpenPGP = m_sig.key().protocol() == Protocol::OpenPGP;
1469   char *buf;
1470   bool hasConflict = false;
1471   int level = get_signature_level ();
1472
1473   log_debug ("%s:%s: Formatting sig. Validity: %x Summary: %x Level: %i",
1474              SRCNAME, __func__, m_sig.validity(), m_sig.summary(),
1475              level);
1476
1477   if (level == 4)
1478     {
1479       /* level 4 check for direct trust */
1480       int four_check = level_4_check (m_uid);
1481
1482       if (four_check == -1)
1483         {
1484           message = _("And you signed this message.");
1485         }
1486       else if (four_check >= 0)
1487         {
1488           /* TODO
1489             And you certified the identity of the sender.
1490             And <uid with ultimate trust> certified the identity
1491             of the sender.
1492           */
1493         }
1494       else
1495         {
1496           log_error ("%s:%s:%i BUG: Invalid sigstate.",
1497                      SRCNAME, __func__, __LINE__);
1498           return message;
1499         }
1500     }
1501   else if (level == 3 && isOpenPGP)
1502     {
1503       /* Level three is only reachable through web of trust and no
1504          direct signature. */
1505       message = _("And the senders identity was certified by several trusted people.");
1506     }
1507   else if (level == 3 && !isOpenPGP)
1508     {
1509       /* Level three is the only level for trusted S/MIME keys. */
1510       gpgrt_asprintf (&buf, _("And the senders identity is cerified by the trusted issuer:\n'%s'\n"),
1511                       m_sig.key().issuerName());
1512       message = buf;
1513       xfree (buf);
1514     }
1515   else if (level == 2)
1516     {
1517       /* Only reachable through TOFU Trust. */
1518       if (m_uid.tofuInfo ().isNull ())
1519         {
1520           log_error ("%s:%s:%i BUG: Invalid sigstate.",
1521                      SRCNAME, __func__, __LINE__);
1522           return message;
1523         }
1524
1525       unsigned long first_contact = std::max (m_uid.tofuInfo().signFirst(),
1526                                               m_uid.tofuInfo().encrFirst());
1527       char *time = format_date_from_gpgme (first_contact);
1528       /* i18n note signcount is always pulral because with signcount 1 we
1529        * would not be in this branch. */
1530       gpgrt_asprintf (&buf, _("And the senders address is trustworthy, because "
1531                               "you have established a communication history "
1532                               "with this address starting on %s.\n"
1533                               "You encrypted %i times to this address and verified %i since."),
1534                               time, m_uid.tofuInfo().signCount (),
1535                               m_uid.tofuInfo().encrCount());
1536       xfree (time);
1537       message = buf;
1538       xfree (buf);
1539     }
1540   else if (level == 1)
1541     {
1542       /* This could be marginal trust through pgp, or tofu with little
1543          history. */
1544       if (m_uid.tofuInfo ().validity() == TofuInfo::Validity::LittleHistory)
1545         {
1546           unsigned long first_contact = std::max (m_uid.tofuInfo().signFirst(),
1547                                                   m_uid.tofuInfo().encrFirst());
1548           char *time = format_date_from_gpgme (first_contact);
1549           gpgrt_asprintf (&buf, _("But the senders address is not trustworthy yet because "
1550                                   "you only verified %i messages and encrypted %i messages to "
1551                                   "it since %s."),
1552                                   m_uid.tofuInfo().signCount (),
1553                                   m_uid.tofuInfo().encrCount (), time);
1554           xfree (time);
1555           message = buf;
1556           xfree (buf);
1557         }
1558       else if (m_uid.tofuInfo ().signCount() == 1)
1559         {
1560           message += _("But the senders signature was verified for the first time.");
1561         }
1562       else
1563         {
1564           /* Marginal trust through pgp */
1565           message = _("Not enough trusted people or yourself "
1566                       "have certified the senders identity.");
1567         }
1568     }
1569   else
1570     {
1571       /* Now we are in level 0, this could be a technical problem, no key
1572          or just unkown. */
1573       message = _("But the sender address is not trustworthy because:");
1574       message += "\n\n";
1575       keyFound = !(m_sig.summary() & Signature::Summary::KeyMissing);
1576
1577       bool general_problem = true;
1578       /* First the general stuff. */
1579       if (m_sig.summary() & Signature::Summary::Red)
1580         {
1581           message += _("The signature is invalid.\n");
1582         }
1583       else if (m_sig.summary() & Signature::Summary::SysError ||
1584                m_verify_result.numSignatures() < 1)
1585         {
1586           message += _("There was an error verifying the signature.\n");
1587         }
1588       else if (m_sig.summary() & Signature::Summary::SigExpired)
1589         {
1590           message += _("The signature is expired.\n");
1591         }
1592       else
1593         {
1594           message += isOpenPGP ? _("The used key") : _("The used certificate");
1595           message += " ";
1596           general_problem = false;
1597         }
1598
1599       /* Now the key problems */
1600       if ((m_sig.summary() & Signature::Summary::KeyMissing))
1601         {
1602           message += _("is not available.");
1603         }
1604       else if ((m_sig.summary() & Signature::Summary::KeyRevoked))
1605         {
1606           message += _("is revoked.");
1607         }
1608       else if ((m_sig.summary() & Signature::Summary::KeyExpired))
1609         {
1610           message += _("is expired.");
1611         }
1612       else if ((m_sig.summary() & Signature::Summary::BadPolicy))
1613         {
1614           message += _("is not meant for signing.");
1615         }
1616       else if ((m_sig.summary() & Signature::Summary::CrlMissing))
1617         {
1618           message += _("could not be checked for revocation.");
1619         }
1620       else if ((m_sig.summary() & Signature::Summary::CrlTooOld))
1621         {
1622           message += _("could not be checked for revocation.");
1623         }
1624       else if ((m_sig.summary() & Signature::Summary::TofuConflict) ||
1625                m_uid.tofuInfo().validity() == TofuInfo::Conflict)
1626         {
1627           message += _("conflicts with another key that was used in the past by the sender.");
1628           hasConflict = true;
1629         }
1630       else if (m_uid.isNull())
1631         {
1632           gpgrt_asprintf (&buf, _("does not claim the address: \"%s\"."),
1633                           get_sender().c_str());
1634           message += buf;
1635           xfree (buf);
1636         }
1637       else if (((m_sig.validity() & Signature::Validity::Undefined) ||
1638                (m_sig.validity() & Signature::Validity::Unknown) ||
1639                (m_sig.summary() == Signature::Summary::None) ||
1640                (m_sig.validity() == 0))&& !general_problem)
1641         {
1642            /* Bit of a catch all for weird results. */
1643           message += _("is not certified by any trustworthy key.");
1644         }
1645       else if ((m_sig.validity() & Signature::Validity::Never))
1646         {
1647           message += _("is marked as not trustworthy.");
1648         }
1649     }
1650   message += _("You cannot be sure who wrote or modified the message.");
1651   message += "\n\n";
1652   if (hasConflict)
1653     {
1654       message += _("Click here to change the key used for this address.");
1655     }
1656   else if (keyFound)
1657     {
1658       message +=  isOpenPGP ? _("Click here for details about the key.") :
1659                               _("Click here for details about the certificate.");
1660     }
1661   else
1662     {
1663       message +=  isOpenPGP ? _("Click here to search the key on the configured keyserver.") :
1664                               _("Click here to search the certificate on the configured X509 keyserver.");
1665     }
1666   return message;
1667 }
1668
1669
1670 int
1671 Mail::get_signature_level () const
1672 {
1673   if (!m_is_signed || !is_encrypted ())
1674     {
1675       return 0;
1676     }
1677
1678   if (m_uid.isNull ())
1679     {
1680       /* No m_uid matches our sender. */
1681       return 0;
1682     }
1683   if (m_is_valid && (m_uid.validity () == UserID::Validity::Ultimate ||
1684       (m_uid.validity () == UserID::Validity::Full &&
1685       level_4_check (m_uid))))
1686     {
1687       return 4;
1688     }
1689   if (m_is_valid && m_uid.validity () == UserID::Validity::Full)
1690     {
1691       return 3;
1692     }
1693   if (m_is_valid)
1694     {
1695       return 2;
1696     }
1697   if (m_sig.validity() == Signature::Validity::Marginal)
1698     {
1699       return 1;
1700     }
1701   if (m_sig.summary() & Signature::Summary::TofuConflict ||
1702       m_uid.tofuInfo().validity() == TofuInfo::Conflict)
1703     {
1704       return 1;
1705     }
1706   return 0;
1707 }
1708
1709 int
1710 Mail::get_crypto_icon_id () const
1711 {
1712   int level = get_signature_level ();
1713   int offset = is_encrypted () ? ENCRYPT_ICON_OFFSET : 0;
1714   return IDI_LEVEL_0 + level + offset;
1715 }
1716
1717 const char*
1718 Mail::get_sig_fpr() const
1719 {
1720   if (!m_is_signed || m_sig.isNull())
1721     {
1722       return nullptr;
1723     }
1724   return m_sig.fingerprint();
1725 }
1726
1727
1728 static DWORD WINAPI
1729 do_locate (LPVOID arg)
1730 {
1731   char *recipient = (char*) arg;
1732   log_debug ("%s:%s searching key for recipient: \"%s\"",
1733              SRCNAME, __func__, recipient);
1734   Context *ctx = Context::createForProtocol (OpenPGP);
1735
1736   if (!ctx)
1737     {
1738       TRACEPOINT;
1739       return 0;
1740     }
1741
1742   ctx->setKeyListMode (GpgME::Extern | GpgME::Local);
1743   ctx->startKeyListing (recipient, false);
1744
1745   std::vector<Key> keys;
1746   Error err;
1747   do {
1748       keys.push_back (ctx->nextKey(err));
1749     } while (!err);
1750   keys.pop_back ();
1751   ctx->endKeyListing ();
1752   delete ctx;
1753
1754   if (keys.size ())
1755     {
1756       log_debug ("%s:%s found key for recipient: \"%s\"",
1757                  SRCNAME, __func__, recipient);
1758     }
1759   xfree (recipient);
1760   do_in_ui_thread (UNKNOWN, NULL);
1761   return 0;
1762 }
1763
1764 /** Try to locate the keys for all recipients */
1765 void Mail::locate_keys()
1766 {
1767   char ** recipients = get_recipients ();
1768
1769   if (!recipients)
1770     {
1771       TRACEPOINT;
1772       return;
1773     }
1774   for (int i = 0; recipients[i]; i++)
1775     {
1776       std::string recp = recipients[i];
1777       if (uids_searched.find (recp) == uids_searched.end ())
1778         {
1779           uids_searched.insert (recp);
1780           HANDLE thread = CreateThread (NULL, 0, do_locate,
1781                                         (LPVOID) strdup(recipients[i]), 0,
1782                                         NULL);
1783           CloseHandle (thread);
1784         }
1785       xfree (recipients[i]);
1786     }
1787   xfree (recipients);
1788 }
1789
1790 bool
1791 Mail::is_html_alternative () const
1792 {
1793   return m_is_html_alternative;
1794 }
1795
1796 const std::string &
1797 Mail::get_cached_html_body () const
1798 {
1799   return m_html_body;
1800 }
1801
1802 int
1803 Mail::get_crypto_flags () const
1804 {
1805   return m_crypto_flags;
1806 }
1807
1808 void
1809 Mail::set_needs_encrypt (bool value)
1810 {
1811   m_needs_encrypt = value;
1812 }
1813
1814 bool
1815 Mail::needs_encrypt() const
1816 {
1817   return m_needs_encrypt;
1818 }