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