NeoMutt  2024-02-01-35-geee02f
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <locale.h>
33#include <stdbool.h>
34#include <stdio.h>
35#include <string.h>
36#include "mutt/lib.h"
37#include "address/lib.h"
38#include "config/lib.h"
39#include "email/lib.h"
40#include "core/lib.h"
41#include "alias/lib.h"
42#include "gui/lib.h"
43#include "mutt.h"
44#include "crypt.h"
45#include "lib.h"
46#include "attach/lib.h"
47#include "question/lib.h"
48#include "send/lib.h"
49#include "copy.h"
50#include "cryptglue.h"
51#include "globals.h"
52#include "handler.h"
53#include "mx.h"
54#ifdef USE_AUTOCRYPT
55#include "autocrypt/lib.h"
56#endif
57
65void crypt_current_time(struct State *state, const char *app_name)
66{
67 char p[256] = { 0 };
68 char tmp[512] = { 0 };
69
70 if (!WithCrypto)
71 return;
72
73 const bool c_crypt_timestamp = cs_subset_bool(NeoMutt->sub, "crypt_timestamp");
74 if (c_crypt_timestamp)
75 {
76 mutt_date_localtime_format(p, sizeof(p), _(" (current time: %c)"), mutt_date_now());
77 }
78 else
79 {
80 *p = '\0';
81 }
82
83 snprintf(tmp, sizeof(tmp), _("[-- %s output follows%s --]\n"), NONULL(app_name), p);
84 state_attach_puts(state, tmp);
85}
86
91{
94
97
98 if (WithCrypto)
99 {
100 /* L10N: Due to the implementation details (e.g. some passwords are managed
101 by gpg-agent) we can't know whether we forgot zero, 1, 12, ...
102 passwords. So in English we use "Passphrases". Your language might
103 have other means to express this. */
104 mutt_message(_("Passphrases forgotten"));
105 }
106}
107
108#ifndef DEBUG
109#include <sys/resource.h>
113static void disable_coredumps(void)
114{
115 struct rlimit rl = { 0, 0 };
116 static bool done = false;
117
118 if (!done)
119 {
120 setrlimit(RLIMIT_CORE, &rl);
121 done = true;
122 }
123}
124#endif
125
133{
134 bool rc = false;
135
136#ifndef DEBUG
137 disable_coredumps();
138#endif
139
140 if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & APPLICATION_PGP))
142
143 if (((WithCrypto & APPLICATION_SMIME) != 0) && (flags & APPLICATION_SMIME))
145
146 return rc;
147}
148
157int mutt_protect(struct Email *e, char *keylist, bool postpone)
158{
159 struct Body *pbody = NULL, *tmp_pbody = NULL;
160 struct Body *tmp_smime_pbody = NULL;
161 struct Body *tmp_pgp_pbody = NULL;
162 bool has_retainable_sig = false;
163
164 if (!WithCrypto)
165 return -1;
166
167 SecurityFlags security = e->security;
168 int sign = security & (SEC_AUTOCRYPT | SEC_SIGN);
169 if (postpone)
170 {
171 sign = SEC_NO_FLAGS;
172 security &= ~SEC_SIGN;
173 }
174
175 if (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) && !sign)
176 return 0;
177
178 if (sign && !(security & SEC_AUTOCRYPT) && !crypt_valid_passphrase(security))
179 return -1;
180
181 if (((WithCrypto & APPLICATION_PGP) != 0) && !(security & SEC_AUTOCRYPT) &&
182 ((security & PGP_INLINE) == PGP_INLINE))
183 {
184 if ((e->body->type != TYPE_TEXT) || !mutt_istr_equal(e->body->subtype, "plain"))
185 {
186 if (query_quadoption(_("Inline PGP can't be used with attachments. Revert to PGP/MIME?"),
187 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
188 {
189 mutt_error(_("Mail not sent: inline PGP can't be used with attachments"));
190 return -1;
191 }
192 }
193 else if (mutt_istr_equal("flowed", mutt_param_get(&e->body->parameter, "format")))
194 {
195 if ((query_quadoption(_("Inline PGP can't be used with format=flowed. Revert to PGP/MIME?"),
196 NeoMutt->sub, "pgp_mime_auto")) != MUTT_YES)
197 {
198 mutt_error(_("Mail not sent: inline PGP can't be used with format=flowed"));
199 return -1;
200 }
201 }
202 else
203 {
204 /* they really want to send it inline... go for it */
205 if (!isendwin())
206 {
207 mutt_endwin();
208 puts(_("Invoking PGP..."));
209 }
210 pbody = crypt_pgp_traditional_encryptsign(e->body, security, keylist);
211 if (pbody)
212 {
213 e->body = pbody;
214 return 0;
215 }
216
217 /* otherwise inline won't work...ask for revert */
218 if (query_quadoption(_("Message can't be sent inline. Revert to using PGP/MIME?"),
219 NeoMutt->sub, "pgp_mime_auto") != MUTT_YES)
220 {
221 mutt_error(_("Mail not sent"));
222 return -1;
223 }
224 }
225
226 /* go ahead with PGP/MIME */
227 }
228
229 if (!isendwin())
230 mutt_endwin();
231
233 tmp_smime_pbody = e->body;
235 tmp_pgp_pbody = e->body;
236
237#ifdef CRYPT_BACKEND_GPGME
238 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
239 if (sign && c_crypt_use_pka)
240#else
241 if (sign)
242#endif
243 {
244 /* Set sender (necessary for e.g. PKA). */
245 const char *mailbox = NULL;
246 struct Address *from = TAILQ_FIRST(&e->env->from);
247 bool free_from = false;
248
249 if (!from)
250 {
251 free_from = true;
253 }
254
255 mailbox = buf_string(from->mailbox);
256 const struct Address *c_envelope_from_address = cs_subset_address(NeoMutt->sub, "envelope_from_address");
257 if (!mailbox && c_envelope_from_address)
258 mailbox = buf_string(c_envelope_from_address->mailbox);
259
260 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
262 else if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
264
265 if (free_from)
266 mutt_addr_free(&from);
267 }
268
269 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
270 if (c_crypt_protected_headers_write)
271 {
272 struct Envelope *protected_headers = mutt_env_new();
273 mutt_env_set_subject(protected_headers, e->env->subject);
274 /* Note: if other headers get added, such as to, cc, then a call to
275 * mutt_env_to_intl() will need to be added here too. */
276 mutt_prepare_envelope(protected_headers, 0, NeoMutt->sub);
277
279 e->body->mime_headers = protected_headers;
280 mutt_param_set(&e->body->parameter, "protected-headers", "v1");
281 }
282
283#ifdef USE_AUTOCRYPT
284 /* A note about e->body->mime_headers. If postpone or send
285 * fails, the mime_headers is cleared out before returning to the
286 * compose menu. So despite the "robustness" code above and in the
287 * gen_gossip_list function below, mime_headers will not be set when
288 * entering mutt_protect().
289 *
290 * This is important to note because the user could toggle
291 * $crypt_protected_headers_write or $autocrypt off back in the
292 * compose menu. We don't want mutt_write_rfc822_header() to write
293 * stale data from one option if the other is set.
294 */
295 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
296 if (c_autocrypt && !postpone && (security & SEC_AUTOCRYPT))
297 {
299 }
300#endif
301
302 if (sign)
303 {
304 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
305 {
306 tmp_pbody = crypt_smime_sign_message(e->body, &e->env->from);
307 if (!tmp_pbody)
308 goto bail;
309 pbody = tmp_pbody;
310 tmp_smime_pbody = tmp_pbody;
311 }
312
313 const bool c_pgp_retainable_sigs = cs_subset_bool(NeoMutt->sub, "pgp_retainable_sigs");
314 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP) &&
315 (!(security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) || c_pgp_retainable_sigs))
316 {
317 tmp_pbody = crypt_pgp_sign_message(e->body, &e->env->from);
318 if (!tmp_pbody)
319 goto bail;
320
321 has_retainable_sig = true;
322 sign = SEC_NO_FLAGS;
323 pbody = tmp_pbody;
324 tmp_pgp_pbody = tmp_pbody;
325 }
326 }
327
328 if (security & (SEC_ENCRYPT | SEC_AUTOCRYPT))
329 {
330 if (((WithCrypto & APPLICATION_SMIME) != 0) && (security & APPLICATION_SMIME))
331 {
332 tmp_pbody = crypt_smime_build_smime_entity(tmp_smime_pbody, keylist);
333 if (!tmp_pbody)
334 {
335 /* signed ? free it! */
336 goto bail;
337 }
338 /* free tmp_body if messages was signed AND encrypted ... */
339 if ((tmp_smime_pbody != e->body) && (tmp_smime_pbody != tmp_pbody))
340 {
341 /* detach and don't delete e->body,
342 * which tmp_smime_pbody->parts after signing. */
343 tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
344 e->body->next = NULL;
345 mutt_body_free(&tmp_smime_pbody);
346 }
347 pbody = tmp_pbody;
348 }
349
350 if (((WithCrypto & APPLICATION_PGP) != 0) && (security & APPLICATION_PGP))
351 {
352 pbody = crypt_pgp_encrypt_message(e, tmp_pgp_pbody, keylist, sign, &e->env->from);
353 if (!pbody)
354 {
355 /* did we perform a retainable signature? */
356 if (has_retainable_sig)
357 {
358 /* remove the outer multipart layer */
359 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
360 /* get rid of the signature */
361 mutt_body_free(&tmp_pgp_pbody->next);
362 }
363
364 goto bail;
365 }
366
367 // destroy temporary signature envelope when doing retainable signatures.
368 if (has_retainable_sig)
369 {
370 tmp_pgp_pbody = mutt_remove_multipart(tmp_pgp_pbody);
371 mutt_body_free(&tmp_pgp_pbody->next);
372 }
373 }
374 }
375
376 if (pbody)
377 {
378 e->body = pbody;
379 return 0;
380 }
381
382bail:
384 mutt_param_delete(&e->body->parameter, "protected-headers");
385 return -1;
386}
387
395{
396 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "signed"))
397 {
398 return SEC_NO_FLAGS;
399 }
400
401 char *p = mutt_param_get(&b->parameter, "protocol");
402 if (!p)
403 return SEC_NO_FLAGS;
404
405 if (mutt_istr_equal(p, "multipart/mixed"))
406 return SEC_SIGN;
407
408 if (((WithCrypto & APPLICATION_PGP) != 0) && mutt_istr_equal(p, "application/pgp-signature"))
409 {
410 return PGP_SIGN;
411 }
412
413 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
414 (mutt_istr_equal(p, "application/x-pkcs7-signature") ||
415 mutt_istr_equal(p, "application/pkcs7-signature")))
416 {
417 return SMIME_SIGN;
418 }
419
420 return SEC_NO_FLAGS;
421}
422
430{
431 if ((WithCrypto & APPLICATION_PGP) == 0)
432 return SEC_NO_FLAGS;
433
434 char *p = NULL;
435
436 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype ||
437 !mutt_istr_equal(b->subtype, "encrypted") ||
438 !(p = mutt_param_get(&b->parameter, "protocol")) ||
439 !mutt_istr_equal(p, "application/pgp-encrypted"))
440 {
441 return SEC_NO_FLAGS;
442 }
443
444 return PGP_ENCRYPT;
445}
446
454{
456 return 0;
457
458 b = b->parts;
459 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
460 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
461 {
462 return 0;
463 }
464
465 b = b->next;
466 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
467 !mutt_istr_equal(b->subtype, "octet-stream"))
468 {
469 return 0;
470 }
471
472 return PGP_ENCRYPT;
473}
474
491{
493 return SEC_NO_FLAGS;
494
495 if (!b || (b->type != TYPE_MULTIPART) || !b->subtype || !mutt_istr_equal(b->subtype, "mixed"))
496 {
497 return SEC_NO_FLAGS;
498 }
499
500 b = b->parts;
501 if (!b || (b->type != TYPE_TEXT) || !b->subtype ||
502 !mutt_istr_equal(b->subtype, "plain") || (b->length != 0))
503 {
504 return SEC_NO_FLAGS;
505 }
506
507 b = b->next;
508 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
509 !mutt_istr_equal(b->subtype, "pgp-encrypted"))
510 {
511 return SEC_NO_FLAGS;
512 }
513
514 b = b->next;
515 if (!b || (b->type != TYPE_APPLICATION) || !b->subtype ||
516 !mutt_istr_equal(b->subtype, "octet-stream"))
517 {
518 return SEC_NO_FLAGS;
519 }
520
521 b = b->next;
522 if (b)
523 return SEC_NO_FLAGS;
524
525 return PGP_ENCRYPT;
526}
527
535{
537 char *p = NULL;
538
539 if (b->type == TYPE_APPLICATION)
540 {
541 if (mutt_istr_equal(b->subtype, "pgp") || mutt_istr_equal(b->subtype, "x-pgp-message"))
542 {
543 p = mutt_param_get(&b->parameter, "x-action");
544 if (p && (mutt_istr_equal(p, "sign") || mutt_istr_equal(p, "signclear")))
545 {
546 t |= PGP_SIGN;
547 }
548
549 p = mutt_param_get(&b->parameter, "format");
550 if (p && mutt_istr_equal(p, "keys-only"))
551 {
552 t |= PGP_KEY;
553 }
554
555 if (t == SEC_NO_FLAGS)
556 t |= PGP_ENCRYPT; /* not necessarily correct, but... */
557 }
558
559 if (mutt_istr_equal(b->subtype, "pgp-signed"))
560 t |= PGP_SIGN;
561
562 if (mutt_istr_equal(b->subtype, "pgp-keys"))
563 t |= PGP_KEY;
564 }
565 else if ((b->type == TYPE_TEXT) && mutt_istr_equal("plain", b->subtype))
566 {
567 if (((p = mutt_param_get(&b->parameter, "x-mutt-action")) ||
568 (p = mutt_param_get(&b->parameter, "x-action")) ||
569 (p = mutt_param_get(&b->parameter, "action"))) &&
570 mutt_istr_startswith(p, "pgp-sign"))
571 {
572 t |= PGP_SIGN;
573 }
574 else if (p && mutt_istr_startswith(p, "pgp-encrypt"))
575 {
576 t |= PGP_ENCRYPT;
577 }
578 else if (p && mutt_istr_startswith(p, "pgp-keys"))
579 {
580 t |= PGP_KEY;
581 }
582 }
583 if (t)
584 t |= PGP_INLINE;
585
586 return t;
587}
588
596{
597 if (!b)
598 return SEC_NO_FLAGS;
599
600 if (((b->type & TYPE_APPLICATION) == 0) || !b->subtype)
601 return SEC_NO_FLAGS;
602
603 char *t = NULL;
604 bool complain = false;
605 /* S/MIME MIME types don't need x- anymore, see RFC2311 */
606 if (mutt_istr_equal(b->subtype, "x-pkcs7-mime") || mutt_istr_equal(b->subtype, "pkcs7-mime"))
607 {
608 t = mutt_param_get(&b->parameter, "smime-type");
609 if (t)
610 {
611 if (mutt_istr_equal(t, "enveloped-data"))
612 return SMIME_ENCRYPT;
613 if (mutt_istr_equal(t, "signed-data"))
614 return SMIME_SIGN | SMIME_OPAQUE;
615 return SEC_NO_FLAGS;
616 }
617 /* Netscape 4.7 uses
618 * Content-Description: S/MIME Encrypted Message
619 * instead of Content-Type parameter */
620 if (mutt_istr_equal(b->description, "S/MIME Encrypted Message"))
621 return SMIME_ENCRYPT;
622 complain = true;
623 }
624 else if (!mutt_istr_equal(b->subtype, "octet-stream"))
625 {
626 return SEC_NO_FLAGS;
627 }
628
629 t = mutt_param_get(&b->parameter, "name");
630
631 if (!t)
632 t = b->d_filename;
633 if (!t)
634 t = b->filename;
635 if (!t)
636 {
637 if (complain)
638 {
639 mutt_message(_("S/MIME messages with no hints on content are unsupported"));
640 }
641 return SEC_NO_FLAGS;
642 }
643
644 /* no .p7c, .p10 support yet. */
645
646 int len = mutt_str_len(t) - 4;
647 if ((len > 0) && (*(t + len) == '.'))
648 {
649 len++;
650 if (mutt_istr_equal((t + len), "p7m"))
651 {
652 /* Not sure if this is the correct thing to do, but
653 * it's required for compatibility with Outlook */
654 return SMIME_SIGN | SMIME_OPAQUE;
655 }
656 else if (mutt_istr_equal((t + len), "p7s"))
657 {
658 return SMIME_SIGN | SMIME_OPAQUE;
659 }
660 }
661
662 return SEC_NO_FLAGS;
663}
664
674{
675 if (!WithCrypto || !b)
676 return SEC_NO_FLAGS;
677
679
680 if (b->type == TYPE_APPLICATION)
681 {
684
686 {
688 if (rc && b->goodsig)
689 rc |= SEC_GOODSIGN;
690 if (rc && b->badsig)
691 rc |= SEC_BADSIGN;
692 }
693 }
694 else if (((WithCrypto & APPLICATION_PGP) != 0) && (b->type == TYPE_TEXT))
695 {
697 if (rc && b->goodsig)
698 rc |= SEC_GOODSIGN;
699 }
700
701 if (b->type == TYPE_MULTIPART)
702 {
706
707 if (rc && b->goodsig)
708 rc |= SEC_GOODSIGN;
709#ifdef USE_AUTOCRYPT
710 if (rc && b->is_autocrypt)
711 rc |= SEC_AUTOCRYPT;
712#endif
713 }
714
715 if ((b->type == TYPE_MULTIPART) || (b->type == TYPE_MESSAGE))
716 {
717 SecurityFlags u = b->parts ? SEC_ALL_FLAGS : SEC_NO_FLAGS; /* Bits set in all parts */
718 SecurityFlags w = SEC_NO_FLAGS; /* Bits set in any part */
719
720 for (b = b->parts; b; b = b->next)
721 {
722 const SecurityFlags v = crypt_query(b);
723 u &= v;
724 w |= v;
725 }
726 rc |= u | (w & ~SEC_GOODSIGN);
727
728 if ((w & SEC_GOODSIGN) && !(u & SEC_GOODSIGN))
729 rc |= SEC_PARTSIGN;
730 }
731
732 return rc;
733}
734
745int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
746{
747 if (!WithCrypto)
748 return -1;
749
750 FILE *fp = mutt_file_fopen(tempfile, "w");
751 if (!fp)
752 {
753 mutt_perror("%s", tempfile);
754 return -1;
755 }
756
757 if (!mutt_file_seek(state->fp_in, b->hdr_offset, SEEK_SET))
758 {
759 mutt_file_fclose(&fp);
760 return -1;
761 }
762 size_t bytes = b->length + b->offset - b->hdr_offset;
763 bool hadcr = false;
764 while (bytes > 0)
765 {
766 const int c = fgetc(state->fp_in);
767 if (c == EOF)
768 break;
769
770 bytes--;
771
772 if (c == '\r')
773 {
774 hadcr = true;
775 }
776 else
777 {
778 if ((c == '\n') && !hadcr)
779 fputc('\r', fp);
780
781 hadcr = false;
782 }
783
784 fputc(c, fp);
785 }
786 mutt_file_fclose(&fp);
787
788 return 0;
789}
790
796{
797 if (!WithCrypto)
798 return;
799
800 const bool c_pgp_strict_enc = cs_subset_bool(NeoMutt->sub, "pgp_strict_enc");
801 while (b)
802 {
803 if (b->type == TYPE_MULTIPART)
804 {
805 if (b->encoding != ENC_7BIT)
806 {
807 b->encoding = ENC_7BIT;
809 }
810 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_pgp_strict_enc)
811 {
813 }
814 }
815 else if ((b->type == TYPE_MESSAGE) && !mutt_istr_equal(b->subtype, "delivery-status"))
816 {
817 if (b->encoding != ENC_7BIT)
819 }
820 else if (b->encoding == ENC_8BIT)
821 {
823 }
824 else if (b->encoding == ENC_BINARY)
825 {
826 b->encoding = ENC_BASE64;
827 }
828 else if (b->content && (b->encoding != ENC_BASE64) &&
829 (b->content->from || (b->content->space && c_pgp_strict_enc)))
830 {
832 }
833 b = b->next;
834 }
835}
836
844void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
845{
846 if (!WithCrypto)
847 return;
848
849 struct Buffer *tempfname = buf_pool_get();
850 buf_mktemp(tempfname);
851 FILE *fp_out = mutt_file_fopen(buf_string(tempfname), "w");
852 if (!fp_out)
853 {
854 mutt_perror("%s", buf_string(tempfname));
855 goto cleanup;
856 }
857
860
861 struct Email **ep = NULL;
862 ARRAY_FOREACH(ep, ea)
863 {
864 struct Email *e = *ep;
865 struct Message *msg = mx_msg_open(m, e);
866 if (!msg)
867 {
868 continue;
869 }
872 {
873 mx_msg_close(m, &msg);
874 mutt_file_fclose(&fp_out);
875 break;
876 }
877
878 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
879 {
881 fflush(fp_out);
882
883 mutt_endwin();
884 puts(_("Trying to extract PGP keys...\n"));
886 }
887
889 {
890 const bool encrypt = e->security & SEC_ENCRYPT;
891 mutt_copy_message(fp_out, e, msg,
894 CH_NO_FLAGS, 0);
895 fflush(fp_out);
896
897 const char *mbox = NULL;
898 if (!TAILQ_EMPTY(&e->env->from))
899 {
901 mbox = buf_string(TAILQ_FIRST(&e->env->from)->mailbox);
902 }
903 else if (!TAILQ_EMPTY(&e->env->sender))
904 {
906 mbox = buf_string(TAILQ_FIRST(&e->env->sender)->mailbox);
907 }
908 if (mbox)
909 {
910 mutt_endwin();
911 puts(_("Trying to extract S/MIME certificates..."));
912 crypt_smime_invoke_import(buf_string(tempfname), mbox);
913 }
914 }
915 mx_msg_close(m, &msg);
916
917 rewind(fp_out);
918 }
919
920 mutt_file_fclose(&fp_out);
921 if (isendwin())
923
924 mutt_file_unlink(buf_string(tempfname));
925
927 OptDontHandlePgpKeys = false;
928
929cleanup:
930 buf_pool_release(&tempfname);
931}
932
947int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
948{
949 if (!WithCrypto)
950 return 0;
951
952 struct AddressList addrlist = TAILQ_HEAD_INITIALIZER(addrlist);
953 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
954 const char *self_encrypt = NULL;
955
956 /* Do a quick check to make sure that we can find all of the encryption
957 * keys if the user has requested this service. */
958
959 *keylist = NULL;
960
961#ifdef USE_AUTOCRYPT
962 if (!oppenc_mode && (e->security & SEC_AUTOCRYPT))
963 {
965 return -1;
966 return 0;
967 }
968#endif
969
971 OptPgpCheckTrust = true;
972
973 mutt_addrlist_copy(&addrlist, &e->env->to, false);
974 mutt_addrlist_copy(&addrlist, &e->env->cc, false);
975 mutt_addrlist_copy(&addrlist, &e->env->bcc, false);
976 mutt_addrlist_qualify(&addrlist, fqdn);
977 mutt_addrlist_dedupe(&addrlist);
978
979 if (oppenc_mode || (e->security & SEC_ENCRYPT))
980 {
981 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
982 {
983 *keylist = crypt_pgp_find_keys(&addrlist, oppenc_mode);
984 if (!*keylist)
985 {
986 mutt_addrlist_clear(&addrlist);
987 return -1;
988 }
989 OptPgpCheckTrust = false;
990 const bool c_pgp_self_encrypt = cs_subset_bool(NeoMutt->sub, "pgp_self_encrypt");
991 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
992 const enum QuadOption c_pgp_encrypt_self = cs_subset_quad(NeoMutt->sub, "pgp_encrypt_self");
993 if (c_pgp_self_encrypt || (c_pgp_encrypt_self == MUTT_YES))
994 self_encrypt = c_pgp_default_key;
995 }
997 {
998 *keylist = crypt_smime_find_keys(&addrlist, oppenc_mode);
999 if (!*keylist)
1000 {
1001 mutt_addrlist_clear(&addrlist);
1002 return -1;
1003 }
1004 const bool c_smime_self_encrypt = cs_subset_bool(NeoMutt->sub, "smime_self_encrypt");
1005 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1006 const enum QuadOption c_smime_encrypt_self = cs_subset_quad(NeoMutt->sub, "smime_encrypt_self");
1007 if (c_smime_self_encrypt || (c_smime_encrypt_self == MUTT_YES))
1008 self_encrypt = c_smime_default_key;
1009 }
1010 }
1011
1012 if (!oppenc_mode && self_encrypt)
1013 {
1014 const size_t keylist_size = mutt_str_len(*keylist);
1015 mutt_mem_realloc(keylist, keylist_size + mutt_str_len(self_encrypt) + 2);
1016 sprintf(*keylist + keylist_size, " %s", self_encrypt);
1017 }
1018
1019 mutt_addrlist_clear(&addrlist);
1020
1021 return 0;
1022}
1023
1032{
1033 if (!WithCrypto)
1034 return;
1035
1036 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1037 if (!(c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT)))
1038 return;
1039
1040 char *pgpkeylist = NULL;
1041
1042 crypt_get_keys(e, &pgpkeylist, true);
1043 if (pgpkeylist)
1044 {
1045 e->security |= SEC_ENCRYPT;
1046 FREE(&pgpkeylist);
1047 }
1048 else
1049 {
1050 e->security &= ~SEC_ENCRYPT;
1051 }
1052}
1053
1060static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
1061{
1062 if (!WithCrypto)
1063 return;
1064
1065 for (; b; b = b->next)
1066 {
1067 if (b->type == TYPE_MULTIPART)
1068 {
1069 crypt_fetch_signatures(b_sigs, b->parts, n);
1070 }
1071 else
1072 {
1073 if ((*n % 5) == 0)
1074 mutt_mem_realloc(b_sigs, (*n + 6) * sizeof(struct Body **));
1075
1076 (*b_sigs)[(*n)++] = b;
1077 }
1078 }
1079}
1080
1087{
1088 const bool c_crypt_protected_headers_write = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_write");
1089 const char *const c_crypt_protected_headers_subject =
1090 cs_subset_string(NeoMutt->sub, "crypt_protected_headers_subject");
1091 if (c_crypt_protected_headers_write && (e->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) &&
1092 !(e->security & SEC_INLINE) && c_crypt_protected_headers_subject)
1093 {
1094 return true;
1095 }
1096
1097 return false;
1098}
1099
1103int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
1104{
1105 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1106 if (c_crypt_protected_headers_read && b_email->mime_headers)
1107 {
1108 if (b_email->mime_headers->subject)
1109 {
1110 const bool display = (state->flags & STATE_DISPLAY);
1111
1112 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1113 if (display && c_weed && mutt_matches_ignore("subject"))
1114 return 0;
1115
1117 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
1118 int wraplen = display ? mutt_window_wrap_cols(state->wraplen, c_wrap) : 0;
1119
1120 mutt_write_one_header(state->fp_out, "Subject",
1121 b_email->mime_headers->subject, state->prefix, wraplen,
1122 display ? CH_DISPLAY : CH_NO_FLAGS, NeoMutt->sub);
1123 state_puts(state, "\n");
1124 }
1125 }
1126
1127 return 0;
1128}
1129
1133int mutt_signed_handler(struct Body *b_email, struct State *state)
1134{
1135 if (!WithCrypto)
1136 return -1;
1137
1138 bool inconsistent = false;
1139 struct Body *top = b_email;
1140 struct Body **signatures = NULL;
1141 int sigcnt = 0;
1142 int rc = 0;
1143 struct Buffer *tempfile = NULL;
1144
1145 b_email = b_email->parts;
1146 SecurityFlags signed_type = mutt_is_multipart_signed(top);
1147 if (signed_type == SEC_NO_FLAGS)
1148 {
1149 /* A null protocol value is already checked for in mutt_body_handler() */
1150 state_printf(state, _("[-- Error: Unknown multipart/signed protocol %s --]\n\n"),
1151 mutt_param_get(&top->parameter, "protocol"));
1152 return mutt_body_handler(b_email, state);
1153 }
1154
1155 if (!(b_email && b_email->next))
1156 {
1157 inconsistent = true;
1158 }
1159 else
1160 {
1161 switch (signed_type)
1162 {
1163 case SEC_SIGN:
1164 if ((b_email->next->type != TYPE_MULTIPART) ||
1165 !mutt_istr_equal(b_email->next->subtype, "mixed"))
1166 {
1167 inconsistent = true;
1168 }
1169 break;
1170 case PGP_SIGN:
1171 if ((b_email->next->type != TYPE_APPLICATION) ||
1172 !mutt_istr_equal(b_email->next->subtype, "pgp-signature"))
1173 {
1174 inconsistent = true;
1175 }
1176 break;
1177 case SMIME_SIGN:
1178 if ((b_email->next->type != TYPE_APPLICATION) ||
1179 (!mutt_istr_equal(b_email->next->subtype, "x-pkcs7-signature") &&
1180 !mutt_istr_equal(b_email->next->subtype, "pkcs7-signature")))
1181 {
1182 inconsistent = true;
1183 }
1184 break;
1185 default:
1186 inconsistent = true;
1187 }
1188 }
1189 if (inconsistent)
1190 {
1191 state_attach_puts(state, _("[-- Error: Missing or bad-format multipart/signed signature --]\n\n"));
1192 return mutt_body_handler(b_email, state);
1193 }
1194
1195 if (state->flags & STATE_DISPLAY)
1196 {
1197 crypt_fetch_signatures(&signatures, b_email->next, &sigcnt);
1198
1199 if (sigcnt != 0)
1200 {
1201 tempfile = buf_pool_get();
1202 buf_mktemp(tempfile);
1203 bool goodsig = true;
1204 if (crypt_write_signed(b_email, state, buf_string(tempfile)) == 0)
1205 {
1206 for (int i = 0; i < sigcnt; i++)
1207 {
1208 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1209 (signatures[i]->type == TYPE_APPLICATION) &&
1210 mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1211 {
1212 if (crypt_pgp_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1213 goodsig = false;
1214
1215 continue;
1216 }
1217
1218 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1219 (signatures[i]->type == TYPE_APPLICATION) &&
1220 (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1221 mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1222 {
1223 if (crypt_smime_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1224 goodsig = false;
1225
1226 continue;
1227 }
1228
1229 state_printf(state, _("[-- Warning: We can't verify %s/%s signatures. --]\n\n"),
1230 TYPE(signatures[i]), signatures[i]->subtype);
1231 }
1232 }
1233
1234 mutt_file_unlink(buf_string(tempfile));
1235 buf_pool_release(&tempfile);
1236
1237 top->goodsig = goodsig;
1238 top->badsig = !goodsig;
1239
1240 /* Now display the signed body */
1241 state_attach_puts(state, _("[-- The following data is signed --]\n\n"));
1242
1243 mutt_protected_headers_handler(b_email, state);
1244
1245 FREE(&signatures);
1246 }
1247 else
1248 {
1249 state_attach_puts(state, _("[-- Warning: Can't find any signatures. --]\n\n"));
1250 }
1251 }
1252
1253 rc = mutt_body_handler(b_email, state);
1254
1255 if ((state->flags & STATE_DISPLAY) && (sigcnt != 0))
1256 state_attach_puts(state, _("\n[-- End of signed data --]\n"));
1257
1258 return rc;
1259}
1260
1275const char *crypt_get_fingerprint_or_id(const char *p, const char **pphint,
1276 const char **ppl, const char **pps)
1277{
1278 const char *ps = NULL, *pl = NULL, *phint = NULL;
1279 char *pfcopy = NULL, *s1 = NULL, *s2 = NULL;
1280 char c;
1281 int isid;
1282 size_t hexdigits;
1283
1284 /* User input may be partial name, fingerprint or short or long key ID,
1285 * independent of `$pgp_long_ids`.
1286 * Fingerprint without spaces is 40 hex digits (SHA-1) or 32 hex digits (MD5).
1287 * Strip leading "0x" for key ID detection and prepare pl and ps to indicate
1288 * if an ID was found and to simplify logic in the key loop's inner
1289 * condition of the caller. */
1290
1291 char *pf = mutt_str_skip_whitespace(p);
1292 if (mutt_istr_startswith(pf, "0x"))
1293 pf += 2;
1294
1295 /* Check if a fingerprint is given, must be hex digits only, blanks
1296 * separating groups of 4 hex digits are allowed. Also pre-check for ID. */
1297 isid = 2; /* unknown */
1298 hexdigits = 0;
1299 s1 = pf;
1300 do
1301 {
1302 c = *(s1++);
1303 if ((('0' <= c) && (c <= '9')) || (('A' <= c) && (c <= 'F')) ||
1304 (('a' <= c) && (c <= 'f')))
1305 {
1306 hexdigits++;
1307 if (isid == 2)
1308 isid = 1; /* it is an ID so far */
1309 }
1310 else if (c)
1311 {
1312 isid = 0; /* not an ID */
1313 if ((c == ' ') && ((hexdigits % 4) == 0))
1314 ; /* skip blank before or after 4 hex digits */
1315 else
1316 break; /* any other character or position */
1317 }
1318 } while (c);
1319
1320 /* If at end of input, check for correct fingerprint length and copy if. */
1321 pfcopy = (!c && ((hexdigits == 40) || (hexdigits == 32)) ? mutt_str_dup(pf) : NULL);
1322
1323 if (pfcopy)
1324 {
1325 /* Use pfcopy to strip all spaces from fingerprint and as hint. */
1326 s1 = pfcopy;
1327 s2 = pfcopy;
1328 do
1329 {
1330 *(s1++) = *(s2 = mutt_str_skip_whitespace(s2));
1331 } while (*(s2++));
1332
1333 phint = pfcopy;
1334 ps = NULL;
1335 pl = NULL;
1336 }
1337 else
1338 {
1339 phint = p;
1340 ps = NULL;
1341 pl = NULL;
1342 if (isid == 1)
1343 {
1344 if (mutt_str_len(pf) == 16)
1345 pl = pf; /* long key ID */
1346 else if (mutt_str_len(pf) == 8)
1347 ps = pf; /* short key ID */
1348 }
1349 }
1350
1351 *pphint = phint;
1352 *ppl = pl;
1353 *pps = ps;
1354 return pfcopy;
1355}
1356
1364bool crypt_is_numerical_keyid(const char *s)
1365{
1366 /* or should we require the "0x"? */
1367 if (mutt_strn_equal(s, "0x", 2))
1368 s += 2;
1369 if (strlen(s) % 8)
1370 return false;
1371 while (*s)
1372 if (!strchr("0123456789ABCDEFabcdef", *s++))
1373 return false;
1374
1375 return true;
1376}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
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:1464
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:462
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1401
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
GUI display the mailboxes in a side panel.
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:597
Autocrypt end-to-end encryption.
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition: lib.h:160
int mutt_autocrypt_generate_gossip_list(struct Email *e)
Create the gossip list headers.
Definition: autocrypt.c:825
enum AutocryptRec mutt_autocrypt_ui_recommendation(const struct Email *e, char **keylist)
Get the recommended action for an Email.
Definition: autocrypt.c:560
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:193
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
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 struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:273
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:908
Duplicate the structure of an entire email.
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:40
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:48
#define CH_DISPLAY
Display result to user.
Definition: copy.h:72
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:50
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition: copy.h:38
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
Convenience wrapper for the core headers.
static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
Create an array of an emails parts.
Definition: crypt.c:1060
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:534
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
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:595
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:132
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:453
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1086
void crypt_extract_keys_from_messages(struct Mailbox *m, struct EmailArray *ea)
Extract keys from a message.
Definition: crypt.c:844
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:429
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:157
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:90
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1275
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:490
int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
Write the message body/part.
Definition: crypt.c:745
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition: crypt.c:947
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 crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:673
Signing/encryption multiplexor.
char * crypt_smime_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition: cryptglue.c:474
struct Body * crypt_smime_build_smime_entity(struct Body *b, char *certlist)
Wrapper for CryptModuleSpecs::smime_build_smime_entity()
Definition: cryptglue.c:496
struct Body * crypt_smime_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition: cryptglue.c:485
struct Body * crypt_pgp_traditional_encryptsign(struct Body *b, SecurityFlags flags, char *keylist)
Wrapper for CryptModuleSpecs::pgp_traditional_encryptsign()
Definition: cryptglue.c:293
char * crypt_pgp_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Wrapper for CryptModuleSpecs::find_keys()
Definition: cryptglue.c:315
struct Body * crypt_pgp_sign_message(struct Body *b, const struct AddressList *from)
Wrapper for CryptModuleSpecs::sign_message()
Definition: cryptglue.c:326
bool crypt_smime_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition: cryptglue.c:421
void crypt_pgp_invoke_import(const char *fname)
Wrapper for CryptModuleSpecs::pgp_invoke_import()
Definition: cryptglue.c:363
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:412
void crypt_smime_invoke_import(const char *infile, const char *mailbox)
Wrapper for CryptModuleSpecs::smime_invoke_import()
Definition: cryptglue.c:507
void crypt_pgp_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition: cryptglue.c:403
void crypt_smime_set_sender(const char *sender)
Wrapper for CryptModuleSpecs::set_sender()
Definition: cryptglue.c:538
int crypt_smime_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:516
void crypt_pgp_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:190
bool crypt_pgp_valid_passphrase(void)
Wrapper for CryptModuleSpecs::valid_passphrase()
Definition: cryptglue.c:199
int crypt_pgp_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:372
struct Body * crypt_pgp_encrypt_message(struct Email *e, struct Body *b, char *keylist, int sign, const struct AddressList *from)
Wrapper for CryptModuleSpecs::pgp_encrypt_message()
Definition: cryptglue.c:337
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:175
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:153
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
Structs that make up an email.
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:320
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition: envelope.c:69
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:771
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:216
#define mutt_file_fclose(FP)
Definition: file.h:148
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:147
bool OptDontHandlePgpKeys
(pseudo) used to extract PGP keys
Definition: globals.c:64
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:73
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1103
int mutt_signed_handler(struct Body *b_email, struct State *state)
Handler for "multipart/signed" - Implements handler_t -.
Definition: crypt.c:1133
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#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
Decide how to display email content.
int mutt_write_one_header(FILE *fp, const char *tag, const char *value, const char *pfx, int wraplen, CopyHeaderFlags chflags, struct ConfigSubset *sub)
Write one header line to a file.
Definition: header.c:423
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
@ ENC_BINARY
Binary.
Definition: mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define TYPE(body)
Definition: mime.h:89
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:953
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
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition: state.c:103
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:186
void state_mark_protected_header(struct State *state)
Write a unique marker around protected headers.
Definition: state.c:87
#define state_puts(STATE, STR)
Definition: state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
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_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
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_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:242
Many unsorted constants and some structs.
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:372
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1178
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1132
API for mailboxes.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
#define PGP_SIGN
Definition: lib.h:97
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define SEC_ALL_FLAGS
Definition: lib.h:94
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:80
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define PGP_ENCRYPT
Definition: lib.h:96
#define SMIME_SIGN
Definition: lib.h:103
#define PGP_INLINE
Definition: lib.h:100
#define SEC_BADSIGN
Email has a bad signature.
Definition: lib.h:81
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_PARTSIGN
Not all parts of the email is signed.
Definition: lib.h:82
#define SMIME_OPAQUE
Definition: lib.h:106
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define PGP_KEY
Definition: lib.h:99
#define SMIME_ENCRYPT
Definition: lib.h:102
#define WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:85
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:143
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:111
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_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:373
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1460
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:706
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:779
void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition: sendlib.c:258
Key value store.
#define NONULL(x)
Definition: string2.h:37
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 badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition: body.h:50
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
char * description
content-description
Definition: body.h:55
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:69
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
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:80
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
bool space
Whitespace at the end of lines?
Definition: content.h:43
bool from
Has a line beginning with "From "?
Definition: content.h:45
The envelope/body of an email.
Definition: email.h:39
struct Envelope * env
Envelope information.
Definition: email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct Body * body
List of MIME parts.
Definition: email.h:69
The header of an Email.
Definition: envelope.h:57
char *const subject
Email's subject.
Definition: envelope.h:70
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A mailbox.
Definition: mailbox.h:79
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
Keep track when processing files.
Definition: state.h:48
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition: state.h:53
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
#define buf_mktemp(buf)
Definition: tmp.h:33