NeoMutt  2025-01-09-117-gace867
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 469 of file enriched.c.

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

535{
536 struct MailcapEntry *entry = mailcap_entry_new();
537 char buf[1024] = { 0 };
538 char type[256] = { 0 };
539 struct Buffer *cmd = buf_pool_get();
540 struct Buffer *tempfile = buf_pool_get();
541 char *fname = NULL;
542 FILE *fp_in = NULL;
543 FILE *fp_out = NULL;
544 FILE *fp_err = NULL;
545 pid_t pid;
546 int rc = 0;
547
548 snprintf(type, sizeof(type), "%s/%s", BODY_TYPE(b_email), b_email->subtype);
549 mailcap_lookup(b_email, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
550
551 fname = mutt_str_dup(b_email->filename);
552 mutt_file_sanitize_filename(fname, true);
553 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
554 FREE(&fname);
555
556 if (entry->command)
557 {
558 buf_strcpy(cmd, entry->command);
559
560 /* mailcap_expand_command returns 0 if the file is required */
561 bool piped = mailcap_expand_command(b_email, buf_string(tempfile), type, cmd);
562
563 if (state->flags & STATE_DISPLAY)
564 {
565 state_mark_attach(state);
566 state_printf(state, _("[-- Autoview using %s --]\n"), buf_string(cmd));
567 mutt_message(_("Invoking autoview command: %s"), buf_string(cmd));
568 }
569
570 fp_in = mutt_file_fopen(buf_string(tempfile), "w+");
571 if (!fp_in)
572 {
573 mutt_perror("fopen");
574 mailcap_entry_free(&entry);
575 rc = -1;
576 goto cleanup;
577 }
578
579 mutt_file_copy_bytes(state->fp_in, fp_in, b_email->length);
580
581 if (piped)
582 {
583 unlink(buf_string(tempfile));
584 fflush(fp_in);
585 rewind(fp_in);
586 pid = filter_create_fd(buf_string(cmd), NULL, &fp_out, &fp_err,
587 fileno(fp_in), -1, -1, NeoMutt->env);
588 }
589 else
590 {
591 mutt_file_fclose(&fp_in);
592 pid = filter_create(buf_string(cmd), NULL, &fp_out, &fp_err, NeoMutt->env);
593 }
594
595 if (pid < 0)
596 {
597 mutt_perror(_("Can't create filter"));
598 if (state->flags & STATE_DISPLAY)
599 {
600 state_mark_attach(state);
601 state_printf(state, _("[-- Can't run %s --]\n"), buf_string(cmd));
602 }
603 rc = -1;
604 goto bail;
605 }
606
607 if (state->prefix)
608 {
609 /* Remove ansi and formatting from autoview output in replies only. The
610 * user may want to see the formatting in the pager, but it shouldn't be
611 * in their quoted reply text too. */
612 struct Buffer *stripped = buf_pool_get();
613 while (fgets(buf, sizeof(buf), fp_out))
614 {
615 buf_strip_formatting(stripped, buf, false);
616 state_puts(state, state->prefix);
617 state_puts(state, buf_string(stripped));
618 }
619 buf_pool_release(&stripped);
620
621 /* check for data on stderr */
622 if (fgets(buf, sizeof(buf), fp_err))
623 {
624 if (state->flags & STATE_DISPLAY)
625 {
626 state_mark_attach(state);
627 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
628 }
629
630 state_puts(state, state->prefix);
631 state_puts(state, buf);
632 while (fgets(buf, sizeof(buf), fp_err))
633 {
634 state_puts(state, state->prefix);
635 state_puts(state, buf);
636 }
637 }
638 }
639 else
640 {
641 mutt_file_copy_stream(fp_out, state->fp_out);
642 /* Check for stderr messages */
643 if (fgets(buf, sizeof(buf), fp_err))
644 {
645 if (state->flags & STATE_DISPLAY)
646 {
647 state_mark_attach(state);
648 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
649 }
650
651 state_puts(state, buf);
652 mutt_file_copy_stream(fp_err, state->fp_out);
653 }
654 }
655
656 bail:
657 mutt_file_fclose(&fp_out);
658 mutt_file_fclose(&fp_err);
659
660 filter_wait(pid);
661 if (piped)
662 mutt_file_fclose(&fp_in);
663 else
664 mutt_file_unlink(buf_string(tempfile));
665
666 if (state->flags & STATE_DISPLAY)
668 }
669
670cleanup:
671 mailcap_entry_free(&entry);
672
673 buf_pool_release(&cmd);
674 buf_pool_release(&tempfile);
675
676 return rc;
677}
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:731
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:254
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
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 687 of file handler.c.

688{
689 char *buf = NULL;
690 size_t sz = 0;
691
692 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
693 while ((buf = mutt_file_read_line(buf, &sz, state->fp_in, NULL, MUTT_RL_NO_FLAGS)))
694 {
695 if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
696 {
697 size_t len = mutt_str_len(buf);
698 while ((len > 0) && (buf[len - 1] == ' '))
699 buf[--len] = '\0';
700 }
701 if (state->prefix)
702 state_puts(state, state->prefix);
703 state_puts(state, buf);
704 state_putc(state, '\n');
705 }
706
707 FREE(&buf);
708 return 0;
709}
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:661
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 714 of file handler.c.

715{
716 struct Body *b = NULL;
717 LOFF_T off_start;
718 int rc = 0;
719
720 off_start = ftello(state->fp_in);
721 if (off_start < 0)
722 return -1;
723
724 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
725 (b_email->encoding == ENC_UUENCODED))
726 {
727 b = mutt_body_new();
729 b->parts = mutt_rfc822_parse_message(state->fp_in, b);
730 }
731 else
732 {
733 b = b_email;
734 }
735
736 if (b->parts)
737 {
739 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
740 if ((state->flags & STATE_WEED) ||
741 ((state->flags & (STATE_DISPLAY | STATE_PRINTING)) && c_weed))
742 {
743 chflags |= CH_WEED | CH_REORDER;
744 }
745 if (state->prefix)
746 chflags |= CH_PREFIX;
747 if (state->flags & STATE_DISPLAY)
748 chflags |= CH_DISPLAY;
749
750 mutt_copy_hdr(state->fp_in, state->fp_out, off_start, b->parts->offset,
751 chflags, state->prefix, 0);
752
753 if (state->prefix)
754 state_puts(state, state->prefix);
755 state_putc(state, '\n');
756
757 rc = mutt_body_handler(b->parts, state);
758 }
759
760 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
761 (b_email->encoding == ENC_UUENCODED))
762 {
763 mutt_body_free(&b);
764 }
765
766 return rc;
767}
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:107
#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:1837
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:1633
@ 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 772 of file handler.c.

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

944{
945 struct Body *const head = b_email;
946 struct Body *choice = NULL;
947 struct Body *b = NULL;
948 bool mustfree = false;
949 int rc = 0;
950
951 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
952 (b_email->encoding == ENC_UUENCODED))
953 {
954 mustfree = true;
955 b = mutt_body_new();
957 b->parts = mutt_parse_multipart(state->fp_in,
958 mutt_param_get(&b_email->parameter, "boundary"),
959 b->length,
960 mutt_istr_equal("digest", b_email->subtype));
961 }
962 else
963 {
964 b = b_email;
965 }
966
967 b_email = b;
968
969 /* First, search list of preferred types */
970 struct ListNode *np = NULL;
972 {
973 int btlen; /* length of basetype */
974 bool wild; /* do we have a wildcard to match all subtypes? */
975
976 char *c = strchr(np->data, '/');
977 if (c)
978 {
979 wild = ((c[1] == '*') && (c[2] == '\0'));
980 btlen = c - np->data;
981 }
982 else
983 {
984 wild = true;
985 btlen = mutt_str_len(np->data);
986 }
987
988 if (b_email->parts)
989 b = b_email->parts;
990 else
991 b = b_email;
992 while (b)
993 {
994 const char *bt = BODY_TYPE(b);
995 if (mutt_istrn_equal(bt, np->data, btlen) && (bt[btlen] == 0))
996 {
997 /* the basetype matches */
998 if (wild || mutt_istr_equal(np->data + btlen + 1, b->subtype))
999 {
1000 choice = b;
1001 }
1002 }
1003 b = b->next;
1004 }
1005
1006 if (choice)
1007 break;
1008 }
1009
1010 /* Next, look for an autoviewable type */
1011 if (!choice)
1012 {
1013 if (b_email->parts)
1014 b = b_email->parts;
1015 else
1016 b = b_email;
1017 while (b)
1018 {
1019 if (is_autoview(b))
1020 choice = b;
1021 b = b->next;
1022 }
1023 }
1024
1025 /* Then, look for a text entry */
1026 if (!choice)
1027 {
1028 if (b_email->parts)
1029 b = b_email->parts;
1030 else
1031 b = b_email;
1032 int type = 0;
1033 while (b)
1034 {
1035 if (b->type == TYPE_TEXT)
1036 {
1037 if (mutt_istr_equal("plain", b->subtype) && (type <= TXT_PLAIN))
1038 {
1039 choice = b;
1040 type = TXT_PLAIN;
1041 }
1042 else if (mutt_istr_equal("enriched", b->subtype) && (type <= TXT_ENRICHED))
1043 {
1044 choice = b;
1045 type = TXT_ENRICHED;
1046 }
1047 else if (mutt_istr_equal("html", b->subtype) && (type <= TXT_HTML))
1048 {
1049 choice = b;
1050 type = TXT_HTML;
1051 }
1052 }
1053 b = b->next;
1054 }
1055 }
1056
1057 /* Finally, look for other possibilities */
1058 if (!choice)
1059 {
1060 if (b_email->parts)
1061 b = b_email->parts;
1062 else
1063 b = b_email;
1064 while (b)
1065 {
1066 if (mutt_can_decode(b))
1067 choice = b;
1068 b = b->next;
1069 }
1070 }
1071
1072 if (choice)
1073 {
1074 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1075 if (state->flags & STATE_DISPLAY && !c_weed &&
1076 mutt_file_seek(state->fp_in, choice->hdr_offset, SEEK_SET))
1077 {
1078 mutt_file_copy_bytes(state->fp_in, state->fp_out, choice->offset - choice->hdr_offset);
1079 }
1080
1081 const char *const c_show_multipart_alternative = cs_subset_string(NeoMutt->sub, "show_multipart_alternative");
1082 if (mutt_str_equal("info", c_show_multipart_alternative))
1083 {
1084 print_part_line(state, choice, 0);
1085 }
1086 mutt_body_handler(choice, state);
1087
1088 /* Let it flow back to the main part */
1089 head->nowrap = choice->nowrap;
1090 choice->nowrap = false;
1091
1092 if (mutt_str_equal("info", c_show_multipart_alternative))
1093 {
1094 if (b_email->parts)
1095 b = b_email->parts;
1096 else
1097 b = b_email;
1098 int count = 0;
1099 while (b)
1100 {
1101 if (choice != b)
1102 {
1103 count += 1;
1104 if (count == 1)
1105 state_putc(state, '\n');
1106
1107 print_part_line(state, b, count);
1108 }
1109 b = b->next;
1110 }
1111 }
1112 }
1113 else if (state->flags & STATE_DISPLAY)
1114 {
1115 /* didn't find anything that we could display! */
1116 state_mark_attach(state);
1117 state_puts(state, _("[-- Error: Could not display any parts of Multipart/Alternative --]\n"));
1118 rc = -1;
1119 }
1120
1121 if (mustfree)
1122 mutt_body_free(&b_email);
1123
1124 return rc;
1125}
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:1853
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:487
bool mutt_can_decode(struct Body *b)
Will decoding the attachment produce any output.
Definition: handler.c:1867
static void print_part_line(struct State *state, struct Body *b_email, int n)
Print a separator for the Mime part.
Definition: handler.c:93
#define TXT_PLAIN
Definition: handler.c:72
#define TXT_HTML
Definition: handler.c:71
#define TXT_ENRICHED
Definition: handler.c:73
@ 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:454
#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 1131 of file handler.c.

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

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

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

Definition at line 1473 of file handler.c.

1474{
1475 struct Body *octetstream = b_email->parts->next;
1476
1477 /* clear out any mime headers before the handler, so they can't be spoofed. */
1478 mutt_env_free(&b_email->mime_headers);
1479 mutt_env_free(&octetstream->mime_headers);
1480
1481 int rc;
1482 /* Some clients improperly encode the octetstream part. */
1483 if (octetstream->encoding != ENC_7BIT)
1484 rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, 0);
1485 else
1486 rc = crypt_pgp_encrypted_handler(octetstream, state);
1487 b_email->goodsig |= octetstream->goodsig;
1488
1489 /* Relocate protected headers onto the multipart/encrypted part */
1490 if (!rc && octetstream->mime_headers)
1491 {
1492 b_email->mime_headers = octetstream->mime_headers;
1493 octetstream->mime_headers = NULL;
1494 }
1495
1496 return rc;
1497}
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
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:1328
@ 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 1502 of file handler.c.

1503{
1504 struct Body *octetstream = b_email->parts->next->next;
1505
1506 /* clear out any mime headers before the handler, so they can't be spoofed. */
1507 mutt_env_free(&b_email->mime_headers);
1508 mutt_env_free(&octetstream->mime_headers);
1509
1510 /* exchange encodes the octet-stream, so re-run it through the decoder */
1511 int rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, false);
1512 b_email->goodsig |= octetstream->goodsig;
1513#ifdef USE_AUTOCRYPT
1514 b_email->is_autocrypt |= octetstream->is_autocrypt;
1515#endif
1516
1517 /* Relocate protected headers onto the multipart/encrypted part */
1518 if (!rc && octetstream->mime_headers)
1519 {
1520 b_email->mime_headers = octetstream->mime_headers;
1521 octetstream->mime_headers = NULL;
1522 }
1523
1524 return rc;
1525}
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);
1136 if (c_devel_security)
1137 weed &= c_crypt_protected_headers_weed;
1138
1139 if (c_devel_security)
1140 {
1141 if (b_email->mime_headers->date && (!display || !c_weed || !mutt_matches_ignore("date")))
1142 {
1143 mutt_write_one_header(state->fp_out, "Date", b_email->mime_headers->date,
1144 state->prefix, wraplen, chflags, NeoMutt->sub);
1145 }
1146
1147 if (!weed || !mutt_matches_ignore("return-path"))
1148 {
1149 mutt_addrlist_write(&b_email->mime_headers->return_path, buf, display);
1150 mutt_write_one_header(state->fp_out, "Return-Path", buf_string(buf),
1151 state->prefix, wraplen, chflags, NeoMutt->sub);
1152 }
1153 if (!weed || !mutt_matches_ignore("from"))
1154 {
1155 buf_reset(buf);
1156 mutt_addrlist_write(&b_email->mime_headers->from, buf, display);
1157 mutt_write_one_header(state->fp_out, "From", buf_string(buf),
1158 state->prefix, wraplen, chflags, NeoMutt->sub);
1159 }
1160 if (!weed || !mutt_matches_ignore("to"))
1161 {
1162 buf_reset(buf);
1163 mutt_addrlist_write(&b_email->mime_headers->to, buf, display);
1164 mutt_write_one_header(state->fp_out, "To", buf_string(buf), state->prefix,
1165 wraplen, chflags, NeoMutt->sub);
1166 }
1167 if (!weed || !mutt_matches_ignore("cc"))
1168 {
1169 buf_reset(buf);
1170 mutt_addrlist_write(&b_email->mime_headers->cc, buf, display);
1171 mutt_write_one_header(state->fp_out, "Cc", buf_string(buf), state->prefix,
1172 wraplen, chflags, NeoMutt->sub);
1173 }
1174 if (!weed || !mutt_matches_ignore("sender"))
1175 {
1176 buf_reset(buf);
1177 mutt_addrlist_write(&b_email->mime_headers->sender, buf, display);
1178 mutt_write_one_header(state->fp_out, "Sender", buf_string(buf),
1179 state->prefix, wraplen, chflags, NeoMutt->sub);
1180 }
1181 if (!weed || !mutt_matches_ignore("reply-to"))
1182 {
1183 buf_reset(buf);
1184 mutt_addrlist_write(&b_email->mime_headers->reply_to, buf, display);
1185 mutt_write_one_header(state->fp_out, "Reply-To", buf_string(buf),
1186 state->prefix, wraplen, chflags, NeoMutt->sub);
1187 }
1188 if (!weed || !mutt_matches_ignore("mail-followup-to"))
1189 {
1190 buf_reset(buf);
1191 mutt_addrlist_write(&b_email->mime_headers->mail_followup_to, buf, display);
1192 mutt_write_one_header(state->fp_out, "Mail-Followup-To", buf_string(buf),
1193 state->prefix, wraplen, chflags, NeoMutt->sub);
1194 }
1195 if (!weed || !mutt_matches_ignore("x-original-to"))
1196 {
1197 buf_reset(buf);
1198 mutt_addrlist_write(&b_email->mime_headers->x_original_to, buf, display);
1199 mutt_write_one_header(state->fp_out, "X-Original-To", buf_string(buf),
1200 state->prefix, wraplen, chflags, NeoMutt->sub);
1201 }
1202 }
1203
1204 if (b_email->mime_headers->subject && (!weed || !mutt_matches_ignore("subject")))
1205 {
1206 mutt_write_one_header(state->fp_out, "Subject", b_email->mime_headers->subject,
1207 state->prefix, wraplen, chflags, NeoMutt->sub);
1208 }
1209
1210 if (c_devel_security)
1211 {
1212 if (b_email->mime_headers->message_id && (!weed || !mutt_matches_ignore("message-id")))
1213 {
1214 mutt_write_one_header(state->fp_out, "Message-ID", b_email->mime_headers->message_id,
1215 state->prefix, wraplen, chflags, NeoMutt->sub);
1216 }
1217 if (!weed || !mutt_matches_ignore("references"))
1218 {
1219 buf_reset(buf);
1220 mutt_list_write(&b_email->mime_headers->references, buf);
1221 mutt_write_one_header(state->fp_out, "References", buf_string(buf),
1222 state->prefix, wraplen, chflags, NeoMutt->sub);
1223 }
1224 if (!weed || !mutt_matches_ignore("in-reply-to"))
1225 {
1226 buf_reset(buf);
1227 mutt_list_write(&b_email->mime_headers->in_reply_to, buf);
1228 mutt_write_one_header(state->fp_out, "In-Reply-To", buf_string(buf),
1229 state->prefix, wraplen, chflags, NeoMutt->sub);
1230 }
1231 }
1232
1233 buf_pool_release(&buf);
1234
1235blank:
1236 state_puts(state, "\n");
1237 return 0;
1238}
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:356
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.
Definition: mutt_window.c:337
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 1243 of file crypt.c.

1244{
1245 if (!WithCrypto)
1246 return -1;
1247
1248 bool inconsistent = false;
1249 struct Body *top = b_email;
1250 struct Body **signatures = NULL;
1251 int sigcnt = 0;
1252 int rc = 0;
1253 struct Buffer *tempfile = NULL;
1254
1255 b_email = b_email->parts;
1256 SecurityFlags signed_type = mutt_is_multipart_signed(top);
1257 if (signed_type == SEC_NO_FLAGS)
1258 {
1259 /* A null protocol value is already checked for in mutt_body_handler() */
1260 state_printf(state, _("[-- Error: Unknown multipart/signed protocol %s --]\n\n"),
1261 mutt_param_get(&top->parameter, "protocol"));
1262 return mutt_body_handler(b_email, state);
1263 }
1264
1265 if (!(b_email && b_email->next))
1266 {
1267 inconsistent = true;
1268 }
1269 else
1270 {
1271 switch (signed_type)
1272 {
1273 case SEC_SIGN:
1274 if ((b_email->next->type != TYPE_MULTIPART) ||
1275 !mutt_istr_equal(b_email->next->subtype, "mixed"))
1276 {
1277 inconsistent = true;
1278 }
1279 break;
1280 case PGP_SIGN:
1281 if ((b_email->next->type != TYPE_APPLICATION) ||
1282 !mutt_istr_equal(b_email->next->subtype, "pgp-signature"))
1283 {
1284 inconsistent = true;
1285 }
1286 break;
1287 case SMIME_SIGN:
1288 if ((b_email->next->type != TYPE_APPLICATION) ||
1289 (!mutt_istr_equal(b_email->next->subtype, "x-pkcs7-signature") &&
1290 !mutt_istr_equal(b_email->next->subtype, "pkcs7-signature")))
1291 {
1292 inconsistent = true;
1293 }
1294 break;
1295 default:
1296 inconsistent = true;
1297 }
1298 }
1299 if (inconsistent)
1300 {
1301 state_attach_puts(state, _("[-- Error: Missing or bad-format multipart/signed signature --]\n\n"));
1302 return mutt_body_handler(b_email, state);
1303 }
1304
1305 if (state->flags & STATE_DISPLAY)
1306 {
1307 crypt_fetch_signatures(&signatures, b_email->next, &sigcnt);
1308
1309 if (sigcnt != 0)
1310 {
1311 tempfile = buf_pool_get();
1312 buf_mktemp(tempfile);
1313 bool goodsig = true;
1314 if (crypt_write_signed(b_email, state, buf_string(tempfile)) == 0)
1315 {
1316 for (int i = 0; i < sigcnt; i++)
1317 {
1318 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1319 (signatures[i]->type == TYPE_APPLICATION) &&
1320 mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1321 {
1322 if (crypt_pgp_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1323 goodsig = false;
1324
1325 continue;
1326 }
1327
1328 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1329 (signatures[i]->type == TYPE_APPLICATION) &&
1330 (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1331 mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1332 {
1333 if (crypt_smime_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1334 goodsig = false;
1335
1336 continue;
1337 }
1338
1339 state_printf(state, _("[-- Warning: We can't verify %s/%s signatures --]\n\n"),
1340 BODY_TYPE(signatures[i]), signatures[i]->subtype);
1341 }
1342 }
1343
1344 mutt_file_unlink(buf_string(tempfile));
1345 buf_pool_release(&tempfile);
1346
1347 top->goodsig = goodsig;
1348 top->badsig = !goodsig;
1349
1350 /* Now display the signed body */
1351 state_attach_puts(state, _("[-- The following data is signed --]\n"));
1352
1353 mutt_protected_headers_handler(b_email, state);
1354
1355 FREE(&signatures);
1356 }
1357 else
1358 {
1359 state_attach_puts(state, _("[-- Warning: Can't find any signatures --]\n\n"));
1360 }
1361 }
1362
1363 rc = mutt_body_handler(b_email, state);
1364
1365 if ((state->flags & STATE_DISPLAY) && (sigcnt != 0))
1366 state_attach_puts(state, _("[-- End of signed data --]\n"));
1367
1368 return rc;
1369}
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:56
int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
Definition: crypt_gpgme.c:2767
+ 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: