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