NeoMutt  2025-12-11-980-ge38c27
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 679 of file rfc2047.c.

680{
681 if (!pd || !*pd)
682 return;
683
684 struct Buffer *buf = buf_pool_get(); // Output buffer
685 char *s = *pd; // Read pointer
686 char *beg = NULL; // Begin of encoded word
687 enum ContentEncoding enc = ENC_OTHER; // ENC_BASE64 or ENC_QUOTED_PRINTABLE
688 char *charset = NULL; // Which charset
689 size_t charsetlen = 0; // Length of the charset
690 char *text = NULL; // Encoded text
691 size_t textlen = 0; // Length of encoded text
692
693 /* Keep some state in case the next decoded word is using the same charset
694 * and it happens to be split in the middle of a multibyte character.
695 * See https://github.com/neomutt/neomutt/issues/1015 */
696 struct Buffer *prev = buf_pool_get(); /* Previously decoded word */
697 char *prev_charset = NULL; /* Previously used charset */
698 size_t prev_charsetlen = 0; /* Length of the previously used charset */
699
700 const struct Slist *c_assumed_charset = cc_assumed_charset();
701 const char *c_charset = cc_charset();
702 while (*s)
703 {
704 beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
705 if (beg != s)
706 {
707 /* Some non-encoded text was found */
708 size_t holelen = beg ? beg - s : mutt_str_len(s);
709
710 /* Ignore whitespace between encoded words */
711 if (beg && (mutt_str_lws_len(s, holelen) == holelen))
712 {
713 s = beg;
714 continue;
715 }
716
717 /* If we have some previously decoded text, add it now */
718 if (!buf_is_empty(prev))
719 {
720 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
721 }
722
723 /* Add non-encoded part */
724 if (slist_is_empty(c_assumed_charset))
725 {
726 buf_addstr_n(buf, s, holelen);
727 }
728 else
729 {
730 char *conv = mutt_strn_dup(s, holelen);
731 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &conv);
732 buf_addstr(buf, conv);
733 FREE(&conv);
734 }
735 s += holelen;
736 }
737 if (beg)
738 {
739 /* Some encoded text was found */
740 text[textlen] = '\0';
741 char *decoded = decode_word(text, textlen, enc);
742 if (!decoded)
743 {
744 goto done;
745 }
746 if (!buf_is_empty(prev) && ((prev_charsetlen != charsetlen) ||
747 !mutt_strn_equal(prev_charset, charset, charsetlen)))
748 {
749 /* Different charset, convert the previous chunk and add it to the
750 * final result */
751 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
752 }
753
754 buf_addstr(prev, decoded);
755 FREE(&decoded);
756 prev_charset = charset;
757 prev_charsetlen = charsetlen;
758 s = text + textlen + 2; /* Skip final ?= */
759 }
760 }
761
762 /* Save the last chunk */
763 if (!buf_is_empty(prev))
764 {
765 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
766 }
767
768 FREE(pd);
769 *pd = buf_strdup(buf);
770
771done:
772 buf_pool_release(&buf);
773 buf_pool_release(&prev);
774}
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:109
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
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:318
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:634
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:377
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition rfc2047.c:353
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 646 of file rfc2047.c.

647{
648 if (!pd || !*pd)
649 return;
650
651 const char *const c_charset = cc_charset();
652 if (!c_charset)
653 return;
654
655 struct Slist *fallback = NULL;
656 if (!charsets)
657 {
658 fallback = slist_parse("utf-8", D_SLIST_SEP_COLON);
659 charsets = fallback;
660 }
661
662 char *e = NULL;
663 size_t elen = 0;
664 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
665
666 slist_free(&fallback);
667 FREE(pd);
668 *pd = e;
669}
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:438
#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 819 of file rfc2047.c.

820{
821 if (!al)
822 return;
823
824 const bool assumed = !slist_is_empty(cc_assumed_charset());
825 struct Address *a = NULL;
826 char *data = NULL;
827 TAILQ_FOREACH(a, al, entries)
828 {
829 if (a->personal && ((buf_find_string(a->personal, "=?")) || assumed))
830 {
831 data = buf_strdup(a->personal);
832 rfc2047_decode(&data);
833 buf_strcpy(a->personal, data);
834 FREE(&data);
835 }
836 else if (a->group && a->mailbox && buf_find_string(a->mailbox, "=?"))
837 {
838 data = buf_strdup(a->mailbox);
839 rfc2047_decode(&data);
840 buf_strcpy(a->mailbox, data);
841 FREE(&data);
842 }
843 }
844}
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:644
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:679
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 784 of file rfc2047.c.

785{
786 if (!al)
787 return;
788
789 int col = tag ? strlen(tag) + 2 : 32;
790 struct Address *a = NULL;
791 char *data = NULL;
792 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
793 TAILQ_FOREACH(a, al, entries)
794 {
795 if (a->personal)
796 {
797 data = buf_strdup(a->personal);
798 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
799 buf_strcpy(a->personal, data);
800 FREE(&data);
801 }
802 else if (a->group && a->mailbox)
803 {
804 data = buf_strdup(a->mailbox);
805 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
806 buf_strcpy(a->mailbox, data);
807 FREE(&data);
808 }
809 }
810}
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:646
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 850 of file rfc2047.c.

851{
852 if (!env)
853 return;
862 rfc2047_decode(&env->x_label);
863
864 char *subj = env->subject;
865 *(char **) &env->subject = NULL;
866 rfc2047_decode(&subj);
867 mutt_env_set_subject(env, subj);
868 FREE(&subj);
869}
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:819
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 875 of file rfc2047.c.

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