NeoMutt  2023-11-03-107-g582dc1
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:50
#define FREE(x)
Definition: memory.h:45
#define FALLTHROUGH
Definition: lib.h:111
#define state_puts(STATE, STR)
Definition: state.h:57
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:32
#define state_putc(STATE, STR)
Definition: state.h:58
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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:52
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
char * prefix
String to add to the beginning of each output line.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:48
+ 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 524 of file handler.c.

525{
526 struct MailcapEntry *entry = mailcap_entry_new();
527 char buf[1024] = { 0 };
528 char type[256] = { 0 };
529 struct Buffer *cmd = buf_pool_get();
530 struct Buffer *tempfile = buf_pool_get();
531 char *fname = NULL;
532 FILE *fp_in = NULL;
533 FILE *fp_out = NULL;
534 FILE *fp_err = NULL;
535 pid_t pid;
536 int rc = 0;
537
538 snprintf(type, sizeof(type), "%s/%s", TYPE(b_email), b_email->subtype);
539 mailcap_lookup(b_email, type, sizeof(type), entry, MUTT_MC_AUTOVIEW);
540
541 fname = mutt_str_dup(b_email->filename);
542 mutt_file_sanitize_filename(fname, true);
543 mailcap_expand_filename(entry->nametemplate, fname, tempfile);
544 FREE(&fname);
545
546 if (entry->command)
547 {
548 buf_strcpy(cmd, entry->command);
549
550 /* mailcap_expand_command returns 0 if the file is required */
551 bool piped = mailcap_expand_command(b_email, buf_string(tempfile), type, cmd);
552
553 if (state->flags & STATE_DISPLAY)
554 {
555 state_mark_attach(state);
556 state_printf(state, _("[-- Autoview using %s --]\n"), buf_string(cmd));
557 mutt_message(_("Invoking autoview command: %s"), buf_string(cmd));
558 }
559
560 fp_in = mutt_file_fopen(buf_string(tempfile), "w+");
561 if (!fp_in)
562 {
563 mutt_perror("fopen");
564 mailcap_entry_free(&entry);
565 rc = -1;
566 goto cleanup;
567 }
568
569 mutt_file_copy_bytes(state->fp_in, fp_in, b_email->length);
570
571 if (piped)
572 {
573 unlink(buf_string(tempfile));
574 fflush(fp_in);
575 rewind(fp_in);
576 pid = filter_create_fd(buf_string(cmd), NULL, &fp_out, &fp_err,
577 fileno(fp_in), -1, -1, EnvList);
578 }
579 else
580 {
581 mutt_file_fclose(&fp_in);
582 pid = filter_create(buf_string(cmd), NULL, &fp_out, &fp_err, EnvList);
583 }
584
585 if (pid < 0)
586 {
587 mutt_perror(_("Can't create filter"));
588 if (state->flags & STATE_DISPLAY)
589 {
590 state_mark_attach(state);
591 state_printf(state, _("[-- Can't run %s. --]\n"), buf_string(cmd));
592 }
593 rc = -1;
594 goto bail;
595 }
596
597 if (state->prefix)
598 {
599 /* Remove ansi and formatting from autoview output in replies only. The
600 * user may want to see the formatting in the pager, but it shouldn't be
601 * in their quoted reply text too. */
602 struct Buffer *stripped = buf_pool_get();
603 while (fgets(buf, sizeof(buf), fp_out))
604 {
605 buf_strip_formatting(stripped, buf, false);
606 state_puts(state, state->prefix);
607 state_puts(state, buf_string(stripped));
608 }
609 buf_pool_release(&stripped);
610
611 /* check for data on stderr */
612 if (fgets(buf, sizeof(buf), fp_err))
613 {
614 if (state->flags & STATE_DISPLAY)
615 {
616 state_mark_attach(state);
617 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
618 }
619
620 state_puts(state, state->prefix);
621 state_puts(state, buf);
622 while (fgets(buf, sizeof(buf), fp_err))
623 {
624 state_puts(state, state->prefix);
625 state_puts(state, buf);
626 }
627 }
628 }
629 else
630 {
631 mutt_file_copy_stream(fp_out, state->fp_out);
632 /* Check for stderr messages */
633 if (fgets(buf, sizeof(buf), fp_err))
634 {
635 if (state->flags & STATE_DISPLAY)
636 {
637 state_mark_attach(state);
638 state_printf(state, _("[-- Autoview stderr of %s --]\n"), buf_string(cmd));
639 }
640
641 state_puts(state, buf);
642 mutt_file_copy_stream(fp_err, state->fp_out);
643 }
644 }
645
646 bail:
647 mutt_file_fclose(&fp_out);
648 mutt_file_fclose(&fp_err);
649
650 filter_wait(pid);
651 if (piped)
652 mutt_file_fclose(&fp_in);
653 else
654 mutt_file_unlink(buf_string(tempfile));
655
656 if (state->flags & STATE_DISPLAY)
658 }
659
660cleanup:
661 mailcap_entry_free(&entry);
662
663 buf_pool_release(&cmd);
664 buf_pool_release(&tempfile);
665
666 return rc;
667}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
void buf_strip_formatting(struct Buffer *dest, const char *src, bool strip_markers)
Removes ANSI and backspace formatting.
Definition: display.c:697
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
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:232
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:667
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:218
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:61
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:207
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:83
#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:451
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:442
int mailcap_expand_command(struct Body *b, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:67
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:549
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:480
@ MUTT_MC_AUTOVIEW
Mailcap autoview field.
Definition: mailcap.h:60
#define TYPE(body)
Definition: mime.h:89
#define _(a)
Definition: message.h:28
void state_mark_attach(struct State *state)
Write a unique marker around content.
Definition: state.c:71
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:185
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
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:34
A mailcap entry.
Definition: mailcap.h:36
char * nametemplate
Definition: mailcap.h:43
char * command
Definition: mailcap.h:37
FILE * fp_out
File to write to.
Definition: state.h:49
+ 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 677 of file handler.c.

678{
679 char *buf = NULL;
680 size_t sz = 0;
681
682 const bool c_text_flowed = cs_subset_bool(NeoMutt->sub, "text_flowed");
683 while ((buf = mutt_file_read_line(buf, &sz, state->fp_in, NULL, MUTT_RL_NO_FLAGS)))
684 {
685 if (!mutt_str_equal(buf, "-- ") && c_text_flowed)
686 {
687 size_t len = mutt_str_len(buf);
688 while ((len > 0) && (buf[len - 1] == ' '))
689 buf[--len] = '\0';
690 }
691 if (state->prefix)
692 state_puts(state, state->prefix);
693 state_puts(state, buf);
694 state_putc(state, '\n');
695 }
696
697 FREE(&buf);
698 return 0;
699}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:763
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:763
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 704 of file handler.c.

705{
706 struct Body *b = NULL;
707 LOFF_T off_start;
708 int rc = 0;
709
710 off_start = ftello(state->fp_in);
711 if (off_start < 0)
712 return -1;
713
714 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
715 (b_email->encoding == ENC_UUENCODED))
716 {
717 b = mutt_body_new();
719 b->parts = mutt_rfc822_parse_message(state->fp_in, b);
720 }
721 else
722 {
723 b = b_email;
724 }
725
726 if (b->parts)
727 {
729 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
730 if ((state->flags & STATE_WEED) ||
731 ((state->flags & (STATE_DISPLAY | STATE_PRINTING)) && c_weed))
732 {
733 chflags |= CH_WEED | CH_REORDER;
734 }
735 if (state->prefix)
736 chflags |= CH_PREFIX;
737 if (state->flags & STATE_DISPLAY)
738 chflags |= CH_DISPLAY;
739
740 mutt_copy_hdr(state->fp_in, state->fp_out, off_start, b->parts->offset,
741 chflags, state->prefix, 0);
742
743 if (state->prefix)
744 state_puts(state, state->prefix);
745 state_putc(state, '\n');
746
747 rc = mutt_body_handler(b->parts, state);
748 }
749
750 if ((b_email->encoding == ENC_BASE64) || (b_email->encoding == ENC_QUOTED_PRINTABLE) ||
751 (b_email->encoding == ENC_UUENCODED))
752 {
753 mutt_body_free(&b);
754 }
755
756 return rc;
757}
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:106
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define CH_PREFIX
Quote header using $indent_string string?
Definition: copy.h:57
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define CH_DISPLAY
Display result to user.
Definition: copy.h:70
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *b)
Parse a Message/RFC822 body.
Definition: parse.c:1775
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1578
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1624
@ 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:35
#define STATE_PRINTING
Are we printing? - STATE_DISPLAY "light".
Definition: state.h:37
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 762 of file handler.c.

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

◆ alternative_handler()

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

Handler for multipart alternative emails - Implements handler_t -.

Definition at line 934 of file handler.c.

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

◆ multilingual_handler()

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

Handler for multi-lingual emails - Implements handler_t -.

Return values
0Always

Definition at line 1122 of file handler.c.

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

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

◆ valid_pgp_encrypted_handler()

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

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

Definition at line 1464 of file handler.c.

1465{
1466 struct Body *octetstream = b_email->parts->next;
1467
1468 /* clear out any mime headers before the handler, so they can't be spoofed. */
1469 mutt_env_free(&b_email->mime_headers);
1470 mutt_env_free(&octetstream->mime_headers);
1471
1472 int rc;
1473 /* Some clients improperly encode the octetstream part. */
1474 if (octetstream->encoding != ENC_7BIT)
1475 rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, 0);
1476 else
1477 rc = crypt_pgp_encrypted_handler(octetstream, state);
1478 b_email->goodsig |= octetstream->goodsig;
1479
1480 /* Relocate protected headers onto the multipart/encrypted part */
1481 if (!rc && octetstream->mime_headers)
1482 {
1483 b_email->mime_headers = octetstream->mime_headers;
1484 octetstream->mime_headers = NULL;
1485 }
1486
1487 return rc;
1488}
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
int crypt_pgp_encrypted_handler(struct Body *b_email, struct State *state)
Wrapper for CryptModuleSpecs::encrypted_handler() - Implements handler_t -.
Definition: cryptglue.c:248
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:1319
@ 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 1493 of file handler.c.

1494{
1495 struct Body *octetstream = b_email->parts->next->next;
1496
1497 /* clear out any mime headers before the handler, so they can't be spoofed. */
1498 mutt_env_free(&b_email->mime_headers);
1499 mutt_env_free(&octetstream->mime_headers);
1500
1501 /* exchange encodes the octet-stream, so re-run it through the decoder */
1502 int rc = run_decode_and_handler(octetstream, state, crypt_pgp_encrypted_handler, false);
1503 b_email->goodsig |= octetstream->goodsig;
1504#ifdef USE_AUTOCRYPT
1505 b_email->is_autocrypt |= octetstream->is_autocrypt;
1506#endif
1507
1508 /* Relocate protected headers onto the multipart/encrypted part */
1509 if (!rc && octetstream->mime_headers)
1510 {
1511 b_email->mime_headers = octetstream->mime_headers;
1512 octetstream->mime_headers = NULL;
1513 }
1514
1515 return rc;
1516}
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 1106 of file crypt.c.

1107{
1108 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
1109 if (c_crypt_protected_headers_read && b_email->mime_headers)
1110 {
1111 if (b_email->mime_headers->subject)
1112 {
1113 const bool display = (state->flags & STATE_DISPLAY);
1114
1115 const bool c_weed = cs_subset_bool(NeoMutt->sub, "weed");
1116 if (display && c_weed && mutt_matches_ignore("subject"))
1117 return 0;
1118
1120 const short c_wrap = cs_subset_number(NeoMutt->sub, "wrap");
1121 int wraplen = display ? mutt_window_wrap_cols(state->wraplen, c_wrap) : 0;
1122
1123 mutt_write_one_header(state->fp_out, "Subject",
1124 b_email->mime_headers->subject, state->prefix, wraplen,
1125 display ? CH_DISPLAY : CH_NO_FLAGS, NeoMutt->sub);
1126 state_puts(state, "\n");
1127 }
1128 }
1129
1130 return 0;
1131}
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:144
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
bool mutt_matches_ignore(const char *s)
Does the string match the ignore list.
Definition: parse.c:315
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:421
void state_mark_protected_header(struct State *state)
Write a unique marker around protected headers.
Definition: state.c:86
int mutt_window_wrap_cols(int width, short wrap)
Calculate the wrap column for a given screen width.
Definition: mutt_window.c:372
char * subject
Email's subject.
Definition: envelope.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_signed_handler()

int mutt_signed_handler ( struct Body b_email,
struct State state 
)

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

Definition at line 1136 of file crypt.c.

1137{
1138 if (!WithCrypto)
1139 return -1;
1140
1141 bool inconsistent = false;
1142 struct Body *top = b_email;
1143 struct Body **signatures = NULL;
1144 int sigcnt = 0;
1145 int rc = 0;
1146 struct Buffer *tempfile = NULL;
1147
1148 b_email = b_email->parts;
1149 SecurityFlags signed_type = mutt_is_multipart_signed(top);
1150 if (signed_type == SEC_NO_FLAGS)
1151 {
1152 /* A null protocol value is already checked for in mutt_body_handler() */
1153 state_printf(state, _("[-- Error: Unknown multipart/signed protocol %s --]\n\n"),
1154 mutt_param_get(&top->parameter, "protocol"));
1155 return mutt_body_handler(b_email, state);
1156 }
1157
1158 if (!(b_email && b_email->next))
1159 {
1160 inconsistent = true;
1161 }
1162 else
1163 {
1164 switch (signed_type)
1165 {
1166 case SEC_SIGN:
1167 if ((b_email->next->type != TYPE_MULTIPART) ||
1168 !mutt_istr_equal(b_email->next->subtype, "mixed"))
1169 {
1170 inconsistent = true;
1171 }
1172 break;
1173 case PGP_SIGN:
1174 if ((b_email->next->type != TYPE_APPLICATION) ||
1175 !mutt_istr_equal(b_email->next->subtype, "pgp-signature"))
1176 {
1177 inconsistent = true;
1178 }
1179 break;
1180 case SMIME_SIGN:
1181 if ((b_email->next->type != TYPE_APPLICATION) ||
1182 (!mutt_istr_equal(b_email->next->subtype, "x-pkcs7-signature") &&
1183 !mutt_istr_equal(b_email->next->subtype, "pkcs7-signature")))
1184 {
1185 inconsistent = true;
1186 }
1187 break;
1188 default:
1189 inconsistent = true;
1190 }
1191 }
1192 if (inconsistent)
1193 {
1194 state_attach_puts(state, _("[-- Error: Missing or bad-format multipart/signed signature --]\n\n"));
1195 return mutt_body_handler(b_email, state);
1196 }
1197
1198 if (state->flags & STATE_DISPLAY)
1199 {
1200 crypt_fetch_signatures(&signatures, b_email->next, &sigcnt);
1201
1202 if (sigcnt != 0)
1203 {
1204 tempfile = buf_pool_get();
1205 buf_mktemp(tempfile);
1206 bool goodsig = true;
1207 if (crypt_write_signed(b_email, state, buf_string(tempfile)) == 0)
1208 {
1209 for (int i = 0; i < sigcnt; i++)
1210 {
1211 if (((WithCrypto & APPLICATION_PGP) != 0) &&
1212 (signatures[i]->type == TYPE_APPLICATION) &&
1213 mutt_istr_equal(signatures[i]->subtype, "pgp-signature"))
1214 {
1215 if (crypt_pgp_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1216 goodsig = false;
1217
1218 continue;
1219 }
1220
1221 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
1222 (signatures[i]->type == TYPE_APPLICATION) &&
1223 (mutt_istr_equal(signatures[i]->subtype, "x-pkcs7-signature") ||
1224 mutt_istr_equal(signatures[i]->subtype, "pkcs7-signature")))
1225 {
1226 if (crypt_smime_verify_one(signatures[i], state, buf_string(tempfile)) != 0)
1227 goodsig = false;
1228
1229 continue;
1230 }
1231
1232 state_printf(state, _("[-- Warning: We can't verify %s/%s signatures. --]\n\n"),
1233 TYPE(signatures[i]), signatures[i]->subtype);
1234 }
1235 }
1236
1237 mutt_file_unlink(buf_string(tempfile));
1238 buf_pool_release(&tempfile);
1239
1240 top->goodsig = goodsig;
1241 top->badsig = !goodsig;
1242
1243 /* Now display the signed body */
1244 state_attach_puts(state, _("[-- The following data is signed --]\n\n"));
1245
1246 mutt_protected_headers_handler(b_email, state);
1247
1248 FREE(&signatures);
1249 }
1250 else
1251 {
1252 state_attach_puts(state, _("[-- Warning: Can't find any signatures. --]\n\n"));
1253 }
1254 }
1255
1256 rc = mutt_body_handler(b_email, state);
1257
1258 if ((state->flags & STATE_DISPLAY) && (sigcnt != 0))
1259 state_attach_puts(state, _("\n[-- End of signed data --]\n"));
1260
1261 return rc;
1262}
static void crypt_fetch_signatures(struct Body ***b_sigs, struct Body *b, int *n)
Create an array of an emails parts.
Definition: crypt.c:1063
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:397
int crypt_write_signed(struct Body *b, struct State *state, const char *tempfile)
Write the message body/part.
Definition: crypt.c:748
int crypt_smime_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:517
int crypt_pgp_verify_one(struct Body *b, struct State *state, const char *tempf)
Wrapper for CryptModuleSpecs::verify_one()
Definition: cryptglue.c:373
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1106
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
#define PGP_SIGN
Definition: lib.h:98
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:77
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define SMIME_SIGN
Definition: lib.h:104
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:117
#define SEC_SIGN
Email is signed.
Definition: lib.h:80
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 237 of file cryptglue.c.

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

◆ crypt_pgp_encrypted_handler()

int crypt_pgp_encrypted_handler ( struct Body b_email,
struct State state 
)

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

Definition at line 248 of file cryptglue.c.

249{
250#ifdef USE_AUTOCRYPT
251 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
252 if (c_autocrypt)
253 {
254 OptAutocryptGpgme = true;
255 int result = pgp_gpgme_encrypted_handler(b_email, state);
256 OptAutocryptGpgme = false;
257 if (result == 0)
258 {
259 b_email->is_autocrypt = true;
260 return result;
261 }
262 }
263#endif
264
265 if (CRYPT_MOD_CALL_CHECK(PGP, encrypted_handler))
266 return CRYPT_MOD_CALL(PGP, encrypted_handler)(b_email, state);
267
268 return -1;
269}
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:67
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:2659
+ 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 444 of file cryptglue.c.

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

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