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