NeoMutt  2022-04-29-70-g0c028c
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 = ((s->wraplen > 4) && ((s->flags & MUTT_DISPLAY) || (s->wraplen < 76))) ?
480  s->wraplen - 4 :
481  72;
482  stte.line_max = stte.wrap_margin * 4;
483  stte.line = mutt_mem_calloc((stte.line_max + 1), sizeof(wchar_t));
484  stte.param = mutt_mem_calloc(256, sizeof(wchar_t));
485 
486  stte.param_len = 256;
487  stte.param_used = 0;
488 
489  if (s->prefix)
490  {
491  state_puts(s, s->prefix);
492  stte.indent_len += mutt_str_len(s->prefix);
493  }
494 
495  while (state != DONE)
496  {
497  if (state != ST_EOF)
498  {
499  if (!bytes || ((wc = fgetwc(s->fp_in)) == WEOF))
500  state = ST_EOF;
501  else
502  bytes--;
503  }
504 
505  switch (state)
506  {
507  case TEXT:
508  switch (wc)
509  {
510  case '<':
511  state = LANGLE;
512  break;
513 
514  case '\n':
515  if (stte.tag_level[RICH_NOFILL])
516  {
517  enriched_flush(&stte, true);
518  }
519  else
520  {
521  enriched_putwc((wchar_t) ' ', &stte);
522  state = NEWLINE;
523  }
524  break;
525 
526  default:
527  enriched_putwc(wc, &stte);
528  }
529  break;
530 
531  case LANGLE:
532  if (wc == (wchar_t) '<')
533  {
534  enriched_putwc(wc, &stte);
535  state = TEXT;
536  break;
537  }
538  else
539  {
540  tag_len = 0;
541  state = TAG;
542  }
543  /* Yes, (it wasn't a <<, so this char is first in TAG) */
544  /* fallthrough */
545  case TAG:
546  if (wc == (wchar_t) '>')
547  {
548  tag[tag_len] = (wchar_t) '\0';
549  enriched_set_flags(tag, &stte);
550  state = TEXT;
551  }
552  else if (tag_len < 1024) /* ignore overly long tags */
553  tag[tag_len++] = wc;
554  else
555  state = BOGUS_TAG;
556  break;
557 
558  case BOGUS_TAG:
559  if (wc == (wchar_t) '>')
560  state = TEXT;
561  break;
562 
563  case NEWLINE:
564  if (wc == (wchar_t) '\n')
565  enriched_flush(&stte, true);
566  else
567  {
568  ungetwc(wc, s->fp_in);
569  bytes++;
570  state = TEXT;
571  }
572  break;
573 
574  case ST_EOF:
575  enriched_putwc((wchar_t) '\0', &stte);
576  enriched_flush(&stte, true);
577  state = DONE;
578  break;
579 
580  default:
581  /* not reached */
582  break;
583  }
584  }
585 
586  state_putc(s, '\n'); /* add a final newline */
587 
588  FREE(&(stte.buffer));
589  FREE(&(stte.line));
590  FREE(&(stte.param));
591 
592  return 0;
593 }
@ 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
#define state_puts(STATE, STR)
Definition: state.h:56
#define state_putc(STATE, STR)
Definition: state.h:57
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
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:51
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
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
+ 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:667
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
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:230
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:647
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 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:435
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:473
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:444
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:542
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
#define TYPE(body)
Definition: mime.h:89
#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_mark_attach(struct State *s)
Write a unique marker around content.
Definition: state.c:71
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
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
char * subtype
content-type subtype
Definition: body.h:60
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
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:48
+ 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:720
#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:784
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:1569
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1597
@ 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
#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
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1752
The body of an email.
Definition: body.h:36
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
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
+ 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 parameter --]\n"));
768  return 0;
769  }
770  else
771  return -1;
772  }
773 
774  const char *expiration = mutt_param_get(&b->parameter, "expiration");
775  time_t expire;
776  if (expiration)
777  expire = mutt_date_parse_date(expiration, NULL);
778  else
779  expire = -1;
780 
781  const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
782  if (mutt_istr_equal(access_type, "x-mutt-deleted"))
783  {
784  if (s->flags & (MUTT_DISPLAY | MUTT_PRINTING))
785  {
786  char pretty_size[10];
787  char *length = mutt_param_get(&b->parameter, "length");
788  if (length)
789  {
790  long size = strtol(length, NULL, 10);
791  mutt_str_pretty_size(pretty_size, sizeof(pretty_size), size);
792  if (expire != -1)
793  {
794  str = ngettext(
795  /* L10N: If the translation of this string is a multi line string, then
796  each line should start with "[-- " and end with " --]".
797  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
798  expands to a date as returned by `mutt_date_parse_date()`.
799 
800  Note: The size argument printed is not the actual number as passed
801  to gettext but the prettified version, e.g. size = 2048 will be
802  printed as 2K. Your language might be sensitive to that: For
803  example although '1K' and '1024' represent the same number your
804  language might inflect the noun 'byte' differently.
805 
806  Sadly, we can't do anything about that at the moment besides
807  passing the precise size in bytes. If you are interested the
808  function responsible for the prettification is
809  mutt_str_pretty_size() in mutt/string.c. */
810  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n"
811  "[-- on %s --]\n",
812  "[-- This %s/%s attachment (size %s bytes) has been deleted --]\n"
813  "[-- on %s --]\n",
814  size);
815  }
816  else
817  {
818  str = ngettext(
819  /* L10N: If the translation of this string is a multi line string, then
820  each line should start with "[-- " and end with " --]".
821  The first "%s/%s" is a MIME type, e.g. "text/plain".
822 
823  Note: The size argument printed is not the actual number as passed
824  to gettext but the prettified version, e.g. size = 2048 will be
825  printed as 2K. Your language might be sensitive to that: For
826  example although '1K' and '1024' represent the same number your
827  language might inflect the noun 'byte' differently.
828 
829  Sadly, we can't do anything about that at the moment besides
830  passing the precise size in bytes. If you are interested the
831  function responsible for the prettification is
832  mutt_str_pretty_size() in mutt/string.c. */
833  "[-- This %s/%s attachment (size %s byte) has been deleted --]\n",
834  "[-- This %s/%s attachment (size %s bytes) has been deleted --]\n", size);
835  }
836  }
837  else
838  {
839  pretty_size[0] = '\0';
840  if (expire != -1)
841  {
842  /* L10N: If the translation of this string is a multi line string, then
843  each line should start with "[-- " and end with " --]".
844  The first "%s/%s" is a MIME type, e.g. "text/plain". The last %s
845  expands to a date as returned by `mutt_date_parse_date()`.
846 
847  Caution: Argument three %3$ is also defined but should not be used
848  in this translation! */
849  str = _("[-- This %s/%s attachment has been deleted --]\n[-- on %4$s --]\n");
850  }
851  else
852  {
853  /* L10N: If the translation of this string is a multi line string, then
854  each line should start with "[-- " and end with " --]".
855  The first "%s/%s" is a MIME type, e.g. "text/plain". */
856  str = _("[-- This %s/%s attachment has been deleted --]\n");
857  }
858  }
859 
860  snprintf(strbuf, sizeof(strbuf), str, TYPE(b->parts), b->parts->subtype,
861  pretty_size, expiration);
862  state_attach_puts(s, strbuf);
863  if (b->parts->filename)
864  {
866  state_printf(s, _("[-- name: %s --]\n"), b->parts->filename);
867  }
868 
869  CopyHeaderFlags chflags = CH_DECODE;
870  if (c_weed)
871  chflags |= CH_WEED | CH_REORDER;
872 
873  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
874  chflags, NULL, 0);
875  }
876  }
877  else if (expiration && (expire < mutt_date_epoch()))
878  {
879  if (s->flags & MUTT_DISPLAY)
880  {
881  /* L10N: If the translation of this string is a multi line string, then
882  each line should start with "[-- " and end with " --]".
883  The "%s/%s" is a MIME type, e.g. "text/plain". */
884  snprintf(strbuf, sizeof(strbuf),
885  _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated external source has --]\n[-- expired. --]\n"),
886  TYPE(b->parts), b->parts->subtype);
887  state_attach_puts(s, strbuf);
888 
890  if (c_weed)
891  chflags |= CH_WEED | CH_REORDER;
892 
893  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
894  chflags, NULL, 0);
895  }
896  }
897  else
898  {
899  if (s->flags & MUTT_DISPLAY)
900  {
901  /* L10N: If the translation of this string is a multi line string, then
902  each line should start with "[-- " and end with " --]".
903  The "%s/%s" is a MIME type, e.g. "text/plain". The %s after
904  access-type is an access-type as defined by the MIME RFCs, e.g. "FTP",
905  "LOCAL-FILE", "MAIL-SERVER". */
906  snprintf(strbuf, sizeof(strbuf),
907  _("[-- This %s/%s attachment is not included, --]\n[-- and the indicated access-type %s is unsupported --]\n"),
908  TYPE(b->parts), b->parts->subtype, access_type);
909  state_attach_puts(s, strbuf);
910 
912  if (c_weed)
913  chflags |= CH_WEED | CH_REORDER;
914 
915  mutt_copy_hdr(s->fp_in, s->fp_out, ftello(s->fp_in), b->parts->offset,
916  chflags, NULL, 0);
917  }
918  }
919 
920  return 0;
921 }
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
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:100
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1672
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
+ 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 926 of file handler.c.

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

1111 {
1112  struct Body *b = NULL;
1113  bool mustfree = false;
1114  int rc = 0;
1115 
1116  mutt_debug(LL_DEBUG2, "RFC8255 >> entering in handler multilingual handler\n");
1117  if ((a->encoding == ENC_BASE64) || (a->encoding == ENC_QUOTED_PRINTABLE) ||
1118  (a->encoding == ENC_UUENCODED))
1119  {
1120  mustfree = true;
1121  b = mutt_body_new();
1123  b->parts = mutt_parse_multipart(s->fp_in, mutt_param_get(&a->parameter, "boundary"),
1124  b->length, mutt_istr_equal("digest", a->subtype));
1125  }
1126  else
1127  b = a;
1128 
1129  a = b;
1130 
1131  if (a->parts)
1132  b = a->parts;
1133  else
1134  b = a;
1135 
1136  struct Body *choice = NULL;
1137  struct Body *first_part = NULL;
1138  struct Body *zxx_part = NULL;
1139  struct ListNode *np = NULL;
1140 
1141  while (b)
1142  {
1143  if (mutt_can_decode(b))
1144  {
1145  first_part = b;
1146  break;
1147  }
1148  b = b->next;
1149  }
1150 
1151  const struct Slist *c_preferred_languages = cs_subset_slist(NeoMutt->sub, "preferred_languages");
1152  if (c_preferred_languages)
1153  {
1154  struct Buffer *langs = mutt_buffer_pool_get();
1155  cs_subset_str_string_get(NeoMutt->sub, "preferred_languages", langs);
1156  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_languages set in config to '%s'\n",
1157  mutt_buffer_string(langs));
1158  mutt_buffer_pool_release(&langs);
1159 
1160  STAILQ_FOREACH(np, &c_preferred_languages->head, entries)
1161  {
1162  while (b)
1163  {
1164  if (mutt_can_decode(b))
1165  {
1166  if (b->language && mutt_str_equal("zxx", b->language))
1167  zxx_part = b;
1168 
1169  mutt_debug(LL_DEBUG2, "RFC8255 >> comparing configuration preferred_language='%s' to mail part content-language='%s'\n",
1170  np->data, b->language);
1171  if (b->language && mutt_str_equal(np->data, b->language))
1172  {
1173  mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_language='%s' matches content-language='%s' >> part selected to be displayed\n",
1174  np->data, b->language);
1175  choice = b;
1176  break;
1177  }
1178  }
1179 
1180  b = b->next;
1181  }
1182 
1183  if (choice)
1184  break;
1185 
1186  if (a->parts)
1187  b = a->parts;
1188  else
1189  b = a;
1190  }
1191  }
1192 
1193  if (choice)
1194  mutt_body_handler(choice, s);
1195  else
1196  {
1197  if (zxx_part)
1198  mutt_body_handler(zxx_part, s);
1199  else
1200  mutt_body_handler(first_part, s);
1201  }
1202 
1203  if (mustfree)
1204  mutt_body_free(&a);
1205 
1206  return rc;
1207 }
#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:77
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 1212 of file handler.c.

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

1438 {
1439  struct Body *octetstream = b->parts->next;
1440 
1441  /* clear out any mime headers before the handler, so they can't be spoofed. */
1443  mutt_env_free(&octetstream->mime_headers);
1444 
1445  int rc;
1446  /* Some clients improperly encode the octetstream part. */
1447  if (octetstream->encoding != ENC_7BIT)
1448  rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, 0);
1449  else
1450  rc = crypt_pgp_encrypted_handler(octetstream, s);
1451  b->goodsig |= octetstream->goodsig;
1452 
1453  /* Relocate protected headers onto the multipart/encrypted part */
1454  if (!rc && octetstream->mime_headers)
1455  {
1456  b->mime_headers = octetstream->mime_headers;
1457  octetstream->mime_headers = NULL;
1458  }
1459 
1460  return rc;
1461 }
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
int crypt_pgp_encrypted_handler(struct Body *b, struct State *s)
Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -.
Definition: cryptglue.c:248
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:1294
@ ENC_7BIT
7-bit text
Definition: mime.h:49
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
bool goodsig
Good cryptographic signature.
Definition: body.h:45
+ 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 1466 of file handler.c.

1467 {
1468  struct Body *octetstream = b->parts->next->next;
1469 
1470  /* clear out any mime headers before the handler, so they can't be spoofed. */
1472  mutt_env_free(&octetstream->mime_headers);
1473 
1474  /* exchange encodes the octet-stream, so re-run it through the decoder */
1475  int rc = run_decode_and_handler(octetstream, s, crypt_pgp_encrypted_handler, false);
1476  b->goodsig |= octetstream->goodsig;
1477 #ifdef USE_AUTOCRYPT
1478  b->is_autocrypt |= octetstream->is_autocrypt;
1479 #endif
1480 
1481  /* Relocate protected headers onto the multipart/encrypted part */
1482  if (!rc && octetstream->mime_headers)
1483  {
1484  b->mime_headers = octetstream->mime_headers;
1485  octetstream->mime_headers = NULL;
1486  }
1487 
1488  return rc;
1489 }
bool is_autocrypt
Flag autocrypt-decrypted messages for replying.
Definition: body.h:50
+ 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 1095 of file crypt.c.

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 }
#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
void state_mark_protected_header(struct State *s)
Write a unique marker around protected headers.
Definition: state.c:86
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:365
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:313
char * subject
Email's subject.
Definition: envelope.h:70
+ 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 1124 of file crypt.c.

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 }
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
int crypt_smime_verify_one(struct Body *sigbdy, struct State *s, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:517
int crypt_pgp_verify_one(struct Body *sigbdy, struct State *s, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:373
int mutt_protected_headers_handler(struct Body *b, struct State *s)
Process a protected header - Implements handler_t -.
Definition: crypt.c:1095
@ 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:97
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:74
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define SMIME_SIGN
Definition: lib.h:103
#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 WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:43
+ 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 237 of file cryptglue.c.

238 {
239  if (CRYPT_MOD_CALL_CHECK(PGP, application_handler))
240  return CRYPT_MOD_CALL(PGP, application_handler)(b, s);
241 
242  return -1;
243 }
#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 248 of file cryptglue.c.

249 {
250 #ifdef USE_AUTOCRYPT
251  const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
252  if (c_autocrypt)
253  {
254  OptAutocryptGpgme = true;
255  int result = pgp_gpgme_encrypted_handler(b, s);
256  OptAutocryptGpgme = false;
257  if (result == 0)
258  {
259  b->is_autocrypt = true;
260  return result;
261  }
262  }
263 #endif
264 
265  if (CRYPT_MOD_CALL_CHECK(PGP, encrypted_handler))
266  return CRYPT_MOD_CALL(PGP, encrypted_handler)(b, s);
267 
268  return -1;
269 }
int pgp_gpgme_encrypted_handler(struct Body *a, struct State *s)
Implements CryptModuleSpecs::encrypted_handler() -.
Definition: crypt_gpgme.c:3067
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 444 of file cryptglue.c.

445 {
446  if (CRYPT_MOD_CALL_CHECK(SMIME, application_handler))
447  return CRYPT_MOD_CALL(SMIME, application_handler)(b, s);
448 
449  return -1;
450 }
+ 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 318 of file rfc3676.c.

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