NeoMutt  2021-10-29-43-g6b8931
Teaching an old dog new tricks
DOXYGEN
Mime Handler API

Prototype for a function to handle MIME parts. More...

Functions

int text_enriched_handler (struct Body *a, struct State *s)
 Handler for enriched text - Implements handler_t -. More...
 
static int autoview_handler (struct Body *a, struct State *s)
 Handler for autoviewable attachments - Implements handler_t -. More...
 
static int text_plain_handler (struct Body *b, struct State *s)
 Handler for plain text - Implements handler_t -. More...
 
static int message_handler (struct Body *a, struct State *s)
 Handler for message/rfc822 body parts - Implements handler_t -. More...
 
static int external_body_handler (struct Body *b, struct State *s)
 Handler for external-body emails - Implements handler_t -. More...
 
static int alternative_handler (struct Body *a, struct State *s)
 Handler for multipart alternative emails - Implements handler_t -. More...
 
static int multilingual_handler (struct Body *a, struct State *s)
 Handler for multi-lingual emails - Implements handler_t -. More...
 
static int multipart_handler (struct Body *a, struct State *s)
 Handler for multipart emails - Implements handler_t -. More...
 
static int valid_pgp_encrypted_handler (struct Body *b, struct State *s)
 Handler for valid pgp-encrypted emails - Implements handler_t -. More...
 
static int malformed_pgp_encrypted_handler (struct Body *b, struct State *s)
 Handler for invalid pgp-encrypted emails - Implements handler_t -. More...
 
int mutt_protected_headers_handler (struct Body *b, struct State *s)
 Process a protected header - Implements handler_t -. More...
 
int mutt_signed_handler (struct Body *b, struct State *s)
 Verify a "multipart/signed" body - Implements handler_t -. More...
 
int crypt_pgp_application_handler (struct Body *b, struct State *s)
 Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -. More...
 
int crypt_pgp_encrypted_handler (struct Body *b, struct State *s)
 Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -. More...
 
int crypt_smime_application_handler (struct Body *b, struct State *s)
 Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -. More...
 
int rfc3676_handler (struct Body *a, struct State *s)
 Body handler implementing RFC3676 for format=flowed - Implements handler_t -. More...
 

Detailed Description

Prototype for a function to handle MIME parts.

Parameters
bBody of the email
sState of text being processed
Return values
0Success
-1Error

Function Documentation

◆ text_enriched_handler()

int text_enriched_handler ( struct Body a,
struct State s 
)

Handler for enriched text - Implements handler_t -.

Return values
0Always

Definition at line 459 of file enriched.c.

460 {
461  enum
462  {
463  TEXT,
464  LANGLE,
465  TAG,
466  BOGUS_TAG,
467  NEWLINE,
468  ST_EOF,
469  DONE
470  } state = TEXT;
471 
472  long bytes = a->length;
473  struct EnrichedState stte = { 0 };
474  wint_t wc = 0;
475  int tag_len = 0;
476  wchar_t tag[1024 + 1];
477 
478  stte.s = s;
479  stte.wrap_margin =
480  ((s->wraplen > 4) && ((s->flags & MUTT_DISPLAY) || (s->wraplen < 76))) ?
481  s->wraplen - 4 :
482  72;
483  stte.line_max = stte.wrap_margin * 4;
484  stte.line = mutt_mem_calloc((stte.line_max + 1), sizeof(wchar_t));
485  stte.param = mutt_mem_calloc(256, sizeof(wchar_t));
486 
487  stte.param_len = 256;
488  stte.param_used = 0;
489 
490  if (s->prefix)
491  {
492  state_puts(s, s->prefix);
493  stte.indent_len += mutt_str_len(s->prefix);
494  }
495 
496  while (state != DONE)
497  {
498  if (state != ST_EOF)
499  {
500  if (!bytes || ((wc = fgetwc(s->fp_in)) == WEOF))
501  state = ST_EOF;
502  else
503  bytes--;
504  }
505 
506  switch (state)
507  {
508  case TEXT:
509  switch (wc)
510  {
511  case '<':
512  state = LANGLE;
513  break;
514 
515  case '\n':
516  if (stte.tag_level[RICH_NOFILL])
517  {
518  enriched_flush(&stte, true);
519  }
520  else
521  {
522  enriched_putwc((wchar_t) ' ', &stte);
523  state = NEWLINE;
524  }
525  break;
526 
527  default:
528  enriched_putwc(wc, &stte);
529  }
530  break;
531 
532  case LANGLE:
533  if (wc == (wchar_t) '<')
534  {
535  enriched_putwc(wc, &stte);
536  state = TEXT;
537  break;
538  }
539  else
540  {
541  tag_len = 0;
542  state = TAG;
543  }
544  /* Yes, (it wasn't a <<, so this char is first in TAG) */
545  /* fallthrough */
546  case TAG:
547  if (wc == (wchar_t) '>')
548  {
549  tag[tag_len] = (wchar_t) '\0';
550  enriched_set_flags(tag, &stte);
551  state = TEXT;
552  }
553  else if (tag_len < 1024) /* ignore overly long tags */
554  tag[tag_len++] = wc;
555  else
556  state = BOGUS_TAG;
557  break;
558 
559  case BOGUS_TAG:
560  if (wc == (wchar_t) '>')
561  state = TEXT;
562  break;
563 
564  case NEWLINE:
565  if (wc == (wchar_t) '\n')
566  enriched_flush(&stte, true);
567  else
568  {
569  ungetwc(wc, s->fp_in);
570  bytes++;
571  state = TEXT;
572  }
573  break;
574 
575  case ST_EOF:
576  enriched_putwc((wchar_t) '\0', &stte);
577  enriched_flush(&stte, true);
578  state = DONE;
579  break;
580 
581  default:
582  /* not reached */
583  break;
584  }
585  }
586 
587  state_putc(s, '\n'); /* add a final newline */
588 
589  FREE(&(stte.buffer));
590  FREE(&(stte.line));
591  FREE(&(stte.param));
592 
593  return 0;
594 }
@ RICH_NOFILL
Text will not be reformatted.
Definition: enriched.c:54
static void enriched_flush(struct EnrichedState *stte, bool wrap)
Write enriched text to the State.
Definition: enriched.c:235
static void enriched_putwc(wchar_t c, struct EnrichedState *stte)
Write one wide character to the state.
Definition: enriched.c:271
static void enriched_set_flags(const wchar_t *tag, struct EnrichedState *stte)
Set flags on the enriched text state.
Definition: enriched.c:370
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:40
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:475
#define state_puts(STATE, STR)
Definition: state.h:55
#define state_putc(STATE, STR)
Definition: state.h:56
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
LOFF_T length
length (in bytes) of attachment
Definition: body.h:52
State of enriched-text parser.
Definition: enriched.c:98
wchar_t * buffer
Definition: enriched.c:99
size_t param_used
Definition: enriched.c:109
wchar_t * param
Definition: enriched.c:101
wchar_t * line
Definition: enriched.c:100
int tag_level[RICH_MAX]
Definition: enriched.c:111
struct State * s
Definition: enriched.c:113
size_t param_len
Definition: enriched.c:110
size_t line_max
Definition: enriched.c:105
int wrap_margin
Definition: enriched.c:112
size_t indent_len
Definition: enriched.c:106
int wraplen
Width to wrap lines to (when flags & MUTT_DISPLAY)
Definition: state.h:50
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ autoview_handler()

static int autoview_handler ( struct Body a,
struct State s 
)
static

Handler for autoviewable attachments - Implements handler_t -.

Definition at line 524 of file handler.c.

525 {
526  struct MailcapEntry *entry = mailcap_entry_new();
527  char buf[1024];
528  char type[256];
529  struct Buffer *cmd = mutt_buffer_pool_get();
530  struct Buffer *tempfile = mutt_buffer_pool_get();
531  char *fname = NULL;
532  FILE *fp_in = NULL;
533  FILE *fp_out = NULL;
534  FILE *fp_err = NULL;
535  pid_t pid;
536  int rc = 0;
537 
538  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
539  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
540 
541  fname = mutt_str_dup(a->filename);
542  mutt_file_sanitize_filename(fname, true);
543  mailcap_expand_filename(entry->nametemplate, fname, tempfile);
544  FREE(&fname);
545 
546  if (entry->command)
547  {
548  mutt_buffer_strcpy(cmd, entry->command);
549 
550  /* mailcap_expand_command returns 0 if the file is required */
551  bool piped = mailcap_expand_command(a, mutt_buffer_string(tempfile), type, cmd);
552 
553  if (s->flags & MUTT_DISPLAY)
554  {
556  state_printf(s, _("[-- Autoview using %s --]\n"), mutt_buffer_string(cmd));
557  mutt_message(_("Invoking autoview command: %s"), mutt_buffer_string(cmd));
558  }
559 
560  fp_in = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
561  if (!fp_in)
562  {
563  mutt_perror("fopen");
564  mailcap_entry_free(&entry);
565  rc = -1;
566  goto cleanup;
567  }
568 
569  mutt_file_copy_bytes(s->fp_in, fp_in, a->length);
570 
571  if (piped)
572  {
573  unlink(mutt_buffer_string(tempfile));
574  fflush(fp_in);
575  rewind(fp_in);
576  pid = filter_create_fd(mutt_buffer_string(cmd), NULL, &fp_out, &fp_err,
577  fileno(fp_in), -1, -1);
578  }
579  else
580  {
581  mutt_file_fclose(&fp_in);
582  pid = filter_create(mutt_buffer_string(cmd), NULL, &fp_out, &fp_err);
583  }
584 
585  if (pid < 0)
586  {
587  mutt_perror(_("Can't create filter"));
588  if (s->flags & MUTT_DISPLAY)
589  {
591  state_printf(s, _("[-- Can't run %s. --]\n"), mutt_buffer_string(cmd));
592  }
593  rc = -1;
594  goto bail;
595  }
596 
597  if (s->prefix)
598  {
599  /* Remove ansi and formatting from autoview output in replies only. The
600  * user may want to see the formatting in the pager, but it shouldn't be
601  * in their quoted reply text too. */
602  struct Buffer *stripped = mutt_buffer_pool_get();
603  while (fgets(buf, sizeof(buf), fp_out))
604  {
605  mutt_buffer_strip_formatting(stripped, buf, false);
606  state_puts(s, s->prefix);
607  state_puts(s, mutt_buffer_string(stripped));
608  }
609  mutt_buffer_pool_release(&stripped);
610 
611  /* check for data on stderr */
612  if (fgets(buf, sizeof(buf), fp_err))
613  {
614  if (s->flags & MUTT_DISPLAY)
615  {
617  state_printf(s, _("[-- Autoview stderr of %s --]\n"), mutt_buffer_string(cmd));
618  }
619 
620  state_puts(s, s->prefix);
621  state_puts(s, buf);
622  while (fgets(buf, sizeof(buf), fp_err))
623  {
624  state_puts(s, s->prefix);
625  state_puts(s, buf);
626  }
627  }
628  }
629  else
630  {
631  mutt_file_copy_stream(fp_out, s->fp_out);
632  /* Check for stderr messages */
633  if (fgets(buf, sizeof(buf), fp_err))
634  {
635  if (s->flags & MUTT_DISPLAY)
636  {
638  state_printf(s, _("[-- Autoview stderr of %s --]\n"), mutt_buffer_string(cmd));
639  }
640 
641  state_puts(s, buf);
642  mutt_file_copy_stream(fp_err, s->fp_out);
643  }
644  }
645 
646  bail:
647  mutt_file_fclose(&fp_out);
648  mutt_file_fclose(&fp_err);
649 
650  filter_wait(pid);
651  if (piped)
652  mutt_file_fclose(&fp_in);
653  else
655 
656  if (s->flags & MUTT_DISPLAY)
658  }
659 
660 cleanup:
661  mailcap_entry_free(&entry);
662 
664  mutt_buffer_pool_release(&tempfile);
665 
666  return rc;
667 }
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_buffer_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition: display.c:736
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:241
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:622
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:437
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:475
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:446
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:545
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
#define TYPE(body)
Definition: mime.h:89
#define _(a)
Definition: message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:181
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
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
int state_printf(struct State *s, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:185
void state_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:71
char * subtype
content-type subtype
Definition: body.h:59
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:57
String manipulation buffer.
Definition: buffer.h:34
A mailcap entry.
Definition: mailcap.h:36
char * nametemplate
Definition: mailcap.h:43
char * command
Definition: mailcap.h:37
FILE * fp_out
File to write to.
Definition: state.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ text_plain_handler()

static int text_plain_handler ( struct Body b,
struct State s 
)
static

Handler for plain text - Implements handler_t -.

Return values
0Always

When generating format=flowed ($text_flowed is set) from format=fixed, strip all trailing spaces to improve interoperability; if $text_flowed is unset, simply verbatim copy input.

Definition at line 677 of file handler.c.

678 {
679  char *buf = NULL;
680  size_t sz = 0;
681 
682  while ((buf = mutt_file_read_line(buf, &sz, s->fp_in, NULL, MUTT_RL_NO_FLAGS)))
683  {
684  const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
685  if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
686  {
687  size_t len = mutt_str_len(buf);
688  while ((len > 0) && (buf[len - 1] == ' '))
689  buf[--len] = '\0';
690  }
691  if (s->prefix)
692  state_puts(s, s->prefix);
693  state_puts(s, buf);
694  state_putc(s, '\n');
695  }
696 
697  FREE(&buf);
698  return 0;
699 }
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:695
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:715
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ message_handler()

static int message_handler ( struct Body a,
struct State s 
)
static

Handler for message/rfc822 body parts - Implements handler_t -.

Definition at line 704 of file handler.c.

705 {
706  struct Body *b = NULL;
707  LOFF_T off_start;
708  int rc = 0;
709 
710  off_start = ftello(s->fp_in);
711  if (off_start < 0)
712  return -1;
713 
714  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
715  (a->encoding == ENC_UUENCODED))
716  {
717  b = mutt_body_new();
720  }
721  else
722  b = a;
723 
724  if (b->parts)
725  {
726  CopyHeaderFlags chflags = CH_DECODE | CH_FROM;
727  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
728  if ((s->flags & MUTT_WEED) || ((s->flags & (MUTT_DISPLAY | MUTT_PRINTING)) && c_weed))
729  chflags |= CH_WEED | CH_REORDER;
730  if (s->prefix)
731  chflags |= CH_PREFIX;
732  if (s->flags & MUTT_DISPLAY)
733  chflags |= CH_DISPLAY;
734 
735  mutt_copy_hdr(s->fp_in, s->fp_out, off_start, b->parts->offset, chflags, s->prefix, 0);
736 
737  if (s->prefix)
738  state_puts(s, s->prefix);
739  state_putc(s, '\n');
740 
741  rc = mutt_body_handler(b->parts, s);
742  }
743 
744  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
745  (a->encoding == ENC_UUENCODED))
746  {
747  mutt_body_free(&b);
748  }
749 
750  return rc;
751 }
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define CH_DISPLAY
Display result to user.
Definition: copy.h:70
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1544
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1600
@ ENC_UUENCODED
UUEncoded text.
Definition: mime.h:54
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1736
#define MUTT_WEED
Weed headers even when not in display mode.
Definition: state.h:35
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
The body of an email.
Definition: body.h:35
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:71
LOFF_T offset
offset where the actual data begins
Definition: body.h:51
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ external_body_handler()

static int external_body_handler ( struct Body b,
struct State s 
)
static

Handler for external-body emails - Implements handler_t -.

Definition at line 756 of file handler.c.

757 {
758  const char *str = NULL;
759  char strbuf[1024];
760 
761  const char *access_type = mutt_param_get(&b->parameter, "access-type");
762  if (!access_type)
763  {
764  if (s->flags & MUTT_DISPLAY)
765  {
767  state_puts(s, _("[-- Error: message/external-body has no access-type "
768  "parameter --]\n"));
769  return 0;
770  }
771  else
772  return -1;
773  }
774 
775  const char *expiration = mutt_param_get(&b->parameter, "expiration");
776  time_t expire;
777  if (expiration)
778  expire = mutt_date_parse_date(expiration, NULL);
779  else
780  expire = -1;
781 
782  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
783  if (mutt_istr_equal(access_type, "x-mutt-deleted"))
784  {
785  if (s->flags & (MUTT_DISPLAY | MUTT_PRINTING))
786  {
787  char pretty_size[10];
788  char *length = mutt_param_get(&b->parameter, "length");
789  if (length)
790  {
791  long size = strtol(length, NULL, 10);
792  mutt_str_pretty_size(pretty_size, sizeof(pretty_size), size);
793  if (expire != -1)
794  {
795  str = ngettext(
796  /* L10N: If the translation of this string is a multi line string, then
797  each line should start with "[-- " and end with " --]".
798  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
799  expands to a date as returned by `mutt_date_parse_date()`.
800 
801  Note: The size argument printed is not the actual number as passed
802  to gettext but the prettified version, e.g. size = 2048 will be
803  printed as 2K. Your language might be sensitive to that: For
804  example although '1K' and '1024' represent the same number your
805  language might inflect the noun 'byte' differently.
806 
807  Sadly, we can't do anything about that at the moment besides
808  passing the precise size in bytes. If you are interested the
809  function responsible for the prettification is
810  mutt_str_pretty_size() in mutt/string.c. */
811  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n"
812  "[-- on %s --]\n",
813  "[-- This %s/%s attachment (size %s bytes) has been deleted --]\n"
814  "[-- on %s --]\n",
815  size);
816  }
817  else
818  {
819  str = ngettext(
820  /* L10N: If the translation of this string is a multi line string, then
821  each line should start with "[-- " and end with " --]".
822  The first "%s/%s" is a MIME type, e.g. "text/plain".
823 
824  Note: The size argument printed is not the actual number as passed
825  to gettext but the prettified version, e.g. size = 2048 will be
826  printed as 2K. Your language might be sensitive to that: For
827  example although '1K' and '1024' represent the same number your
828  language might inflect the noun 'byte' differently.
829 
830  Sadly, we can't do anything about that at the moment besides
831  passing the precise size in bytes. If you are interested the
832  function responsible for the prettification is
833  mutt_str_pretty_size() in mutt/string.c. */
834  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n",
835  "[-- This %s/%s attachment (size %s bytes) has been deleted "
836  "--]\n",
837  size);
838  }
839  }
840  else
841  {
842  pretty_size[0] = '\0';
843  if (expire != -1)
844  {
845  /* L10N: If the translation of this string is a multi line string, then
846  each line should start with "[-- " and end with " --]".
847  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
848  expands to a date as returned by `mutt_date_parse_date()`.
849 
850  Caution: Argument three %3$ is also defined but should not be used
851  in this translation! */
852  str = _("[-- This %s/%s attachment has been deleted --]\n[-- on %4$s "
853  "--]\n");
854  }
855  else
856  {
857  /* L10N: If the translation of this string is a multi line string, then
858  each line should start with "[-- " and end with " --]".
859  The first "%s/%s" is a MIME type, e.g. "text/plain". */
860  str = _("[-- This %s/%s attachment has been deleted --]\n");
861  }
862  }
863 
864  snprintf(strbuf, sizeof(strbuf), str, TYPE(b->parts), b->parts->subtype,
865  pretty_size, expiration);
866  state_attach_puts(s, strbuf);
867  if (b->parts->filename)
868  {
870  state_printf(s, _("[-- name: %s --]\n"), b->parts->filename);
871  }
872 
873  CopyHeaderFlags chflags = CH_DECODE;
874  if (c_weed)
875  chflags |= CH_WEED | CH_REORDER;
876 
877  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
878  chflags, NULL, 0);
879  }
880  }
881  else if (expiration && (expire < mutt_date_epoch()))
882  {
883  if (s->flags & MUTT_DISPLAY)
884  {
885  /* L10N: If the translation of this string is a multi line string, then
886  each line should start with "[-- " and end with " --]".
887  The "%s/%s" is a MIME type, e.g. "text/plain". */
888  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated external source has --]\n[-- expired. --]\n"),
889  TYPE(b->parts), b->parts->subtype);
890  state_attach_puts(s, strbuf);
891 
893  if (c_weed)
894  chflags |= CH_WEED | CH_REORDER;
895 
896  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
897  chflags, NULL, 0);
898  }
899  }
900  else
901  {
902  if (s->flags & MUTT_DISPLAY)
903  {
904  /* L10N: If the translation of this string is a multi line string, then
905  each line should start with "[-- " and end with " --]".
906  The "%s/%s" is a MIME type, e.g. "text/plain". The %s after
907  access-type is an access-type as defined by the MIME RFCs, e.g. "FTP",
908  "LOCAL-FILE", "MAIL-SERVER". */
909  snprintf(strbuf, sizeof(strbuf), _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated access-type %s is unsupported --]\n"),
910  TYPE(b->parts), b->parts->subtype, access_type);
911  state_attach_puts(s, strbuf);
912 
914  if (c_weed)
915  chflags |= CH_WEED | CH_REORDER;
916 
917  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
918  chflags, NULL, 0);
919  }
920  }
921 
922  return 0;
923 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
time_t mutt_date_parse_date(const char *s, struct Tz *tz_out)
Parse a date string in RFC822 format.
Definition: date.c:456
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:727
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1679
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:102
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alternative_handler()

static int alternative_handler ( struct Body a,
struct State s 
)
static

Handler for multipart alternative emails - Implements handler_t -.

Definition at line 928 of file handler.c.

929 {
930  struct Body *const head = a;
931  struct Body *choice = NULL;
932  struct Body *b = NULL;
933  bool mustfree = false;
934  int rc = 0;
935 
936  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
937  (a->encoding == ENC_UUENCODED))
938  {
939  mustfree = true;
940  b = mutt_body_new();
942  b->parts =
943  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
944  b->length, mutt_istr_equal("digest", a->subtype));
945  }
946  else
947  b = a;
948 
949  a = b;
950 
951  /* First, search list of preferred types */
952  struct ListNode *np = NULL;
953  STAILQ_FOREACH(np, &AlternativeOrderList, entries)
954  {
955  int btlen; /* length of basetype */
956  bool wild; /* do we have a wildcard to match all subtypes? */
957 
958  char *c = strchr(np->data, '/');
959  if (c)
960  {
961  wild = ((c[1] == '*') && (c[2] == '\0'));
962  btlen = c - np->data;
963  }
964  else
965  {
966  wild = true;
967  btlen = mutt_str_len(np->data);
968  }
969 
970  if (a->parts)
971  b = a->parts;
972  else
973  b = a;
974  while (b)
975  {
976  const char *bt = TYPE(b);
977  if (mutt_istrn_equal(bt, np->data, btlen) && (bt[btlen] == 0))
978  {
979  /* the basetype matches */
980  if (wild || mutt_istr_equal(np->data + btlen + 1, b->subtype))
981  {
982  choice = b;
983  }
984  }
985  b = b->next;
986  }
987 
988  if (choice)
989  break;
990  }
991 
992  /* Next, look for an autoviewable type */
993  if (!choice)
994  {
995  if (a->parts)
996  b = a->parts;
997  else
998  b = a;
999  while (b)
1000  {
1001  if (is_autoview(b))
1002  choice = b;
1003  b = b->next;
1004  }
1005  }
1006 
1007  /* Then, look for a text entry */
1008  if (!choice)
1009  {
1010  if (a->parts)
1011  b = a->parts;
1012  else
1013  b = a;
1014  int type = 0;
1015  while (b)
1016  {
1017  if (b->type == TYPE_TEXT)
1018  {
1019  if (mutt_istr_equal("plain", b->subtype) && (type <= TXT_PLAIN))
1020  {
1021  choice = b;
1022  type = TXT_PLAIN;
1023  }
1024  else if (mutt_istr_equal("enriched", b->subtype) && (type <= TXT_ENRICHED))
1025  {
1026  choice = b;
1027  type = TXT_ENRICHED;
1028  }
1029  else if (mutt_istr_equal("html", b->subtype) && (type <= TXT_HTML))
1030  {
1031  choice = b;
1032  type = TXT_HTML;
1033  }
1034  }
1035  b = b->next;
1036  }
1037  }
1038 
1039  /* Finally, look for other possibilities */
1040  if (!choice)
1041  {
1042  if (a->parts)
1043  b = a->parts;
1044  else
1045  b = a;
1046  while (b)
1047  {
1048  if (mutt_can_decode(b))
1049  choice = b;
1050  b = b->next;
1051  }
1052  }
1053 
1054  if (choice)
1055  {
1056  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1057  if (s->flags & MUTT_DISPLAY && !c_weed &&
1058  mutt_file_seek(s->fp_in, choice->hdr_offset, SEEK_SET))
1059  {
1060  mutt_file_copy_bytes(s->fp_in, s->fp_out, choice->offset - choice->hdr_offset);
1061  }
1062 
1063  const char *const c_show_multipart_alternative =
1064  cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1065  if (mutt_str_equal("info", c_show_multipart_alternative))
1066  {
1067  print_part_line(s, choice, 0);
1068  }
1069  mutt_body_handler(choice, s);
1070 
1071  /* Let it flow back to the main part */
1072  head->nowrap = choice->nowrap;
1073  choice->nowrap = false;
1074 
1075  if (mutt_str_equal("info", c_show_multipart_alternative))
1076  {
1077  if (a->parts)
1078  b = a->parts;
1079  else
1080  b = a;
1081  int count = 0;
1082  while (b)
1083  {
1084  if (choice != b)
1085  {
1086  count += 1;
1087  if (count == 1)
1088  state_putc(s, '\n');
1089 
1090  print_part_line(s, b, count);
1091  }
1092  b = b->next;
1093  }
1094  }
1095  }
1096  else if (s->flags & MUTT_DISPLAY)
1097  {
1098  /* didn't find anything that we could display! */
1099  state_mark_attach(s);
1100  state_puts(s, _("[-- Error: Could not display any parts of "
1101  "Multipart/Alternative --]\n"));
1102  rc = -1;
1103  }
1104 
1105  if (mustfree)
1106  mutt_body_free(&a);
1107 
1108  return rc;
1109 }
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:665
static bool is_autoview(struct Body *b)
Should email body be filtered by mailcap.
Definition: handler.c:477
static void print_part_line(struct State *s, struct Body *b, int n)
Print a separator for the Mime part.
Definition: handler.c:88
#define TXT_PLAIN
Definition: handler.c:67
#define TXT_HTML
Definition: handler.c:66
#define TXT_ENRICHED
Definition: handler.c:68
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1817
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition: string.c:432
struct ListHead AlternativeOrderList
List of preferred mime types to display.
Definition: mutt_globals.h:64
struct Body * mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off, bool digest)
Parse a multipart structure.
Definition: parse.c:1752
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
bool nowrap
Do not wrap the output in the pager.
Definition: body.h:88
struct Body * next
next attachment in the list
Definition: body.h:70
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:79
unsigned int type
content-type primary type, ContentType
Definition: body.h:39
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ multilingual_handler()

static int multilingual_handler ( struct Body a,
struct State s 
)
static

Handler for multi-lingual emails - Implements handler_t -.

Return values
0Always

Definition at line 1115 of file handler.c.

1116 {
1117  struct Body *b = NULL;
1118  bool mustfree = false;
1119  int rc = 0;
1120 
1122  "RFC8255 >> entering in handler multilingual handler\n");
1123  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1124  (a->encoding == ENC_UUENCODED))
1125  {
1126  mustfree = true;
1127  b = mutt_body_new();
1129  b->parts =
1130  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
1131  b->length, mutt_istr_equal("digest", a->subtype));
1132  }
1133  else
1134  b = a;
1135 
1136  a = b;
1137 
1138  if (a->parts)
1139  b = a->parts;
1140  else
1141  b = a;
1142 
1143  struct Body *choice = NULL;
1144  struct Body *first_part = NULL;
1145  struct Body *zxx_part = NULL;
1146  struct ListNode *np = NULL;
1147 
1148  const struct Slist *c_preferred_languages =
1149  cs_subset_slist(NeoMutt->sub, "preferred_languages");
1150  if (c_preferred_languages)
1151  {
1152  struct Buffer *langs = mutt_buffer_pool_get();
1153  cs_subset_str_string_get(NeoMutt->sub, "preferred_languages", langs);
1154  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_languages set in config to '%s'\n",
1155  mutt_buffer_string(langs));
1156  mutt_buffer_pool_release(&langs);
1157 
1158  STAILQ_FOREACH(np, &c_preferred_languages->head, entries)
1159  {
1160  while (b)
1161  {
1162  if (mutt_can_decode(b))
1163  {
1164  if (!first_part)
1165  first_part = b;
1166 
1167  if (b->language && mutt_str_equal("zxx", b->language))
1168  zxx_part = b;
1169 
1170  mutt_debug(LL_DEBUG2, "RFC8255 >> comparing configuration preferred_language='%s' to mail part content-language='%s'\n",
1171  np->data, b->language);
1172  if (b->language && mutt_str_equal(np->data, b->language))
1173  {
1174  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_language='%s' matches content-language='%s' >> part selected to be displayed\n",
1175  np->data, b->language);
1176  choice = b;
1177  break;
1178  }
1179  }
1180 
1181  b = b->next;
1182  }
1183 
1184  if (choice)
1185  break;
1186 
1187  if (a->parts)
1188  b = a->parts;
1189  else
1190  b = a;
1191  }
1192  }
1193 
1194  if (choice)
1195  mutt_body_handler(choice, s);
1196  else
1197  {
1198  if (zxx_part)
1199  mutt_body_handler(zxx_part, s);
1200  else
1201  mutt_body_handler(first_part, s);
1202  }
1203 
1204  if (mustfree)
1205  mutt_body_free(&a);
1206 
1207  return rc;
1208 }
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
char * language
content-language (RFC8255)
Definition: body.h:76
String list.
Definition: slist.h:47
struct ListHead head
List containing values.
Definition: slist.h:48
int cs_subset_str_string_get(const struct ConfigSubset *sub, const char *name, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:370
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ multipart_handler()

static int multipart_handler ( struct Body a,
struct State s 
)
static

Handler for multipart emails - Implements handler_t -.

Definition at line 1213 of file handler.c.

1214 {
1215  struct Body *b = NULL, *p = NULL;
1216  int count;
1217  int rc = 0;
1218 
1219  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1220  (a->encoding == ENC_UUENCODED))
1221  {
1222  b = mutt_body_new();
1224  b->parts =
1225  mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
1226  b->length, mutt_istr_equal("digest", a->subtype));
1227  }
1228  else
1229  b = a;
1230 
1231  for (p = b->parts, count = 1; p; p = p->next, count++)
1232  {
1233  if (s->flags & MUTT_DISPLAY)
1234  {
1235  state_mark_attach(s);
1236  if (p->description || p->filename || p->form_name)
1237  {
1238  /* L10N: %s is the attachment description, filename or form_name. */
1239  state_printf(s, _("[-- Attachment #%d: %s --]\n"), count,
1240  p->description ? p->description :
1241  p->filename ? p->filename :
1242  p->form_name);
1243  }
1244  else
1245  state_printf(s, _("[-- Attachment #%d --]\n"), count);
1246  print_part_line(s, p, 0);
1247  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1248  if (c_weed)
1249  {
1250  state_putc(s, '\n');
1251  }
1252  else if (mutt_file_seek(s->fp_in, p->hdr_offset, SEEK_SET))
1253  {
1254  mutt_file_copy_bytes(s->fp_in, s->fp_out, p->offset - p->hdr_offset);
1255  }
1256  }
1257 
1258  rc = mutt_body_handler(p, s);
1259  state_putc(s, '\n');
1260 
1261  if (rc != 0)
1262  {
1263  mutt_error(_("One or more parts of this message could not be displayed"));
1264  mutt_debug(LL_DEBUG1, "Failed on attachment #%d, type %s/%s\n", count,
1265  TYPE(p), NONULL(p->subtype));
1266  }
1267 
1268  const bool c_include_only_first =
1269  cs_subset_bool(NeoMutt->sub, "include_only_first");
1270  if ((s->flags & MUTT_REPLYING) && c_include_only_first && (s->flags & MUTT_FIRSTDONE))
1271  {
1272  break;
1273  }
1274  }
1275 
1276  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1277  (a->encoding == ENC_UUENCODED))
1278  {
1279  mutt_body_free(&b);
1280  }
1281 
1282  /* make failure of a single part non-fatal */
1283  if (rc < 0)
1284  rc = 1;
1285  return rc;
1286 }
#define mutt_error(...)
Definition: logging.h:87
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define MUTT_FIRSTDONE
The first attachment has been done.
Definition: state.h:39
#define MUTT_REPLYING
Are we replying?
Definition: state.h:38
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ valid_pgp_encrypted_handler()

static int valid_pgp_encrypted_handler ( struct Body b,
struct State s 
)
static

Handler for valid pgp-encrypted emails - Implements handler_t -.

Definition at line 1440 of file handler.c.

1441 {
1442  struct Body *octetstream = b->parts->next;
1443 
1444  /* clear out any mime headers before the handler, so they can't be spoofed. */
1446  mutt_env_free(&octetstream->mime_headers);
1447 
1448  int rc;
1449  /* Some clients improperly encode the octetstream part. */
1450  if (octetstream->encoding != ENC_7BIT)
1451  rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, 0);
1452  else
1453  rc = crypt_pgp_encrypted_handler(octetstream, s);
1454  b->goodsig |= octetstream->goodsig;
1455 
1456  /* Relocate protected headers onto the multipart/encrypted part */
1457  if (!rc && octetstream->mime_headers)
1458  {
1459  b->mime_headers = octetstream->mime_headers;
1460  octetstream->mime_headers = NULL;
1461  }
1462 
1463  return rc;
1464 }
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
int crypt_pgp_encrypted_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -.
Definition: cryptglue.c:249
static int run_decode_and_handler(struct Body *b, struct State *s, handler_t handler, bool plaintext)
Run an appropriate decoder for an email.
Definition: handler.c:1297
@ ENC_7BIT
7-bit text
Definition: mime.h:49
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:74
bool goodsig
Good cryptographic signature.
Definition: body.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ malformed_pgp_encrypted_handler()

static int malformed_pgp_encrypted_handler ( struct Body b,
struct State s 
)
static

Handler for invalid pgp-encrypted emails - Implements handler_t -.

Definition at line 1469 of file handler.c.

1470 {
1471  struct Body *octetstream = b->parts->next->next;
1472 
1473  /* clear out any mime headers before the handler, so they can't be spoofed. */
1475  mutt_env_free(&octetstream->mime_headers);
1476 
1477  /* exchange encodes the octet-stream, so re-run it through the decoder */
1478  int rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, false);
1479  b->goodsig |= octetstream->goodsig;
1480 #ifdef USE_AUTOCRYPT
1481  b->is_autocrypt |= octetstream->is_autocrypt;
1482 #endif
1483 
1484  /* Relocate protected headers onto the multipart/encrypted part */
1485  if (!rc && octetstream->mime_headers)
1486  {
1487  b->mime_headers = octetstream->mime_headers;
1488  octetstream->mime_headers = NULL;
1489  }
1490 
1491  return rc;
1492 }
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition: body.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_protected_headers_handler()

int mutt_protected_headers_handler ( struct Body b,
struct State s 
)

Process a protected header - Implements handler_t -.

Definition at line 1121 of file crypt.c.

1122 {
1123  const bool c_crypt_protected_headers_read =
1124  cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1125  if (c_crypt_protected_headers_read && b->mime_headers)
1126  {
1127  if (b->mime_headers->subject)
1128  {
1129  const bool display = (s->flags & MUTT_DISPLAY);
1130 
1131  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1132  if (display && c_weed && mutt_matches_ignore("subject"))
1133  return 0;
1134 
1136  const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
1137  int wraplen = display ? mutt_window_wrap_cols(s->wraplen, c_wrap) : 0;
1138 
1139  mutt_write_one_header(s->fp_out, "Subject", b->mime_headers->subject, s->prefix,
1140  wraplen, display ? CH_DISPLAY : CH_NO_FLAGS, NeoMutt->sub);
1141  state_puts(s, "\n");
1142  }
1143  }
1144 
1145  return 0;
1146 }
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
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
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:364
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:314
void state_mark_protected_header(struct State *s)
Write a unique marker around protected headers.
Definition: state.c:87
char * subject
Email's subject.
Definition: envelope.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_signed_handler()

int mutt_signed_handler ( struct Body b,
struct State s 
)

Verify a "multipart/signed" body - Implements handler_t -.

Definition at line 1151 of file crypt.c.

1152 {
1153  if (!WithCrypto)
1154  return -1;
1155 
1156  bool inconsistent = false;
1157  struct Body *top = b;
1158  struct Body **signatures = NULL;
1159  int sigcnt = 0;
1160  int rc = 0;
1161  struct Buffer *tempfile = NULL;
1162 
1163  b = b->parts;
1164  SecurityFlags signed_type = mutt_is_multipart_signed(top);
1165  if (signed_type == SEC_NO_FLAGS)
1166  {
1167  /* A null protocol value is already checked for in mutt_body_handler() */
1168  state_printf(s,
1169  _("[-- Error: "
1170  "Unknown multipart/signed protocol %s --]\n\n"),
1171  mutt_param_get(&top->parameter, "protocol"));
1172  return mutt_body_handler(b, s);
1173  }
1174 
1175  if (!(b && b->next))
1176  inconsistent = true;
1177  else
1178  {
1179  switch (signed_type)
1180  {
1181  case SEC_SIGN:
1182  if ((b->next->type != TYPE_MULTIPART) || !mutt_istr_equal(b->next->subtype, "mixed"))
1183  {
1184  inconsistent = true;
1185  }
1186  break;
1187  case PGP_SIGN:
1188  if ((b->next->type != TYPE_APPLICATION) ||
1189  !mutt_istr_equal(b->next->subtype, "pgp-signature"))
1190  {
1191  inconsistent = true;
1192  }
1193  break;
1194  case SMIME_SIGN:
1195  if ((b->next->type != TYPE_APPLICATION) ||
1196  (!mutt_istr_equal(b->next->subtype, "x-pkcs7-signature") &&
1197  !mutt_istr_equal(b->next->subtype, "pkcs7-signature")))
1198  {
1199  inconsistent = true;
1200  }
1201  break;
1202  default:
1203  inconsistent = true;
1204  }
1205  }
1206  if (inconsistent)
1207  {
1208  state_attach_puts(s, _("[-- Error: Missing or bad-format multipart/signed "
1209  "signature --]\n\n"));
1210  return mutt_body_handler(b, s);
1211  }
1212 
1213  if (s->flags & MUTT_DISPLAY)
1214  {
1215  crypt_fetch_signatures(&signatures, b->next, &sigcnt);
1216 
1217  if (sigcnt != 0)
1218  {
1219  tempfile = mutt_buffer_pool_get();
1220  mutt_buffer_mktemp(tempfile);
1221  bool goodsig = true;
1222  if (crypt_write_signed(b, s, mutt_buffer_string(tempfile)) == 0)
1223  {
1224  for (int i = 0; i < sigcnt; i++)
1225  {
1226  if (((WithCrypto & APPLICATION_PGP) != 0) &&
1227  (signatures[i]->type == TYPE_APPLICATION) &&
1228  mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1229  {
1230  if (crypt_pgp_verify_one(signatures[i], s, mutt_buffer_string(tempfile)) != 0)
1231  goodsig = false;
1232 
1233  continue;
1234  }
1235 
1236  if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1237  (signatures[i]->type == TYPE_APPLICATION) &&
1238  (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1239  mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1240  {
1241  if (crypt_smime_verify_one(signatures[i], s, mutt_buffer_string(tempfile)) != 0)
1242  goodsig = false;
1243 
1244  continue;
1245  }
1246 
1247  state_printf(s,
1248  _("[-- Warning: "
1249  "We can't verify %s/%s signatures. --]\n\n"),
1250  TYPE(signatures[i]), signatures[i]->subtype);
1251  }
1252  }
1253 
1255  mutt_buffer_pool_release(&tempfile);
1256 
1257  top->goodsig = goodsig;
1258  top->badsig = !goodsig;
1259 
1260  /* Now display the signed body */
1261  state_attach_puts(s, _("[-- The following data is signed --]\n\n"));
1262 
1264 
1265  FREE(&signatures);
1266  }
1267  else
1268  {
1270  _("[-- Warning: Can't find any signatures. --]\n\n"));
1271  }
1272  }
1273 
1274  rc = mutt_body_handler(b, s);
1275 
1276  if ((s->flags & MUTT_DISPLAY) && (sigcnt != 0))
1277  state_attach_puts(s, _("\n[-- End of signed data --]\n"));
1278 
1279  return rc;
1280 }
int crypt_write_signed(struct Body *a, struct State *s, const char *tempfile)
Write the message body/part.
Definition: crypt.c:764
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:414
static void crypt_fetch_signatures(struct Body ***signatures, struct Body *a, int *n)
Create an array of an emails parts.
Definition: crypt.c:1079
int crypt_smime_verify_one(struct Body *sigbdy, struct State *s, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:518
int crypt_pgp_verify_one(struct Body *sigbdy, struct State *s, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:374
int mutt_protected_headers_handler(struct Body *b, struct State *s)
Process a protected header - Implements handler_t -.
Definition: crypt.c:1121
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
#define PGP_SIGN
Definition: lib.h:94
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:71
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define SMIME_SIGN
Definition: lib.h:100
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:74
#define WithCrypto
Definition: lib.h:113
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_pgp_application_handler()

int crypt_pgp_application_handler ( struct Body b,
struct State s 
)

Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.

Definition at line 238 of file cryptglue.c.

239 {
240  if (CRYPT_MOD_CALL_CHECK(PGP, application_handler))
241  return CRYPT_MOD_CALL(PGP, application_handler)(b, s);
242 
243  return -1;
244 }
#define CRYPT_MOD_CALL_CHECK(identifier, func)
Definition: cryptglue.c:80
#define CRYPT_MOD_CALL(identifier, func)
Definition: cryptglue.c:86
+ Here is the caller graph for this function:

◆ crypt_pgp_encrypted_handler()

int crypt_pgp_encrypted_handler ( struct Body b,
struct State s 
)

Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -.

Definition at line 249 of file cryptglue.c.

250 {
251 #ifdef USE_AUTOCRYPT
252  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
253  if (c_autocrypt)
254  {
255  OptAutocryptGpgme = true;
256  int result = pgp_gpgme_encrypted_handler(b, s);
257  OptAutocryptGpgme = false;
258  if (result == 0)
259  {
260  b->is_autocrypt = true;
261  return result;
262  }
263  }
264 #endif
265 
266  if (CRYPT_MOD_CALL_CHECK(PGP, encrypted_handler))
267  return CRYPT_MOD_CALL(PGP, encrypted_handler)(b, s);
268 
269  return -1;
270 }
int pgp_gpgme_encrypted_handler(struct Body *a, struct State *s)
Implements CryptModuleSpecs::encrypted_handler() -.
Definition: crypt_gpgme.c:3071
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ crypt_smime_application_handler()

int crypt_smime_application_handler ( struct Body b,
struct State s 
)

Wrapper for CryptModuleSpecs::application_handler() - Implements handler_t -.

Definition at line 445 of file cryptglue.c.

446 {
447  if (CRYPT_MOD_CALL_CHECK(SMIME, application_handler))
448  return CRYPT_MOD_CALL(SMIME, application_handler)(b, s);
449 
450  return -1;
451 }
+ Here is the caller graph for this function:

◆ rfc3676_handler()

int rfc3676_handler ( struct Body a,
struct State s 
)

Body handler implementing RFC3676 for format=flowed - Implements handler_t -.

Return values
0Always

Definition at line 320 of file rfc3676.c.

321 {
322  char *buf = NULL;
323  unsigned int quotelevel = 0;
324  bool delsp = false;
325  size_t sz = 0;
326  struct FlowedState fst = { 0 };
327 
328  /* respect DelSp of RFC3676 only with f=f parts */
329  char *t = mutt_param_get(&a->parameter, "delsp");
330  if (t)
331  {
332  delsp = mutt_istr_equal(t, "yes");
333  t = NULL;
334  fst.delsp = true;
335  }
336 
337  mutt_debug(LL_DEBUG3, "f=f: DelSp: %s\n", delsp ? "yes" : "no");
338 
339  while ((buf = mutt_file_read_line(buf, &sz, s->fp_in, NULL, MUTT_RL_NO_FLAGS)))
340  {
341  const size_t buf_len = mutt_str_len(buf);
342  const unsigned int newql = get_quote_level(buf);
343 
344  /* end flowed paragraph (if we're within one) if quoting level
345  * changes (should not but can happen, see RFC3676, sec. 4.5.) */
346  if (newql != quotelevel)
347  flush_par(s, &fst);
348 
349  quotelevel = newql;
350  int buf_off = newql;
351 
352  /* respect sender's space-stuffing by removing one leading space */
353  if (buf[buf_off] == ' ')
354  buf_off++;
355 
356  /* test for signature separator */
357  const unsigned int sigsep = mutt_str_equal(buf + buf_off, "-- ");
358 
359  /* a fixed line either has no trailing space or is the
360  * signature separator */
361  const bool fixed = (buf_len == buf_off) || (buf[buf_len - 1] != ' ') || sigsep;
362 
363  /* print fixed-and-standalone, fixed-and-empty and sigsep lines as
364  * fixed lines */
365  if ((fixed && ((fst.width == 0) || (buf_len == 0))) || sigsep)
366  {
367  /* if we're within a flowed paragraph, terminate it */
368  flush_par(s, &fst);
369  print_fixed_line(buf + buf_off, s, quotelevel, &fst);
370  continue;
371  }
372 
373  /* for DelSp=yes, we need to strip one SP prior to CRLF on flowed lines */
374  if (delsp && !fixed)
375  buf[buf_len - 1] = '\0';
376 
377  print_flowed_line(buf + buf_off, s, quotelevel, &fst, fixed);
378  }
379 
380  flush_par(s, &fst);
381 
382  FREE(&buf);
383  return 0;
384 }
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
static void print_fixed_line(const char *line, struct State *s, int ql, struct FlowedState *fst)
Print a fixed format line.
Definition: rfc3676.c:305
static void print_flowed_line(char *line, struct State *s, int ql, struct FlowedState *fst, bool term)
Print a format-flowed line.
Definition: rfc3676.c:226
static int get_quote_level(const char *line)
Get the quote level of a line.
Definition: rfc3676.c:62
static void flush_par(struct State *s, struct FlowedState *fst)
Write out the paragraph.
Definition: rfc3676.c:173
State of a Format-Flowed line of text.
Definition: rfc3676.c:51
bool delsp
Definition: rfc3676.c:54
size_t width
Definition: rfc3676.c:52
+ Here is the call graph for this function:
+ Here is the caller graph for this function: