Nico Golde:
[apps/madmutt.git] / rfc2047.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3  * Copyright (C) 2000-2001 Edmund Grimley Evans <edmundo@rano.org>
4  * 
5  *     This program is free software; you can redistribute it and/or modify
6  *     it under the terms of the GNU General Public License as published by
7  *     the Free Software Foundation; either version 2 of the License, or
8  *     (at your option) any later version.
9  * 
10  *     This program is distributed in the hope that it will be useful,
11  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *     GNU General Public License for more details.
14  * 
15  *     You should have received a copy of the GNU General Public License
16  *     along with this program; if not, write to the Free Software
17  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
18  */ 
19
20 #if HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "mutt.h"
25 #include "mime.h"
26 #include "charset.h"
27 #include "rfc2047.h"
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 /* If you are debugging this file, comment out the following line. */
36 /*#define NDEBUG*/
37
38 #ifdef NDEBUG
39 #define assert(x)
40 #else
41 #include <assert.h>
42 #endif
43
44 #define ENCWORD_LEN_MAX 75
45 #define ENCWORD_LEN_MIN 9 /* strlen ("=?.?.?.?=") */
46
47 #define HSPACE(x) ((x) == '\0' || (x) == ' ' || (x) == '\t')
48
49 #define CONTINUATION_BYTE(c) (((c) & 0xc0) == 0x80)
50
51 extern char RFC822Specials[];
52
53 typedef size_t (*encoder_t) (char *, ICONV_CONST char *, size_t,
54                              const char *);
55
56 static size_t convert_string (ICONV_CONST char *f, size_t flen,
57                               const char *from, const char *to,
58                               char **t, size_t *tlen)
59 {
60   iconv_t cd;
61   char *buf, *ob;
62   size_t obl, n;
63   int e;
64
65   cd = mutt_iconv_open (to, from, 0);
66   if (cd == (iconv_t)(-1))
67     return (size_t)(-1);
68   obl = 4 * flen + 1;
69   ob = buf = safe_malloc (obl);
70   n = iconv (cd, &f, &flen, &ob, &obl);
71   if (n == (size_t)(-1) || iconv (cd, 0, 0, &ob, &obl) == (size_t)(-1))
72   {
73     e = errno;
74     FREE (&buf);
75     iconv_close (cd);
76     errno = e;
77     return (size_t)(-1);
78   }
79   *ob = '\0';
80   
81   *tlen = ob - buf;
82
83   safe_realloc (&buf, ob - buf + 1);
84   *t = buf;
85   iconv_close (cd);
86
87   return n;
88 }
89
90 char *mutt_choose_charset (const char *fromcode, const char *charsets,
91                       char *u, size_t ulen, char **d, size_t *dlen)
92 {
93   char canonical_buff[LONG_STRING];
94   char *e = 0, *tocode = 0;
95   size_t elen = 0, bestn = 0;
96   const char *p, *q;
97
98   for (p = charsets; p; p = q ? q + 1 : 0)
99   {
100     char *s, *t;
101     size_t slen, n;
102
103     q = strchr (p, ':');
104
105     n = q ? q - p : strlen (p);
106
107     if (!n ||
108         /* Assume that we never need more than 12 characters of
109            encoded-text to encode a single character. */
110         n > (ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 2 - 12))
111       continue;
112
113     t = safe_malloc (n + 1);
114     memcpy (t, p, n);
115     t[n] = '\0';
116
117     n = convert_string (u, ulen, fromcode, t, &s, &slen);
118     if (n == (size_t)(-1))
119       continue;
120
121     if (!tocode || n < bestn)
122     {
123       bestn = n;
124       FREE (&tocode);
125       tocode = t;
126       if (d)
127       {
128         FREE (&e);
129         e = s;
130       }
131       else
132         FREE (&s);
133       elen = slen;
134       if (!bestn)
135         break;
136     }
137     else
138     {
139       FREE (&t);
140       FREE (&s);
141     }
142   }
143   if (tocode)
144   {
145     if (d)
146       *d = e;
147     if (dlen)
148       *dlen = elen;
149     
150     mutt_canonical_charset (canonical_buff, sizeof (canonical_buff), tocode);
151     mutt_str_replace (&tocode, canonical_buff);
152   }
153   return tocode;
154 }
155
156 static size_t b_encoder (char *s, ICONV_CONST char *d, size_t dlen,
157                          const char *tocode)
158 {
159   char *s0 = s;
160
161   memcpy (s, "=?", 2), s += 2;
162   memcpy (s, tocode, strlen (tocode)), s += strlen (tocode);
163   memcpy (s, "?B?", 3), s += 3;
164   for (;;)
165   {
166     if (!dlen)
167       break;
168     else if (dlen == 1)
169     {
170       *s++ = B64Chars[(*d >> 2) & 0x3f];
171       *s++ = B64Chars[(*d & 0x03) << 4];
172       *s++ = '=';
173       *s++ = '=';
174       break;
175     }
176     else if (dlen == 2)
177     {
178       *s++ = B64Chars[(*d >> 2) & 0x3f];
179       *s++ = B64Chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)];
180       *s++ = B64Chars[(d[1] & 0x0f) << 2];
181       *s++ = '=';
182       break;
183     }
184     else
185     {
186       *s++ = B64Chars[(*d >> 2) & 0x3f];
187       *s++ = B64Chars[((*d & 0x03) << 4) | ((d[1] >> 4) & 0x0f)];
188       *s++ = B64Chars[((d[1] & 0x0f) << 2) | ((d[2] >> 6) & 0x03)];
189       *s++ = B64Chars[d[2] & 0x3f];
190       d += 3, dlen -= 3;
191     }
192   }
193   memcpy (s, "?=", 2), s += 2;
194   return s - s0;
195 }
196
197 static size_t q_encoder (char *s, ICONV_CONST char *d, size_t dlen,
198                          const char *tocode)
199 {
200   char hex[] = "0123456789ABCDEF";
201   char *s0 = s;
202
203   memcpy (s, "=?", 2), s += 2;
204   memcpy (s, tocode, strlen (tocode)), s += strlen (tocode);
205   memcpy (s, "?Q?", 3), s += 3;
206   while (dlen--)
207   {
208     unsigned char c = *d++;
209     if (c == ' ')
210       *s++ = '_';
211     else if (c >= 0x7f || c < 0x20 || c == '_' ||  strchr (MimeSpecials, c))
212     {
213       *s++ = '=';
214       *s++ = hex[(c & 0xf0) >> 4];
215       *s++ = hex[c & 0x0f];
216     }
217     else
218       *s++ = c;
219   }
220   memcpy (s, "?=", 2), s += 2;
221   return s - s0;
222 }
223
224 /*
225  * Return 0 if and set *encoder and *wlen if the data (d, dlen) could
226  * be converted to an encoded word of length *wlen using *encoder.
227  * Otherwise return an upper bound on the maximum length of the data
228  * which could be converted.
229  * The data is converted from fromcode (which must be stateless) to
230  * tocode, unless fromcode is 0, in which case the data is assumed to
231  * be already in tocode, which should be 8-bit and stateless.
232  */
233 static size_t try_block (ICONV_CONST char *d, size_t dlen,
234                          const char *fromcode, const char *tocode,
235                          encoder_t *encoder, size_t *wlen)
236 {
237   char buf1[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
238   iconv_t cd;
239   ICONV_CONST char *ib;
240   char *ob, *p;
241   size_t ibl, obl;
242   int count, len, len_b, len_q;
243
244   if (fromcode)
245   {
246     cd = mutt_iconv_open (tocode, fromcode, 0);
247     assert (cd != (iconv_t)(-1));
248     ib = d, ibl = dlen, ob = buf1, obl = sizeof (buf1) - strlen (tocode);
249     if (iconv (cd, &ib, &ibl, &ob, &obl) == (size_t)(-1) ||
250         iconv (cd, 0, 0, &ob, &obl) == (size_t)(-1))
251     {
252       assert (errno == E2BIG);
253       iconv_close (cd);
254       assert (ib > d);
255       return (ib - d == dlen) ? dlen : ib - d + 1;
256     }
257     iconv_close (cd);
258   }
259   else
260   {
261     if (dlen > sizeof (buf1) - strlen (tocode))
262       return sizeof (buf1) - strlen (tocode) + 1;
263     memcpy (buf1, d, dlen);
264     ob = buf1 + dlen;
265   }
266
267   count = 0;
268   for (p = buf1; p < ob; p++)
269   {
270     unsigned char c = *p;
271     assert (strchr (MimeSpecials, '?'));
272     if (c >= 0x7f || c < 0x20 || *p == '_' ||
273         (c != ' ' && strchr (MimeSpecials, *p)))
274       ++count;
275   }
276
277   len = ENCWORD_LEN_MIN - 2 + strlen (tocode);
278   len_b = len + (((ob - buf1) + 2) / 3) * 4;
279   len_q = len + (ob - buf1) + 2 * count;
280
281   /* Apparently RFC 1468 says to use B encoding for iso-2022-jp. */
282   if (!ascii_strcasecmp (tocode, "ISO-2022-JP"))
283     len_q = ENCWORD_LEN_MAX + 1;
284
285   if (len_b < len_q && len_b <= ENCWORD_LEN_MAX)
286   {
287     *encoder = b_encoder;
288     *wlen = len_b;
289     return 0;
290   }
291   else if (len_q <= ENCWORD_LEN_MAX)
292   {
293     *encoder = q_encoder;
294     *wlen = len_q;
295     return 0;
296   }
297   else
298     return dlen;
299 }
300
301 /*
302  * Encode the data (d, dlen) into s using the encoder.
303  * Return the length of the encoded word.
304  */
305 static size_t encode_block (char *s, char *d, size_t dlen,
306                             const char *fromcode, const char *tocode,
307                             encoder_t encoder)
308 {
309   char buf1[ENCWORD_LEN_MAX - ENCWORD_LEN_MIN + 1];
310   iconv_t cd;
311   ICONV_CONST char *ib;
312   char *ob;
313   size_t ibl, obl, n1, n2;
314
315   if (fromcode)
316   {
317     cd = mutt_iconv_open (tocode, fromcode, 0);
318     assert (cd != (iconv_t)(-1));
319     ib = d, ibl = dlen, ob = buf1, obl = sizeof (buf1) - strlen (tocode);
320     n1 = iconv (cd, &ib, &ibl, &ob, &obl);
321     n2 = iconv (cd, 0, 0, &ob, &obl);
322     assert (n1 != (size_t)(-1) && n2 != (size_t)(-1));
323     iconv_close (cd);
324     return (*encoder) (s, buf1, ob - buf1, tocode);
325   }
326   else
327     return (*encoder) (s, d, dlen, tocode);
328 }
329
330 /*
331  * Discover how much of the data (d, dlen) can be converted into
332  * a single encoded word. Return how much data can be converted,
333  * and set the length *wlen of the encoded word and *encoder.
334  * We start in column col, which limits the length of the word.
335  */
336 static size_t choose_block (char *d, size_t dlen, int col,
337                             const char *fromcode, const char *tocode,
338                             encoder_t *encoder, size_t *wlen)
339 {
340   size_t n, nn;
341   int utf8 = fromcode && !ascii_strcasecmp (fromcode, "UTF-8");
342
343   n = dlen;
344   for (;;)
345   {
346     assert (d + n > d);
347     nn = try_block (d, n, fromcode, tocode, encoder, wlen);
348     if (!nn && (col + *wlen <= ENCWORD_LEN_MAX + 1 || n <= 1))
349       break;
350     n = (nn ? nn : n) - 1;
351     assert (n > 0);
352     if (utf8)
353       while (n > 1 && CONTINUATION_BYTE(d[n]))
354         --n;
355   }
356   return n;
357 }
358
359 /*
360  * Place the result of RFC-2047-encoding (d, dlen) into the dynamically
361  * allocated buffer (e, elen). The input data is in charset fromcode
362  * and is converted into a charset chosen from charsets.
363  * Return 1 if the conversion to UTF-8 failed, 2 if conversion from UTF-8
364  * failed, otherwise 0. If conversion failed, fromcode is assumed to be
365  * compatible with us-ascii and the original data is used.
366  * The input data is assumed to be a single line starting at column col;
367  * if col is non-zero, the preceding character was a space.
368  */
369 static int rfc2047_encode (ICONV_CONST char *d, size_t dlen, int col,
370                            const char *fromcode, const char *charsets,
371                            char **e, size_t *elen, char *specials)
372 {
373   int ret = 0;
374   char *buf;
375   size_t bufpos, buflen;
376   char *u, *t0, *t1, *t;
377   char *s0, *s1;
378   size_t ulen, r, n, wlen;
379   encoder_t encoder;
380   char *tocode1 = 0;
381   const char *tocode;
382   char *icode = "UTF-8";
383
384   /* Try to convert to UTF-8. */
385   if (convert_string (d, dlen, fromcode, icode, &u, &ulen))
386   {
387     ret = 1; 
388     icode = 0;
389     u = safe_malloc ((ulen = dlen) + 1);
390     memcpy (u, d, dlen);
391     u[ulen] = 0;
392   }
393
394   /* Find earliest and latest things we must encode. */
395   s0 = s1 = t0 = t1 = 0;
396   for (t = u; t < u + ulen; t++)
397   {
398     if ((*t & 0x80) || 
399         (*t == '=' && t[1] == '?' && (t == u || HSPACE(*(t-1)))))
400     {
401       if (!t0) t0 = t;
402       t1 = t;
403     }
404     else if (specials && strchr (specials, *t))
405     {
406       if (!s0) s0 = t;
407       s1 = t;
408     }
409   }
410
411   /* If we have something to encode, include RFC822 specials */
412   if (t0 && s0 && s0 < t0)
413     t0 = s0;
414   if (t1 && s1 && s1 > t1)
415     t1 = s1;
416
417   if (!t0)
418   {
419     /* No encoding is required. */
420     *e = u;
421     *elen = ulen;
422     return ret;
423   }
424
425   /* Choose target charset. */
426   tocode = fromcode;
427   if (icode)
428   {
429     if ((tocode1 = mutt_choose_charset (icode, charsets, u, ulen, 0, 0)))
430       tocode = tocode1;
431     else
432       ret = 2, icode = 0;
433   }
434
435   /* Hack to avoid labelling 8-bit data as us-ascii. */
436   if (!icode && mutt_is_us_ascii (tocode))
437     tocode = "unknown-8bit";
438   
439   /* Adjust t0 for maximum length of line. */
440   t = u + (ENCWORD_LEN_MAX + 1) - col - ENCWORD_LEN_MIN;
441   if (t < u)  t = u;
442   if (t < t0) t0 = t;
443   
444
445   /* Adjust t0 until we can encode a character after a space. */
446   for (; t0 > u; t0--)
447   {
448     if (!HSPACE(*(t0-1)))
449       continue;
450     t = t0 + 1;
451     if (icode)
452       while (t < u + ulen && CONTINUATION_BYTE(*t))
453         ++t;
454     if (!try_block (t0, t - t0, icode, tocode, &encoder, &wlen) &&
455         col + (t0 - u) + wlen <= ENCWORD_LEN_MAX + 1)
456       break;
457   }
458
459   /* Adjust t1 until we can encode a character before a space. */
460   for (; t1 < u + ulen; t1++)
461   {
462     if (!HSPACE(*t1))
463       continue;
464     t = t1 - 1;
465     if (icode)
466       while (CONTINUATION_BYTE(*t))
467         --t;
468     if (!try_block (t, t1 - t, icode, tocode, &encoder, &wlen) &&
469         1 + wlen + (u + ulen - t1) <= ENCWORD_LEN_MAX + 1)
470       break;
471   }
472
473   /* We shall encode the region [t0,t1). */
474
475   /* Initialise the output buffer with the us-ascii prefix. */
476   buflen = 2 * ulen;
477   buf = safe_malloc (buflen);
478   bufpos = t0 - u;
479   memcpy (buf, u, t0 - u);
480
481   col += t0 - u;
482
483   t = t0;
484   for (;;)
485   {
486     /* Find how much we can encode. */
487     n = choose_block (t, t1 - t, col, icode, tocode, &encoder, &wlen);
488     if (n == t1 - t)
489     {
490       /* See if we can fit the us-ascii suffix, too. */
491       if (col + wlen + (u + ulen - t1) <= ENCWORD_LEN_MAX + 1)
492         break;
493       n = t1 - t - 1;
494       if (icode)
495         while (CONTINUATION_BYTE(t[n]))
496           --n;
497       assert (t + n >= t);
498       if (!n)
499       {
500         /* This should only happen in the really stupid case where the
501            only word that needs encoding is one character long, but
502            there is too much us-ascii stuff after it to use a single
503            encoded word. We add the next word to the encoded region
504            and try again. */
505         assert (t1 < u + ulen);
506         for (t1++; t1 < u + ulen && !HSPACE(*t1); t1++)
507           ;
508         continue;
509       }
510       n = choose_block (t, n, col, icode, tocode, &encoder, &wlen);
511     }
512
513     /* Add to output buffer. */
514 #define LINEBREAK "\n\t"
515     if (bufpos + wlen + strlen (LINEBREAK) > buflen)
516     {
517       buflen = bufpos + wlen + strlen (LINEBREAK);
518       safe_realloc (&buf, buflen);
519     }
520     r = encode_block (buf + bufpos, t, n, icode, tocode, encoder);
521     assert (r == wlen);
522     bufpos += wlen;
523     memcpy (buf + bufpos, LINEBREAK, strlen (LINEBREAK));
524     bufpos += strlen (LINEBREAK);
525 #undef LINEBREAK
526
527     col = 1;
528
529     t += n;
530   }
531
532   /* Add last encoded word and us-ascii suffix to buffer. */
533   buflen = bufpos + wlen + (u + ulen - t1);
534   safe_realloc (&buf, buflen + 1);
535   r = encode_block (buf + bufpos, t, t1 - t, icode, tocode, encoder);
536   assert (r == wlen);
537   bufpos += wlen;
538   memcpy (buf + bufpos, t1, u + ulen - t1);
539
540   FREE (&tocode1);
541   FREE (&u);
542
543   buf[buflen] = '\0';
544   
545   *e = buf;
546   *elen = buflen + 1;
547   return ret;
548 }
549
550 void _rfc2047_encode_string (char **pd, int encode_specials, int col)
551 {
552   char *e;
553   size_t elen;
554   char *charsets;
555
556   if (!Charset || !*pd)
557     return;
558
559   charsets = SendCharset;
560   if (!charsets || !*charsets)
561     charsets = "UTF-8";
562
563   rfc2047_encode (*pd, strlen (*pd), col,
564                   Charset, charsets, &e, &elen,
565                   encode_specials ? RFC822Specials : NULL);
566
567   FREE (pd);
568   *pd = e;
569 }
570
571 void rfc2047_encode_adrlist (ADDRESS *addr, const char *tag)
572 {
573   ADDRESS *ptr = addr;
574   int col = tag ? strlen (tag) + 2 : 32;
575   
576   while (ptr)
577   {
578     if (ptr->personal)
579       _rfc2047_encode_string (&ptr->personal, 1, col);
580 #ifdef EXACT_ADDRESS
581     if (ptr->val)
582       _rfc2047_encode_string (&ptr->val, 1, col);
583 #endif
584     ptr = ptr->next;
585   }
586 }
587
588 static int rfc2047_decode_word (char *d, const char *s, size_t len)
589 {
590   const char *pp, *pp1;
591   char *pd, *d0;
592   const char *t, *t1;
593   int enc = 0, count = 0;
594   char *charset = NULL;
595
596   pd = d0 = safe_malloc (strlen (s));
597
598   for (pp = s; (pp1 = strchr (pp, '?')); pp = pp1 + 1)
599   {
600     count++;
601     switch (count)
602     {
603       case 2:
604         /* ignore language specification a la RFC 2231 */        
605         t = pp1;
606         if ((t1 = memchr (pp, '*', t - pp)))
607           t = t1;
608         charset = safe_malloc (t - pp + 1);
609         memcpy (charset, pp, t - pp);
610         charset[t-pp] = '\0';
611         break;
612       case 3:
613         if (toupper ((unsigned char) *pp) == 'Q')
614           enc = ENCQUOTEDPRINTABLE;
615         else if (toupper ((unsigned char) *pp) == 'B')
616           enc = ENCBASE64;
617         else
618         {
619           FREE (&charset);
620           FREE (&d0);
621           return (-1);
622         }
623         break;
624       case 4:
625         if (enc == ENCQUOTEDPRINTABLE)
626         {
627           for (; pp < pp1; pp++)
628           {
629             if (*pp == '_')
630               *pd++ = ' ';
631             else if (*pp == '=' &&
632                      (!(pp[1] & ~127) && hexval(pp[1]) != -1) &&
633                      (!(pp[2] & ~127) && hexval(pp[2]) != -1))
634             {
635               *pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]);
636               pp += 2;
637             }
638             else
639               *pd++ = *pp;
640           }
641           *pd = 0;
642         }
643         else if (enc == ENCBASE64)
644         {
645           int c, b = 0, k = 0;
646
647           for (; pp < pp1; pp++)
648           {
649             if (*pp == '=')
650               break;
651             if ((*pp & ~127) || (c = base64val(*pp)) == -1)
652               continue;
653             if (k + 6 >= 8)
654             {
655               k -= 2;
656               *pd++ = b | (c >> k);
657               b = c << (8 - k);
658             }
659             else
660             {
661               b |= c << (k + 2);
662               k += 6;
663             }
664           }
665           *pd = 0;
666         }
667         break;
668     }
669   }
670   
671   if (charset)
672     mutt_convert_string (&d0, charset, Charset, M_ICONV_HOOK_FROM);
673   strfcpy (d, d0, len);
674   FREE (&charset);
675   FREE (&d0);
676   return (0);
677 }
678
679 /*
680  * Find the start and end of the first encoded word in the string.
681  * We use the grammar in section 2 of RFC 2047, but the "encoding"
682  * must be B or Q. Also, we don't require the encoded word to be
683  * separated by linear-white-space (section 5(1)).
684  */
685 static const char *find_encoded_word (const char *s, const char **x)
686 {
687   const char *p, *q;
688
689   q = s;
690   while ((p = strstr (q, "=?")))
691   {
692     for (q = p + 2;
693          0x20 < *q && *q < 0x7f && !strchr ("()<>@,;:\"/[]?.=", *q);
694          q++)
695       ;
696     if (q[0] != '?' || !strchr ("BbQq", q[1]) || q[2] != '?')
697       continue;
698     for (q = q + 3; 0x20 <= *q && *q < 0x7f && *q != '?'; q++)
699       ;
700     if (q[0] != '?' || q[1] != '=')
701     {
702       --q;
703       continue;
704     }
705
706     *x = q + 2;
707     return p;
708   }
709
710   return 0;
711 }
712
713 /* return length of linear white space */
714 static size_t lwslen (const char *s, size_t n)
715 {
716   const char *p = s;
717   size_t len = n;
718
719   if (n <= 0)
720     return 0;
721
722   for (; p < s + n; p++)
723     if (!strchr (" \t\r\n", *p))
724     {
725       len = (size_t)(p - s);
726       break;
727     }
728   if (strchr ("\r\n", *(p-1))) /* LWS doesn't end with CRLF */
729     len = (size_t)0;
730   return len;
731 }
732
733 /* return length of linear white space : reverse */
734 static size_t lwsrlen (const char *s, size_t n)
735 {
736   const char *p = s + n - 1;
737   size_t len = n;
738
739   if (n <= 0)
740     return 0;
741
742   if (strchr ("\r\n", *p)) /* LWS doesn't end with CRLF */
743     return (size_t)0;
744
745   for (; p >= s; p--)
746     if (!strchr (" \t\r\n", *p))
747     {
748       len = (size_t)(s + n - 1 - p);
749       break;
750     }
751   return len;
752 }
753
754 /* try to decode anything that looks like a valid RFC2047 encoded
755  * header field, ignoring RFC822 parsing rules
756  */
757 void rfc2047_decode (char **pd)
758 {
759   const char *p, *q;
760   size_t m, n;
761   int found_encoded = 0;
762   char *d0, *d;
763   const char *s = *pd;
764   size_t dlen;
765
766   if (!s || !*s)
767     return;
768
769   dlen = 4 * strlen (s); /* should be enough */
770   d = d0 = safe_malloc (dlen + 1);
771
772   while (*s && dlen > 0)
773   {
774     if (!(p = find_encoded_word (s, &q)))
775     {
776       /* no encoded words */
777       if (!option (OPTSTRICTMIME))
778       {
779         n = mutt_strlen (s);
780         if (found_encoded && (m = lwslen (s, n)) != 0)
781         {
782           if (m != n)
783             *d = ' ', d++, dlen--;
784           n -= m, s += m;
785         }
786         if (ascii_strcasecmp (AssumedCharset, "us-ascii"))
787         {
788           char *t;
789           size_t tlen;
790
791           t = safe_malloc (n + 1);
792           strfcpy (t, s, n + 1);
793           if (mutt_convert_nonmime_string (&t) == 0)
794           {
795             tlen = mutt_strlen (t);
796             strncpy (d, t, tlen);
797             d += tlen;
798           }
799           else
800           {
801             strncpy (d, s, n);
802             d += n;
803           }
804           FREE (&t);
805           break;
806         }
807       }
808       strncpy (d, s, dlen);
809       d += dlen;
810       break;
811     }
812
813     if (p != s)
814     {
815       n = (size_t) (p - s);
816       /* ignore spaces between encoded words
817        * and linear white spaces between encoded word and *text */
818       if (!option (OPTSTRICTMIME))
819       {
820         if (found_encoded && (m = lwslen (s, n)) != 0)
821         {
822           if (m != n)
823             *d = ' ', d++, dlen--;
824           n -= m, s += m;
825         }
826
827         if ((m = n - lwsrlen (s, n)) != 0)
828         {
829           if (m > dlen)
830             m = dlen;
831           memcpy (d, s, m);
832           d += m;
833           dlen -= m;
834           if (m != n)
835             *d = ' ', d++, dlen--;
836         }
837       }
838       else if (!found_encoded || strspn (s, " \t\r\n") != n)
839       {
840         if (n > dlen)
841           n = dlen;
842         memcpy (d, s, n);
843         d += n;
844         dlen -= n;
845       }
846     }
847
848     rfc2047_decode_word (d, p, dlen);
849     found_encoded = 1;
850     s = q;
851     n = mutt_strlen (d);
852     dlen -= n;
853     d += n;
854   }
855   *d = 0;
856
857   FREE (pd);
858   *pd = d0;
859   mutt_str_adjust (pd);
860 }
861
862 void rfc2047_decode_adrlist (ADDRESS *a)
863 {
864   while (a)
865   {
866     if (a->personal)
867       rfc2047_decode (&a->personal);
868 #ifdef EXACT_ADDRESS
869     if (a->val && strstr (a->val, "=?") != NULL)
870       rfc2047_decode (&a->val);
871 #endif
872     a = a->next;
873   }
874 }