NeoMutt  2022-04-29-323-g5fcc6c
Teaching an old dog new tricks
DOXYGEN
rfc2047.h File Reference

RFC2047 MIME extensions encoding / decoding routines. More...

+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void rfc2047_decode (char **pd)
 Decode any RFC2047-encoded header fields. More...
 
void rfc2047_encode (char **pd, const char *specials, int col, const struct Slist *charsets)
 RFC-2047-encode a string. More...
 
void rfc2047_decode_addrlist (struct AddressList *al)
 Decode any RFC2047 headers in an Address list. More...
 
void rfc2047_encode_addrlist (struct AddressList *al, const char *tag)
 Encode any RFC2047 headers, where required, in an Address list. More...
 
void rfc2047_decode_envelope (struct Envelope *env)
 Decode the fields of an Envelope. More...
 
void rfc2047_encode_envelope (struct Envelope *env)
 Encode the fields of an Envelope. More...
 

Detailed Description

RFC2047 MIME extensions encoding / decoding routines.

Authors
  • Michael R. Elkins
  • Edmund Grimley Evans
  • Pietro Cerutti

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file rfc2047.h.

Function Documentation

◆ rfc2047_decode()

void rfc2047_decode ( char **  pd)

Decode any RFC2047-encoded header fields.

Parameters
[in,out]pdString to be decoded, and resulting decoded string

Try to decode anything that looks like a valid RFC2047 encoded header field, ignoring RFC822 parsing rules. If decoding fails, for example due to an invalid base64 string, the original input is left untouched.

Definition at line 649 of file rfc2047.c.

650{
651 if (!pd || !*pd)
652 return;
653
654 struct Buffer buf = mutt_buffer_make(0); /* Output buffer */
655 char *s = *pd; /* Read pointer */
656 char *beg = NULL; /* Begin of encoded word */
657 enum ContentEncoding enc; /* ENC_BASE64 or ENC_QUOTED_PRINTABLE */
658 char *charset = NULL; /* Which charset */
659 size_t charsetlen; /* Length of the charset */
660 char *text = NULL; /* Encoded text */
661 size_t textlen; /* Length of encoded text */
662
663 /* Keep some state in case the next decoded word is using the same charset
664 * and it happens to be split in the middle of a multibyte character.
665 * See https://github.com/neomutt/neomutt/issues/1015 */
666 struct Buffer prev = mutt_buffer_make(0); /* Previously decoded word */
667 char *prev_charset = NULL; /* Previously used charset */
668 size_t prev_charsetlen = 0; /* Length of the previously used charset */
669
670 while (*s)
671 {
672 beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
673 if (beg != s)
674 {
675 /* Some non-encoded text was found */
676 size_t holelen = beg ? beg - s : mutt_str_len(s);
677
678 /* Ignore whitespace between encoded words */
679 if (beg && (mutt_str_lws_len(s, holelen) == holelen))
680 {
681 s = beg;
682 continue;
683 }
684
685 /* If we have some previously decoded text, add it now */
686 if (!mutt_buffer_is_empty(&prev))
687 {
688 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
689 }
690
691 /* Add non-encoded part */
692 {
693 const struct Slist *const c_assumed_charset = cs_subset_slist(NeoMutt->sub, "assumed_charset");
694 if (c_assumed_charset)
695 {
696 char *conv = mutt_strn_dup(s, holelen);
698 mutt_buffer_addstr(&buf, conv);
699 FREE(&conv);
700 }
701 else
702 {
703 mutt_buffer_addstr_n(&buf, s, holelen);
704 }
705 }
706 s += holelen;
707 }
708 if (beg)
709 {
710 /* Some encoded text was found */
711 text[textlen] = '\0';
712 char *decoded = decode_word(text, textlen, enc);
713 if (!decoded)
714 {
716 return;
717 }
718 if (prev.data && ((prev_charsetlen != charsetlen) ||
719 !mutt_strn_equal(prev_charset, charset, charsetlen)))
720 {
721 /* Different charset, convert the previous chunk and add it to the
722 * final result */
723 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
724 }
725
726 mutt_buffer_addstr(&prev, decoded);
727 FREE(&decoded);
728 prev_charset = charset;
729 prev_charsetlen = charsetlen;
730 s = text + textlen + 2; /* Skip final ?= */
731 }
732 }
733
734 /* Save the last chunk */
735 if (prev.data)
736 {
737 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
738 }
739
740 mutt_buffer_addch(&buf, '\0');
741 FREE(pd);
742 *pd = buf.data;
743}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:105
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
#define FREE(x)
Definition: memory.h:43
ContentEncoding
Content-Transfer-Encoding.
Definition: mime.h:47
int mutt_ch_convert_nonmime_string(char **ps)
Try to convert a string using a list of character sets.
Definition: charset.c:307
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:451
size_t mutt_str_lws_len(const char *s, size_t n)
Measure the linear-white-space at the beginning of a string.
Definition: string.c:709
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:496
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
static char * parse_encoded_word(char *str, enum ContentEncoding *enc, char **charset, size_t *charsetlen, char **text, size_t *textlen)
Parse a string and report RFC2047 elements.
Definition: rfc2047.c:143
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:361
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition: rfc2047.c:337
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
String list.
Definition: slist.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2047_encode()

void rfc2047_encode ( char **  pd,
const char *  specials,
int  col,
const struct Slist charsets 
)

RFC-2047-encode a string.

Parameters
[in,out]pdString to be encoded, and resulting encoded string
[in]specialsSpecial characters to be encoded
[in]colStarting index in string
[in]charsetsList of charsets to choose from

Definition at line 619 of file rfc2047.c.

620{
621 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
622 if (!c_charset || !pd || !*pd)
623 return;
624
625 struct Slist *fallback = NULL;
626 if (!charsets)
627 {
628 fallback = slist_parse("utf-8", SLIST_SEP_COLON);
629 charsets = fallback;
630 }
631
632 char *e = NULL;
633 size_t elen = 0;
634 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
635
636 slist_free(&fallback);
637 FREE(pd);
638 *pd = e;
639}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition: slist.c:200
void slist_free(struct Slist **list)
Free an Slist object.
Definition: slist.c:162
static int encode(const char *d, size_t dlen, int col, const char *fromcode, const struct Slist *charsets, char **e, size_t *elen, const char *specials)
RFC2047-encode a string.
Definition: rfc2047.c:419
#define SLIST_SEP_COLON
Definition: slist.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2047_decode_addrlist()

void rfc2047_decode_addrlist ( struct AddressList *  al)

Decode any RFC2047 headers in an Address list.

Parameters
alAddressList

Definition at line 771 of file rfc2047.c.

772{
773 if (!al)
774 return;
775
776 struct Address *a = NULL;
777 TAILQ_FOREACH(a, al, entries)
778 {
779 const struct Slist *const c_assumed_charset = cs_subset_slist(NeoMutt->sub, "assumed_charset");
780 if (a->personal && ((strstr(a->personal, "=?")) || c_assumed_charset))
781 {
783 }
784 else if (a->group && a->mailbox && strstr(a->mailbox, "=?"))
786 }
787}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2047_encode_addrlist()

void rfc2047_encode_addrlist ( struct AddressList *  al,
const char *  tag 
)

Encode any RFC2047 headers, where required, in an Address list.

Parameters
alAddressList
tagHeader tag (used for wrapping calculation)

Definition at line 750 of file rfc2047.c.

751{
752 if (!al)
753 return;
754
755 int col = tag ? strlen(tag) + 2 : 32;
756 struct Address *a = NULL;
757 TAILQ_FOREACH(a, al, entries)
758 {
759 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
760 if (a->personal)
761 rfc2047_encode(&a->personal, AddressSpecials, col, c_send_charset);
762 else if (a->group && a->mailbox)
763 rfc2047_encode(&a->mailbox, AddressSpecials, col, c_send_charset);
764 }
765}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:619
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rfc2047_decode_envelope()

void rfc2047_decode_envelope ( struct Envelope env)

Decode the fields of an Envelope.

Parameters
envEnvelope

Definition at line 793 of file rfc2047.c.

794{
795 if (!env)
796 return;
805 rfc2047_decode(&env->x_label);
806 rfc2047_decode(&env->subject);
807}
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:771
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:58
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 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
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
char * x_label
X-Label.
Definition: envelope.h:76
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:

◆ rfc2047_encode_envelope()

void rfc2047_encode_envelope ( struct Envelope env)

Encode the fields of an Envelope.

Parameters
envEnvelope

Definition at line 813 of file rfc2047.c.

814{
815 if (!env)
816 return;
817 rfc2047_encode_addrlist(&env->from, "From");
818 rfc2047_encode_addrlist(&env->to, "To");
819 rfc2047_encode_addrlist(&env->cc, "Cc");
820 rfc2047_encode_addrlist(&env->bcc, "Bcc");
821 rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
822 rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
823 rfc2047_encode_addrlist(&env->sender, "Sender");
824 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
825 rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), c_send_charset);
826 rfc2047_encode(&env->subject, NULL, sizeof("Subject:"), c_send_charset);
827}
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:750
+ Here is the call graph for this function:
+ Here is the caller graph for this function: