NeoMutt  2023-11-03-85-g512e01
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
  • 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 659 of file rfc2047.c.

660{
661 if (!pd || !*pd)
662 return;
663
664 struct Buffer buf = buf_make(0); // Output buffer
665 char *s = *pd; // Read pointer
666 char *beg = NULL; // Begin of encoded word
667 enum ContentEncoding enc = ENC_OTHER; // ENC_BASE64 or ENC_QUOTED_PRINTABLE
668 char *charset = NULL; // Which charset
669 size_t charsetlen; // Length of the charset
670 char *text = NULL; // Encoded text
671 size_t textlen = 0; // Length of encoded text
672
673 /* Keep some state in case the next decoded word is using the same charset
674 * and it happens to be split in the middle of a multibyte character.
675 * See https://github.com/neomutt/neomutt/issues/1015 */
676 struct Buffer prev = buf_make(0); /* Previously decoded word */
677 char *prev_charset = NULL; /* Previously used charset */
678 size_t prev_charsetlen = 0; /* Length of the previously used charset */
679
680 const struct Slist *c_assumed_charset = cc_assumed_charset();
681 const char *c_charset = cc_charset();
682 while (*s)
683 {
684 beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
685 if (beg != s)
686 {
687 /* Some non-encoded text was found */
688 size_t holelen = beg ? beg - s : mutt_str_len(s);
689
690 /* Ignore whitespace between encoded words */
691 if (beg && (mutt_str_lws_len(s, holelen) == holelen))
692 {
693 s = beg;
694 continue;
695 }
696
697 /* If we have some previously decoded text, add it now */
698 if (!buf_is_empty(&prev))
699 {
700 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
701 }
702
703 /* Add non-encoded part */
704 if (slist_is_empty(c_assumed_charset))
705 {
706 buf_addstr_n(&buf, s, holelen);
707 }
708 else
709 {
710 char *conv = mutt_strn_dup(s, holelen);
711 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &conv);
712 buf_addstr(&buf, conv);
713 FREE(&conv);
714 }
715 s += holelen;
716 }
717 if (beg)
718 {
719 /* Some encoded text was found */
720 text[textlen] = '\0';
721 char *decoded = decode_word(text, textlen, enc);
722 if (!decoded)
723 {
724 buf_dealloc(&buf);
725 return;
726 }
727 if (prev.data && ((prev_charsetlen != charsetlen) ||
728 !mutt_strn_equal(prev_charset, charset, charsetlen)))
729 {
730 /* Different charset, convert the previous chunk and add it to the
731 * final result */
732 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
733 }
734
735 buf_addstr(&prev, decoded);
736 FREE(&decoded);
737 prev_charset = charset;
738 prev_charsetlen = charsetlen;
739 s = text + textlen + 2; /* Skip final ?= */
740 }
741 }
742
743 /* Save the last chunk */
744 if (prev.data)
745 {
746 finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
747 }
748
749 buf_addch(&buf, '\0');
750 FREE(pd);
751 *pd = buf.data;
752}
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:108
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:115
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:100
#define FREE(x)
Definition: memory.h:45
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:328
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:178
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:452
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:700
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:497
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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:147
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:364
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition: rfc2047.c:340
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
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 626 of file rfc2047.c.

627{
628 if (!pd || !*pd)
629 return;
630
631 const char *const c_charset = cc_charset();
632 if (!c_charset)
633 return;
634
635 struct Slist *fallback = NULL;
636 if (!charsets)
637 {
638 fallback = slist_parse("utf-8", SLIST_SEP_COLON);
639 charsets = fallback;
640 }
641
642 char *e = NULL;
643 size_t elen = 0;
644 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
645
646 slist_free(&fallback);
647 FREE(pd);
648 *pd = e;
649}
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition: slist.c:215
void slist_free(struct Slist **ptr)
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:424
#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
Note
rfc2047_decode() may realloc the data pointer it's given, so work on a copy to avoid breaking the Buffer

Definition at line 797 of file rfc2047.c.

798{
799 if (!al)
800 return;
801
802 const bool assumed = !slist_is_empty(cc_assumed_charset());
803 struct Address *a = NULL;
804 char *data = NULL;
805 TAILQ_FOREACH(a, al, entries)
806 {
807 if (a->personal && ((buf_find_string(a->personal, "=?")) || assumed))
808 {
809 data = buf_strdup(a->personal);
810 rfc2047_decode(&data);
811 buf_strcpy(a->personal, data);
812 FREE(&data);
813 }
814 else if (a->group && a->mailbox && buf_find_string(a->mailbox, "=?"))
815 {
816 data = buf_strdup(a->mailbox);
817 rfc2047_decode(&data);
818 buf_strcpy(a->mailbox, data);
819 FREE(&data);
820 }
821 }
822}
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:608
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:659
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
+ 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 762 of file rfc2047.c.

763{
764 if (!al)
765 return;
766
767 int col = tag ? strlen(tag) + 2 : 32;
768 struct Address *a = NULL;
769 char *data = NULL;
770 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
771 TAILQ_FOREACH(a, al, entries)
772 {
773 if (a->personal)
774 {
775 data = buf_strdup(a->personal);
776 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
777 buf_strcpy(a->personal, data);
778 FREE(&data);
779 }
780 else if (a->group && a->mailbox)
781 {
782 data = buf_strdup(a->mailbox);
783 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
784 buf_strcpy(a->mailbox, data);
785 FREE(&data);
786 }
787 }
788}
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:43
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
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:626
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:

◆ rfc2047_decode_envelope()

void rfc2047_decode_envelope ( struct Envelope env)

Decode the fields of an Envelope.

Parameters
envEnvelope

Definition at line 828 of file rfc2047.c.

829{
830 if (!env)
831 return;
840 rfc2047_decode(&env->x_label);
841 rfc2047_decode(&env->subject);
842}
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:797
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 848 of file rfc2047.c.

849{
850 if (!env)
851 return;
852 rfc2047_encode_addrlist(&env->from, "From");
853 rfc2047_encode_addrlist(&env->to, "To");
854 rfc2047_encode_addrlist(&env->cc, "Cc");
855 rfc2047_encode_addrlist(&env->bcc, "Bcc");
856 rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
857 rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
858 rfc2047_encode_addrlist(&env->sender, "Sender");
859 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
860 rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), c_send_charset);
861 rfc2047_encode(&env->subject, NULL, sizeof("Subject:"), c_send_charset);
862}
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:762
+ Here is the call graph for this function:
+ Here is the caller graph for this function: