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