NeoMutt  2024-04-16-36-g75b6fb
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 662 of file rfc2047.c.

663{
664 if (!pd || !*pd)
665 return;
666
667 struct Buffer *buf = buf_pool_get(); // Output buffer
668 char *s = *pd; // Read pointer
669 char *beg = NULL; // Begin of encoded word
670 enum ContentEncoding enc = ENC_OTHER; // ENC_BASE64 or ENC_QUOTED_PRINTABLE
671 char *charset = NULL; // Which charset
672 size_t charsetlen; // Length of the charset
673 char *text = NULL; // Encoded text
674 size_t textlen = 0; // Length of encoded text
675
676 /* Keep some state in case the next decoded word is using the same charset
677 * and it happens to be split in the middle of a multibyte character.
678 * See https://github.com/neomutt/neomutt/issues/1015 */
679 struct Buffer *prev = buf_pool_get(); /* Previously decoded word */
680 char *prev_charset = NULL; /* Previously used charset */
681 size_t prev_charsetlen = 0; /* Length of the previously used charset */
682
683 const struct Slist *c_assumed_charset = cc_assumed_charset();
684 const char *c_charset = cc_charset();
685 while (*s)
686 {
687 beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
688 if (beg != s)
689 {
690 /* Some non-encoded text was found */
691 size_t holelen = beg ? beg - s : mutt_str_len(s);
692
693 /* Ignore whitespace between encoded words */
694 if (beg && (mutt_str_lws_len(s, holelen) == holelen))
695 {
696 s = beg;
697 continue;
698 }
699
700 /* If we have some previously decoded text, add it now */
701 if (!buf_is_empty(prev))
702 {
703 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
704 }
705
706 /* Add non-encoded part */
707 if (slist_is_empty(c_assumed_charset))
708 {
709 buf_addstr_n(buf, s, holelen);
710 }
711 else
712 {
713 char *conv = mutt_strn_dup(s, holelen);
714 mutt_ch_convert_nonmime_string(c_assumed_charset, c_charset, &conv);
715 buf_addstr(buf, conv);
716 FREE(&conv);
717 }
718 s += holelen;
719 }
720 if (beg)
721 {
722 /* Some encoded text was found */
723 text[textlen] = '\0';
724 char *decoded = decode_word(text, textlen, enc);
725 if (!decoded)
726 {
727 goto done;
728 }
729 if (!buf_is_empty(prev) && ((prev_charsetlen != charsetlen) ||
730 !mutt_strn_equal(prev_charset, charset, charsetlen)))
731 {
732 /* Different charset, convert the previous chunk and add it to the
733 * final result */
734 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
735 }
736
737 buf_addstr(prev, decoded);
738 FREE(&decoded);
739 prev_charset = charset;
740 prev_charsetlen = charsetlen;
741 s = text + textlen + 2; /* Skip final ?= */
742 }
743 }
744
745 /* Save the last chunk */
746 if (!buf_is_empty(prev))
747 {
748 finalize_chunk(buf, prev, prev_charset, prev_charsetlen);
749 }
750
751 FREE(pd);
752 *pd = buf_strdup(buf);
753
754done:
755 buf_pool_release(&buf);
756 buf_pool_release(&prev);
757}
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:95
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
const struct Slist * cc_assumed_charset(void)
Get the cached value of $assumed_charset.
Definition: config_cache.c:101
#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:331
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:142
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:374
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:622
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:419
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
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:149
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:366
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition: rfc2047.c:342
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 629 of file rfc2047.c.

630{
631 if (!pd || !*pd)
632 return;
633
634 const char *const c_charset = cc_charset();
635 if (!c_charset)
636 return;
637
638 struct Slist *fallback = NULL;
639 if (!charsets)
640 {
641 fallback = slist_parse("utf-8", D_SLIST_SEP_COLON);
642 charsets = fallback;
643 }
644
645 char *e = NULL;
646 size_t elen = 0;
647 encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
648
649 slist_free(&fallback);
650 FREE(pd);
651 *pd = e;
652}
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition: slist.c:179
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition: slist.c:126
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:427
#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 802 of file rfc2047.c.

803{
804 if (!al)
805 return;
806
807 const bool assumed = !slist_is_empty(cc_assumed_charset());
808 struct Address *a = NULL;
809 char *data = NULL;
810 TAILQ_FOREACH(a, al, entries)
811 {
812 if (a->personal && ((buf_find_string(a->personal, "=?")) || assumed))
813 {
814 data = buf_strdup(a->personal);
815 rfc2047_decode(&data);
816 buf_strcpy(a->personal, data);
817 FREE(&data);
818 }
819 else if (a->group && a->mailbox && buf_find_string(a->mailbox, "=?"))
820 {
821 data = buf_strdup(a->mailbox);
822 rfc2047_decode(&data);
823 buf_strcpy(a->mailbox, data);
824 FREE(&data);
825 }
826 }
827}
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:639
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:662
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 767 of file rfc2047.c.

768{
769 if (!al)
770 return;
771
772 int col = tag ? strlen(tag) + 2 : 32;
773 struct Address *a = NULL;
774 char *data = NULL;
775 const struct Slist *const c_send_charset = cs_subset_slist(NeoMutt->sub, "send_charset");
776 TAILQ_FOREACH(a, al, entries)
777 {
778 if (a->personal)
779 {
780 data = buf_strdup(a->personal);
781 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
782 buf_strcpy(a->personal, data);
783 FREE(&data);
784 }
785 else if (a->group && a->mailbox)
786 {
787 data = buf_strdup(a->mailbox);
788 rfc2047_encode(&data, AddressSpecials, col, c_send_charset);
789 buf_strcpy(a->mailbox, data);
790 FREE(&data);
791 }
792 }
793}
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:243
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:629
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 833 of file rfc2047.c.

834{
835 if (!env)
836 return;
845 rfc2047_decode(&env->x_label);
846
847 char *subj = env->subject;
848 *(char **) &env->subject = NULL;
849 rfc2047_decode(&subj);
850 mutt_env_set_subject(env, subj);
851 FREE(&subj);
852}
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition: envelope.c:69
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:802
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 858 of file rfc2047.c.

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