NeoMutt  2024-04-25-89-g194907
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 466 of file enriched.c.

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

532{
533 struct MailcapEntry *entry = mailcap_entry_new();
534 char buf[1024] = { 0 };
535 char type[256] = { 0 };
536 struct Buffer *cmd = buf_pool_get();
537 struct Buffer *tempfile = buf_pool_get();
538 char *fname = NULL;
539 FILE *fp_in = NULL;
540 FILE *fp_out = NULL;
541 FILE *fp_err = NULL;
542 pid_t pid;
543 int rc = 0;
544
545 snprintf(type, sizeof(type), "%s/%s", TYPE(b_email), b_email->subtype);
546 mailcap_lookup(b_email, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
547
548 fname = mutt_str_dup(b_email->filename);
549 mutt_file_sanitize_filename(fname, true);
550 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
551 FREE(&fname);
552
553 if (entry->command)
554 {
555 buf_strcpy(cmd, entry->command);
556
557 /* mailcap_expand_command returns 0 if the file is required */
558 bool piped = mailcap_expand_command(b_email, buf_string(tempfile), type, cmd);
559
560 if (state->flags & STATE_DISPLAY)
561 {
562 state_mark_attach(state);
563 state_printf(state, _("[-- Autoview using %s --]\n"), buf_string(cmd));
564 mutt_message(_("Invoking autoview command: %s"), buf_string(cmd));
565 }
566
567 fp_in = mutt_file_fopen(buf_string(tempfile), "w+");
568 if (!fp_in)
569 {
570 mutt_perror("fopen");
571 mailcap_entry_free(&entry);
572 rc = -1;
573 goto cleanup;
574 }
575
576 mutt_file_copy_bytes(state->fp_in, fp_in, b_email->length);
577
578 if (piped)
579 {
580 unlink(buf_string(tempfile));
581 fflush(fp_in);
582 rewind(fp_in);
583 pid = filter_create_fd(buf_string(cmd), NULL, &fp_out, &fp_err,
584 fileno(fp_in), -1, -1, EnvList);
585 }
586 else
587 {
588 mutt_file_fclose(&fp_in);
589 pid = filter_create(buf_string(cmd), NULL, &fp_out, &fp_err, EnvList);
590 }
591
592 if (pid < 0)
593 {
594 mutt_perror(_("Can't create filter"));
595 if (state->flags & STATE_DISPLAY)
596 {
597 state_mark_attach(state);
598 state_printf(state, _("[-- Can't run %s --]\n"), buf_string(cmd));
599 }
600 rc = -1;
601 goto bail;
602 }
603
604 if (state->prefix)
605 {
606 /* Remove ansi and formatting from autoview output in replies only. The
607 * user may want to see the formatting in the pager, but it shouldn't be
608 * in their quoted reply text too. */
609 struct Buffer *stripped = buf_pool_get();
610 while (fgets(buf, sizeof(buf), fp_out))
611 {
612 buf_strip_formatting(stripped, buf, false);
613 state_puts(state, state->prefix);
614 state_puts(state, buf_string(stripped));
615 }
616 buf_pool_release(&stripped);
617
618 /* check for data on stderr */
619 if (fgets(buf, sizeof(buf), fp_err))
620 {
621 if (state->flags & STATE_DISPLAY)
622 {
623 state_mark_attach(state);
624 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
625 }
626
627 state_puts(state, state->prefix);
628 state_puts(state, buf);
629 while (fgets(buf, sizeof(buf), fp_err))
630 {
631 state_puts(state, state->prefix);
632 state_puts(state, buf);
633 }
634 }
635 }
636 else
637 {
638 mutt_file_copy_stream(fp_out, state->fp_out);
639 /* Check for stderr messages */
640 if (fgets(buf, sizeof(buf), fp_err))
641 {
642 if (state->flags & STATE_DISPLAY)
643 {
644 state_mark_attach(state);
645 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
646 }
647
648 state_puts(state, buf);
649 mutt_file_copy_stream(fp_err, state->fp_out);
650 }
651 }
652
653 bail:
654 mutt_file_fclose(&fp_out);
655 mutt_file_fclose(&fp_err);
656
657 filter_wait(pid);
658 if (piped)
659 mutt_file_fclose(&fp_in);
660 else
661 mutt_file_unlink(buf_string(tempfile));
662
663 if (state->flags & STATE_DISPLAY)
665 }
666
667cleanup:
668 mailcap_entry_free(&entry);
669
670 buf_pool_release(&cmd);
671 buf_pool_release(&tempfile);
672
673 return rc;
674}
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:721
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:287
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:257
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:712
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
#define mutt_file_fclose(FP)
Definition: file.h:149
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:148
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
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 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:72
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:186
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
char * subtype
content-type subtype
Definition: body.h:60
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:36
A mailcap entry.
Definition: mailcap.h:37
char * nametemplate
Definition: mailcap.h:44
char * command
Definition: mailcap.h:38
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 684 of file handler.c.

685{
686 char *buf = NULL;
687 size_t sz = 0;
688
689 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
690 while ((buf = mutt_file_read_line(buf, &sz, state->fp_in, NULL, MUTT_RL_NO_FLAGS)))
691 {
692 if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
693 {
694 size_t len = mutt_str_len(buf);
695 while ((len > 0) && (buf[len - 1] == ' '))
696 buf[--len] = '\0';
697 }
698 if (state->prefix)
699 state_puts(state, state->prefix);
700 state_puts(state, buf);
701 state_putc(state, '\n');
702 }
703
704 FREE(&buf);
705 return 0;
706}
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:808
#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
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 711 of file handler.c.

712{
713 struct Body *b = NULL;
714 LOFF_T off_start;
715 int rc = 0;
716
717 off_start = ftello(state->fp_in);
718 if (off_start < 0)
719 return -1;
720
721 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
722 (b_email->encoding == ENC_UUENCODED))
723 {
724 b = mutt_body_new();
726 b->parts = mutt_rfc822_parse_message(state->fp_in, b);
727 }
728 else
729 {
730 b = b_email;
731 }
732
733 if (b->parts)
734 {
736 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
737 if ((state->flags & STATE_WEED) ||
738 ((state->flags & (STATE_DISPLAY | STATE_PRINTING)) && c_weed))
739 {
740 chflags |= CH_WEED | CH_REORDER;
741 }
742 if (state->prefix)
743 chflags |= CH_PREFIX;
744 if (state->flags & STATE_DISPLAY)
745 chflags |= CH_DISPLAY;
746
747 mutt_copy_hdr(state->fp_in, state->fp_out, off_start, b->parts->offset,
748 chflags, state->prefix, 0);
749
750 if (state->prefix)
751 state_puts(state, state->prefix);
752 state_putc(state, '\n');
753
754 rc = mutt_body_handler(b->parts, state);
755 }
756
757 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
758 (b_email->encoding == ENC_UUENCODED))
759 {
760 mutt_body_free(&b);
761 }
762
763 return rc;
764}
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:108
#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:1832
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1537
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1631
@ 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:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ external_body_handler()

static int external_body_handler ( struct Body b_email,
struct State state 
)
static

Handler for external-body emails - Implements handler_t -.

Definition at line 769 of file handler.c.

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

◆ alternative_handler()

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

Handler for multipart alternative emails - Implements handler_t -.

Definition at line 941 of file handler.c.

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

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

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

1472{
1473 struct Body *octetstream = b_email->parts->next;
1474
1475 /* clear out any mime headers before the handler, so they can't be spoofed. */
1476 mutt_env_free(&b_email->mime_headers);
1477 mutt_env_free(&octetstream->mime_headers);
1478
1479 int rc;
1480 /* Some clients improperly encode the octetstream part. */
1481 if (octetstream->encoding != ENC_7BIT)
1482 rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, 0);
1483 else
1484 rc = crypt_pgp_encrypted_handler(octetstream, state);
1485 b_email->goodsig |= octetstream->goodsig;
1486
1487 /* Relocate protected headers onto the multipart/encrypted part */
1488 if (!rc && octetstream->mime_headers)
1489 {
1490 b_email->mime_headers = octetstream->mime_headers;
1491 octetstream->mime_headers = NULL;
1492 }
1493
1494 return rc;
1495}
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:1326
@ ENC_7BIT
7-bit text
Definition: mime.h:49
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
bool goodsig
Good cryptographic signature.
Definition: body.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ malformed_pgp_encrypted_handler()

static int malformed_pgp_encrypted_handler ( struct Body b_email,
struct State state 
)
static

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

Definition at line 1500 of file handler.c.

1501{
1502 struct Body *octetstream = b_email->parts->next->next;
1503
1504 /* clear out any mime headers before the handler, so they can't be spoofed. */
1505 mutt_env_free(&b_email->mime_headers);
1506 mutt_env_free(&octetstream->mime_headers);
1507
1508 /* exchange encodes the octet-stream, so re-run it through the decoder */
1509 int rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, false);
1510 b_email->goodsig |= octetstream->goodsig;
1511#ifdef USE_AUTOCRYPT
1512 b_email->is_autocrypt |= octetstream->is_autocrypt;
1513#endif
1514
1515 /* Relocate protected headers onto the multipart/encrypted part */
1516 if (!rc && octetstream->mime_headers)
1517 {
1518 b_email->mime_headers = octetstream->mime_headers;
1519 octetstream->mime_headers = NULL;
1520 }
1521
1522 return rc;
1523}
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 (!weed || !mutt_matches_ignore("references"))
1213 {
1214 buf_reset(buf);
1215 mutt_list_write(&b_email->mime_headers->references, buf);
1216 mutt_write_one_header(state->fp_out, "References", buf_string(buf),
1217 state->prefix, wraplen, chflags, NeoMutt->sub);
1218 }
1219 if (!weed || !mutt_matches_ignore("in-reply-to"))
1220 {
1221 buf_reset(buf);
1222 mutt_list_write(&b_email->mime_headers->in_reply_to, buf);
1223 mutt_write_one_header(state->fp_out, "In-Reply-To", buf_string(buf),
1224 state->prefix, wraplen, chflags, NeoMutt->sub);
1225 }
1226 }
1227
1228 buf_pool_release(&buf);
1229
1230blank:
1231 state_puts(state, "\n");
1232 return 0;
1233}
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:87
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:372
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
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 1238 of file crypt.c.

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