NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
Mime Handler API

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

Functions

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

Detailed Description

Prototype for a function to handle MIME parts.

Parameters
b_emailBody of the email
stateState of text being processed
Return values
0Success
-1Error

Function Documentation

◆ text_enriched_handler()

int text_enriched_handler ( struct Body * b_email,
struct State * state )

Handler for enriched text - Implements handler_t -.

Return values
0Always

Definition at line 468 of file enriched.c.

469{
470 enum
471 {
472 TEXT,
473 LANGLE,
474 TAG,
475 BOGUS_TAG,
476 NEWLINE,
477 ST_EOF,
478 DONE
479 } text_state = TEXT;
480
481 long bytes = b_email->length;
482 struct EnrichedState enriched = { 0 };
483 wint_t wc = 0;
484 int tag_len = 0;
485 wchar_t tag[1024 + 1];
486
487 enriched.state = state;
488 enriched.wrap_margin = ((state->wraplen > 4) &&
489 ((state->flags & STATE_DISPLAY) || (state->wraplen < 76))) ?
490 state->wraplen - 4 :
491 72;
492 enriched.line_max = enriched.wrap_margin * 4;
493 enriched.line = MUTT_MEM_CALLOC(enriched.line_max + 1, wchar_t);
494 enriched.param = MUTT_MEM_CALLOC(256, wchar_t);
495
496 enriched.param_len = 256;
497 enriched.param_used = 0;
498
499 if (state->prefix)
500 {
502 enriched.indent_len += mutt_str_len(state->prefix);
503 }
504
505 while (text_state != DONE)
506 {
507 if (text_state != ST_EOF)
508 {
509 if (!bytes || ((wc = fgetwc(state->fp_in)) == WEOF))
510 text_state = ST_EOF;
511 else
512 bytes--;
513 }
514
515 switch (text_state)
516 {
517 case TEXT:
518 switch (wc)
519 {
520 case '<':
521 text_state = LANGLE;
522 break;
523
524 case '\n':
525 if (enriched.tag_level[RICH_NOFILL])
526 {
527 enriched_flush(&enriched, true);
528 }
529 else
530 {
531 enriched_putwc((wchar_t) ' ', &enriched);
532 text_state = NEWLINE;
533 }
534 break;
535
536 default:
537 enriched_putwc(wc, &enriched);
538 }
539 break;
540
541 case LANGLE:
542 if (wc == (wchar_t) '<')
543 {
544 enriched_putwc(wc, &enriched);
545 text_state = TEXT;
546 break;
547 }
548 else
549 {
550 tag_len = 0;
551 text_state = TAG;
552 }
553 /* Yes, (it wasn't a <<, so this char is first in TAG) */
555
556 case TAG:
557 if (wc == (wchar_t) '>')
558 {
559 tag[tag_len] = (wchar_t) '\0';
560 enriched_set_flags(tag, &enriched);
561 text_state = TEXT;
562 }
563 else if (tag_len < 1024) /* ignore overly long tags */
564 {
565 tag[tag_len++] = wc;
566 }
567 else
568 {
569 text_state = BOGUS_TAG;
570 }
571 break;
572
573 case BOGUS_TAG:
574 if (wc == (wchar_t) '>')
575 text_state = TEXT;
576 break;
577
578 case NEWLINE:
579 if (wc == (wchar_t) '\n')
580 {
581 enriched_flush(&enriched, true);
582 }
583 else
584 {
585 ungetwc(wc, state->fp_in);
586 bytes++;
587 text_state = TEXT;
588 }
589 break;
590
591 case ST_EOF:
592 enriched_putwc((wchar_t) '\0', &enriched);
593 enriched_flush(&enriched, true);
594 text_state = DONE;
595 break;
596
597 default:
598 /* not reached */
599 break;
600 }
601 }
602
603 state_putc(state, '\n'); /* add a final newline */
604
605 FREE(&(enriched.buffer));
606 FREE(&(enriched.line));
607 FREE(&(enriched.param));
608
609 return 0;
610}
static void enriched_set_flags(const wchar_t *tag, struct EnrichedState *enriched)
Set flags on the enriched text state.
Definition enriched.c:376
@ RICH_NOFILL
Text will not be reformatted.
Definition enriched.c:53
static void enriched_putwc(wchar_t c, struct EnrichedState *enriched)
Write one wide character to the state.
Definition enriched.c:274
static void enriched_flush(struct EnrichedState *enriched, bool wrap)
Write enriched text to the State.
Definition enriched.c:237
#define FREE(x)
Definition memory.h:62
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
#define FALLTHROUGH
Definition lib.h:113
#define state_puts(STATE, STR)
Definition state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition state.h:33
#define state_putc(STATE, STR)
Definition state.h:59
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:498
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 * state
Definition enriched.c:113
size_t param_len
Definition enriched.c:110
size_t line_max
Definition enriched.c:105
size_t indent_len
Definition enriched.c:106
int wraplen
Width to wrap lines to (when flags & STATE_DISPLAY)
Definition state.h:53
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:52
FILE * fp_in
File to read from.
Definition state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition state.h:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ autoview_handler()

static int autoview_handler ( struct Body * b_email,
struct State * state )
static

Handler for autoviewable attachments - Implements handler_t -.

Definition at line 533 of file handler.c.

534{
535 struct MailcapEntry *entry = mailcap_entry_new();
536 char buf[1024] = { 0 };
537 char type[256] = { 0 };
538 struct Buffer *cmd = buf_pool_get();
539 struct Buffer *tempfile = buf_pool_get();
540 char *fname = NULL;
541 FILE *fp_in = NULL;
542 FILE *fp_out = NULL;
543 FILE *fp_err = NULL;
544 pid_t pid;
545 int rc = 0;
546
547 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b_email), b_email->subtype);
548 mailcap_lookup(b_email, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
549
550 fname = mutt_str_dup(b_email->filename);
551 mutt_file_sanitize_filename(fname, true);
552 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
553 FREE(&fname);
554
555 if (entry->command)
556 {
557 buf_strcpy(cmd, entry->command);
558
559 /* mailcap_expand_command returns 0 if the file is required */
560 bool piped = mailcap_expand_command(b_email, buf_string(tempfile), type, cmd);
561
562 if (state->flags & STATE_DISPLAY)
563 {
564 state_mark_attach(state);
565 state_printf(state, _("[-- Autoview using %s --]\n"), buf_string(cmd));
566 mutt_message(_("Invoking autoview command: %s"), buf_string(cmd));
567 }
568
569 fp_in = mutt_file_fopen(buf_string(tempfile), "w+");
570 if (!fp_in)
571 {
572 mutt_perror("fopen");
573 mailcap_entry_free(&entry);
574 rc = -1;
575 goto cleanup;
576 }
577
578 mutt_file_copy_bytes(state->fp_in, fp_in, b_email->length);
579
580 if (piped)
581 {
582 unlink(buf_string(tempfile));
583 fflush(fp_in);
584 rewind(fp_in);
585 pid = filter_create_fd(buf_string(cmd), NULL, &fp_out, &fp_err,
586 fileno(fp_in), -1, -1, NeoMutt->env);
587 }
588 else
589 {
590 mutt_file_fclose(&fp_in);
591 pid = filter_create(buf_string(cmd), NULL, &fp_out, &fp_err, NeoMutt->env);
592 }
593
594 if (pid < 0)
595 {
596 mutt_perror(_("Can't create filter"));
597 if (state->flags & STATE_DISPLAY)
598 {
599 state_mark_attach(state);
600 state_printf(state, _("[-- Can't run %s --]\n"), buf_string(cmd));
601 }
602 rc = -1;
603 goto bail;
604 }
605
606 if (state->prefix)
607 {
608 /* Remove ansi and formatting from autoview output in replies only. The
609 * user may want to see the formatting in the pager, but it shouldn't be
610 * in their quoted reply text too. */
611 struct Buffer *stripped = buf_pool_get();
612 while (fgets(buf, sizeof(buf), fp_out))
613 {
614 buf_strip_formatting(stripped, buf, false);
615 state_puts(state, state->prefix);
616 state_puts(state, buf_string(stripped));
617 }
618 buf_pool_release(&stripped);
619
620 /* check for data on stderr */
621 if (fgets(buf, sizeof(buf), fp_err))
622 {
623 if (state->flags & STATE_DISPLAY)
624 {
625 state_mark_attach(state);
626 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
627 }
628
629 state_puts(state, state->prefix);
630 state_puts(state, buf);
631 while (fgets(buf, sizeof(buf), fp_err))
632 {
633 state_puts(state, state->prefix);
634 state_puts(state, buf);
635 }
636 }
637 }
638 else
639 {
640 mutt_file_copy_stream(fp_out, state->fp_out);
641 /* Check for stderr messages */
642 if (fgets(buf, sizeof(buf), fp_err))
643 {
644 if (state->flags & STATE_DISPLAY)
645 {
646 state_mark_attach(state);
647 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
648 }
649
650 state_puts(state, buf);
651 mutt_file_copy_stream(fp_err, state->fp_out);
652 }
653 }
654
655 bail:
656 mutt_file_fclose(&fp_out);
657 mutt_file_fclose(&fp_err);
658
659 filter_wait(pid);
660 if (piped)
661 mutt_file_fclose(&fp_in);
662 else
663 mutt_file_unlink(buf_string(tempfile));
664
665 if (state->flags & STATE_DISPLAY)
667 }
668
669cleanup:
670 mailcap_entry_free(&entry);
671
672 buf_pool_release(&cmd);
673 buf_pool_release(&tempfile);
674
675 return rc;
676}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
void buf_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition display.c:730
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:225
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:195
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition file.c:589
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:159
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#define mutt_message(...)
Definition logging2.h:92
#define mutt_perror(...)
Definition logging2.h:94
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition mailcap.c:454
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition mailcap.c:445
int mailcap_expand_command(struct Body *b, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition mailcap.c:69
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:552
bool mailcap_lookup(struct Body *b, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition mailcap.c:483
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition mailcap.h:61
#define BODY_TYPE(body)
Definition mime.h:89
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:220
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout)
Definition filter.c:62
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:209
#define _(a)
Definition message.h:28
void state_mark_attach(struct State *state)
Write a unique marker around content.
Definition state.c:73
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition state.c:187
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
char * subtype
content-type subtype
Definition body.h:61
char * filename
When sending a message, this is the file to which this structure refers.
Definition body.h:59
String manipulation buffer.
Definition buffer.h:36
A mailcap entry.
Definition mailcap.h:37
char * nametemplate
Definition mailcap.h:44
char * command
Definition mailcap.h:38
Container for Accounts, Notifications.
Definition neomutt.h:43
char ** env
Private copy of the environment variables.
Definition neomutt.h:55
FILE * fp_out
File to write to.
Definition state.h:50
+ 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_email,
struct State * state )
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 686 of file handler.c.

687{
688 char *buf = NULL;
689 size_t sz = 0;
690
691 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
692 while ((buf = mutt_file_read_line(buf, &sz, state->fp_in, NULL, MUTT_RL_NO_FLAGS)))
693 {
694 if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
695 {
696 size_t len = mutt_str_len(buf);
697 while ((len > 0) && (buf[len - 1] == ' '))
698 buf[--len] = '\0';
699 }
700 if (state->prefix)
701 state_puts(state, state->prefix);
702 state_puts(state, buf);
703 state_putc(state, '\n');
704 }
705
706 FREE(&buf);
707 return 0;
708}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
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:685
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition file.h:40
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:660
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ message_handler()

static int message_handler ( struct Body * b_email,
struct State * state )
static

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

Definition at line 713 of file handler.c.

714{
715 struct Body *b = NULL;
716 LOFF_T off_start;
717 int rc = 0;
718
719 off_start = ftello(state->fp_in);
720 if (off_start < 0)
721 return -1;
722
723 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
724 (b_email->encoding == ENC_UUENCODED))
725 {
726 b = mutt_body_new();
728 b->parts = mutt_rfc822_parse_message(state->fp_in, b);
729 }
730 else
731 {
732 b = b_email;
733 }
734
735 if (b->parts)
736 {
738 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
739 if ((state->flags & STATE_WEED) ||
740 ((state->flags & (STATE_DISPLAY | STATE_PRINTING)) && c_weed))
741 {
742 chflags |= CH_WEED | CH_REORDER;
743 }
744 if (state->prefix)
745 chflags |= CH_PREFIX;
746 if (state->flags & STATE_DISPLAY)
747 chflags |= CH_DISPLAY;
748
749 mutt_copy_hdr(state->fp_in, state->fp_out, off_start, b->parts->offset,
750 chflags, state->prefix, 0);
751
752 if (state->prefix)
753 state_puts(state, state->prefix);
754 state_putc(state, '\n');
755
756 rc = mutt_body_handler(b->parts, state);
757 }
758
759 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
760 (b_email->encoding == ENC_UUENCODED))
761 {
762 mutt_body_free(&b);
763 }
764
765 return rc;
766}
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:56
#define CH_PREFIX
Quote header using $indent_string string?
Definition copy.h:59
#define CH_FROM
Retain the "From " message separator?
Definition copy.h:58
#define CH_WEED
Weed the headers?
Definition copy.h:55
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition copy.h:61
#define CH_DISPLAY
Display result to user.
Definition copy.h:72
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition copy.h:52
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *b)
Parse a Message/RFC822 body.
Definition parse.c:1836
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1430
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1632
@ 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 STATE_WEED
Weed headers even when not in display mode.
Definition state.h:36
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition state.h:38
The body of an email.
Definition body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
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_email,
struct State * state )
static

Handler for external-body emails - Implements handler_t -.

Definition at line 771 of file handler.c.

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

◆ alternative_handler()

static int alternative_handler ( struct Body * b_email,
struct State * state )
static

Handler for multipart alternative emails - Implements handler_t -.

Definition at line 942 of file handler.c.

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

◆ multilingual_handler()

static int multilingual_handler ( struct Body * b_email,
struct State * state )
static

Handler for multi-lingual emails - Implements handler_t -.

Return values
0Always

Definition at line 1130 of file handler.c.

1131{
1132 struct Body *b = NULL;
1133 bool mustfree = false;
1134 int rc = 0;
1135
1136 mutt_debug(LL_DEBUG2, "RFC8255 >> entering in handler multilingual handler\n");
1137 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
1138 (b_email->encoding == ENC_UUENCODED))
1139 {
1140 mustfree = true;
1141 b = mutt_body_new();
1142 b->length = mutt_file_get_size_fp(state->fp_in);
1143 b->parts = mutt_parse_multipart(state->fp_in,
1144 mutt_param_get(&b_email->parameter, "boundary"),
1145 b->length,
1146 mutt_istr_equal("digest", b_email->subtype));
1147 }
1148 else
1149 {
1150 b = b_email;
1151 }
1152
1153 b_email = b;
1154
1155 if (b_email->parts)
1156 b = b_email->parts;
1157 else
1158 b = b_email;
1159
1160 struct Body *choice = NULL;
1161 struct Body *first_part = NULL;
1162 struct Body *zxx_part = NULL;
1163 struct ListNode *np = NULL;
1164
1165 while (b)
1166 {
1167 if (mutt_can_decode(b))
1168 {
1169 first_part = b;
1170 break;
1171 }
1172 b = b->next;
1173 }
1174
1175 const struct Slist *c_preferred_languages = cs_subset_slist(NeoMutt->sub, "preferred_languages");
1176 if (c_preferred_languages)
1177 {
1178 struct Buffer *langs = buf_pool_get();
1179 cs_subset_str_string_get(NeoMutt->sub, "preferred_languages", langs);
1180 mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_languages set in config to '%s'\n",
1181 buf_string(langs));
1182 buf_pool_release(&langs);
1183
1184 STAILQ_FOREACH(np, &c_preferred_languages->head, entries)
1185 {
1186 while (b)
1187 {
1188 if (mutt_can_decode(b))
1189 {
1190 if (b->language && mutt_str_equal("zxx", b->language))
1191 zxx_part = b;
1192
1193 mutt_debug(LL_DEBUG2, "RFC8255 >> comparing configuration preferred_language='%s' to mail part content-language='%s'\n",
1194 np->data, b->language);
1195 if (b->language && mutt_str_equal(np->data, b->language))
1196 {
1197 mutt_debug(LL_DEBUG2, "RFC8255 >> preferred_language='%s' matches content-language='%s' >> part selected to be displayed\n",
1198 np->data, b->language);
1199 choice = b;
1200 break;
1201 }
1202 }
1203
1204 b = b->next;
1205 }
1206
1207 if (choice)
1208 break;
1209
1210 if (b_email->parts)
1211 b = b_email->parts;
1212 else
1213 b = b_email;
1214 }
1215 }
1216
1217 if (choice)
1218 {
1219 mutt_body_handler(choice, state);
1220 }
1221 else
1222 {
1223 if (zxx_part)
1224 mutt_body_handler(zxx_part, state);
1225 else
1226 mutt_body_handler(first_part, state);
1227 }
1228
1229 if (mustfree)
1230 mutt_body_free(&b_email);
1231
1232 return rc;
1233}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:45
char * language
content-language (RFC8255)
Definition body.h:78
String list.
Definition slist.h:37
struct ListHead head
List containing values.
Definition slist.h:38
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:354
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ multipart_handler()

static int multipart_handler ( struct Body * b_email,
struct State * state )
static

Handler for multipart emails - Implements handler_t -.

Definition at line 1238 of file handler.c.

1239{
1240 struct Body *b = NULL, *p = NULL;
1241 int count;
1242 int rc = 0;
1243
1244 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
1245 (b_email->encoding == ENC_UUENCODED))
1246 {
1247 b = mutt_body_new();
1248 b->length = mutt_file_get_size_fp(state->fp_in);
1249 b->parts = mutt_parse_multipart(state->fp_in,
1250 mutt_param_get(&b_email->parameter, "boundary"),
1251 b->length,
1252 mutt_istr_equal("digest", b_email->subtype));
1253 }
1254 else
1255 {
1256 b = b_email;
1257 }
1258
1259 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1260 const bool c_include_only_first = cs_subset_bool(NeoMutt->sub, "include_only_first");
1261
1262 for (p = b->parts, count = 1; p; p = p->next, count++)
1263 {
1264 if (state->flags & STATE_DISPLAY)
1265 {
1266 state_mark_attach(state);
1267 if (p->description || p->filename || p->form_name)
1268 {
1269 /* L10N: %s is the attachment description, filename or form_name. */
1270 state_printf(state, _("[-- Attachment #%d: %s --]\n"), count,
1271 p->description ? p->description :
1272 p->filename ? p->filename :
1273 p->form_name);
1274 }
1275 else
1276 {
1277 state_printf(state, _("[-- Attachment #%d --]\n"), count);
1278 }
1279 print_part_line(state, p, 0);
1280 if (c_weed)
1281 {
1282 state_putc(state, '\n');
1283 }
1284 else if (mutt_file_seek(state->fp_in, p->hdr_offset, SEEK_SET))
1285 {
1286 mutt_file_copy_bytes(state->fp_in, state->fp_out, p->offset - p->hdr_offset);
1287 }
1288 }
1289
1290 rc = mutt_body_handler(p, state);
1291 state_putc(state, '\n');
1292
1293 if (rc != 0)
1294 {
1295 mutt_error(_("One or more parts of this message could not be displayed"));
1296 mutt_debug(LL_DEBUG1, "Failed on attachment #%d, type %s/%s\n", count,
1297 BODY_TYPE(p), NONULL(p->subtype));
1298 }
1299
1300 if ((state->flags & STATE_REPLYING) && c_include_only_first && (state->flags & STATE_FIRSTDONE))
1301 {
1302 break;
1303 }
1304 }
1305
1306 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
1307 (b_email->encoding == ENC_UUENCODED))
1308 {
1309 mutt_body_free(&b);
1310 }
1311
1312 /* make failure of a single part non-fatal */
1313 if (rc < 0)
1314 rc = 1;
1315 return rc;
1316}
#define mutt_error(...)
Definition logging2.h:93
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:44
#define STATE_FIRSTDONE
The first attachment has been done.
Definition state.h:40
#define STATE_REPLYING
Are we replying?
Definition state.h:39
#define NONULL(x)
Definition string2.h:43
+ 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_email,
struct State * state )
static

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

Definition at line 1472 of file handler.c.

1473{
1474 struct Body *octetstream = b_email->parts->next;
1475
1476 /* clear out any mime headers before the handler, so they can't be spoofed. */
1477 mutt_env_free(&b_email->mime_headers);
1478 mutt_env_free(&octetstream->mime_headers);
1479
1480 int rc;
1481 /* Some clients improperly encode the octetstream part. */
1482 if (octetstream->encoding != ENC_7BIT)
1483 rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, 0);
1484 else
1485 rc = crypt_pgp_encrypted_handler(octetstream, state);
1486 b_email->goodsig |= octetstream->goodsig;
1487
1488 /* Relocate protected headers onto the multipart/encrypted part */
1489 if (!rc && octetstream->mime_headers)
1490 {
1491 b_email->mime_headers = octetstream->mime_headers;
1492 octetstream->mime_headers = NULL;
1493 }
1494
1495 return rc;
1496}
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
int crypt_pgp_encrypted_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -.
Definition cryptglue.c:247
static int run_decode_and_handler(struct Body *b, struct State *state, handler_t handler, bool plaintext)
Run an appropriate decoder for an email.
Definition handler.c:1327
@ ENC_7BIT
7-bit text
Definition mime.h:49
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
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_email,
struct State * state )
static

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

Definition at line 1501 of file handler.c.

1502{
1503 struct Body *octetstream = b_email->parts->next->next;
1504
1505 /* clear out any mime headers before the handler, so they can't be spoofed. */
1506 mutt_env_free(&b_email->mime_headers);
1507 mutt_env_free(&octetstream->mime_headers);
1508
1509 /* exchange encodes the octet-stream, so re-run it through the decoder */
1510 int rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, false);
1511 b_email->goodsig |= octetstream->goodsig;
1512#ifdef USE_AUTOCRYPT
1513 b_email->is_autocrypt |= octetstream->is_autocrypt;
1514#endif
1515
1516 /* Relocate protected headers onto the multipart/encrypted part */
1517 if (!rc && octetstream->mime_headers)
1518 {
1519 b_email->mime_headers = octetstream->mime_headers;
1520 octetstream->mime_headers = NULL;
1521 }
1522
1523 return rc;
1524}
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_email,
struct State * state )

Handler for protected headers - Implements handler_t -.

Definition at line 1117 of file crypt.c.

1118{
1119 if (!cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read"))
1120 return 0;
1121
1123
1124 if (!b_email->mime_headers)
1125 goto blank;
1126
1127 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
1128 const bool display = (state->flags & STATE_DISPLAY);
1129 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1130 const bool c_crypt_protected_headers_weed = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_weed");
1131 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
1132 const int wraplen = display ? mutt_window_wrap_cols(state->wraplen, c_wrap) : 0;
1133 const CopyHeaderFlags chflags = display ? CH_DISPLAY : CH_NO_FLAGS;
1134 struct Buffer *buf = buf_pool_get();
1135 bool weed = (display && c_weed && c_crypt_protected_headers_weed);
1136
1137 if (c_devel_security)
1138 {
1139 if (b_email->mime_headers->date && (!display || !c_weed || !mutt_matches_ignore("date")))
1140 {
1141 mutt_write_one_header(state->fp_out, "Date", b_email->mime_headers->date,
1142 state->prefix, wraplen, chflags, NeoMutt->sub);
1143 }
1144
1145 if (!weed || !mutt_matches_ignore("return-path"))
1146 {
1147 mutt_addrlist_write(&b_email->mime_headers->return_path, buf, display);
1148 mutt_write_one_header(state->fp_out, "Return-Path", buf_string(buf),
1149 state->prefix, wraplen, chflags, NeoMutt->sub);
1150 }
1151 if (!weed || !mutt_matches_ignore("from"))
1152 {
1153 buf_reset(buf);
1154 mutt_addrlist_write(&b_email->mime_headers->from, buf, display);
1155 mutt_write_one_header(state->fp_out, "From", buf_string(buf),
1156 state->prefix, wraplen, chflags, NeoMutt->sub);
1157 }
1158 if (!weed || !mutt_matches_ignore("to"))
1159 {
1160 buf_reset(buf);
1161 mutt_addrlist_write(&b_email->mime_headers->to, buf, display);
1162 mutt_write_one_header(state->fp_out, "To", buf_string(buf), state->prefix,
1163 wraplen, chflags, NeoMutt->sub);
1164 }
1165 if (!weed || !mutt_matches_ignore("cc"))
1166 {
1167 buf_reset(buf);
1168 mutt_addrlist_write(&b_email->mime_headers->cc, buf, display);
1169 mutt_write_one_header(state->fp_out, "Cc", buf_string(buf), state->prefix,
1170 wraplen, chflags, NeoMutt->sub);
1171 }
1172 if (!weed || !mutt_matches_ignore("sender"))
1173 {
1174 buf_reset(buf);
1175 mutt_addrlist_write(&b_email->mime_headers->sender, buf, display);
1176 mutt_write_one_header(state->fp_out, "Sender", buf_string(buf),
1177 state->prefix, wraplen, chflags, NeoMutt->sub);
1178 }
1179 if (!weed || !mutt_matches_ignore("reply-to"))
1180 {
1181 buf_reset(buf);
1182 mutt_addrlist_write(&b_email->mime_headers->reply_to, buf, display);
1183 mutt_write_one_header(state->fp_out, "Reply-To", buf_string(buf),
1184 state->prefix, wraplen, chflags, NeoMutt->sub);
1185 }
1186 if (!weed || !mutt_matches_ignore("mail-followup-to"))
1187 {
1188 buf_reset(buf);
1189 mutt_addrlist_write(&b_email->mime_headers->mail_followup_to, buf, display);
1190 mutt_write_one_header(state->fp_out, "Mail-Followup-To", buf_string(buf),
1191 state->prefix, wraplen, chflags, NeoMutt->sub);
1192 }
1193 if (!weed || !mutt_matches_ignore("x-original-to"))
1194 {
1195 buf_reset(buf);
1196 mutt_addrlist_write(&b_email->mime_headers->x_original_to, buf, display);
1197 mutt_write_one_header(state->fp_out, "X-Original-To", buf_string(buf),
1198 state->prefix, wraplen, chflags, NeoMutt->sub);
1199 }
1200 }
1201
1202 if (b_email->mime_headers->subject && (!weed || !mutt_matches_ignore("subject")))
1203 {
1204 mutt_write_one_header(state->fp_out, "Subject", b_email->mime_headers->subject,
1205 state->prefix, wraplen, chflags, NeoMutt->sub);
1206 }
1207
1208 if (c_devel_security)
1209 {
1210 if (b_email->mime_headers->message_id && (!weed || !mutt_matches_ignore("message-id")))
1211 {
1212 mutt_write_one_header(state->fp_out, "Message-ID", b_email->mime_headers->message_id,
1213 state->prefix, wraplen, chflags, NeoMutt->sub);
1214 }
1215 if (!weed || !mutt_matches_ignore("references"))
1216 {
1217 buf_reset(buf);
1218 mutt_list_write(&b_email->mime_headers->references, buf);
1219 mutt_write_one_header(state->fp_out, "References", buf_string(buf),
1220 state->prefix, wraplen, chflags, NeoMutt->sub);
1221 }
1222 if (!weed || !mutt_matches_ignore("in-reply-to"))
1223 {
1224 buf_reset(buf);
1225 mutt_list_write(&b_email->mime_headers->in_reply_to, buf);
1226 mutt_write_one_header(state->fp_out, "In-Reply-To", buf_string(buf),
1227 state->prefix, wraplen, chflags, NeoMutt->sub);
1228 }
1229 }
1230
1231 buf_pool_release(&buf);
1232
1233blank:
1234 state_puts(state, "\n");
1235 return 0;
1236}
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1206
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
#define CH_NO_FLAGS
No flags are set.
Definition copy.h:53
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition parse.c:355
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:423
size_t mutt_list_write(const struct ListHead *h, struct Buffer *buf)
Write a list to a buffer.
Definition list.c:293
void state_mark_protected_header(struct State *state)
Write a unique marker around protected headers.
Definition state.c:88
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
struct AddressList return_path
Return path for the Email.
Definition envelope.h:58
char *const subject
Email's subject.
Definition envelope.h:70
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition envelope.h:64
char * message_id
Message ID.
Definition envelope.h:73
struct AddressList x_original_to
Email's 'X-Original-to'.
Definition envelope.h:66
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList sender
Email's sender.
Definition envelope.h:63
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
char * date
Sent date.
Definition envelope.h:75
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
+ 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_email,
struct State * state )

Handler for "multipart/signed" - Implements handler_t -.

Definition at line 1241 of file crypt.c.

1242{
1243 if (!WithCrypto)
1244 return -1;
1245
1246 bool inconsistent = false;
1247 struct Body *top = b_email;
1248 struct Body **signatures = NULL;
1249 int sigcnt = 0;
1250 int rc = 0;
1251 struct Buffer *tempfile = NULL;
1252
1253 b_email = b_email->parts;
1254 SecurityFlags signed_type = mutt_is_multipart_signed(top);
1255 if (signed_type == SEC_NO_FLAGS)
1256 {
1257 /* A null protocol value is already checked for in mutt_body_handler() */
1258 state_printf(state, _("[-- Error: Unknown multipart/signed protocol %s --]\n\n"),
1259 mutt_param_get(&top->parameter, "protocol"));
1260 return mutt_body_handler(b_email, state);
1261 }
1262
1263 if (!(b_email && b_email->next))
1264 {
1265 inconsistent = true;
1266 }
1267 else
1268 {
1269 switch (signed_type)
1270 {
1271 case SEC_SIGN:
1272 if ((b_email->next->type != TYPE_MULTIPART) ||
1273 !mutt_istr_equal(b_email->next->subtype, "mixed"))
1274 {
1275 inconsistent = true;
1276 }
1277 break;
1278 case PGP_SIGN:
1279 if ((b_email->next->type != TYPE_APPLICATION) ||
1280 !mutt_istr_equal(b_email->next->subtype, "pgp-signature"))
1281 {
1282 inconsistent = true;
1283 }
1284 break;
1285 case SMIME_SIGN:
1286 if ((b_email->next->type != TYPE_APPLICATION) ||
1287 (!mutt_istr_equal(b_email->next->subtype, "x-pkcs7-signature") &&
1288 !mutt_istr_equal(b_email->next->subtype, "pkcs7-signature")))
1289 {
1290 inconsistent = true;
1291 }
1292 break;
1293 default:
1294 inconsistent = true;
1295 }
1296 }
1297 if (inconsistent)
1298 {
1299 state_attach_puts(state, _("[-- Error: Missing or bad-format multipart/signed signature --]\n\n"));
1300 return mutt_body_handler(b_email, state);
1301 }
1302
1303 if (state->flags & STATE_DISPLAY)
1304 {
1305 crypt_fetch_signatures(&signatures, b_email->next, &sigcnt);
1306
1307 if (sigcnt != 0)
1308 {
1309 tempfile = buf_pool_get();
1310 buf_mktemp(tempfile);
1311 bool goodsig = true;
1312 if (crypt_write_signed(b_email, state, buf_string(tempfile)) == 0)
1313 {
1314 for (int i = 0; i < sigcnt; i++)
1315 {
1316 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1317 (signatures[i]->type == TYPE_APPLICATION) &&
1318 mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1319 {
1320 if (crypt_pgp_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1321 goodsig = false;
1322
1323 continue;
1324 }
1325
1326 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1327 (signatures[i]->type == TYPE_APPLICATION) &&
1328 (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1329 mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1330 {
1331 if (crypt_smime_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1332 goodsig = false;
1333
1334 continue;
1335 }
1336
1337 state_printf(state, _("[-- Warning: We can't verify %s/%s signatures --]\n\n"),
1338 BODY_TYPE(signatures[i]), signatures[i]->subtype);
1339 }
1340 }
1341
1342 mutt_file_unlink(buf_string(tempfile));
1343 buf_pool_release(&tempfile);
1344
1345 top->goodsig = goodsig;
1346 top->badsig = !goodsig;
1347
1348 /* Now display the signed body */
1349 state_attach_puts(state, _("[-- The following data is signed --]\n"));
1350
1351 mutt_protected_headers_handler(b_email, state);
1352
1353 FREE(&signatures);
1354 }
1355 else
1356 {
1357 state_attach_puts(state, _("[-- Warning: Can't find any signatures --]\n\n"));
1358 }
1359 }
1360
1361 rc = mutt_body_handler(b_email, state);
1362
1363 if ((state->flags & STATE_DISPLAY) && (sigcnt != 0))
1364 state_attach_puts(state, _("[-- End of signed data --]\n"));
1365
1366 return rc;
1367}
static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
Create an array of an emails parts.
Definition crypt.c:1074
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:408
int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
Write the message body/part.
Definition crypt.c:759
int crypt_smime_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition cryptglue.c:516
int crypt_pgp_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition cryptglue.c:372
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1117
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition mime.h:33
#define PGP_SIGN
Definition lib.h:103
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:82
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:96
#define SMIME_SIGN
Definition lib.h:109
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:97
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:83
#define WithCrypto
Definition lib.h:122
#define SEC_SIGN
Email is signed.
Definition lib.h:85
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition body.h:43
#define buf_mktemp(buf)
Definition tmp.h:33
+ 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_email,
struct State * state )

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

Definition at line 236 of file cryptglue.c.

237{
238 if (CRYPT_MOD_CALL_CHECK(PGP, application_handler))
239 return CRYPT_MOD_CALL(PGP, application_handler)(b_email, state);
240
241 return -1;
242}
#define CRYPT_MOD_CALL_CHECK(identifier, func)
Definition cryptglue.c:79
#define CRYPT_MOD_CALL(identifier, func)
Definition cryptglue.c:85
+ Here is the caller graph for this function:

◆ crypt_pgp_encrypted_handler()

int crypt_pgp_encrypted_handler ( struct Body * b_email,
struct State * state )

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

Definition at line 247 of file cryptglue.c.

248{
249#ifdef USE_AUTOCRYPT
250 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
251 if (c_autocrypt)
252 {
253 OptAutocryptGpgme = true;
254 int result = pgp_gpgme_encrypted_handler(b_email, state);
255 OptAutocryptGpgme = false;
256 if (result == 0)
257 {
258 b_email->is_autocrypt = true;
259 return result;
260 }
261 }
262#endif
263
264 if (CRYPT_MOD_CALL_CHECK(PGP, encrypted_handler))
265 return CRYPT_MOD_CALL(PGP, encrypted_handler)(b_email, state);
266
267 return -1;
268}
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition globals.c:55
int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
+ 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_email,
struct State * state )

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

Definition at line 443 of file cryptglue.c.

444{
445 if (CRYPT_MOD_CALL_CHECK(SMIME, application_handler))
446 return CRYPT_MOD_CALL(SMIME, application_handler)(b_email, state);
447
448 return -1;
449}
+ Here is the caller graph for this function:

◆ rfc3676_handler()

int rfc3676_handler ( struct Body * b_email,
struct State * state )

Handler for format=flowed - Implements handler_t -.

Return values
0Always

Definition at line 323 of file rfc3676.c.

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