NeoMutt  2020-11-20
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 639 of file rfc2047.c.

640 {
641  if (!pd || !*pd)
642  return;
643 
644  struct Buffer buf = mutt_buffer_make(0); /* Output buffer */
645  char *s = *pd; /* Read pointer */
646  char *beg = NULL; /* Begin of encoded word */
647  enum ContentEncoding enc; /* ENC_BASE64 or ENC_QUOTED_PRINTABLE */
648  char *charset = NULL; /* Which charset */
649  size_t charsetlen; /* Length of the charset */
650  char *text = NULL; /* Encoded text */
651  size_t textlen; /* Length of encoded text */
652 
653  /* Keep some state in case the next decoded word is using the same charset
654  * and it happens to be split in the middle of a multibyte character.
655  * See https://github.com/neomutt/neomutt/issues/1015 */
656  struct Buffer prev = mutt_buffer_make(0); /* Previously decoded word */
657  char *prev_charset = NULL; /* Previously used charset */
658  size_t prev_charsetlen = 0; /* Length of the previously used charset */
659 
660  while (*s)
661  {
662  beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
663  if (beg != s)
664  {
665  /* Some non-encoded text was found */
666  size_t holelen = beg ? beg - s : mutt_str_len(s);
667 
668  /* Ignore whitespace between encoded words */
669  if (beg && (mutt_str_lws_len(s, holelen) == holelen))
670  {
671  s = beg;
672  continue;
673  }
674 
675  /* If we have some previously decoded text, add it now */
676  if (!mutt_buffer_is_empty(&prev))
677  {
678  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
679  }
680 
681  /* Add non-encoded part */
682  {
683  if (C_AssumedCharset)
684  {
685  char *conv = mutt_strn_dup(s, holelen);
687  mutt_buffer_addstr(&buf, conv);
688  FREE(&conv);
689  }
690  else
691  {
692  mutt_buffer_addstr_n(&buf, s, holelen);
693  }
694  }
695  s += holelen;
696  }
697  if (beg)
698  {
699  /* Some encoded text was found */
700  text[textlen] = '\0';
701  char *decoded = decode_word(text, textlen, enc);
702  if (!decoded)
703  {
704  return;
705  }
706  if (prev.data && ((prev_charsetlen != charsetlen) ||
707  !mutt_strn_equal(prev_charset, charset, charsetlen)))
708  {
709  /* Different charset, convert the previous chunk and add it to the
710  * final result */
711  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
712  }
713 
714  mutt_buffer_addstr(&prev, decoded);
715  FREE(&decoded);
716  prev_charset = charset;
717  prev_charsetlen = charsetlen;
718  s = text + textlen + 2; /* Skip final ?= */
719  }
720  }
721 
722  /* Save the last chunk */
723  if (prev.data)
724  {
725  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
726  }
727 
728  mutt_buffer_addch(&buf, '\0');
729  FREE(pd);
730  *pd = buf.data;
731 }
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:357
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:773
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:309
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
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:593
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
#define FREE(x)
Definition: memory.h:40
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:52
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 615 of file rfc2047.c.

616 {
617  if (!C_Charset || !pd || !*pd)
618  return;
619 
620  if (!charsets)
621  charsets = "utf-8";
622 
623  char *e = NULL;
624  size_t elen = 0;
625  encode(*pd, strlen(*pd), col, C_Charset, charsets, &e, &elen, specials);
626 
627  FREE(pd);
628  *pd = e;
629 }
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:415
#define FREE(x)
Definition: memory.h:40
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:53
+ 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 758 of file rfc2047.c.

759 {
760  if (!al)
761  return;
762 
763  struct Address *a = NULL;
764  TAILQ_FOREACH(a, al, entries)
765  {
766  if (a->personal && ((strstr(a->personal, "=?")) || C_AssumedCharset))
767  {
769  }
770  else if (a->group && a->mailbox && strstr(a->mailbox, "=?"))
771  rfc2047_decode(&a->mailbox);
772  }
773 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:639
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:52
+ 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 738 of file rfc2047.c.

739 {
740  if (!al)
741  return;
742 
743  int col = tag ? strlen(tag) + 2 : 32;
744  struct Address *a = NULL;
745  TAILQ_FOREACH(a, al, entries)
746  {
747  if (a->personal)
749  else if (a->group && a->mailbox)
751  }
752 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:615
char * personal
Real name of address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:38
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: globals.c:38
+ 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 779 of file rfc2047.c.

780 {
781  if (!env)
782  return;
791  rfc2047_decode(&env->x_label);
792  rfc2047_decode(&env->subject);
793 }
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:758
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:639
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 799 of file rfc2047.c.

800 {
801  if (!env)
802  return;
803  rfc2047_encode_addrlist(&env->from, "From");
804  rfc2047_encode_addrlist(&env->to, "To");
805  rfc2047_encode_addrlist(&env->cc, "Cc");
806  rfc2047_encode_addrlist(&env->bcc, "Bcc");
807  rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
808  rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
809  rfc2047_encode_addrlist(&env->sender, "Sender");
810  rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), C_SendCharset);
811  rfc2047_encode(&env->subject, NULL, sizeof("Subject:"), C_SendCharset);
812 }
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:738
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:615
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
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: globals.c:38
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: