NeoMutt  2025-12-11-596-g7cc1dd
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pgp.c
Go to the documentation of this file.
1
24
34
35#include "config.h"
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/types.h>
41#include <unistd.h>
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "gui/lib.h"
48#include "mutt.h"
49#include "lib.h"
50#include "attach/lib.h"
51#include "editor/lib.h"
52#include "history/lib.h"
53#include "hooks/lib.h"
54#include "question/lib.h"
55#include "send/lib.h"
56#include "crypt.h"
57#include "cryptglue.h"
58#include "globals.h"
59#include "pgpinvoke.h"
60#include "pgpkey.h"
61#include "pgpmicalg.h"
62#ifdef CRYPT_BACKEND_CLASSIC_PGP
63#include "pgp.h"
64#include "pgplib.h"
65#endif
66
68static char PgpPass[1024];
70static time_t PgpExptime = 0; /* when does the cached passphrase expire? */
71
76{
77 memset(PgpPass, 0, sizeof(PgpPass));
78 PgpExptime = 0;
79}
80
85{
87 {
88 *PgpPass = '\0';
89 return true; /* handled by gpg-agent */
90 }
91
93 {
94 /* Use cached copy. */
95 return true;
96 }
97
99
100 struct Buffer *buf = buf_pool_get();
101 const int rc = mw_get_field(_("Enter PGP passphrase:"), buf,
103 mutt_str_copy(PgpPass, buf_string(buf), sizeof(PgpPass));
104 buf_pool_release(&buf);
105
106 if (rc == 0)
107 {
108 const long c_pgp_timeout = cs_subset_long(NeoMutt->sub, "pgp_timeout");
110 return true;
111 }
112 else
113 {
114 PgpExptime = 0;
115 }
116
117 return false;
118}
119
127{
128 char *tty = NULL;
129
130 /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
131 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
132 if (!c_pgp_use_gpg_agent)
133 return false;
134
135 tty = ttyname(0);
136 if (tty)
137 {
138 setenv("GPG_TTY", tty, 0);
139 envlist_set(&NeoMutt->env, "GPG_TTY", tty, false);
140 }
141
142 return true;
143}
144
150static struct PgpKeyInfo *key_parent(struct PgpKeyInfo *k)
151{
152 const bool c_pgp_ignore_subkeys = cs_subset_bool(NeoMutt->sub, "pgp_ignore_subkeys");
153 if ((k->flags & KEYFLAG_SUBKEY) && k->parent && c_pgp_ignore_subkeys)
154 k = k->parent;
155
156 return k;
157}
158
165{
166 k = key_parent(k);
167
168 return k->keyid;
169}
170
177{
178 k = key_parent(k);
179
180 return k->keyid + 8;
181}
182
191{
192 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
193 if (c_pgp_long_ids)
194 return k->keyid;
195 return k->keyid + 8;
196}
197
203char *pgp_keyid(struct PgpKeyInfo *k)
204{
205 k = key_parent(k);
206
207 return pgp_this_keyid(k);
208}
209
215static char *pgp_fingerprint(struct PgpKeyInfo *k)
216{
217 k = key_parent(k);
218
219 return k->fingerprint;
220}
221
234{
235 char *fingerprint = pgp_fingerprint(k);
237}
238
239/* ----------------------------------------------------------------------------
240 * Routines for handing PGP input.
241 */
242
250static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
251{
252 if (!fp_in || !fp_out)
253 return -1;
254
255 int rc = -1;
256
257 const struct Regex *c_pgp_good_sign = cs_subset_regex(NeoMutt->sub, "pgp_good_sign");
258 if (c_pgp_good_sign && c_pgp_good_sign->regex)
259 {
260 char *line = NULL;
261 size_t linelen;
262
263 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
264 {
265 if (mutt_regex_match(c_pgp_good_sign, line))
266 {
267 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
268 rc = 0;
269 }
270 else
271 {
272 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
273 }
274
275 if (mutt_strn_equal(line, "[GNUPG:] ", 9))
276 continue;
277 fputs(line, fp_out);
278 fputc('\n', fp_out);
279 }
280 FREE(&line);
281 }
282 else
283 {
284 mutt_debug(LL_DEBUG2, "No pattern\n");
285 mutt_file_copy_stream(fp_in, fp_out);
286 rc = 1;
287 }
288
289 return rc;
290}
291
303{
304 int rc = -1;
305
306 const struct Regex *c_pgp_decryption_okay = cs_subset_regex(NeoMutt->sub, "pgp_decryption_okay");
307 if (c_pgp_decryption_okay && c_pgp_decryption_okay->regex)
308 {
309 char *line = NULL;
310 size_t linelen;
311
312 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
313 {
314 if (mutt_regex_match(c_pgp_decryption_okay, line))
315 {
316 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
317 rc = 0;
318 break;
319 }
320 else
321 {
322 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
323 }
324 }
325 FREE(&line);
326 }
327 else
328 {
329 mutt_debug(LL_DEBUG2, "No pattern\n");
330 rc = 1;
331 }
332
333 return rc;
334}
335
356static int pgp_check_decryption_okay(FILE *fp_in)
357{
358 int rc = -1;
359 char *line = NULL, *s = NULL;
360 size_t linelen;
361 int inside_decrypt = 0;
362
363 const bool c_pgp_check_gpg_decrypt_status_fd = cs_subset_bool(NeoMutt->sub, "pgp_check_gpg_decrypt_status_fd");
364 if (!c_pgp_check_gpg_decrypt_status_fd)
366
367 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
368 {
369 size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
370 if (plen == 0)
371 continue;
372 s = line + plen;
373 mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
374 if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
375 {
376 inside_decrypt = 1;
377 }
378 else if (mutt_str_startswith(s, "END_DECRYPTION"))
379 {
380 inside_decrypt = 0;
381 }
382 else if (mutt_str_startswith(s, "PLAINTEXT"))
383 {
384 if (!inside_decrypt)
385 {
386 mutt_debug(LL_DEBUG2, " PLAINTEXT encountered outside of DECRYPTION\n");
387 rc = -2;
388 break;
389 }
390 }
391 else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
392 {
393 mutt_debug(LL_DEBUG2, " DECRYPTION_FAILED encountered. Failure\n");
394 rc = -3;
395 break;
396 }
397 else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
398 {
399 /* Don't break out because we still have to check for
400 * PLAINTEXT outside of the decryption boundaries. */
401 mutt_debug(LL_DEBUG2, " DECRYPTION_OKAY encountered\n");
402 rc = 0;
403 }
404 }
405 FREE(&line);
406
407 return rc;
408}
409
423static void pgp_copy_clearsigned(FILE *fp_in, struct State *state, char *charset)
424{
425 char buf[8192] = { 0 };
426 bool complete, armor_header;
427
428 rewind(fp_in);
429
430 /* fromcode comes from the MIME Content-Type charset label. It might
431 * be a wrong label, so we want the ability to do corrections via
432 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
433 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_in, charset, cc_charset(), MUTT_ICONV_HOOK_FROM);
434
435 for (complete = true, armor_header = true;
436 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
437 {
438 if (!complete)
439 {
440 if (!armor_header)
441 state_puts(state, buf);
442 continue;
443 }
444
445 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
446 break;
447
448 if (armor_header)
449 {
450 char *p = mutt_str_skip_whitespace(buf);
451 if (*p == '\0')
452 armor_header = false;
453 continue;
454 }
455
456 if (state->prefix)
457 state_puts(state, state->prefix);
458
459 if ((buf[0] == '-') && (buf[1] == ' '))
460 state_puts(state, buf + 2);
461 else
462 state_puts(state, buf);
463 }
464
466}
467
471int pgp_class_application_handler(struct Body *b, struct State *state)
472{
473 bool could_not_decrypt = false;
474 int decrypt_okay_rc = 0;
475 int needpass = -1;
476 bool pgp_keyblock = false;
477 bool clearsign = false;
478 int rc = -1;
479 int c = 1;
480 long bytes;
481 LOFF_T last_pos, offset;
482 char buf[8192] = { 0 };
483 FILE *fp_pgp_out = NULL, *fp_pgp_in = NULL, *fp_pgp_err = NULL;
484 FILE *fp_tmp = NULL;
485 pid_t pid;
486 struct Buffer *tempfile = buf_pool_get();
487
488 bool maybe_goodsig = true;
489 bool have_any_sigs = false;
490
491 char *gpgcharset = NULL;
492 char body_charset[256] = { 0 };
493 mutt_body_get_charset(b, body_charset, sizeof(body_charset));
494
495 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
496 {
497 return -1;
498 }
499 last_pos = b->offset;
500
501 for (bytes = b->length; bytes > 0;)
502 {
503 if (!fgets(buf, sizeof(buf), state->fp_in))
504 break;
505
506 offset = ftello(state->fp_in);
507 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
508 last_pos = offset;
509
510 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
511 if (plen != 0)
512 {
513 needpass = false;
514 clearsign = false;
515 could_not_decrypt = false;
516 decrypt_okay_rc = 0;
517
518 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
519 {
520 needpass = 1;
521 }
522 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
523 {
524 clearsign = true;
525 }
526 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
527 {
528 pgp_keyblock = true;
529 }
530 else
531 {
532 /* XXX we may wish to recode here */
533 if (state->prefix)
534 state_puts(state, state->prefix);
535 state_puts(state, buf);
536 continue;
537 }
538
539 have_any_sigs = have_any_sigs || (clearsign && (state->flags & STATE_VERIFY));
540
541 /* Copy PGP material to temporary file */
542 buf_mktemp(tempfile);
543 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
544 if (!fp_tmp)
545 {
546 mutt_perror("%s", buf_string(tempfile));
547 FREE(&gpgcharset);
548 goto out;
549 }
550
551 fputs(buf, fp_tmp);
552 while ((bytes > 0) && fgets(buf, sizeof(buf) - 1, state->fp_in))
553 {
554 offset = ftello(state->fp_in);
555 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
556 last_pos = offset;
557
558 fputs(buf, fp_tmp);
559
560 if ((needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf)) ||
561 (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
562 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf))))
563 {
564 break;
565 }
566 /* remember optional Charset: armor header as defined by RFC4880 */
567 if (mutt_str_startswith(buf, "Charset: "))
568 {
569 size_t l = 0;
570 FREE(&gpgcharset);
571 gpgcharset = mutt_str_dup(buf + 9);
572 l = mutt_str_len(gpgcharset);
573 if ((l > 0) && (gpgcharset[l - 1] == '\n'))
574 gpgcharset[l - 1] = 0;
575 if (!mutt_ch_check_charset(gpgcharset, false))
576 mutt_str_replace(&gpgcharset, "UTF-8");
577 }
578 }
579
580 /* leave fp_tmp open in case we still need it - but flush it! */
581 fflush(fp_tmp);
582
583 /* Invoke PGP if needed */
584 if (!clearsign || (state->flags & STATE_VERIFY))
585 {
586 fp_pgp_out = mutt_file_mkstemp();
587 if (!fp_pgp_out)
588 {
589 mutt_perror(_("Can't create temporary file"));
590 goto out;
591 }
592
593 fp_pgp_err = mutt_file_mkstemp();
594 if (!fp_pgp_err)
595 {
596 mutt_perror(_("Can't create temporary file"));
597 goto out;
598 }
599
600 pid = pgp_invoke_decode(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
601 fileno(fp_pgp_err), buf_string(tempfile),
602 (needpass != 0));
603 if (pid == -1)
604 {
605 mutt_file_fclose(&fp_pgp_out);
606 maybe_goodsig = false;
607 fp_pgp_in = NULL;
608 state_attach_puts(state, _("[-- Error: unable to create PGP subprocess --]\n"));
609 }
610 else /* PGP started successfully */
611 {
612 if (needpass)
613 {
616 if (pgp_use_gpg_agent())
617 *PgpPass = '\0';
618 fprintf(fp_pgp_in, "%s\n", PgpPass);
619 }
620
621 mutt_file_fclose(&fp_pgp_in);
622
623 int wait_filter_rc = filter_wait(pid);
624
625 fflush(fp_pgp_err);
626 /* If we are expecting an encrypted message, verify status fd output.
627 * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted,
628 * so we need to be more selective about the value of decrypt_okay_rc.
629 *
630 * -3 indicates we actively found a DECRYPTION_FAILED.
631 * -2 and -1 indicate part or all of the content was plaintext. */
632 if (needpass)
633 {
634 rewind(fp_pgp_err);
635 decrypt_okay_rc = pgp_check_decryption_okay(fp_pgp_err);
636 if (decrypt_okay_rc <= -3)
637 mutt_file_fclose(&fp_pgp_out);
638 }
639
640 if (state->flags & STATE_DISPLAY)
641 {
642 rewind(fp_pgp_err);
643 crypt_current_time(state, "PGP");
644 int checksig_rc = pgp_copy_checksig(fp_pgp_err, state->fp_out);
645
646 if (checksig_rc == 0)
647 have_any_sigs = true;
648 /* Sig is bad if
649 * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
650 * Sig _is_ correct if
651 * gpg_good_sign="" && pgp_decode_command returned 0 */
652 if (checksig_rc == -1 || (wait_filter_rc != 0))
653 maybe_goodsig = false;
654
655 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
656 }
657 if (pgp_use_gpg_agent())
658 {
660 }
661 }
662
663 /* treat empty result as sign of failure */
664 /* TODO: maybe on failure neomutt should include the original undecoded text. */
665 if (fp_pgp_out)
666 {
667 rewind(fp_pgp_out);
668 c = fgetc(fp_pgp_out);
669 ungetc(c, fp_pgp_out);
670 }
671 if (!clearsign && (!fp_pgp_out || (c == EOF)))
672 {
673 could_not_decrypt = true;
675 }
676
677 if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && !(state->flags & STATE_DISPLAY))
678 {
679 mutt_error(_("Could not decrypt PGP message"));
680 goto out;
681 }
682 }
683
684 /* Now, copy cleartext to the screen. */
685 if (state->flags & STATE_DISPLAY)
686 {
687 if (needpass)
688 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
689 else if (pgp_keyblock)
690 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
691 else
692 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
693 }
694
695 if (clearsign)
696 {
697 rewind(fp_tmp);
698 pgp_copy_clearsigned(fp_tmp, state, body_charset);
699 }
700 else if (fp_pgp_out)
701 {
702 struct FgetConv *fc = NULL;
703 int ch;
704 char *expected_charset = (gpgcharset && *gpgcharset) ? gpgcharset : "utf-8";
705
706 mutt_debug(LL_DEBUG3, "pgp: recoding inline from [%s] to [%s]\n",
707 expected_charset, cc_charset());
708
709 rewind(fp_pgp_out);
710 state_set_prefix(state);
711 fc = mutt_ch_fgetconv_open(fp_pgp_out, expected_charset, cc_charset(),
713 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
714 state_prefix_putc(state, ch);
716 }
717
718 /* Multiple PGP blocks can exist, so these need to be closed and
719 * unlinked inside the loop. */
720 mutt_file_fclose(&fp_tmp);
721 mutt_file_unlink(buf_string(tempfile));
722 mutt_file_fclose(&fp_pgp_out);
723 mutt_file_fclose(&fp_pgp_err);
724
725 if (state->flags & STATE_DISPLAY)
726 {
727 state_putc(state, '\n');
728 if (needpass)
729 {
730 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
731 if (could_not_decrypt || (decrypt_okay_rc <= -3))
732 {
733 mutt_error(_("Could not decrypt PGP message"));
734 }
735 else if (decrypt_okay_rc < 0)
736 {
737 /* L10N: You will see this error message if (1) you are decrypting
738 (not encrypting) something and (2) it is a plaintext. So the
739 message does not mean "You failed to encrypt the message." */
740 mutt_error(_("PGP message is not encrypted"));
741 }
742 else
743 {
744 mutt_message(_("PGP message successfully decrypted"));
745 }
746 }
747 else if (pgp_keyblock)
748 {
749 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
750 }
751 else
752 {
753 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
754 }
755 }
756 }
757 else
758 {
759 /* A traditional PGP part may mix signed and unsigned content */
760 /* XXX we may wish to recode here */
761 if (state->prefix)
762 state_puts(state, state->prefix);
763 state_puts(state, buf);
764 }
765 }
766
767 rc = 0;
768
769out:
770 b->goodsig = (maybe_goodsig && have_any_sigs);
771
772 if (fp_tmp)
773 {
774 mutt_file_fclose(&fp_tmp);
775 mutt_file_unlink(buf_string(tempfile));
776 }
777 mutt_file_fclose(&fp_pgp_out);
778 mutt_file_fclose(&fp_pgp_err);
779
780 buf_pool_release(&tempfile);
781
782 FREE(&gpgcharset);
783
784 if (needpass == -1)
785 {
786 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
787 return -1;
788 }
789
790 return rc;
791}
792
800static bool pgp_check_traditional_one_body(FILE *fp, struct Body *b)
801{
802 struct Buffer *tempfile = NULL;
803 char buf[8192] = { 0 };
804 bool rc = false;
805
806 bool sgn = false;
807 bool enc = false;
808 bool key = false;
809
810 if (b->type != TYPE_TEXT)
811 goto cleanup;
812
813 tempfile = buf_pool_get();
814 buf_mktemp(tempfile);
816 MUTT_SAVE_NO_FLAGS) != 0)
817 {
818 unlink(buf_string(tempfile));
819 goto cleanup;
820 }
821
822 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
823 if (!fp_tmp)
824 {
825 unlink(buf_string(tempfile));
826 goto cleanup;
827 }
828
829 while (fgets(buf, sizeof(buf), fp_tmp))
830 {
831 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
832 if (plen != 0)
833 {
834 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
835 enc = true;
836 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
837 sgn = true;
838 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
839 key = true;
840 }
841 }
842 mutt_file_fclose(&fp_tmp);
843 unlink(buf_string(tempfile));
844
845 if (!enc && !sgn && !key)
846 goto cleanup;
847
848 /* fix the content type */
849
850 mutt_param_set(&b->parameter, "format", "fixed");
851 if (enc)
852 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
853 else if (sgn)
854 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
855 else if (key)
856 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
857
858 rc = true;
859
860cleanup:
861 buf_pool_release(&tempfile);
862 return rc;
863}
864
868bool pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
869{
870 bool rc = false;
871 int r;
872 for (; b; b = b->next)
873 {
874 if (!just_one && is_multipart(b))
875 {
876 rc = pgp_class_check_traditional(fp, b->parts, false) || rc;
877 }
878 else if (b->type == TYPE_TEXT)
879 {
881 if (r)
882 rc = rc || r;
883 else
884 rc = pgp_check_traditional_one_body(fp, b) || rc;
885 }
886
887 if (just_one)
888 break;
889 }
890
891 return rc;
892}
893
897int pgp_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
898{
899 FILE *fp_pgp_out = NULL;
900 pid_t pid;
901 int badsig = -1;
902 struct Buffer *sigfile = buf_pool_get();
903
904 buf_printf(sigfile, "%s.asc", tempfile);
905
906 FILE *fp_sig = mutt_file_fopen(buf_string(sigfile), "w");
907 if (!fp_sig)
908 {
909 mutt_perror("%s", buf_string(sigfile));
910 goto cleanup;
911 }
912
913 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
914 {
915 mutt_file_fclose(&fp_sig);
916 goto cleanup;
917 }
918 mutt_file_copy_bytes(state->fp_in, fp_sig, b->length);
919 mutt_file_fclose(&fp_sig);
920
921 FILE *fp_pgp_err = mutt_file_mkstemp();
922 if (!fp_pgp_err)
923 {
924 mutt_perror(_("Can't create temporary file"));
925 unlink(buf_string(sigfile));
926 goto cleanup;
927 }
928
929 crypt_current_time(state, "PGP");
930
931 pid = pgp_invoke_verify(NULL, &fp_pgp_out, NULL, -1, -1, fileno(fp_pgp_err),
932 tempfile, buf_string(sigfile));
933 if (pid != -1)
934 {
935 if (pgp_copy_checksig(fp_pgp_out, state->fp_out) >= 0)
936 badsig = 0;
937
938 mutt_file_fclose(&fp_pgp_out);
939 fflush(fp_pgp_err);
940 rewind(fp_pgp_err);
941
942 if (pgp_copy_checksig(fp_pgp_err, state->fp_out) >= 0)
943 badsig = 0;
944
945 const int rv = filter_wait(pid);
946 if (rv)
947 badsig = -1;
948
949 mutt_debug(LL_DEBUG1, "filter_wait returned %d\n", rv);
950 }
951
952 mutt_file_fclose(&fp_pgp_err);
953
954 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
955
957
958cleanup:
959 buf_pool_release(&sigfile);
960
961 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
962 return badsig;
963}
964
970static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *b)
971{
972 struct State state = { 0 };
973 struct Buffer *tempfile = buf_pool_get();
974
975 buf_mktemp(tempfile);
976 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
977 if (!fp_tmp)
978 {
979 mutt_perror("%s", buf_string(tempfile));
980 goto cleanup;
981 }
982
983 state.fp_in = fp;
984 state.fp_out = fp_tmp;
985
986 mutt_body_handler(b, &state);
987
988 mutt_file_fclose(&fp_tmp);
989
992
993 mutt_file_unlink(buf_string(tempfile));
994
995cleanup:
996 buf_pool_release(&tempfile);
997}
998
1003{
1004 if (!fp)
1005 {
1006 mutt_error(_("Internal error. Please submit a bug report."));
1007 return;
1008 }
1009
1010 mutt_endwin();
1011
1012 OptDontHandlePgpKeys = true;
1014 OptDontHandlePgpKeys = false;
1015}
1016
1025static struct Body *pgp_decrypt_part(struct Body *a, struct State *state,
1026 FILE *fp_out, struct Body *p)
1027{
1028 if (!a || !state || !fp_out || !p)
1029 return NULL;
1030
1031 char buf[1024] = { 0 };
1032 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_tmp = NULL;
1033 struct Body *tattach = NULL;
1034 pid_t pid;
1035 int rv;
1036 struct Buffer *tempfile = buf_pool_get();
1037
1038 FILE *fp_pgp_err = mutt_file_mkstemp();
1039 if (!fp_pgp_err)
1040 {
1041 mutt_perror(_("Can't create temporary file"));
1042 goto cleanup;
1043 }
1044
1045 buf_mktemp(tempfile);
1046 fp_pgp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
1047 if (!fp_pgp_tmp)
1048 {
1049 mutt_perror("%s", buf_string(tempfile));
1050 mutt_file_fclose(&fp_pgp_err);
1051 goto cleanup;
1052 }
1053
1054 /* Position the stream at the beginning of the body, and send the data to
1055 * the temporary file. */
1056
1057 if (!mutt_file_seek(state->fp_in, a->offset, SEEK_SET))
1058 {
1059 mutt_file_fclose(&fp_pgp_tmp);
1060 mutt_file_fclose(&fp_pgp_err);
1061 goto cleanup;
1062 }
1063 mutt_file_copy_bytes(state->fp_in, fp_pgp_tmp, a->length);
1064 mutt_file_fclose(&fp_pgp_tmp);
1065
1066 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1067 fileno(fp_pgp_err), buf_string(tempfile));
1068 if (pid == -1)
1069 {
1070 mutt_file_fclose(&fp_pgp_err);
1071 unlink(buf_string(tempfile));
1072 if (state->flags & STATE_DISPLAY)
1073 {
1074 state_attach_puts(state, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1075 }
1076 goto cleanup;
1077 }
1078
1079 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1080 * active, because this might lead to a passphrase send as the message. */
1081 if (!pgp_use_gpg_agent())
1082 fputs(PgpPass, fp_pgp_in);
1083 fputc('\n', fp_pgp_in);
1084 mutt_file_fclose(&fp_pgp_in);
1085
1086 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1087 * read_mime_header has a hard time parsing the message. */
1088 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1089 {
1090 size_t len = mutt_str_len(buf);
1091 if ((len > 1) && (buf[len - 2] == '\r'))
1092 strcpy(buf + len - 2, "\n");
1093 fputs(buf, fp_out);
1094 }
1095
1096 mutt_file_fclose(&fp_pgp_out);
1097
1098 rv = filter_wait(pid);
1099 const bool c_pgp_use_gpg_agent = cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1100 if (c_pgp_use_gpg_agent)
1102
1103 mutt_file_unlink(buf_string(tempfile));
1104
1105 fflush(fp_pgp_err);
1106 rewind(fp_pgp_err);
1107 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1108 {
1109 mutt_error(_("Decryption failed"));
1111 mutt_file_fclose(&fp_pgp_err);
1112 goto cleanup;
1113 }
1114
1115 if (state->flags & STATE_DISPLAY)
1116 {
1117 rewind(fp_pgp_err);
1118 if ((pgp_copy_checksig(fp_pgp_err, state->fp_out) == 0) && !rv)
1119 p->goodsig = true;
1120 else
1121 p->goodsig = false;
1122 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
1123 }
1124 mutt_file_fclose(&fp_pgp_err);
1125
1126 fflush(fp_out);
1127 rewind(fp_out);
1128
1129 if (fgetc(fp_out) == EOF)
1130 {
1131 mutt_error(_("Decryption failed"));
1133 goto cleanup;
1134 }
1135
1136 rewind(fp_out);
1137 const long size = mutt_file_get_size_fp(fp_out);
1138 if (size == 0)
1139 {
1140 goto cleanup;
1141 }
1142
1143 tattach = mutt_read_mime_header(fp_out, 0);
1144 if (tattach)
1145 {
1146 /* Need to set the length of this body part. */
1147 tattach->length = size - tattach->offset;
1148
1149 /* See if we need to recurse on this MIME part. */
1150 mutt_parse_part(fp_out, tattach);
1151 }
1152
1153cleanup:
1154 buf_pool_release(&tempfile);
1155 return tattach;
1156}
1157
1161int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1162{
1163 struct State state = { 0 };
1164 struct Body *p = b;
1165 bool need_decode = false;
1166 LOFF_T saved_offset = 0;
1167 size_t saved_length = 0;
1168 FILE *fp_decoded = NULL;
1169 int rc = 0;
1170
1172 {
1173 b = b->parts->next;
1174 /* Some clients improperly encode the octetstream part. */
1175 if (b->encoding != ENC_7BIT)
1176 need_decode = true;
1177 }
1179 {
1180 b = b->parts->next->next;
1181 need_decode = true;
1182 }
1183 else
1184 {
1185 return -1;
1186 }
1187
1188 state.fp_in = fp_in;
1189
1190 if (need_decode)
1191 {
1192 saved_offset = b->offset;
1193 saved_length = b->length;
1194
1195 fp_decoded = mutt_file_mkstemp();
1196 if (!fp_decoded)
1197 {
1198 mutt_perror(_("Can't create temporary file"));
1199 return -1;
1200 }
1201
1202 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1203 {
1204 rc = -1;
1205 goto bail;
1206 }
1207 state.fp_out = fp_decoded;
1208
1209 mutt_decode_attachment(b, &state);
1210
1211 fflush(fp_decoded);
1212 b->length = ftello(fp_decoded);
1213 b->offset = 0;
1214 rewind(fp_decoded);
1215 state.fp_in = fp_decoded;
1216 state.fp_out = 0;
1217 }
1218
1219 *fp_out = mutt_file_mkstemp();
1220 if (!*fp_out)
1221 {
1222 mutt_perror(_("Can't create temporary file"));
1223 rc = -1;
1224 goto bail;
1225 }
1226
1227 *b_dec = pgp_decrypt_part(b, &state, *fp_out, p);
1228 if (!*b_dec)
1229 rc = -1;
1230 rewind(*fp_out);
1231
1232bail:
1233 if (need_decode)
1234 {
1235 b->length = saved_length;
1236 b->offset = saved_offset;
1237 mutt_file_fclose(&fp_decoded);
1238 }
1239
1240 return rc;
1241}
1242
1246int pgp_class_encrypted_handler(struct Body *b, struct State *state)
1247{
1248 FILE *fp_in = NULL;
1249 struct Body *tattach = NULL;
1250 int rc = 0;
1251
1252 FILE *fp_out = mutt_file_mkstemp();
1253 if (!fp_out)
1254 {
1255 mutt_perror(_("Can't create temporary file"));
1256 if (state->flags & STATE_DISPLAY)
1257 {
1258 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
1259 }
1260 return -1;
1261 }
1262
1263 if (state->flags & STATE_DISPLAY)
1264 crypt_current_time(state, "PGP");
1265
1266 tattach = pgp_decrypt_part(b, state, fp_out, b);
1267 if (tattach)
1268 {
1269 if (state->flags & STATE_DISPLAY)
1270 {
1271 state_attach_puts(state, _("[-- The following data is PGP/MIME encrypted --]\n"));
1272 mutt_protected_headers_handler(tattach, state);
1273 }
1274
1275 /* Store any protected headers in the parent so they can be
1276 * accessed for index updates after the handler recursion is done.
1277 * This is done before the handler to prevent a nested encrypted
1278 * handler from freeing the headers. */
1280 b->mime_headers = tattach->mime_headers;
1281 tattach->mime_headers = NULL;
1282
1283 fp_in = state->fp_in;
1284 state->fp_in = fp_out;
1285 rc = mutt_body_handler(tattach, state);
1286 state->fp_in = fp_in;
1287
1288 /* Embedded multipart signed protected headers override the
1289 * encrypted headers. We need to do this after the handler so
1290 * they can be printed in the pager. */
1291 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
1292 {
1294 b->mime_headers = tattach->parts->mime_headers;
1295 tattach->parts->mime_headers = NULL;
1296 }
1297
1298 /* if a multipart/signed is the _only_ sub-part of a
1299 * multipart/encrypted, cache signature verification
1300 * status. */
1301 if (mutt_is_multipart_signed(tattach) && !tattach->next)
1302 b->goodsig |= tattach->goodsig;
1303
1304 if (state->flags & STATE_DISPLAY)
1305 state_attach_puts(state, _("[-- End of PGP/MIME encrypted data --]\n"));
1306
1307 mutt_body_free(&tattach);
1308 /* clear 'Invoking...' message, since there's no error */
1309 mutt_message(_("PGP message successfully decrypted"));
1310 }
1311 else
1312 {
1313 mutt_error(_("Could not decrypt PGP message"));
1314 /* void the passphrase, even if it's not necessarily the problem */
1316 rc = -1;
1317 }
1318
1319 mutt_file_fclose(&fp_out);
1320
1321 return rc;
1322}
1323
1324/* ----------------------------------------------------------------------------
1325 * Routines for sending PGP/MIME messages.
1326 */
1327
1331struct Body *pgp_class_sign_message(struct Body *b, const struct AddressList *from)
1332{
1333 struct Body *b_enc = NULL, *rv = NULL;
1334 char buf[1024] = { 0 };
1335 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_err = NULL, *fp_signed = NULL;
1336 bool err = false;
1337 bool empty = true;
1338 pid_t pid;
1339 struct Buffer *sigfile = buf_pool_get();
1340 struct Buffer *signedfile = buf_pool_get();
1341
1342 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
1343
1344 buf_mktemp(sigfile);
1345 FILE *fp_sig = mutt_file_fopen(buf_string(sigfile), "w");
1346 if (!fp_sig)
1347 {
1348 goto cleanup;
1349 }
1350
1351 buf_mktemp(signedfile);
1352 fp_signed = mutt_file_fopen(buf_string(signedfile), "w");
1353 if (!fp_signed)
1354 {
1355 mutt_perror("%s", buf_string(signedfile));
1356 mutt_file_fclose(&fp_sig);
1357 unlink(buf_string(sigfile));
1358 goto cleanup;
1359 }
1360
1361 mutt_write_mime_header(b, fp_signed, NeoMutt->sub);
1362 fputc('\n', fp_signed);
1363 mutt_write_mime_body(b, fp_signed, NeoMutt->sub);
1364 mutt_file_fclose(&fp_signed);
1365
1366 pid = pgp_invoke_sign(&fp_pgp_in, &fp_pgp_out, &fp_pgp_err, -1, -1, -1,
1367 buf_string(signedfile));
1368 if (pid == -1)
1369 {
1370 mutt_perror(_("Can't open PGP subprocess"));
1371 mutt_file_fclose(&fp_sig);
1372 unlink(buf_string(sigfile));
1373 unlink(buf_string(signedfile));
1374 goto cleanup;
1375 }
1376
1377 if (!pgp_use_gpg_agent())
1378 fputs(PgpPass, fp_pgp_in);
1379 fputc('\n', fp_pgp_in);
1380 mutt_file_fclose(&fp_pgp_in);
1381
1382 /* Read back the PGP signature. Also, change MESSAGE=>SIGNATURE as
1383 * recommended for future releases of PGP. */
1384 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1385 {
1386 if (mutt_str_equal("-----BEGIN PGP MESSAGE-----\n", buf))
1387 fputs("-----BEGIN PGP SIGNATURE-----\n", fp_sig);
1388 else if (mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
1389 fputs("-----END PGP SIGNATURE-----\n", fp_sig);
1390 else
1391 fputs(buf, fp_sig);
1392 empty = false; /* got some output, so we're ok */
1393 }
1394
1395 /* check for errors from PGP */
1396 err = false;
1397 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1398 {
1399 err = true;
1400 fputs(buf, stdout);
1401 }
1402
1403 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1404 if (filter_wait(pid) && c_pgp_check_exit)
1405 empty = true;
1406
1407 mutt_file_fclose(&fp_pgp_err);
1408 mutt_file_fclose(&fp_pgp_out);
1409 unlink(buf_string(signedfile));
1410
1411 if (mutt_file_fclose(&fp_sig) != 0)
1412 {
1413 mutt_perror("fclose");
1414 unlink(buf_string(sigfile));
1415 goto cleanup;
1416 }
1417
1418 if (err)
1420 if (empty)
1421 {
1422 unlink(buf_string(sigfile));
1423 /* most likely error is a bad passphrase, so automatically forget it */
1425 goto cleanup; /* fatal error while signing */
1426 }
1427
1428 b_enc = mutt_body_new();
1429 b_enc->type = TYPE_MULTIPART;
1430 b_enc->subtype = mutt_str_dup("signed");
1431 b_enc->encoding = ENC_7BIT;
1432 b_enc->use_disp = false;
1433 b_enc->disposition = DISP_INLINE;
1434 rv = b_enc;
1435
1437 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-signature");
1438 mutt_param_set(&b_enc->parameter, "micalg", pgp_micalg(buf_string(sigfile)));
1439
1440 b_enc->parts = b;
1441
1442 b_enc->parts->next = mutt_body_new();
1443 b_enc = b_enc->parts->next;
1444 b_enc->type = TYPE_APPLICATION;
1445 b_enc->subtype = mutt_str_dup("pgp-signature");
1446 b_enc->filename = buf_strdup(sigfile);
1447 b_enc->use_disp = false;
1448 b_enc->disposition = DISP_NONE;
1449 b_enc->encoding = ENC_7BIT;
1450 b_enc->unlink = true; /* ok to remove this file after sending. */
1451 mutt_param_set(&b_enc->parameter, "name", "signature.asc");
1452
1453cleanup:
1454 buf_pool_release(&sigfile);
1455 buf_pool_release(&signedfile);
1456 return rv;
1457}
1458
1462char *pgp_class_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
1463{
1464 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
1465 struct ListNode *crypt_hook = NULL;
1466 const char *keyid = NULL;
1467 char *keylist = NULL;
1468 size_t keylist_size = 0;
1469 size_t keylist_used = 0;
1470 struct Address *p = NULL;
1471 struct PgpKeyInfo *k_info = NULL;
1472 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
1473 char buf[1024] = { 0 };
1474 bool key_selected;
1475 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
1476
1477 struct Address *a = NULL;
1478 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
1479 /* Iterate through each recipient address to find an encryption key */
1480 TAILQ_FOREACH(a, addrlist, entries)
1481 {
1482 key_selected = false;
1483 /* Check for crypt-hook overrides for this recipient */
1484 mutt_crypt_hook(&crypt_hook_list, a);
1485 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
1486 do
1487 {
1488 p = a;
1489 k_info = NULL;
1490
1491 /* If a crypt-hook provides a key ID, confirm with the user unless
1492 * in opportunistic encryption mode */
1493 if (crypt_hook)
1494 {
1495 keyid = crypt_hook->data;
1496 enum QuadOption ans = MUTT_YES;
1497 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
1498 {
1499 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
1500 buf_string(p->mailbox));
1501 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
1502 }
1503 if (ans == MUTT_YES)
1504 {
1505 if (crypt_is_numerical_keyid(keyid))
1506 {
1507 if (mutt_strn_equal(keyid, "0x", 2))
1508 keyid += 2;
1509 goto bypass_selection; /* you don't see this. */
1510 }
1511
1512 /* check for e-mail address */
1513 mutt_addrlist_clear(&hookal);
1514 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
1515 {
1516 mutt_addrlist_qualify(&hookal, fqdn);
1517 p = TAILQ_FIRST(&hookal);
1518 }
1519 else if (!oppenc_mode)
1520 {
1522 }
1523 }
1524 else if (ans == MUTT_NO)
1525 {
1526 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
1527 {
1528 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1529 continue;
1530 }
1531 }
1532 else if (ans == MUTT_ABORT)
1533 {
1534 FREE(&keylist);
1535 mutt_addrlist_clear(&hookal);
1536 mutt_list_free(&crypt_hook_list);
1537 return NULL;
1538 }
1539 }
1540
1541 /* If no key found yet, try looking up by address in the keyring */
1542 if (!k_info)
1543 {
1545 k_info = pgp_getkeybyaddr(p, KEYFLAG_CANENCRYPT, PGP_PUBRING, oppenc_mode);
1546 }
1547
1548 /* Last resort: prompt the user to enter a key ID interactively */
1549 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
1550 {
1551 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
1553 }
1554
1555 if (!k_info)
1556 {
1557 FREE(&keylist);
1558 mutt_addrlist_clear(&hookal);
1559 mutt_list_free(&crypt_hook_list);
1560 return NULL;
1561 }
1562
1563 keyid = pgp_fpr_or_lkeyid(k_info);
1564
1565 bypass_selection:
1566 /* Append the selected key ID to the space-separated keylist string */
1567 keylist_size += mutt_str_len(keyid) + 4;
1568 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
1569 sprintf(keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", keyid);
1570 keylist_used = mutt_str_len(keylist);
1571
1572 key_selected = true;
1573
1574 pgp_key_free(&k_info);
1575 mutt_addrlist_clear(&hookal);
1576
1577 if (crypt_hook)
1578 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1579
1580 } while (crypt_hook);
1581
1582 mutt_list_free(&crypt_hook_list);
1583 }
1584 return keylist;
1585}
1586
1593struct Body *pgp_class_encrypt_message(struct Body *b, char *keylist, bool sign,
1594 const struct AddressList *from)
1595{
1596 char buf[1024] = { 0 };
1597 FILE *fp_pgp_in = NULL, *fp_tmp = NULL;
1598 struct Body *b_enc = NULL;
1599 bool err = false;
1600 bool empty = false;
1601 pid_t pid;
1602 struct Buffer *tempfile = buf_pool_get();
1603 struct Buffer *pgpinfile = buf_pool_get();
1604
1605 buf_mktemp(tempfile);
1606 FILE *fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
1607 if (!fp_out)
1608 {
1609 mutt_perror("%s", buf_string(tempfile));
1610 goto cleanup;
1611 }
1612
1613 FILE *fp_pgp_err = mutt_file_mkstemp();
1614 if (!fp_pgp_err)
1615 {
1616 mutt_perror(_("Can't create temporary file"));
1617 unlink(buf_string(tempfile));
1618 mutt_file_fclose(&fp_out);
1619 goto cleanup;
1620 }
1621
1622 buf_mktemp(pgpinfile);
1623 fp_tmp = mutt_file_fopen(buf_string(pgpinfile), "w");
1624 if (!fp_tmp)
1625 {
1626 mutt_perror("%s", buf_string(pgpinfile));
1627 unlink(buf_string(tempfile));
1628 mutt_file_fclose(&fp_out);
1629 mutt_file_fclose(&fp_pgp_err);
1630 goto cleanup;
1631 }
1632
1633 if (sign)
1635
1636 mutt_write_mime_header(b, fp_tmp, NeoMutt->sub);
1637 fputc('\n', fp_tmp);
1638 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
1639 mutt_file_fclose(&fp_tmp);
1640
1641 pid = pgp_invoke_encrypt(&fp_pgp_in, NULL, NULL, -1, fileno(fp_out),
1642 fileno(fp_pgp_err), buf_string(pgpinfile), keylist, sign);
1643 if (pid == -1)
1644 {
1645 mutt_file_fclose(&fp_out);
1646 mutt_file_fclose(&fp_pgp_err);
1647 unlink(buf_string(pgpinfile));
1648 goto cleanup;
1649 }
1650
1651 if (sign)
1652 {
1653 if (!pgp_use_gpg_agent())
1654 fputs(PgpPass, fp_pgp_in);
1655 fputc('\n', fp_pgp_in);
1656 }
1657 mutt_file_fclose(&fp_pgp_in);
1658
1659 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1660 if (filter_wait(pid) && c_pgp_check_exit)
1661 empty = true;
1662
1663 unlink(buf_string(pgpinfile));
1664
1665 fflush(fp_out);
1666 rewind(fp_out);
1667 if (!empty)
1668 empty = (fgetc(fp_out) == EOF);
1669 mutt_file_fclose(&fp_out);
1670
1671 fflush(fp_pgp_err);
1672 rewind(fp_pgp_err);
1673 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1674 {
1675 err = true;
1676 fputs(buf, stdout);
1677 }
1678 mutt_file_fclose(&fp_pgp_err);
1679
1680 /* pause if there is any error output from PGP */
1681 if (err)
1683
1684 if (empty)
1685 {
1686 /* fatal error while trying to encrypt message */
1687 if (sign)
1688 pgp_class_void_passphrase(); /* just in case */
1689 unlink(buf_string(tempfile));
1690 goto cleanup;
1691 }
1692
1693 b_enc = mutt_body_new();
1694 b_enc->type = TYPE_MULTIPART;
1695 b_enc->subtype = mutt_str_dup("encrypted");
1696 b_enc->encoding = ENC_7BIT;
1697 b_enc->use_disp = false;
1698 b_enc->disposition = DISP_INLINE;
1699
1701 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1702
1703 b_enc->parts = mutt_body_new();
1704 b_enc->parts->type = TYPE_APPLICATION;
1705 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1706 b_enc->parts->encoding = ENC_7BIT;
1707
1708 b_enc->parts->next = mutt_body_new();
1709 b_enc->parts->next->type = TYPE_APPLICATION;
1710 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1711 b_enc->parts->next->encoding = ENC_7BIT;
1712 b_enc->parts->next->filename = buf_strdup(tempfile);
1713 b_enc->parts->next->use_disp = true;
1714 b_enc->parts->next->disposition = DISP_ATTACH;
1715 b_enc->parts->next->unlink = true; /* delete after sending the message */
1716 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime can save */
1717
1718cleanup:
1719 buf_pool_release(&tempfile);
1720 buf_pool_release(&pgpinfile);
1721 return b_enc;
1722}
1723
1727struct Body *pgp_class_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
1728{
1729 struct Body *b_enc = NULL;
1730 char body_charset[256] = { 0 };
1731 const char *from_charset = NULL;
1732 const char *send_charset = NULL;
1733 bool empty = false;
1734 bool err;
1735 char buf[256] = { 0 };
1736 pid_t pid;
1737 struct Buffer *pgpinfile = buf_pool_get();
1738 struct Buffer *pgpoutfile = buf_pool_get();
1739
1740 if (b->type != TYPE_TEXT)
1741 goto cleanup;
1742 if (!mutt_istr_equal(b->subtype, "plain"))
1743 goto cleanup;
1744
1745 FILE *fp_body = mutt_file_fopen(b->filename, "r");
1746 if (!fp_body)
1747 {
1748 mutt_perror("%s", b->filename);
1749 goto cleanup;
1750 }
1751
1752 buf_mktemp(pgpinfile);
1753 FILE *fp_pgp_in = mutt_file_fopen(buf_string(pgpinfile), "w");
1754 if (!fp_pgp_in)
1755 {
1756 mutt_perror("%s", buf_string(pgpinfile));
1757 mutt_file_fclose(&fp_body);
1758 goto cleanup;
1759 }
1760
1761 /* The following code is really correct: If noconv is set,
1762 * b's charset parameter contains the on-disk character set, and
1763 * we have to convert from that to utf-8. If noconv is not set,
1764 * we have to convert from $charset to utf-8. */
1765
1766 mutt_body_get_charset(b, body_charset, sizeof(body_charset));
1767 if (b->noconv)
1768 from_charset = body_charset;
1769 else
1770 from_charset = cc_charset();
1771
1772 if (mutt_ch_is_us_ascii(body_charset))
1773 {
1774 send_charset = "us-ascii";
1775 mutt_file_copy_stream(fp_body, fp_pgp_in);
1776 }
1777 else
1778 {
1779 int c;
1780 struct FgetConv *fc = NULL;
1781
1782 if (flags & SEC_ENCRYPT)
1783 send_charset = "us-ascii";
1784 else
1785 send_charset = "utf-8";
1786
1787 /* fromcode is assumed to be correct: we set flags to 0 */
1788 fc = mutt_ch_fgetconv_open(fp_body, from_charset, "utf-8", MUTT_ICONV_NO_FLAGS);
1789 while ((c = mutt_ch_fgetconv(fc)) != EOF)
1790 fputc(c, fp_pgp_in);
1791
1793 }
1794 mutt_file_fclose(&fp_body);
1795 mutt_file_fclose(&fp_pgp_in);
1796
1797 buf_mktemp(pgpoutfile);
1798 FILE *fp_pgp_out = mutt_file_fopen(buf_string(pgpoutfile), "w+");
1799 FILE *fp_pgp_err = mutt_file_mkstemp();
1800 if (!fp_pgp_out || !fp_pgp_err)
1801 {
1802 mutt_perror("%s", fp_pgp_out ? "Can't create temporary file" : buf_string(pgpoutfile));
1803 unlink(buf_string(pgpinfile));
1804 if (fp_pgp_out)
1805 {
1806 mutt_file_fclose(&fp_pgp_out);
1807 unlink(buf_string(pgpoutfile));
1808 }
1809 mutt_file_fclose(&fp_pgp_err);
1810 goto cleanup;
1811 }
1812
1813 pid = pgp_invoke_traditional(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
1814 fileno(fp_pgp_err), buf_string(pgpinfile), keylist, flags);
1815 if (pid == -1)
1816 {
1817 mutt_perror(_("Can't invoke PGP"));
1818 mutt_file_fclose(&fp_pgp_out);
1819 mutt_file_fclose(&fp_pgp_err);
1820 mutt_file_unlink(buf_string(pgpinfile));
1821 unlink(buf_string(pgpoutfile));
1822 goto cleanup;
1823 }
1824
1825 if (pgp_use_gpg_agent())
1826 *PgpPass = '\0';
1827 if (flags & SEC_SIGN)
1828 fprintf(fp_pgp_in, "%s\n", PgpPass);
1829 mutt_file_fclose(&fp_pgp_in);
1830
1831 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1832 if (filter_wait(pid) && c_pgp_check_exit)
1833 empty = true;
1834
1835 mutt_file_unlink(buf_string(pgpinfile));
1836
1837 fflush(fp_pgp_out);
1838 fflush(fp_pgp_err);
1839
1840 rewind(fp_pgp_out);
1841 rewind(fp_pgp_err);
1842
1843 if (!empty)
1844 empty = (fgetc(fp_pgp_out) == EOF);
1845 mutt_file_fclose(&fp_pgp_out);
1846
1847 err = false;
1848
1849 while (fgets(buf, sizeof(buf), fp_pgp_err))
1850 {
1851 err = true;
1852 fputs(buf, stdout);
1853 }
1854
1855 mutt_file_fclose(&fp_pgp_err);
1856
1857 if (err)
1859
1860 if (empty)
1861 {
1862 if (flags & SEC_SIGN)
1863 pgp_class_void_passphrase(); /* just in case */
1864 unlink(buf_string(pgpoutfile));
1865 goto cleanup;
1866 }
1867
1868 b_enc = mutt_body_new();
1869
1870 b_enc->encoding = ENC_7BIT;
1871
1872 b_enc->type = TYPE_TEXT;
1873 b_enc->subtype = mutt_str_dup("plain");
1874
1875 mutt_param_set(&b_enc->parameter, "x-action",
1876 (flags & SEC_ENCRYPT) ? "pgp-encrypted" : "pgp-signed");
1877 mutt_param_set(&b_enc->parameter, "charset", send_charset);
1878
1879 b_enc->filename = buf_strdup(pgpoutfile);
1880
1881 b_enc->disposition = DISP_NONE;
1882 b_enc->unlink = true;
1883
1884 b_enc->noconv = true;
1885 b_enc->use_disp = false;
1886
1887 if (!(flags & SEC_ENCRYPT))
1888 b_enc->encoding = b->encoding;
1889
1890cleanup:
1891 buf_pool_release(&pgpinfile);
1892 buf_pool_release(&pgpoutfile);
1893 return b_enc;
1894}
1895
1900{
1901 struct PgpKeyInfo *p = NULL;
1902 const char *prompt = NULL;
1903 const char *letters = NULL;
1904 const char *choices = NULL;
1905 char promptbuf[1024] = { 0 };
1906 int choice;
1907
1908 if (!(WithCrypto & APPLICATION_PGP))
1909 return e->security;
1910
1911 /* If autoinline and no crypto options set, then set inline. */
1912 const bool c_pgp_auto_inline = cs_subset_bool(NeoMutt->sub, "pgp_auto_inline");
1913 if (c_pgp_auto_inline &&
1914 !((e->security & APPLICATION_PGP) && (e->security & (SEC_SIGN | SEC_ENCRYPT))))
1915 {
1916 e->security |= SEC_INLINE;
1917 }
1918
1920
1921 char *mime_inline = NULL;
1922 if (e->security & SEC_INLINE)
1923 {
1924 /* L10N: The next string MUST have the same highlighted letter
1925 One of them will appear in each of the three strings marked "(inline"), below. */
1926 mime_inline = _("PGP/M(i)ME");
1927 }
1928 else
1929 {
1930 /* L10N: The previous string MUST have the same highlighted letter
1931 One of them will appear in each of the three strings marked "(inline"), below. */
1932 mime_inline = _("(i)nline");
1933 }
1934 /* Opportunistic encrypt is controlling encryption. Allow to toggle
1935 * between inline and mime, but not turn encryption on or off.
1936 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
1937 * letter choices for those. */
1938 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1939 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
1940 {
1941 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1942 {
1943 snprintf(promptbuf, sizeof(promptbuf),
1944 /* L10N: PGP options (inline) (opportunistic encryption is on) */
1945 _("PGP (s)ign, sign (a)s, %s format, (c)lear, or (o)ppenc mode off?"),
1946 mime_inline);
1947 prompt = promptbuf;
1948 /* L10N: PGP options (inline) (opportunistic encryption is on)
1949 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1950 letters = _("saico");
1951 choices = "SaiCo";
1952 }
1953 else
1954 {
1955 /* L10N: PGP options (opportunistic encryption is on) */
1956 prompt = _("PGP (s)ign, sign (a)s, (c)lear, or (o)ppenc mode off?");
1957 /* L10N: PGP options (opportunistic encryption is on) */
1958 letters = _("saco");
1959 choices = "SaCo";
1960 }
1961 }
1962 else if (c_crypt_opportunistic_encrypt)
1963 {
1964 /* Opportunistic encryption option is set, but is toggled off
1965 * for this message. */
1966 /* When the message is not selected for signing or encryption, the toggle
1967 * between PGP/MIME and Traditional doesn't make sense. */
1968 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1969 {
1970 snprintf(promptbuf, sizeof(promptbuf),
1971 /* L10N: PGP options (inline) (opportunistic encryption is off) */
1972 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, (c)lear, or (o)ppenc mode?"),
1973 mime_inline);
1974 prompt = promptbuf;
1975 /* L10N: PGP options (inline) (opportunistic encryption is off)
1976 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1977 letters = _("esabico");
1978 choices = "esabicO";
1979 }
1980 else
1981 {
1982 /* L10N: PGP options (opportunistic encryption is off) */
1983 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
1984 /* L10N: PGP options (opportunistic encryption is off) */
1985 letters = _("esabco");
1986 choices = "esabcO";
1987 }
1988 }
1989 else
1990 {
1991 /* Opportunistic encryption is unset */
1992 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1993 {
1994 snprintf(promptbuf, sizeof(promptbuf),
1995 /* L10N: PGP options (inline) */
1996 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, or (c)lear?"),
1997 mime_inline);
1998 prompt = promptbuf;
1999 /* L10N: PGP options (inline)
2000 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
2001 letters = _("esabic");
2002 choices = "esabic";
2003 }
2004 else
2005 {
2006 /* L10N: PGP options */
2007 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (c)lear?");
2008 /* L10N: PGP options */
2009 letters = _("esabc");
2010 choices = "esabc";
2011 }
2012 }
2013
2014 choice = mw_multi_choice(prompt, letters);
2015 if (choice > 0)
2016 {
2017 switch (choices[choice - 1])
2018 {
2019 case 'a': /* sign (a)s */
2020 OptPgpCheckTrust = false;
2021
2022 p = pgp_ask_for_key(_("Sign as: "), NULL, KEYFLAG_NO_FLAGS, PGP_SECRING);
2023 if (p)
2024 {
2025 char input_signas[128] = { 0 };
2026 snprintf(input_signas, sizeof(input_signas), "0x%s", pgp_fpr_or_lkeyid(p));
2027 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
2028 pgp_key_free(&p);
2029
2030 e->security |= SEC_SIGN;
2031
2032 crypt_pgp_void_passphrase(); /* probably need a different passphrase */
2033 }
2034 break;
2035
2036 case 'b': /* (b)oth */
2037 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2038 break;
2039
2040 case 'C':
2041 e->security &= ~SEC_SIGN;
2042 break;
2043
2044 case 'c': /* (c)lear */
2045 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2046 break;
2047
2048 case 'e': /* (e)ncrypt */
2049 e->security |= SEC_ENCRYPT;
2050 e->security &= ~SEC_SIGN;
2051 break;
2052
2053 case 'i': /* toggle (i)nline */
2054 e->security ^= SEC_INLINE;
2055 break;
2056
2057 case 'O': /* oppenc mode on */
2060 break;
2061
2062 case 'o': /* oppenc mode off */
2064 break;
2065
2066 case 'S': /* (s)ign in oppenc mode */
2067 e->security |= SEC_SIGN;
2068 break;
2069
2070 case 's': /* (s)ign */
2071 e->security &= ~SEC_ENCRYPT;
2072 e->security |= SEC_SIGN;
2073 break;
2074 }
2075 }
2076
2077 return e->security;
2078}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
Email Address Handling.
GUI display the mailboxes in a side panel.
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
long cs_subset_long(const struct ConfigSubset *sub, const char *name)
Get a long config item by name.
Definition helpers.c:95
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1045
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition crypt.c:1479
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition crypt.c:467
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition crypt.c:504
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:809
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:548
Signing/encryption multiplexor.
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition cryptglue.c:190
Wrapper around crypto functions.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:173
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition curs_lib.c:100
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:151
Edit a string.
#define MUTT_COMP_PASS
Password mode (no echo)
Definition wdata.h:44
#define MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition wdata.h:45
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition body.c:133
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1833
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1370
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
bool envlist_set(char ***envp, const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition envlist.c:88
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:222
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition file.c:682
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition file.c:192
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1427
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:652
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition globals.c:46
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition globals.c:55
Global variables.
int pgp_class_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition pgp.c:471
int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
Definition pgp.c:1161
int pgp_class_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
Definition pgp.c:1246
char * pgp_class_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition pgp.c:1462
bool pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
Look for inline (non-MIME) PGP content - Implements CryptModuleSpecs::pgp_check_traditional() -.
Definition pgp.c:868
struct Body * pgp_class_encrypt_message(struct Body *b, char *keylist, bool sign, const struct AddressList *from)
PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
Definition pgp.c:1593
void pgp_class_extract_key_from_attachment(FILE *fp, struct Body *b)
Extract PGP key from an attachment - Implements CryptModuleSpecs::pgp_extract_key_from_attachment() -...
Definition pgp.c:1002
void pgp_class_invoke_getkeys(struct Address *addr)
Run a command to download a PGP key - Implements CryptModuleSpecs::pgp_invoke_getkeys() -.
Definition pgpinvoke.c:315
void pgp_class_invoke_import(const char *fname)
Import a key from a message into the user's public key ring - Implements CryptModuleSpecs::pgp_invoke...
Definition pgpinvoke.c:287
struct Body * pgp_class_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
Create an inline PGP encrypted, signed email - Implements CryptModuleSpecs::pgp_traditional_encryptsi...
Definition pgp.c:1727
SecurityFlags pgp_class_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition pgp.c:1899
struct Body * pgp_class_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition pgp.c:1331
bool pgp_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition pgp.c:84
int pgp_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition pgp.c:897
void pgp_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition pgp.c:75
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:463
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1117
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1664
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1938
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition exec.c:314
Hook Commands.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
@ ENC_7BIT
7-bit text
Definition mime.h:49
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
@ DISP_ATTACH
Content is attached.
Definition mime.h:63
@ DISP_INLINE
Content is inline.
Definition mime.h:62
@ DISP_NONE
No preferred disposition.
Definition mime.h:65
#define is_multipart(body)
Check if a body part is multipart or a message container.
Definition mime.h:85
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition charset.c:880
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition charset.c:966
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition charset.c:919
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition charset.c:1028
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:948
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
#define mutt_ch_is_us_ascii(str)
Definition charset.h:108
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition charset.h:66
time_t mutt_date_add_timeout(time_t now, time_t timeout)
Safely add a timeout to a given time_t value.
Definition date.c:891
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition regex.c:614
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
void state_prefix_putc(struct State *state, char c)
Write a prefixed character to the state.
Definition state.c:168
#define state_puts(STATE, STR)
Definition state.h:58
#define state_set_prefix(state)
Definition state.h:56
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
#define state_putc(STATE, STR)
Definition state.h:59
#define STATE_VERIFY
Perform signature verification.
Definition state.h:34
#define STATE_NO_FLAGS
No flags are set.
Definition state.h:32
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition string.c:429
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
char * mutt_str_skip_whitespace(const char *p)
Find the first non-whitespace character in a string.
Definition string.c:556
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition mutt_attach.h:58
API for encryption/signing of emails.
#define SEC_INLINE
Email has an inline signature.
Definition lib.h:93
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:84
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:94
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:136
#define KEYFLAG_SUBKEY
Key is a subkey.
Definition lib.h:142
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition lib.h:134
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
#define WithCrypto
Definition lib.h:124
#define SEC_SIGN
Email is signed.
Definition lib.h:87
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition pgp.c:164
char * pgp_this_keyid(struct PgpKeyInfo *k)
Get the ID of this key.
Definition pgp.c:190
static struct Body * pgp_decrypt_part(struct Body *a, struct State *state, FILE *fp_out, struct Body *p)
Decrypt part of a PGP message.
Definition pgp.c:1025
static char * pgp_fingerprint(struct PgpKeyInfo *k)
Get the key's fingerprint.
Definition pgp.c:215
static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
Check PGP output to look for successful outcome.
Definition pgp.c:302
static char PgpPass[1024]
Cached PGP Passphrase.
Definition pgp.c:68
static time_t PgpExptime
Unix time when PgpPass expires.
Definition pgp.c:70
char * pgp_keyid(struct PgpKeyInfo *k)
Get the ID of the main (parent) key.
Definition pgp.c:203
char * pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
Get the fingerprint or long keyid.
Definition pgp.c:233
static struct PgpKeyInfo * key_parent(struct PgpKeyInfo *k)
Find a key's parent (if it's a subkey)
Definition pgp.c:150
static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
Copy PGP output and look for signs of a good signature.
Definition pgp.c:250
char * pgp_short_keyid(struct PgpKeyInfo *k)
Get a key's short id.
Definition pgp.c:176
static void pgp_copy_clearsigned(FILE *fp_in, struct State *state, char *charset)
Copy a clearsigned message, stripping the signature.
Definition pgp.c:423
static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *b)
Extract pgp keys from messages/attachments.
Definition pgp.c:970
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition pgp.c:126
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition pgp.c:356
static bool pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check the body of an inline PGP message.
Definition pgp.c:800
PGP sign, encrypt, check routines.
pid_t pgp_invoke_encrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, bool sign)
Use PGP to encrypt a file.
Definition pgpinvoke.c:229
pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, bool need_passphrase)
Use PGP to decode a message.
Definition pgpinvoke.c:132
pid_t pgp_invoke_traditional(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *uids, SecurityFlags flags)
Use PGP to create in inline-signed message.
Definition pgpinvoke.c:264
pid_t pgp_invoke_sign(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to sign a file.
Definition pgpinvoke.c:204
pid_t pgp_invoke_verify(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, const char *sig_fname)
Use PGP to verify a message.
Definition pgpinvoke.c:157
pid_t pgp_invoke_decrypt(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname)
Use PGP to decrypt a file.
Definition pgpinvoke.c:181
Wrapper around calls to external PGP program.
struct PgpKeyInfo * pgp_ask_for_key(char *tag, const char *whatfor, KeyFlags abilities, enum PgpRing keyring)
Ask the user for a PGP key.
Definition pgpkey.c:198
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition pgpkey.c:374
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition pgpkey.c:513
PGP key management routines.
@ PGP_SECRING
Secret keys.
Definition pgpkey.h:40
@ PGP_PUBRING
Public keys.
Definition pgpkey.h:39
void pgp_key_free(struct PgpKeyInfo **kpp)
Free a PGP key info.
Definition pgplib.c:201
Misc PGP helper routines.
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition pgpmicalg.c:228
Identify the hash algorithm from a PGP signature.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
QuadOption
Possible values for a quad-option.
Definition quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition question.c:357
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define STAILQ_FIRST(head)
Definition queue.h:388
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:302
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
Convenience wrapper for the send headers.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:713
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
LOFF_T offset
offset where the actual data begins
Definition body.h:52
bool noconv
Don't do character set conversion.
Definition body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
bool use_disp
Content-Disposition uses filename= ?
Definition body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition body.h:42
struct Body * next
next attachment in the list
Definition body.h:72
char * subtype
content-type subtype
Definition body.h:61
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition body.h:41
bool goodsig
Good cryptographic signature.
Definition body.h:45
unsigned int type
content-type primary type, ContentType
Definition body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
The envelope/body of an email.
Definition email.h:39
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
Cursor for converting a file's encoding.
Definition charset.h:45
FILE * fp
File to read from.
Definition charset.h:46
char * p
Current position in output buffer.
Definition charset.h:50
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Information about a PGP key.
Definition pgplib.h:49
char * keyid
Key ID.
Definition pgplib.h:50
KeyFlags flags
Key flags.
Definition pgplib.h:53
char * fingerprint
Key fingerprint.
Definition pgplib.h:51
struct PgpKeyInfo * parent
Parent key.
Definition pgplib.h:58
Cached regular expression.
Definition regex3.h:85
regex_t * regex
compiled expression
Definition regex3.h:87
Keep track when processing files.
Definition state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_out
File to write to.
Definition state.h:50
FILE * fp_in
File to read from.
Definition state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition state.h:51
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:392
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36