NeoMutt  2023-05-17-33-gce4425
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 656 of file rfc2047.c.

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

624{
625 if (!pd || !*pd)
626 return;
627
628 const char *const c_charset = cc_charset();
629 if (!c_charset)
630 return;
631
632 struct Slist *fallback = NULL;
633 if (!charsets)
634 {
635 fallback = slist_parse("utf-8", SLIST_SEP_COLON);
636 charsets = fallback;
637 }
638
639 char *e = NULL;
640 size_t elen = 0;
641 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
642
643 slist_free(&fallback);
644 FREE(pd);
645 *pd = e;
646}
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition: slist.c:213
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:421
#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 777 of file rfc2047.c.

778{
779 if (!al)
780 return;
781
782 const bool assumed = !slist_is_empty(cc_assumed_charset());
783 struct Address *a = NULL;
784 TAILQ_FOREACH(a, al, entries)
785 {
786 if (a->personal && ((strstr(a->personal, "=?")) || assumed))
787 {
789 }
790 else if (a->group && a->mailbox && strstr(a->mailbox, "=?"))
791 {
793 }
794 }
795}
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:656
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 756 of file rfc2047.c.

757{
758 if (!al)
759 return;
760
761 int col = tag ? strlen(tag) + 2 : 32;
762 struct Address *a = NULL;
763 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
764 TAILQ_FOREACH(a, al, entries)
765 {
766 if (a->personal)
767 rfc2047_encode(&a->personal, AddressSpecials, col, c_send_charset);
768 else if (a->group && a->mailbox)
769 rfc2047_encode(&a->mailbox, AddressSpecials, col, c_send_charset);
770 }
771}
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:268
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:623
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 801 of file rfc2047.c.

802{
803 if (!env)
804 return;
813 rfc2047_decode(&env->x_label);
814 rfc2047_decode(&env->subject);
815}
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:777
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 821 of file rfc2047.c.

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