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