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