NeoMutt  2021-02-05-666-ge300cd
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 char *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 641 of file rfc2047.c.

642 {
643  if (!pd || !*pd)
644  return;
645 
646  struct Buffer buf = mutt_buffer_make(0); /* Output buffer */
647  char *s = *pd; /* Read pointer */
648  char *beg = NULL; /* Begin of encoded word */
649  enum ContentEncoding enc; /* ENC_BASE64 or ENC_QUOTED_PRINTABLE */
650  char *charset = NULL; /* Which charset */
651  size_t charsetlen; /* Length of the charset */
652  char *text = NULL; /* Encoded text */
653  size_t textlen; /* Length of encoded text */
654 
655  /* Keep some state in case the next decoded word is using the same charset
656  * and it happens to be split in the middle of a multibyte character.
657  * See https://github.com/neomutt/neomutt/issues/1015 */
658  struct Buffer prev = mutt_buffer_make(0); /* Previously decoded word */
659  char *prev_charset = NULL; /* Previously used charset */
660  size_t prev_charsetlen = 0; /* Length of the previously used charset */
661 
662  while (*s)
663  {
664  beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
665  if (beg != s)
666  {
667  /* Some non-encoded text was found */
668  size_t holelen = beg ? beg - s : mutt_str_len(s);
669 
670  /* Ignore whitespace between encoded words */
671  if (beg && (mutt_str_lws_len(s, holelen) == holelen))
672  {
673  s = beg;
674  continue;
675  }
676 
677  /* If we have some previously decoded text, add it now */
678  if (!mutt_buffer_is_empty(&prev))
679  {
680  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
681  }
682 
683  /* Add non-encoded part */
684  {
685  const char *const c_assumed_charset =
686  cs_subset_string(NeoMutt->sub, "assumed_charset");
687  if (c_assumed_charset)
688  {
689  char *conv = mutt_strn_dup(s, holelen);
691  mutt_buffer_addstr(&buf, conv);
692  FREE(&conv);
693  }
694  else
695  {
696  mutt_buffer_addstr_n(&buf, s, holelen);
697  }
698  }
699  s += holelen;
700  }
701  if (beg)
702  {
703  /* Some encoded text was found */
704  text[textlen] = '\0';
705  char *decoded = decode_word(text, textlen, enc);
706  if (!decoded)
707  {
708  return;
709  }
710  if (prev.data && ((prev_charsetlen != charsetlen) ||
711  !mutt_strn_equal(prev_charset, charset, charsetlen)))
712  {
713  /* Different charset, convert the previous chunk and add it to the
714  * final result */
715  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
716  }
717 
718  mutt_buffer_addstr(&prev, decoded);
719  FREE(&decoded);
720  prev_charset = charset;
721  prev_charsetlen = charsetlen;
722  s = text + textlen + 2; /* Skip final ?= */
723  }
724  }
725 
726  /* Save the last chunk */
727  if (prev.data)
728  {
729  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
730  }
731 
732  mutt_buffer_addch(&buf, '\0');
733  FREE(pd);
734  *pd = buf.data;
735 }
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:358
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
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:140
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:806
Container for Accounts, Notifications.
Definition: neomutt.h:36
char * mutt_strn_dup(const char *begin, size_t len)
Duplicate a sub-string.
Definition: string.c:548
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:99
char * data
Pointer to data.
Definition: buffer.h:35
int mutt_ch_convert_nonmime_string(char **ps)
Try to convert a string using a list of character sets.
Definition: charset.c:308
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
Perform charset conversion and filtering.
Definition: rfc2047.c:334
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
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:593
#define FREE(x)
Definition: memory.h:40
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
ContentEncoding
Content-Transfer-Encoding.
Definition: mime.h:46
+ 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 char *  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 616 of file rfc2047.c.

617 {
618  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
619  if (!c_charset || !pd || !*pd)
620  return;
621 
622  if (!charsets)
623  charsets = "utf-8";
624 
625  char *e = NULL;
626  size_t elen = 0;
627  encode(*pd, strlen(*pd), col, c_charset, charsets, &e, &elen, specials);
628 
629  FREE(pd);
630  *pd = e;
631 }
static int encode(const char *d, size_t dlen, int col, const char *fromcode, const char *charsets, char **e, size_t *elen, const char *specials)
RFC2047-encode a string.
Definition: rfc2047.c:416
Container for Accounts, Notifications.
Definition: neomutt.h:36
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define FREE(x)
Definition: memory.h:40
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_addrlist()

void rfc2047_decode_addrlist ( struct AddressList *  al)

Decode any RFC2047 headers in an Address list.

Parameters
alAddressList

Definition at line 764 of file rfc2047.c.

765 {
766  if (!al)
767  return;
768 
769  struct Address *a = NULL;
770  TAILQ_FOREACH(a, al, entries)
771  {
772  const char *const c_assumed_charset =
773  cs_subset_string(NeoMutt->sub, "assumed_charset");
774  if (a->personal && ((strstr(a->personal, "=?")) || c_assumed_charset))
775  {
777  }
778  else if (a->group && a->mailbox && strstr(a->mailbox, "=?"))
779  rfc2047_decode(&a->mailbox);
780  }
781 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:36
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
char * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
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_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 742 of file rfc2047.c.

743 {
744  if (!al)
745  return;
746 
747  int col = tag ? strlen(tag) + 2 : 32;
748  struct Address *a = NULL;
749  TAILQ_FOREACH(a, al, entries)
750  {
751  const char *const c_send_charset =
752  cs_subset_string(NeoMutt->sub, "send_charset");
753  if (a->personal)
754  rfc2047_encode(&a->personal, AddressSpecials, col, c_send_charset);
755  else if (a->group && a->mailbox)
756  rfc2047_encode(&a->mailbox, AddressSpecials, col, c_send_charset);
757  }
758 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:36
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
char * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
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 787 of file rfc2047.c.

788 {
789  if (!env)
790  return;
799  rfc2047_decode(&env->x_label);
800  rfc2047_decode(&env->subject);
801 }
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:764
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:63
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:62
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
char * subject
Email's subject.
Definition: envelope.h:66
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
struct AddressList sender
Email's sender.
Definition: envelope.h:61
char * x_label
X-Label.
Definition: envelope.h:72
+ 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 807 of file rfc2047.c.

808 {
809  if (!env)
810  return;
811  rfc2047_encode_addrlist(&env->from, "From");
812  rfc2047_encode_addrlist(&env->to, "To");
813  rfc2047_encode_addrlist(&env->cc, "Cc");
814  rfc2047_encode_addrlist(&env->bcc, "Bcc");
815  rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
816  rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
817  rfc2047_encode_addrlist(&env->sender, "Sender");
818  const char *const c_send_charset =
819  cs_subset_string(NeoMutt->sub, "send_charset");
820  rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), c_send_charset);
821  rfc2047_encode(&env->subject, NULL, sizeof("Subject:"), c_send_charset);
822 }
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:63
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:62
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:742
Container for Accounts, Notifications.
Definition: neomutt.h:36
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
char * subject
Email's subject.
Definition: envelope.h:66
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
struct AddressList sender
Email's sender.
Definition: envelope.h:61
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
char * x_label
X-Label.
Definition: envelope.h:72
+ Here is the call graph for this function:
+ Here is the caller graph for this function: