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