NeoMutt  2020-03-20-65-g141838
Teaching an old dog new tricks
DOXYGEN
rfc2047.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <assert.h>
33 #include <errno.h>
34 #include <iconv.h>
35 #include <stdbool.h>
36 #include <string.h>
37 #include "mutt/lib.h"
38 #include "address/lib.h"
39 #include "rfc2047.h"
40 #include "email_globals.h"
41 #include "envelope.h"
42 #include "mime.h"
43 
44 #define ENCWORD_LEN_MAX 75
45 #define ENCWORD_LEN_MIN 9 /* strlen ("=?.?.?.?=") */
46 
47 #define HSPACE(ch) (((ch) == '\0') || ((ch) == ' ') || ((ch) == '\t'))
48 
49 #define CONTINUATION_BYTE(ch) (((ch) &0xc0) == 0x80)
50 
59 typedef size_t (*encoder_t)(char *str, const char *buf, size_t buflen, const char *tocode);
60 
64 static size_t b_encoder(char *str, const char *buf, size_t buflen, const char *tocode)
65 {
66  char *s0 = str;
67 
68  memcpy(str, "=?", 2);
69  str += 2;
70  memcpy(str, tocode, strlen(tocode));
71  str += strlen(tocode);
72  memcpy(str, "?B?", 3);
73  str += 3;
74 
75  while (buflen)
76  {
77  char encoded[11];
78  size_t ret;
79  size_t in_len = MIN(3, buflen);
80 
81  ret = mutt_b64_encode(buf, in_len, encoded, sizeof(encoded));
82  for (size_t i = 0; i < ret; i++)
83  *str++ = encoded[i];
84 
85  buflen -= in_len;
86  buf += in_len;
87  }
88 
89  memcpy(str, "?=", 2);
90  str += 2;
91  return str - s0;
92 }
93 
97 static size_t q_encoder(char *str, const char *buf, size_t buflen, const char *tocode)
98 {
99  static const char hex[] = "0123456789ABCDEF";
100  char *s0 = str;
101 
102  memcpy(str, "=?", 2);
103  str += 2;
104  memcpy(str, tocode, strlen(tocode));
105  str += strlen(tocode);
106  memcpy(str, "?Q?", 3);
107  str += 3;
108  while (buflen--)
109  {
110  unsigned char c = *buf++;
111  if (c == ' ')
112  *str++ = '_';
113  else if ((c >= 0x7f) || (c < 0x20) || (c == '_') || strchr(MimeSpecials, c))
114  {
115  *str++ = '=';
116  *str++ = hex[(c & 0xf0) >> 4];
117  *str++ = hex[c & 0x0f];
118  }
119  else
120  *str++ = c;
121  }
122  memcpy(str, "?=", 2);
123  str += 2;
124  return str - s0;
125 }
126 
138 static char *parse_encoded_word(char *str, enum ContentEncoding *enc, char **charset,
139  size_t *charsetlen, char **text, size_t *textlen)
140 {
141  regmatch_t *match = mutt_prex_capture(PREX_RFC2047_ENCODED_WORD, str);
142  if (!match)
143  return NULL;
144 
145  const regmatch_t *mfull = &match[PREX_RFC2047_ENCODED_WORD_MATCH_FULL];
146  const regmatch_t *mcharset = &match[PREX_RFC2047_ENCODED_WORD_MATCH_CHARSET];
147  const regmatch_t *mencoding = &match[PREX_RFC2047_ENCODED_WORD_MATCH_ENCODING];
148  const regmatch_t *mtext = &match[PREX_RFC2047_ENCODED_WORD_MATCH_TEXT];
149 
150  /* Charset */
151  *charset = str + mutt_regmatch_start(mcharset);
152  *charsetlen = mutt_regmatch_len(mcharset);
153 
154  /* Encoding: either Q or B */
155  *enc = (tolower(str[mutt_regmatch_start(mencoding)]) == 'q') ? ENC_QUOTED_PRINTABLE : ENC_BASE64;
156 
157  *text = str + mutt_regmatch_start(mtext);
158  *textlen = mutt_regmatch_len(mtext);
159  return str + mutt_regmatch_start(mfull);
160 }
161 
181 static size_t try_block(const char *d, size_t dlen, const char *fromcode,
182  const char *tocode, encoder_t *encoder, size_t *wlen)
183 {
184  char buf[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
185  const char *ib = NULL;
186  char *ob = NULL;
187  size_t ibl, obl;
188  int count, len, len_b, len_q;
189 
190  if (fromcode)
191  {
192  iconv_t cd = mutt_ch_iconv_open(tocode, fromcode, 0);
193  assert(cd != (iconv_t)(-1));
194  ib = d;
195  ibl = dlen;
196  ob = buf;
197  obl = sizeof(buf) - strlen(tocode);
198  if ((iconv(cd, (ICONV_CONST char **) &ib, &ibl, &ob, &obl) == (size_t)(-1)) ||
199  (iconv(cd, NULL, NULL, &ob, &obl) == (size_t)(-1)))
200  {
201  assert(errno == E2BIG);
202  iconv_close(cd);
203  assert(ib > d);
204  return ((ib - d) == dlen) ? dlen : ib - d + 1;
205  }
206  iconv_close(cd);
207  }
208  else
209  {
210  if (dlen > (sizeof(buf) - strlen(tocode)))
211  return sizeof(buf) - strlen(tocode) + 1;
212  memcpy(buf, d, dlen);
213  ob = buf + dlen;
214  }
215 
216  count = 0;
217  for (char *p = buf; p < ob; p++)
218  {
219  unsigned char c = *p;
220  assert(strchr(MimeSpecials, '?'));
221  if ((c >= 0x7f) || (c < 0x20) || (*p == '_') ||
222  ((c != ' ') && strchr(MimeSpecials, *p)))
223  {
224  count++;
225  }
226  }
227 
228  len = ENCWORD_LEN_MIN - 2 + strlen(tocode);
229  len_b = len + (((ob - buf) + 2) / 3) * 4;
230  len_q = len + (ob - buf) + 2 * count;
231 
232  /* Apparently RFC1468 says to use B encoding for iso-2022-jp. */
233  if (mutt_str_strcasecmp(tocode, "ISO-2022-JP") == 0)
234  len_q = ENCWORD_LEN_MAX + 1;
235 
236  if ((len_b < len_q) && (len_b <= ENCWORD_LEN_MAX))
237  {
238  *encoder = b_encoder;
239  *wlen = len_b;
240  return 0;
241  }
242  else if (len_q <= ENCWORD_LEN_MAX)
243  {
244  *encoder = q_encoder;
245  *wlen = len_q;
246  return 0;
247  }
248  else
249  return dlen;
250 }
251 
264 static size_t encode_block(char *str, char *buf, size_t buflen, const char *fromcode,
265  const char *tocode, encoder_t encoder)
266 {
267  if (!fromcode)
268  {
269  return (*encoder)(str, buf, buflen, tocode);
270  }
271 
272  const iconv_t cd = mutt_ch_iconv_open(tocode, fromcode, 0);
273  assert(cd != (iconv_t)(-1));
274  const char *ib = buf;
275  size_t ibl = buflen;
276  char tmp[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
277  char *ob = tmp;
278  size_t obl = sizeof(tmp) - strlen(tocode);
279  const size_t n1 = iconv(cd, (ICONV_CONST char **) &ib, &ibl, &ob, &obl);
280  const size_t n2 = iconv(cd, NULL, NULL, &ob, &obl);
281  assert(n1 != (size_t)(-1) && n2 != (size_t)(-1));
282  iconv_close(cd);
283  return (*encoder)(str, tmp, ob - tmp, tocode);
284 }
285 
302 static size_t choose_block(char *d, size_t dlen, int col, const char *fromcode,
303  const char *tocode, encoder_t *encoder, size_t *wlen)
304 {
305  const bool utf8 = fromcode && (mutt_str_strcasecmp(fromcode, "utf-8") == 0);
306 
307  size_t n = dlen;
308  while (true)
309  {
310  assert(n > 0);
311  const size_t nn = try_block(d, n, fromcode, tocode, encoder, wlen);
312  if ((nn == 0) && (((col + *wlen) <= (ENCWORD_LEN_MAX + 1)) || (n <= 1)))
313  break;
314  n = ((nn != 0) ? nn : n) - 1;
315  assert(n > 0);
316  if (utf8)
317  while ((n > 1) && CONTINUATION_BYTE(d[n]))
318  n--;
319  }
320  return n;
321 }
322 
332 static void finalize_chunk(struct Buffer *res, struct Buffer *buf, char *charset, size_t charsetlen)
333 {
334  if (!charset)
335  return;
336  char end = charset[charsetlen];
337  charset[charsetlen] = '\0';
339  charset[charsetlen] = end;
341  mutt_buffer_addstr(res, buf->data);
342  FREE(&buf->data);
343  mutt_buffer_init(buf);
344 }
345 
355 static char *decode_word(const char *s, size_t len, enum ContentEncoding enc)
356 {
357  const char *it = s;
358  const char *end = s + len;
359 
360  if (enc == ENC_QUOTED_PRINTABLE)
361  {
362  struct Buffer buf = mutt_buffer_make(0);
363  for (; it < end; it++)
364  {
365  if (*it == '_')
366  {
367  mutt_buffer_addch(&buf, ' ');
368  }
369  else if ((it[0] == '=') && (!(it[1] & ~127) && (hexval(it[1]) != -1)) &&
370  (!(it[2] & ~127) && (hexval(it[2]) != -1)))
371  {
372  mutt_buffer_addch(&buf, (hexval(it[1]) << 4) | hexval(it[2]));
373  it += 2;
374  }
375  else
376  {
377  mutt_buffer_addch(&buf, *it);
378  }
379  }
380  mutt_buffer_addch(&buf, '\0');
381  return buf.data;
382  }
383  else if (enc == ENC_BASE64)
384  {
385  const int olen = 3 * len / 4 + 1;
386  char *out = mutt_mem_malloc(olen);
387  int dlen = mutt_b64_decode(it, out, olen);
388  if (dlen == -1)
389  {
390  FREE(&out);
391  return NULL;
392  }
393  out[dlen] = '\0';
394  return out;
395  }
396 
397  assert(0); /* The enc parameter has an invalid value */
398  return NULL;
399 }
400 
413 static int encode(const char *d, size_t dlen, int col, const char *fromcode,
414  const char *charsets, char **e, size_t *elen, const char *specials)
415 {
416  int rc = 0;
417  char *buf = NULL;
418  size_t bufpos, buflen;
419  char *t0 = NULL, *t1 = NULL, *t = NULL;
420  char *s0 = NULL, *s1 = NULL;
421  size_t ulen, r, wlen = 0;
422  encoder_t encoder = NULL;
423  char *tocode1 = NULL;
424  const char *tocode = NULL;
425  const char *icode = "utf-8";
426 
427  /* Try to convert to UTF-8. */
428  char *u = mutt_str_substr_dup(d, d + dlen);
429  if (mutt_ch_convert_string(&u, fromcode, icode, 0) != 0)
430  {
431  rc = 1;
432  icode = 0;
433  }
434  ulen = mutt_str_strlen(u);
435 
436  /* Find earliest and latest things we must encode. */
437  s0 = 0;
438  s1 = 0;
439  t0 = 0;
440  t1 = 0;
441  for (t = u; t < (u + ulen); t++)
442  {
443  if ((*t & 0x80) || ((*t == '=') && (t[1] == '?') && ((t == u) || HSPACE(*(t - 1)))))
444  {
445  if (!t0)
446  t0 = t;
447  t1 = t;
448  }
449  else if (specials && *t && strchr(specials, *t))
450  {
451  if (!s0)
452  s0 = t;
453  s1 = t;
454  }
455  }
456 
457  /* If we have something to encode, include RFC822 specials */
458  if (t0 && s0 && (s0 < t0))
459  t0 = s0;
460  if (t1 && s1 && (s1 > t1))
461  t1 = s1;
462 
463  if (!t0)
464  {
465  /* No encoding is required. */
466  *e = u;
467  *elen = ulen;
468  return rc;
469  }
470 
471  /* Choose target charset. */
472  tocode = fromcode;
473  if (icode)
474  {
475  tocode1 = mutt_ch_choose(icode, charsets, u, ulen, 0, 0);
476  if (tocode1)
477  tocode = tocode1;
478  else
479  {
480  rc = 2;
481  icode = 0;
482  }
483  }
484 
485  /* Hack to avoid labelling 8-bit data as us-ascii. */
486  if (!icode && mutt_ch_is_us_ascii(tocode))
487  tocode = "unknown-8bit";
488 
489  /* Adjust t0 for maximum length of line. */
490  t = u + (ENCWORD_LEN_MAX + 1) - col - ENCWORD_LEN_MIN;
491  if (t < u)
492  t = u;
493  if (t < t0)
494  t0 = t;
495 
496  /* Adjust t0 until we can encode a character after a space. */
497  for (; t0 > u; t0--)
498  {
499  if (!HSPACE(*(t0 - 1)))
500  continue;
501  t = t0 + 1;
502  if (icode)
503  while ((t < (u + ulen)) && CONTINUATION_BYTE(*t))
504  t++;
505  if ((try_block(t0, t - t0, icode, tocode, &encoder, &wlen) == 0) &&
506  ((col + (t0 - u) + wlen) <= (ENCWORD_LEN_MAX + 1)))
507  {
508  break;
509  }
510  }
511 
512  /* Adjust t1 until we can encode a character before a space. */
513  for (; t1 < (u + ulen); t1++)
514  {
515  if (!HSPACE(*t1))
516  continue;
517  t = t1 - 1;
518  if (icode)
519  while (CONTINUATION_BYTE(*t))
520  t--;
521  if ((try_block(t, t1 - t, icode, tocode, &encoder, &wlen) == 0) &&
522  ((1 + wlen + (u + ulen - t1)) <= (ENCWORD_LEN_MAX + 1)))
523  {
524  break;
525  }
526  }
527 
528  /* We shall encode the region [t0,t1). */
529 
530  /* Initialise the output buffer with the us-ascii prefix. */
531  buflen = 2 * ulen;
532  buf = mutt_mem_malloc(buflen);
533  bufpos = t0 - u;
534  memcpy(buf, u, t0 - u);
535 
536  col += t0 - u;
537 
538  t = t0;
539  while (true)
540  {
541  /* Find how much we can encode. */
542  size_t n = choose_block(t, t1 - t, col, icode, tocode, &encoder, &wlen);
543  if (n == (t1 - t))
544  {
545  /* See if we can fit the us-ascii suffix, too. */
546  if ((col + wlen + (u + ulen - t1)) <= (ENCWORD_LEN_MAX + 1))
547  break;
548  n = t1 - t - 1;
549  if (icode)
550  while (CONTINUATION_BYTE(t[n]))
551  n--;
552  if (n == 0)
553  {
554  /* This should only happen in the really stupid case where the
555  * only word that needs encoding is one character long, but
556  * there is too much us-ascii stuff after it to use a single
557  * encoded word. We add the next word to the encoded region
558  * and try again. */
559  assert(t1 < (u + ulen));
560  for (t1++; (t1 < (u + ulen)) && !HSPACE(*t1); t1++)
561  ;
562  continue;
563  }
564  n = choose_block(t, n, col, icode, tocode, &encoder, &wlen);
565  }
566 
567  /* Add to output buffer. */
568  const char *line_break = "\n\t";
569  const int lb_len = 2; /* strlen(line_break) */
570 
571  if ((bufpos + wlen + lb_len) > buflen)
572  {
573  buflen = bufpos + wlen + lb_len;
574  mutt_mem_realloc(&buf, buflen);
575  }
576  r = encode_block(buf + bufpos, t, n, icode, tocode, encoder);
577  assert(r == wlen);
578  bufpos += wlen;
579  memcpy(buf + bufpos, line_break, lb_len);
580  bufpos += lb_len;
581 
582  col = 1;
583 
584  t += n;
585  }
586 
587  /* Add last encoded word and us-ascii suffix to buffer. */
588  buflen = bufpos + wlen + (u + ulen - t1);
589  mutt_mem_realloc(&buf, buflen + 1);
590  r = encode_block(buf + bufpos, t, t1 - t, icode, tocode, encoder);
591  assert(r == wlen);
592  bufpos += wlen;
593  memcpy(buf + bufpos, t1, u + ulen - t1);
594 
595  FREE(&tocode1);
596  FREE(&u);
597 
598  buf[buflen] = '\0';
599 
600  *e = buf;
601  *elen = buflen + 1;
602  return rc;
603 }
604 
612 void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
613 {
614  if (!C_Charset || !pd || !*pd)
615  return;
616 
617  if (!charsets)
618  charsets = "utf-8";
619 
620  char *e = NULL;
621  size_t elen = 0;
622  encode(*pd, strlen(*pd), col, C_Charset, charsets, &e, &elen, specials);
623 
624  FREE(pd);
625  *pd = e;
626 }
627 
636 void rfc2047_decode(char **pd)
637 {
638  if (!pd || !*pd)
639  return;
640 
641  struct Buffer buf = mutt_buffer_make(0); /* Output buffer */
642  char *s = *pd; /* Read pointer */
643  char *beg = NULL; /* Begin of encoded word */
644  enum ContentEncoding enc; /* ENC_BASE64 or ENC_QUOTED_PRINTABLE */
645  char *charset = NULL; /* Which charset */
646  size_t charsetlen; /* Length of the charset */
647  char *text = NULL; /* Encoded text */
648  size_t textlen; /* Length of encoded text */
649 
650  /* Keep some state in case the next decoded word is using the same charset
651  * and it happens to be split in the middle of a multibyte character.
652  * See https://github.com/neomutt/neomutt/issues/1015 */
653  struct Buffer prev = mutt_buffer_make(0); /* Previously decoded word */
654  char *prev_charset = NULL; /* Previously used charset */
655  size_t prev_charsetlen = 0; /* Length of the previously used charset */
656 
657  while (*s)
658  {
659  beg = parse_encoded_word(s, &enc, &charset, &charsetlen, &text, &textlen);
660  if (beg != s)
661  {
662  /* Some non-encoded text was found */
663  size_t holelen = beg ? beg - s : mutt_str_strlen(s);
664 
665  /* Ignore whitespace between encoded words */
666  if (beg && (mutt_str_lws_len(s, holelen) == holelen))
667  {
668  s = beg;
669  continue;
670  }
671 
672  /* If we have some previously decoded text, add it now */
673  if (!mutt_buffer_is_empty(&prev))
674  {
675  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
676  }
677 
678  /* Add non-encoded part */
679  {
680  if (C_AssumedCharset)
681  {
682  char *conv = mutt_str_substr_dup(s, s + holelen);
684  mutt_buffer_addstr(&buf, conv);
685  FREE(&conv);
686  }
687  else
688  {
689  mutt_buffer_addstr_n(&buf, s, holelen);
690  }
691  }
692  s += holelen;
693  }
694  if (beg)
695  {
696  /* Some encoded text was found */
697  text[textlen] = '\0';
698  char *decoded = decode_word(text, textlen, enc);
699  if (!decoded)
700  {
701  return;
702  }
703  if (prev.data && ((prev_charsetlen != charsetlen) ||
704  (mutt_str_strncmp(prev_charset, charset, charsetlen) != 0)))
705  {
706  /* Different charset, convert the previous chunk and add it to the
707  * final result */
708  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
709  }
710 
711  mutt_buffer_addstr(&prev, decoded);
712  FREE(&decoded);
713  prev_charset = charset;
714  prev_charsetlen = charsetlen;
715  s = text + textlen + 2; /* Skip final ?= */
716  }
717  }
718 
719  /* Save the last chunk */
720  if (prev.data)
721  {
722  finalize_chunk(&buf, &prev, prev_charset, prev_charsetlen);
723  }
724 
725  mutt_buffer_addch(&buf, '\0');
726  FREE(pd);
727  *pd = buf.data;
728 }
729 
735 void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
736 {
737  if (!al)
738  return;
739 
740  int col = tag ? strlen(tag) + 2 : 32;
741  struct Address *a = NULL;
742  TAILQ_FOREACH(a, al, entries)
743  {
744  if (a->personal)
746  else if (a->group && a->mailbox)
748  }
749 }
750 
755 void rfc2047_decode_addrlist(struct AddressList *al)
756 {
757  if (!al)
758  return;
759 
760  struct Address *a = NULL;
761  TAILQ_FOREACH(a, al, entries)
762  {
763  if (a->personal && ((strstr(a->personal, "=?")) || C_AssumedCharset))
764  {
766  }
767  else if (a->group && a->mailbox && strstr(a->mailbox, "=?"))
768  rfc2047_decode(&a->mailbox);
769  }
770 }
771 
777 {
778  if (!env)
779  return;
788  rfc2047_decode(&env->x_label);
789  rfc2047_decode(&env->subject);
790 }
791 
797 {
798  if (!env)
799  return;
800  rfc2047_encode_addrlist(&env->from, "From");
801  rfc2047_encode_addrlist(&env->to, "To");
802  rfc2047_encode_addrlist(&env->cc, "Cc");
803  rfc2047_encode_addrlist(&env->bcc, "Bcc");
804  rfc2047_encode_addrlist(&env->reply_to, "Reply-To");
805  rfc2047_encode_addrlist(&env->mail_followup_to, "Mail-Followup-To");
806  rfc2047_encode_addrlist(&env->sender, "Sender");
807  rfc2047_encode(&env->x_label, NULL, sizeof("X-Label:"), C_SendCharset);
808  rfc2047_encode(&env->subject, NULL, sizeof("Subject:"), C_SendCharset);
809 }
char * C_AssumedCharset
Config: If a message is missing a character set, assume this character set.
Definition: charset.c:53
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:796
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:413
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:748
#define MIN(a, b)
Definition: memory.h:31
char * mutt_ch_choose(const char *fromcode, const char *charsets, const char *u, size_t ulen, char **d, size_t *dlen)
Figure the best charset to encode a string.
Definition: charset.c:1030
=?[utf-8]?Q?=E8=81...?=
Definition: prex.h:90
void rfc2047_decode_addrlist(struct AddressList *al)
Decode any RFC2047 headers in an Address list.
Definition: rfc2047.c:755
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
static size_t q_encoder(char *str, const char *buf, size_t buflen, const char *tocode)
Quoted-printable Encode a string - Implements encoder_t.
Definition: rfc2047.c:97
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
static char * decode_word(const char *s, size_t len, enum ContentEncoding enc)
Decode an RFC2047-encoded string.
Definition: rfc2047.c:355
[=?utf-8?Q?=E8=81...?=]
Definition: prex.h:89
=?utf-8?[Q]?=E8=81...?=
Definition: prex.h:91
#define CONTINUATION_BYTE(ch)
Definition: rfc2047.c:49
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
static size_t mutt_regmatch_len(const regmatch_t *match)
Return the length of a match.
Definition: regex3.h:79
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:138
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:776
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:838
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:735
=?utf-8?Q?[=E8=81...]?=
Definition: prex.h:92
RFC2047 MIME extensions encoding / decoding routines.
size_t(* encoder_t)(char *str, const char *buf, size_t buflen, const char *tocode)
Prototype for an encoding function.
Definition: rfc2047.c:59
Email Address Handling.
char * C_SendCharset
Config: Character sets for outgoing mail.
Definition: email_globals.c:38
static size_t try_block(const char *d, size_t dlen, const char *fromcode, const char *tocode, encoder_t *encoder, size_t *wlen)
Attempt to convert a block of text.
Definition: rfc2047.c:181
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:636
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to null-terminated base64 string.
Definition: base64.c:88
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
Email Global Variables.
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:107
Base-64 encoded text.
Definition: mime.h:52
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
Constants and macros for managing MIME encoding.
#define HSPACE(ch)
Definition: rfc2047.c:47
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
match a precompiled regex against a string
Definition: prex.c:145
Representation of an email header (envelope)
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:59
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
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
static size_t encode_block(char *str, char *buf, size_t buflen, const char *fromcode, const char *tocode, encoder_t encoder)
Encode a block of text using an encoder.
Definition: rfc2047.c:264
char * data
Pointer to data.
Definition: buffer.h:35
static const char encoded[]
iconv_t mutt_ch_iconv_open(const char *tocode, const char *fromcode, int flags)
Set up iconv for conversions.
Definition: charset.c:559
static size_t b_encoder(char *str, const char *buf, size_t buflen, const char *tocode)
Base64 Encode a string - Implements encoder_t.
Definition: rfc2047.c:64
[=?utf-8?Q?=E8=81=AA=E6=98=8E=E7=9A=84?=]
Definition: prex.h:35
#define hexval(ch)
Definition: mime.h:75
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:332
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:612
char * personal
Real name of address.
Definition: address.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
struct AddressList return_path
Return path for the Email.
Definition: envelope.h:56
bool group
Group mailbox?
Definition: address.h:38
int n
Definition: acutest.h:477
int mutt_str_strncmp(const char *a, const char *b, size_t l)
Compare two strings (to a maximum), safely.
Definition: string.c:665
int mutt_ch_convert_nonmime_string(char **ps)
Try to convert a string using a list of character sets.
Definition: charset.c:301
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
Quoted-printable text.
Definition: mime.h:51
#define ENCWORD_LEN_MAX
Definition: rfc2047.c:44
#define FREE(x)
Definition: memory.h:40
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
int mutt_mb_filter_unprintable(char **s)
Replace unprintable characters.
Definition: mbyte.c:424
#define ENCWORD_LEN_MIN
Definition: rfc2047.c:45
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
Convenience wrapper for the library headers.
static size_t choose_block(char *d, size_t dlen, int col, const char *fromcode, const char *tocode, encoder_t *encoder, size_t *wlen)
Calculate how much data can be converted.
Definition: rfc2047.c:302
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:81
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
char * mutt_str_substr_dup(const char *begin, const char *end)
Duplicate a sub-string.
Definition: string.c:602
char * x_label
X-Label.
Definition: envelope.h:72
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert null-terminated base64 string to raw bytes.
Definition: base64.c:136
ContentEncoding
Content-Transfer-Encoding.
Definition: mime.h:46
The header of an Email.
Definition: envelope.h:54