mutt stable branch with some hacks
1/*
2 * Copyright (C) 2019 Kevin J. McCarthy <kevin@8t8.us>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#if HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "mutt.h"
24#include "mutt_curses.h"
25#include "mutt_crypt.h"
26#include "mime.h"
27#include "mutt_idna.h"
28#include "mailbox.h"
29#include "autocrypt.h"
30#include "autocrypt_private.h"
31
32#ifdef HAVE_SYS_TIME_H
33#include <sys/time.h>
34#endif
35#include <errno.h>
36
37static int autocrypt_dir_init (int can_create)
38{
39 int rv = 0;
40 struct stat sb;
41 BUFFER *prompt = NULL;
42
43 if (!stat (AutocryptDir, &sb))
44 return 0;
45
46 if (!can_create)
47 return -1;
48
49 prompt = mutt_buffer_pool_get ();
50 /* L10N:
51 %s is a directory. Mutt is looking for a directory it needs
52 for some reason (e.g. autocrypt, header cache, bcache), but it
53 doesn't exist. The prompt is asking whether to create the directory
54 */
55 mutt_buffer_printf (prompt, _("%s does not exist. Create it?"), AutocryptDir);
56 if (mutt_yesorno (mutt_b2s (prompt), MUTT_YES) == MUTT_YES)
57 {
58 if (mutt_mkdir (AutocryptDir, 0700) < 0)
59 {
60 /* L10N:
61 mkdir() on the directory %s failed. The second %s is the
62 error message returned by libc
63 */
64 mutt_error ( _("Can't create %s: %s."), AutocryptDir, strerror (errno));
65 mutt_sleep (0);
66 rv = -1;
67 }
68 }
69
70 mutt_buffer_pool_release (&prompt);
71 return rv;
72}
73
74int mutt_autocrypt_init (int can_create)
75{
76 if (AutocryptDB)
77 return 0;
78
79 if (!option (OPTAUTOCRYPT) || !AutocryptDir)
80 return -1;
81
82 set_option (OPTIGNOREMACROEVENTS);
83 /* The init process can display menus at various points
84 * (e.g. browser, pgp key selection). This allows the screen to be
85 * autocleared after each menu, so the subsequent prompts can be
86 * read. */
87 set_option (OPTMENUPOPCLEARSCREEN);
88
89 if (autocrypt_dir_init (can_create))
90 goto bail;
91
92 if (mutt_autocrypt_gpgme_init ())
93 goto bail;
94
95 if (mutt_autocrypt_db_init (can_create))
96 goto bail;
97
98 unset_option (OPTIGNOREMACROEVENTS);
99 unset_option (OPTMENUPOPCLEARSCREEN);
100
101 return 0;
102
103bail:
104 unset_option (OPTIGNOREMACROEVENTS);
105 unset_option (OPTMENUPOPCLEARSCREEN);
106 unset_option (OPTAUTOCRYPT);
107 mutt_autocrypt_db_close ();
108 return -1;
109}
110
111void mutt_autocrypt_cleanup (void)
112{
113 mutt_autocrypt_db_close ();
114}
115
116/* Creates a brand new account.
117 * This is used the first time autocrypt is initialized, and
118 * in the account menu. */
119int mutt_autocrypt_account_init (int prompt)
120{
121 ADDRESS *addr = NULL;
122 BUFFER *keyid = NULL, *keydata = NULL;
123 AUTOCRYPT_ACCOUNT *account = NULL;
124 int done = 0, rv = -1, prefer_encrypt = 0;
125
126 if (prompt)
127 {
128 /* L10N:
129 The first time mutt is started with $autocrypt set, it will
130 create $autocrypt_dir and then prompt to create an autocrypt
131 account with this message.
132 */
133 if (mutt_yesorno (_("Create an initial autocrypt account?"),
134 MUTT_YES) != MUTT_YES)
135 return 0;
136 }
137
138 keyid = mutt_buffer_pool_get ();
139 keydata = mutt_buffer_pool_get ();
140
141 if (From)
142 {
143 addr = rfc822_cpy_adr_real (From);
144 if (!addr->personal && Realname)
145 addr->personal = safe_strdup (Realname);
146 }
147
148 do
149 {
150 /* L10N:
151 Autocrypt is asking for the email address to use for the
152 autocrypt account. This will generate a key and add a record
153 to the database for use in autocrypt operations.
154 */
155 if (mutt_edit_address (&addr, _("Autocrypt account address: "), 0))
156 goto cleanup;
157 if (!addr || !addr->mailbox || addr->next)
158 {
159 /* L10N:
160 Autocrypt prompts for an account email address, and requires
161 a single address. This is shown if they entered something invalid,
162 nothing, or more than one address for some reason.
163 */
164 mutt_error (_("Please enter a single email address"));
165 mutt_sleep (2);
166 done = 0;
167 }
168 else
169 done = 1;
170 } while (!done);
171
172 if (mutt_autocrypt_db_account_get (addr, &account) < 0)
173 goto cleanup;
174 if (account)
175 {
176 /* L10N:
177 When creating an autocrypt account, this message will be displayed
178 if there is already an account in the database with the email address
179 they just entered.
180 */
181 mutt_error _("That email address already has an autocrypt account");
182 mutt_sleep (1);
183 goto cleanup;
184 }
185
186 if (mutt_autocrypt_gpgme_select_or_create_key (addr, keyid, keydata))
187 goto cleanup;
188
189 /* L10N:
190 Autocrypt has a setting "prefer-encrypt".
191 When the recommendation algorithm returns "available" and BOTH
192 sender and recipient choose "prefer-encrypt", encryption will be
193 automatically enabled.
194 Otherwise the UI will show encryption is "available" but the user
195 will be required to enable encryption manually.
196 */
197 if (mutt_yesorno (_("Prefer encryption?"), MUTT_NO) == MUTT_YES)
198 prefer_encrypt = 1;
199
200 if (mutt_autocrypt_db_account_insert (addr, mutt_b2s (keyid), mutt_b2s (keydata),
201 prefer_encrypt))
202 goto cleanup;
203
204 rv = 0;
205
206cleanup:
207 if (rv)
208 /* L10N:
209 Error message displayed if creating an autocrypt account failed
210 or was aborted by the user.
211 */
212 mutt_error _("Autocrypt account creation aborted.");
213 else
214 /* L10N:
215 Message displayed after an autocrypt account is successfully created.
216 */
217 mutt_message _("Autocrypt account creation succeeded");
218 mutt_sleep (1);
219
220 mutt_autocrypt_db_account_free (&account);
221 rfc822_free_address (&addr);
222 mutt_buffer_pool_release (&keyid);
223 mutt_buffer_pool_release (&keydata);
224 return rv;
225}
226
227int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env)
228{
229 AUTOCRYPTHDR *ac_hdr, *valid_ac_hdr = NULL;
230 struct timeval now;
231 AUTOCRYPT_PEER *peer = NULL;
232 AUTOCRYPT_PEER_HISTORY *peerhist = NULL;
233 BUFFER *keyid = NULL;
234 int update_db = 0, insert_db = 0, insert_db_history = 0, import_gpg = 0;
235 int rv = -1;
236
237 if (!option (OPTAUTOCRYPT))
238 return 0;
239
240 if (mutt_autocrypt_init (0))
241 return -1;
242
243 if (!hdr || !hdr->content || !env)
244 return 0;
245
246 /* 1.1 spec says to skip emails with more than one From header */
247 if (!env->from || env->from->next)
248 return 0;
249
250 /* 1.1 spec also says to skip multipart/report emails */
251 if (hdr->content->type == TYPEMULTIPART &&
252 !(ascii_strcasecmp (hdr->content->subtype, "report")))
253 return 0;
254
255 /* Ignore emails that appear to be more than a week in the future,
256 * since they can block all future updates during that time. */
257 gettimeofday (&now, NULL);
258 if (hdr->date_sent > (now.tv_sec + 7 * 24 * 60 * 60))
259 return 0;
260
261 for (ac_hdr = env->autocrypt; ac_hdr; ac_hdr = ac_hdr->next)
262 {
263 if (ac_hdr->invalid)
264 continue;
265
266 /* NOTE: this assumes the processing is occurring right after
267 * mutt_parse_rfc822_line() and the from ADDR is still in the same
268 * form (intl) as the autocrypt header addr field */
269 if (ascii_strcasecmp (env->from->mailbox, ac_hdr->addr))
270 continue;
271
272 /* 1.1 spec says ignore all, if more than one valid header is found. */
273 if (valid_ac_hdr)
274 {
275 valid_ac_hdr = NULL;
276 break;
277 }
278 valid_ac_hdr = ac_hdr;
279 }
280
281 if (mutt_autocrypt_db_peer_get (env->from, &peer) < 0)
282 goto cleanup;
283
284 if (peer)
285 {
286 if (hdr->date_sent <= peer->autocrypt_timestamp)
287 {
288 rv = 0;
289 goto cleanup;
290 }
291
292 if (hdr->date_sent > peer->last_seen)
293 {
294 update_db = 1;
295 peer->last_seen = hdr->date_sent;
296 }
297
298 if (valid_ac_hdr)
299 {
300 update_db = 1;
301 peer->autocrypt_timestamp = hdr->date_sent;
302 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
303 if (mutt_strcmp (peer->keydata, valid_ac_hdr->keydata))
304 {
305 import_gpg = 1;
306 insert_db_history = 1;
307 mutt_str_replace (&peer->keydata, valid_ac_hdr->keydata);
308 }
309 }
310 }
311 else if (valid_ac_hdr)
312 {
313 import_gpg = 1;
314 insert_db = 1;
315 insert_db_history = 1;
316 }
317
318 if (!(import_gpg || insert_db || update_db))
319 {
320 rv = 0;
321 goto cleanup;
322 }
323
324 if (!peer)
325 {
326 peer = mutt_autocrypt_db_peer_new ();
327 peer->last_seen = hdr->date_sent;
328 peer->autocrypt_timestamp = hdr->date_sent;
329 peer->keydata = safe_strdup (valid_ac_hdr->keydata);
330 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
331 }
332
333 if (import_gpg)
334 {
335 keyid = mutt_buffer_pool_get ();
336 if (mutt_autocrypt_gpgme_import_key (peer->keydata, keyid))
337 goto cleanup;
338 mutt_str_replace (&peer->keyid, mutt_b2s (keyid));
339 }
340
341 if (insert_db &&
342 mutt_autocrypt_db_peer_insert (env->from, peer))
343 goto cleanup;
344
345 if (update_db &&
346 mutt_autocrypt_db_peer_update (peer))
347 goto cleanup;
348
349 if (insert_db_history)
350 {
351 peerhist = mutt_autocrypt_db_peer_history_new ();
352 peerhist->email_msgid = safe_strdup (env->message_id);
353 peerhist->timestamp = hdr->date_sent;
354 peerhist->keydata = safe_strdup (peer->keydata);
355 if (mutt_autocrypt_db_peer_history_insert (env->from, peerhist))
356 goto cleanup;
357 }
358
359 rv = 0;
360
361cleanup:
362 mutt_autocrypt_db_peer_free (&peer);
363 mutt_autocrypt_db_peer_history_free (&peerhist);
364 mutt_buffer_pool_release (&keyid);
365
366 return rv;
367}
368
369int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *prot_headers)
370{
371 ENVELOPE *env;
372 AUTOCRYPTHDR *ac_hdr;
373 struct timeval now;
374 AUTOCRYPT_PEER *peer = NULL;
375 AUTOCRYPT_GOSSIP_HISTORY *gossip_hist = NULL;
376 ADDRESS *peer_addr, *recips = NULL, *last = NULL, ac_hdr_addr = {0};
377 BUFFER *keyid = NULL;
378 int update_db = 0, insert_db = 0, insert_db_history = 0, import_gpg = 0;
379 int rv = -1;
380
381 if (!option (OPTAUTOCRYPT))
382 return 0;
383
384 if (mutt_autocrypt_init (0))
385 return -1;
386
387 if (!hdr || !hdr->env || !prot_headers)
388 return 0;
389
390 env = hdr->env;
391
392 if (!env->from)
393 return 0;
394
395 /* Ignore emails that appear to be more than a week in the future,
396 * since they can block all future updates during that time. */
397 gettimeofday (&now, NULL);
398 if (hdr->date_sent > (now.tv_sec + 7 * 24 * 60 * 60))
399 return 0;
400
401 keyid = mutt_buffer_pool_get ();
402
403 /* Normalize the recipient list for comparison */
404 last = rfc822_append (&recips, env->to, 0);
405 last = rfc822_append (last ? &last : &recips, env->cc, 0);
406 rfc822_append (last ? &last : &recips, env->reply_to, 0);
407 mutt_autocrypt_db_normalize_addrlist (recips);
408
409 for (ac_hdr = prot_headers->autocrypt_gossip; ac_hdr; ac_hdr = ac_hdr->next)
410 {
411 if (ac_hdr->invalid)
412 continue;
413
414 /* normalize for comparison against recipient list */
415 mutt_str_replace (&ac_hdr_addr.mailbox, ac_hdr->addr);
416 ac_hdr_addr.is_intl = 1;
417 ac_hdr_addr.intl_checked = 1;
418 mutt_autocrypt_db_normalize_addrlist (&ac_hdr_addr);
419
420 /* Check to make sure the address is in the recipient list. Since the
421 * addresses are normalized we use strcmp, not ascii_strcasecmp. */
422 for (peer_addr = recips; peer_addr; peer_addr = peer_addr->next)
423 if (!mutt_strcmp (peer_addr->mailbox, ac_hdr_addr.mailbox))
424 break;
425 if (!peer_addr)
426 continue;
427
428 if (mutt_autocrypt_db_peer_get (peer_addr, &peer) < 0)
429 goto cleanup;
430
431 if (peer)
432 {
433 if (hdr->date_sent <= peer->gossip_timestamp)
434 {
435 mutt_autocrypt_db_peer_free (&peer);
436 continue;
437 }
438
439 update_db = 1;
440 peer->gossip_timestamp = hdr->date_sent;
441 /* This is slightly different from the autocrypt 1.1 spec.
442 * Avoid setting an empty peer.gossip_keydata with a value that matches
443 * the current peer.keydata. */
444 if ((peer->gossip_keydata && mutt_strcmp (peer->gossip_keydata, ac_hdr->keydata)) ||
445 (!peer->gossip_keydata && mutt_strcmp (peer->keydata, ac_hdr->keydata)))
446 {
447 import_gpg = 1;
448 insert_db_history = 1;
449 mutt_str_replace (&peer->gossip_keydata, ac_hdr->keydata);
450 }
451 }
452 else
453 {
454 import_gpg = 1;
455 insert_db = 1;
456 insert_db_history = 1;
457 }
458
459 if (!peer)
460 {
461 peer = mutt_autocrypt_db_peer_new ();
462 peer->gossip_timestamp = hdr->date_sent;
463 peer->gossip_keydata = safe_strdup (ac_hdr->keydata);
464 }
465
466 if (import_gpg)
467 {
468 if (mutt_autocrypt_gpgme_import_key (peer->gossip_keydata, keyid))
469 goto cleanup;
470 mutt_str_replace (&peer->gossip_keyid, mutt_b2s (keyid));
471 }
472
473 if (insert_db &&
474 mutt_autocrypt_db_peer_insert (peer_addr, peer))
475 goto cleanup;
476
477 if (update_db &&
478 mutt_autocrypt_db_peer_update (peer))
479 goto cleanup;
480
481 if (insert_db_history)
482 {
483 gossip_hist = mutt_autocrypt_db_gossip_history_new ();
484 gossip_hist->sender_email_addr = safe_strdup (env->from->mailbox);
485 gossip_hist->email_msgid = safe_strdup (env->message_id);
486 gossip_hist->timestamp = hdr->date_sent;
487 gossip_hist->gossip_keydata = safe_strdup (peer->gossip_keydata);
488 if (mutt_autocrypt_db_gossip_history_insert (peer_addr, gossip_hist))
489 goto cleanup;
490 }
491
492 mutt_autocrypt_db_peer_free (&peer);
493 mutt_autocrypt_db_gossip_history_free (&gossip_hist);
494 mutt_buffer_clear (keyid);
495 update_db = insert_db = insert_db_history = import_gpg = 0;
496 }
497
498 rv = 0;
499
500cleanup:
501 FREE (&ac_hdr_addr.mailbox);
502 rfc822_free_address (&recips);
503 mutt_autocrypt_db_peer_free (&peer);
504 mutt_autocrypt_db_gossip_history_free (&gossip_hist);
505 mutt_buffer_pool_release (&keyid);
506
507 return rv;
508}
509
510/* Returns the recommendation. If the recommendataion is > NO and
511 * keylist is not NULL, keylist will be populated with the autocrypt
512 * keyids
513 */
514autocrypt_rec_t mutt_autocrypt_ui_recommendation (HEADER *hdr, char **keylist)
515{
516 autocrypt_rec_t rv = AUTOCRYPT_REC_OFF;
517 AUTOCRYPT_ACCOUNT *account = NULL;
518 AUTOCRYPT_PEER *peer = NULL;
519 ADDRESS *recip, *recips = NULL, *last = NULL;
520 int all_encrypt = 1, has_discourage = 0;
521 BUFFER *keylist_buf = NULL;
522 const char *matching_key;
523
524 if (!option (OPTAUTOCRYPT) ||
525 mutt_autocrypt_init (0) ||
526 !hdr ||
527 !hdr->env->from ||
528 hdr->env->from->next)
529 return AUTOCRYPT_REC_OFF;
530
531 if (hdr->security & APPLICATION_SMIME)
532 return AUTOCRYPT_REC_OFF;
533
534 if (mutt_autocrypt_db_account_get (hdr->env->from, &account) <= 0)
535 goto cleanup;
536
537 if (!account->enabled)
538 goto cleanup;
539
540 keylist_buf = mutt_buffer_pool_get ();
541 mutt_buffer_addstr (keylist_buf, account->keyid);
542
543 last = rfc822_append (&recips, hdr->env->to, 0);
544 last = rfc822_append (last ? &last : &recips, hdr->env->cc, 0);
545 rfc822_append (last ? &last : &recips, hdr->env->bcc, 0);
546
547 rv = AUTOCRYPT_REC_NO;
548 if (!recips)
549 goto cleanup;
550
551 for (recip = recips; recip; recip = recip->next)
552 {
553 if (mutt_autocrypt_db_peer_get (recip, &peer) <= 0)
554 {
555 if (keylist)
556 /* L10N:
557 %s is an email address. Autocrypt is scanning for the keyids
558 to use to encrypt, but it can't find a valid keyid for this address.
559 The message is printed and they are returned to the compose menu.
560 */
561 mutt_message (_("No (valid) autocrypt key found for %s."), recip->mailbox);
562 goto cleanup;
563 }
564
565 if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
566 {
567 matching_key = peer->keyid;
568
569 if (!(peer->last_seen && peer->autocrypt_timestamp) ||
570 (peer->last_seen - peer->autocrypt_timestamp > 35 * 24 * 60 * 60))
571 {
572 has_discourage = 1;
573 all_encrypt = 0;
574 }
575
576 if (!account->prefer_encrypt || !peer->prefer_encrypt)
577 all_encrypt = 0;
578 }
579 else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
580 {
581 matching_key = peer->gossip_keyid;
582
583 has_discourage = 1;
584 all_encrypt = 0;
585 }
586 else
587 {
588 if (keylist)
589 mutt_message (_("No (valid) autocrypt key found for %s."), recip->mailbox);
590 goto cleanup;
591 }
592
593 if (mutt_buffer_len (keylist_buf))
594 mutt_buffer_addch (keylist_buf, ' ');
595 mutt_buffer_addstr (keylist_buf, matching_key);
596
597 mutt_autocrypt_db_peer_free (&peer);
598 }
599
600 if (all_encrypt)
601 rv = AUTOCRYPT_REC_YES;
602 else if (has_discourage)
603 rv = AUTOCRYPT_REC_DISCOURAGE;
604 else
605 rv = AUTOCRYPT_REC_AVAILABLE;
606
607 if (keylist)
608 mutt_str_replace (keylist, mutt_b2s (keylist_buf));
609
610cleanup:
611 mutt_autocrypt_db_account_free (&account);
612 rfc822_free_address (&recips);
613 mutt_autocrypt_db_peer_free (&peer);
614 mutt_buffer_pool_release (&keylist_buf);
615 return rv;
616}
617
618int mutt_autocrypt_set_sign_as_default_key (HEADER *hdr)
619{
620 int rv = -1;
621 AUTOCRYPT_ACCOUNT *account = NULL;
622
623 if (!option (OPTAUTOCRYPT) ||
624 mutt_autocrypt_init (0) ||
625 !hdr ||
626 !hdr->env->from ||
627 hdr->env->from->next)
628 return -1;
629
630 if (mutt_autocrypt_db_account_get (hdr->env->from, &account) <= 0)
631 goto cleanup;
632 if (!account->keyid)
633 goto cleanup;
634 if (!account->enabled)
635 goto cleanup;
636
637 mutt_str_replace (&AutocryptSignAs, account->keyid);
638 mutt_str_replace (&AutocryptDefaultKey, account->keyid);
639
640 rv = 0;
641
642cleanup:
643 mutt_autocrypt_db_account_free (&account);
644 return rv;
645}
646
647
648static void write_autocrypt_header_line (FILE *fp, const char *addr,
649 int prefer_encrypt,
650 const char *keydata)
651{
652 int count = 0;
653
654 fprintf (fp, "addr=%s; ", addr);
655 if (prefer_encrypt)
656 fputs ("prefer-encrypt=mutual; ", fp);
657 fputs ("keydata=\n", fp);
658
659 while (*keydata)
660 {
661 count = 0;
662 fputs ("\t", fp);
663 while (*keydata && count < 75)
664 {
665 fputc (*keydata, fp);
666 count++;
667 keydata++;
668 }
669 fputs ("\n", fp);
670 }
671}
672
673int mutt_autocrypt_write_autocrypt_header (ENVELOPE *env, FILE *fp)
674{
675 int rv = -1;
676 AUTOCRYPT_ACCOUNT *account = NULL;
677
678 if (!option (OPTAUTOCRYPT) ||
679 mutt_autocrypt_init (0) ||
680 !env ||
681 !env->from ||
682 env->from->next)
683 return -1;
684
685 if (mutt_autocrypt_db_account_get (env->from, &account) <= 0)
686 goto cleanup;
687 if (!account->keydata)
688 goto cleanup;
689 if (!account->enabled)
690 goto cleanup;
691
692 fputs ("Autocrypt: ", fp);
693 write_autocrypt_header_line (fp, account->email_addr, account->prefer_encrypt,
694 account->keydata);
695
696 rv = 0;
697
698cleanup:
699 mutt_autocrypt_db_account_free (&account);
700 return rv;
701}
702
703int mutt_autocrypt_write_gossip_headers (ENVELOPE *env, FILE *fp)
704{
705 AUTOCRYPTHDR *gossip;
706
707 if (!option (OPTAUTOCRYPT) ||
708 mutt_autocrypt_init (0) ||
709 !env)
710 return -1;
711
712 for (gossip = env->autocrypt_gossip; gossip; gossip = gossip->next)
713 {
714 fputs ("Autocrypt-Gossip: ", fp);
715 write_autocrypt_header_line (fp, gossip->addr, 0, gossip->keydata);
716 }
717
718 return 0;
719}
720
721int mutt_autocrypt_generate_gossip_list (HEADER *hdr)
722{
723 int rv = -1;
724 AUTOCRYPT_PEER *peer = NULL;
725 AUTOCRYPT_ACCOUNT *account = NULL;
726 ADDRESS *recip, *recips = NULL, *last = NULL;
727 AUTOCRYPTHDR *gossip;
728 const char *keydata, *addr;
729 ENVELOPE *mime_headers;
730
731 if (!option (OPTAUTOCRYPT) ||
732 mutt_autocrypt_init (0) ||
733 !hdr)
734 return -1;
735
736 mime_headers = hdr->content->mime_headers;
737 if (!mime_headers)
738 mime_headers = hdr->content->mime_headers = mutt_new_envelope ();
739 mutt_free_autocrypthdr (&mime_headers->autocrypt_gossip);
740
741 last = rfc822_append (&recips, hdr->env->to, 0);
742 last = rfc822_append (last ? &last : &recips, hdr->env->cc, 0);
743
744 for (recip = recips; recip; recip = recip->next)
745 {
746 /* At this point, we just accept missing keys and include what
747 * we can. */
748 if (mutt_autocrypt_db_peer_get (recip, &peer) <= 0)
749 continue;
750
751 keydata = NULL;
752 if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
753 keydata = peer->keydata;
754 else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
755 keydata = peer->gossip_keydata;
756
757 if (keydata)
758 {
759 gossip = mutt_new_autocrypthdr ();
760 gossip->addr = safe_strdup (peer->email_addr);
761 gossip->keydata = safe_strdup (keydata);
762 gossip->next = mime_headers->autocrypt_gossip;
763 mime_headers->autocrypt_gossip = gossip;
764 }
765
766 mutt_autocrypt_db_peer_free (&peer);
767 }
768
769 for (recip = hdr->env->reply_to; recip; recip = recip->next)
770 {
771 addr = keydata = NULL;
772 if (mutt_autocrypt_db_account_get (recip, &account) > 0)
773 {
774 addr = account->email_addr;
775 keydata = account->keydata;
776 }
777 else if (mutt_autocrypt_db_peer_get (recip, &peer) > 0)
778 {
779 addr = peer->email_addr;
780 if (mutt_autocrypt_gpgme_is_valid_key (peer->keyid))
781 keydata = peer->keydata;
782 else if (mutt_autocrypt_gpgme_is_valid_key (peer->gossip_keyid))
783 keydata = peer->gossip_keydata;
784 }
785
786 if (keydata)
787 {
788 gossip = mutt_new_autocrypthdr ();
789 gossip->addr = safe_strdup (addr);
790 gossip->keydata = safe_strdup (keydata);
791 gossip->next = mime_headers->autocrypt_gossip;
792 mime_headers->autocrypt_gossip = gossip;
793 }
794 mutt_autocrypt_db_account_free (&account);
795 mutt_autocrypt_db_peer_free (&peer);
796 }
797
798 rfc822_free_address (&recips);
799 mutt_autocrypt_db_account_free (&account);
800 mutt_autocrypt_db_peer_free (&peer);
801 return rv;
802}
803
804/* This is invoked during the first autocrypt initialization,
805 * to scan one or more mailboxes for autocrypt headers.
806 *
807 * Due to the implementation, header-cached headers are not scanned,
808 * so this routine just opens up the mailboxes with $header_cache
809 * temporarily disabled.
810 */
811void mutt_autocrypt_scan_mailboxes (void)
812{
813 int scan;
814 BUFFER *folderbuf = NULL;
815 CONTEXT *ctx = NULL;
816
817#ifdef USE_HCACHE
818 char *old_hdrcache = HeaderCache;
819 HeaderCache = NULL;
820#endif
821
822 folderbuf = mutt_buffer_pool_get ();
823
824 /* L10N:
825 The first time autocrypt is enabled, Mutt will ask to scan
826 through one or more mailboxes for Autocrypt: headers.
827 Those headers are then captured in the database as peer records
828 and used for encryption.
829 If this is answered yes, they will be prompted for a mailbox.
830 */
831 scan = mutt_yesorno (_("Scan a mailbox for autocrypt headers?"),
832 MUTT_YES);
833 while (scan == MUTT_YES)
834 {
835 /* L10N:
836 The prompt for a mailbox to scan for Autocrypt: headers
837 */
838 if ((!mutt_buffer_enter_fname (_("Scan mailbox"), folderbuf, 1)) &&
839 mutt_buffer_len (folderbuf))
840 {
841 mutt_buffer_expand_path (folderbuf);
842 /* NOTE: I am purposely *not* executing folder hooks here,
843 * as they can do all sorts of things like push into the getch() buffer.
844 * Authentication should be in account-hooks. */
845 ctx = mx_open_mailbox (mutt_b2s (folderbuf), MUTT_READONLY, NULL);
846 mutt_sleep (1);
847 mx_close_mailbox (ctx, NULL);
848
849 FREE (&ctx);
850 mutt_buffer_clear (folderbuf);
851 }
852
853 /* L10N:
854 This is the second prompt to see if the user would like
855 to scan more than one mailbox for Autocrypt headers.
856 I'm purposely being extra verbose; asking first then prompting
857 for a mailbox. This is because this is a one-time operation
858 and I don't want them to accidentally ctrl-g and abort it.
859 */
860 scan = mutt_yesorno (_("Scan another mailbox for autocrypt headers?"),
861 MUTT_YES);
862 }
863
864#ifdef USE_HCACHE
865 HeaderCache = old_hdrcache;
866#endif
867 mutt_buffer_pool_release (&folderbuf);
868}