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