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