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