NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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.
 
void rfc2047_encode (char **pd, const char *specials, int col, const struct Slist *charsets)
 RFC-2047-encode a string.
 
void rfc2047_decode_addrlist (struct AddressList *al)
 Decode any RFC2047 headers in an Address list.
 
void rfc2047_encode_addrlist (struct AddressList *al, const char *tag)
 Encode any RFC2047 headers, where required, in an Address list.
 
void rfc2047_decode_envelope (struct Envelope *env)
 Decode the fields of an Envelope.
 
void rfc2047_encode_envelope (struct Envelope *env)
 Encode the fields of an Envelope.
 

Detailed Description

RFC2047 MIME extensions encoding / decoding routines.

Authors
  • Richard Russon
  • 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 669 of file rfc2047.c.

670{
671 if (!pd || !*pd)
672 return;
673
674 struct Buffer *buf = buf_pool_get(); // Output buffer
675 char *s = *pd; // Read pointer
676 char *beg = NULL; // Begin of encoded word
677 enum ContentEncoding enc = ENC_OTHER; // ENC_BASE64 or ENC_QUOTED_PRINTABLE
678 char *charset = NULL; // Which charset
679 size_t charsetlen; // Length of the charset
680 char *text = NULL; // Encoded text
681 size_t textlen = 0; // Length of encoded text
682
683 /* Keep some state in case the next decoded word is using the same charset
684 * and it happens to be split in the middle of a multibyte character.
685 * See https://github.com/neomutt/neomutt/issues/1015 */
686 struct Buffer *prev = buf_pool_get(); /* Previously decoded word */
687 char *prev_charset = NULL; /* Previously used charset */
688 size_t prev_charsetlen = 0; /* Length of the previously used charset */
689
690 const struct Slist *c_assumed_charset = cc_assumed_charset();
691 const char *c_charset = cc_charset();
692 while (*s)
693 {
694 beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
695 if (beg != s)
696 {
697 /* Some non-encoded text was found */
698 size_t holelen = beg ? beg - s : mutt_str_len(s);
699
700 /* Ignore whitespace between encoded words */
701 if (beg && (mutt_str_lws_len(s, holelen) == holelen))
702 {
703 s = beg;
704 continue;
705 }
706
707 /* If we have some previously decoded text, add it now */
708 if (!buf_is_empty(prev))
709 {
710 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
711 }
712
713 /* Add non-encoded part */
714 if (slist_is_empty(c_assumed_charset))
715 {
716 buf_addstr_n(buf, s, holelen);
717 }
718 else
719 {
720 char *conv = mutt_strn_dup(s, holelen);
721 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &conv);
722 buf_addstr(buf, conv);
723 FREE(&conv);
724 }
725 s += holelen;
726 }
727 if (beg)
728 {
729 /* Some encoded text was found */
730 text[textlen] = '\0';
731 char *decoded = decode_word(text, textlen, enc);
732 if (!decoded)
733 {
734 goto done;
735 }
736 if (!buf_is_empty(prev) && ((prev_charsetlen != charsetlen) ||
737 !mutt_strn_equal(prev_charset, charset, charsetlen)))
738 {
739 /* Different charset, convert the previous chunk and add it to the
740 * final result */
741 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
742 }
743
744 buf_addstr(prev, decoded);
745 FREE(&decoded);
746 prev_charset = charset;
747 prev_charsetlen = charsetlen;
748 s = text + textlen + 2; /* Skip final ?= */
749 }
750 }
751
752 /* Save the last chunk */
753 if (!buf_is_empty(prev))
754 {
755 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
756 }
757
758 FREE(pd);
759 *pd = buf_strdup(buf);
760
761done:
762 buf_pool_release(&buf);
763 buf_pool_release(&prev);
764}
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition buffer.c:96
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
const char * cc_charset(void)
Get the cached value of $charset.
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
ContentEncoding
Content-Transfer-Encoding.
Definition mime.h:47
@ ENC_OTHER
Encoding unknown.
Definition mime.h:48
int mutt_ch_convert_nonmime_string(const struct Slist *const assumed_charset, const char *charset, char **ps)
Try to convert a string using a list of character sets.
Definition charset.c:317
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition slist.c:140
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition string.c:384
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:633
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:429
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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:155
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition rfc2047.c:373
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition rfc2047.c:349
String manipulation buffer.
Definition buffer.h:36
String list.
Definition slist.h:37
+ 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 636 of file rfc2047.c.

637{
638 if (!pd || !*pd)
639 return;
640
641 const char *const c_charset = cc_charset();
642 if (!c_charset)
643 return;
644
645 struct Slist *fallback = NULL;
646 if (!charsets)
647 {
648 fallback = slist_parse("utf-8", D_SLIST_SEP_COLON);
649 charsets = fallback;
650 }
651
652 char *e = NULL;
653 size_t elen = 0;
654 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
655
656 slist_free(&fallback);
657 FREE(pd);
658 *pd = e;
659}
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition slist.c:177
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition slist.c:124
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:434
#define D_SLIST_SEP_COLON
Slist items are colon-separated.
Definition types.h:112
+ 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
Note
rfc2047_decode() may realloc the data pointer it's given, so work on a copy to avoid breaking the Buffer

Definition at line 809 of file rfc2047.c.

810{
811 if (!al)
812 return;
813
814 const bool assumed = !slist_is_empty(cc_assumed_charset());
815 struct Address *a = NULL;
816 char *data = NULL;
817 TAILQ_FOREACH(a, al, entries)
818 {
819 if (a->personal && ((buf_find_string(a->personal, "=?")) || assumed))
820 {
821 data = buf_strdup(a->personal);
822 rfc2047_decode(&data);
823 buf_strcpy(a->personal, data);
824 FREE(&data);
825 }
826 else if (a->group && a->mailbox && buf_find_string(a->mailbox, "=?"))
827 {
828 data = buf_strdup(a->mailbox);
829 rfc2047_decode(&data);
830 buf_strcpy(a->mailbox, data);
831 FREE(&data);
832 }
833 }
834}
const char * buf_find_string(const struct Buffer *buf, const char *s)
Return a pointer to a substring found in the buffer.
Definition buffer.c:638
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:669
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host 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)
Note
rfc2047_encode() may realloc the data pointer it's given, so work on a copy to avoid breaking the Buffer

Definition at line 774 of file rfc2047.c.

775{
776 if (!al)
777 return;
778
779 int col = tag ? strlen(tag) + 2 : 32;
780 struct Address *a = NULL;
781 char *data = NULL;
782 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
783 TAILQ_FOREACH(a, al, entries)
784 {
785 if (a->personal)
786 {
787 data = buf_strdup(a->personal);
788 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
789 buf_strcpy(a->personal, data);
790 FREE(&data);
791 }
792 else if (a->group && a->mailbox)
793 {
794 data = buf_strdup(a->mailbox);
795 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
796 buf_strcpy(a->mailbox, data);
797 FREE(&data);
798 }
799 }
800}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition address.c:45
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
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:636
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 840 of file rfc2047.c.

841{
842 if (!env)
843 return;
852 rfc2047_decode(&env->x_label);
853
854 char *subj = env->subject;
855 *(char **) &env->subject = NULL;
856 rfc2047_decode(&subj);
857 mutt_env_set_subject(env, subj);
858 FREE(&subj);
859}
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition rfc2047.c:809
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 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 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 865 of file rfc2047.c.

866{
867 if (!env)
868 return;
869 rfc2047_encode_addrlist(&env->from, "From");
870 rfc2047_encode_addrlist(&env->to, "To");
871 rfc2047_encode_addrlist(&env->cc, "Cc");
872 rfc2047_encode_addrlist(&env->bcc, "Bcc");
873 rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
874 rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
875 rfc2047_encode_addrlist(&env->sender, "Sender");
876 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
877 rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), c_send_charset);
878
879 char *subj = env->subject;
880 *(char **) &env->subject = NULL;
881 rfc2047_encode(&subj, NULL, sizeof("Subject:"), c_send_charset);
882 mutt_env_set_subject(env, subj);
883 FREE(&subj);
884}
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition rfc2047.c:774
+ Here is the call graph for this function:
+ Here is the caller graph for this function: