Import Upstream version 0.69.0
[hcoop/debian/courier-authlib.git] / libs / rfc822 / rfc2047u.c
1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include "rfc822.h"
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <courier-unicode.h>
13
14 #include "rfc822hdr.h"
15 #include "rfc2047.h"
16
17 #if LIBIDN
18 #include <idna.h>
19 #include <stringprep.h>
20 #endif
21
22
23 static ssize_t rfc822_decode_rfc2047_atom(const char *str,
24 size_t cnt,
25
26 void (*callback)(const char *,
27 const char *,
28 const char *,
29 size_t,
30 void *),
31 void *ptr);
32
33 static int rfc2047_decode_unicode(const char *text,
34 const char *chset,
35 void (*callback)(const char *, size_t,
36 void *),
37 void *ptr);
38
39 struct decode_unicode_s {
40 const char *mychset;
41
42 char *bufptr;
43 size_t bufsize;
44 } ;
45
46 static void save_unicode_text(const char *p, size_t l, void *ptr)
47 {
48 struct decode_unicode_s *s=
49 (struct decode_unicode_s *)ptr;
50
51 if (s->bufptr)
52 memcpy(s->bufptr+s->bufsize, p, l);
53
54 s->bufsize += l;
55 }
56
57 struct rfc822_display_name_s {
58 const char *chset;
59 void (*print_func)(const char *, size_t, void *);
60 void *ptr;
61 };
62
63 static void unknown_charset(const char *chset,
64 const char *tochset,
65 void (*print_func)(const char *, size_t, void *),
66 void *ptr)
67 {
68 static const char unknown[]="[unknown character set: ";
69
70 (*print_func)(unknown, sizeof(unknown)-1, ptr);
71 (*print_func)(chset, strlen(chset), ptr);
72 (*print_func)(" -> ", 4, ptr);
73 (*print_func)(tochset, strlen(tochset), ptr);
74 (*print_func)("]", 1, ptr);
75 }
76
77 static void rfc822_display_addr_cb(const char *chset,
78 const char *lang,
79 const char *content,
80 size_t cnt,
81 void *dummy)
82 {
83 struct rfc822_display_name_s *s=
84 (struct rfc822_display_name_s *)dummy;
85 char *ptr;
86 char *buf;
87
88 buf=malloc(cnt+1);
89
90 if (!buf)
91 return;
92
93 memcpy(buf, content, cnt);
94 buf[cnt]=0;
95
96 ptr=unicode_convert_tobuf(buf, chset, s->chset, NULL);
97 free(buf);
98
99 if (ptr)
100 {
101 (*s->print_func)(ptr, strlen(ptr), s->ptr);
102 free(ptr);
103 }
104 else
105 {
106 unknown_charset(chset, s->chset, s->print_func, s->ptr);
107 return;
108 }
109 }
110
111 static
112 int rfc822_display_name_int(const struct rfc822a *rfcp, int index,
113 const char *chset,
114 void (*print_func)(const char *, size_t, void *),
115 void *ptr)
116 {
117 struct rfc822_display_name_s s;
118 const struct rfc822addr *addrs;
119
120 struct rfc822token *i;
121 int prev_isatom=0;
122 int isatom=0;
123 ssize_t rc;
124
125 if (index < 0 || index >= rfcp->naddrs) return 0;
126
127 addrs=rfcp->addrs+index;
128
129 if (!addrs->name)
130 return rfc822_display_addr(rfcp, index, chset, print_func, ptr);
131
132 if (chset == NULL)
133 {
134 s.chset="utf-8";
135 }
136 else
137 {
138 s.chset=chset;
139 }
140
141 s.print_func=print_func;
142 s.ptr=ptr;
143
144 for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
145 {
146 isatom=rfc822_is_atom(i->token);
147 if (isatom && prev_isatom)
148 (*print_func)(" ", 1, ptr);
149
150 if (i->token == '"' || i->token == '(')
151 {
152 size_t l=i->len;
153 char *p, *q, *r;
154
155 if (i->token == '(')
156 {
157 if (l > 2)
158 l -= 2;
159 else
160 l=0;
161 }
162
163 p=malloc(l+1);
164
165 if (!p)
166 return -1;
167
168 if (l)
169 {
170 if (i->token == '(')
171 {
172 memcpy(p, i->ptr+1, l);
173 }
174 else
175 {
176 memcpy(p, i->ptr, l);
177 }
178 }
179
180
181 p[l]=0;
182
183 for (q=r=p; *q; *r++ = *q++)
184 if (*q == '\\' && q[1])
185 ++q;
186
187 *r=0;
188
189 if (chset == NULL)
190 {
191 (*print_func)(p, strlen(p), ptr);
192 }
193 else if (rfc822_display_hdrvalue("subject",
194 p, s.chset,
195 print_func,
196 NULL, ptr) < 0)
197 {
198 free(p);
199 return -1;
200 }
201 free(p);
202 continue;
203 }
204
205 if (i->token)
206 {
207 char c= (char)i->token;
208
209 (*print_func)(&c, 1, ptr);
210 continue;
211 }
212
213 rc=chset ? rfc822_decode_rfc2047_atom(i->ptr, i->len,
214 rfc822_display_addr_cb,
215 &s):0;
216
217 if (rc < 0)
218 return -1;
219
220 if (rc == 0)
221 {
222 (*print_func)(i->ptr, i->len, ptr);
223 continue;
224 }
225
226 if (i->next && i->next->token == 0)
227 {
228 rc=rfc822_decode_rfc2047_atom(i->next->ptr,
229 i->next->len,
230 NULL, NULL);
231
232 if (rc < 0)
233 return -1;
234
235 if (rc > 0)
236 isatom=0; /* Suppress the separating space */
237 }
238 }
239 return 0;
240 }
241
242 int rfc822_display_name(const struct rfc822a *rfcp, int index,
243 const char *chset,
244 void (*print_func)(const char *, size_t, void *),
245 void *ptr)
246 {
247 const struct rfc822addr *addrs;
248
249 if (index < 0 || index >= rfcp->naddrs) return 0;
250
251 addrs=rfcp->addrs+index;
252
253 if (!addrs->tokens)
254 return 0;
255
256 return rfc822_display_name_int(rfcp, index, chset,
257 print_func, ptr);
258 }
259
260 char *rfc822_display_name_tobuf(const struct rfc822a *rfcp, int index,
261 const char *chset)
262 {
263 struct decode_unicode_s s;
264 char *p;
265
266 s.bufptr=0;
267 s.bufsize=1;
268
269 if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0)
270 return NULL;
271 s.bufptr=p=malloc(s.bufsize);
272 if (!p)
273 return (0);
274
275 s.bufsize=0;
276 if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0)
277 {
278 free(s.bufptr);
279 return (0);
280 }
281 save_unicode_text("", 1, &s);
282
283 return (p);
284 }
285
286 int rfc822_display_namelist(const struct rfc822a *rfcp,
287 const char *chset,
288 void (*print_func)(const char *, size_t, void *),
289 void *ptr)
290 {
291 int n;
292
293 for (n=0; n<rfcp->naddrs; n++)
294 {
295 if (rfcp->addrs[n].tokens)
296 {
297 int err=rfc822_display_name(rfcp, n, chset,
298 print_func, ptr);
299
300 if (err < 0)
301 return err;
302
303 (*print_func)("\n", 1, ptr);
304 }
305 }
306 return 0;
307 }
308
309 int rfc822_display_addr_str(const char *tok,
310 const char *chset,
311 void (*print_func)(const char *, size_t, void *),
312 void *ptr)
313 {
314 const char *p;
315
316 p=strchr(tok,'@');
317
318 if (!p)
319 p=tok;
320 else
321 ++p;
322
323 if (chset != NULL)
324 {
325 int err=0;
326 char *utf8_ptr;
327
328 if (p > tok)
329 (*print_func)(tok, p-tok, ptr);
330
331 #if LIBIDN
332 /*
333 ** Invalid UTF-8 can make libidn go off the deep end. Add
334 ** padding as a workaround.
335 */
336 {
337 size_t s=strlen(p)+16;
338 char *cpy=malloc(s);
339
340 if (!cpy)
341 return 0;
342 memset(cpy, 0, s);
343 strcpy(cpy, p);
344
345 err=idna_to_unicode_8z8z(cpy, &utf8_ptr, 0);
346 free(cpy);
347 }
348
349 if (err != IDNA_SUCCESS)
350 utf8_ptr=0;
351 #else
352 utf8_ptr=0;
353 #endif
354
355 if (utf8_ptr == 0)
356 (*print_func)(p, strlen(p), ptr);
357 else
358 {
359 char *q=unicode_convert_tobuf(utf8_ptr,
360 "utf-8",
361 chset, NULL);
362 if (q)
363 {
364 (*print_func)(q, strlen(q), ptr);
365 free(q);
366 }
367 else
368 {
369 (*print_func)(p, strlen(p), ptr);
370 }
371 free(utf8_ptr);
372 }
373 }
374 else
375 {
376 (*print_func)(tok, strlen(tok), ptr);
377 }
378 return 0;
379 }
380
381 int rfc822_display_addr(const struct rfc822a *rfcp, int index,
382 const char *chset,
383 void (*print_func)(const char *, size_t, void *),
384 void *ptr)
385 {
386 const struct rfc822addr *addrs;
387 char *tok;
388 int rc;
389
390 if (index < 0 || index >= rfcp->naddrs) return 0;
391
392 addrs=rfcp->addrs+index;
393
394 if (!addrs->tokens)
395 return 0;
396
397 tok=rfc822_gettok(addrs->tokens);
398
399 if (!tok)
400 return 0;
401
402 rc=rfc822_display_addr_str(tok, chset, print_func, ptr);
403 free(tok);
404 return rc;
405 }
406
407 int rfc2047_print_unicodeaddr(const struct rfc822a *a,
408 const char *charset,
409 void (*print_func)(char, void *),
410 void (*print_separator)(const char *, void *),
411 void *ptr)
412 {
413 const char *sep=NULL;
414 int n;
415
416 for (n=0; n<a->naddrs; ++n)
417 {
418 struct decode_unicode_s nbuf;
419 const struct rfc822addr *addrs;
420 size_t i=0;
421 char *cpbuf;
422 int need_braces=0;
423
424 addrs=a->addrs+n;
425
426 nbuf.bufptr=0;
427 nbuf.bufsize=1;
428
429 if (rfc822_display_name_int(a, n, charset,
430 save_unicode_text, &nbuf) < 0)
431 return -1;
432
433 nbuf.bufptr=malloc(nbuf.bufsize);
434 nbuf.bufsize=0;
435 if (!nbuf.bufptr)
436 return -1;
437
438 if (rfc822_display_name_int(a, n, charset,
439 save_unicode_text, &nbuf) < 0)
440 {
441 free(nbuf.bufptr);
442 return -1;
443 }
444 nbuf.bufptr[nbuf.bufsize]=0;
445
446 if (addrs->tokens == 0)
447 {
448 size_t i;
449
450 if (nbuf.bufsize == 1) /* ; */
451 sep=0;
452
453 if (sep)
454 (*print_separator)(sep, ptr);
455
456 for (i=0; i<nbuf.bufsize; ++i)
457 (*print_func)(nbuf.bufptr[i], ptr);
458 free(nbuf.bufptr);
459 if (nbuf.bufsize > 1)
460 (*print_separator)(" ", ptr);
461 sep=NULL;
462 continue;
463 }
464 if (sep)
465 (*print_separator)(sep, ptr);
466
467 if (!addrs->name)
468 {
469 nbuf.bufsize=0;
470 nbuf.bufptr[0]=0;
471 }
472
473 for (i=0; i<nbuf.bufsize; i++)
474 if (strchr(RFC822_SPECIALS, nbuf.bufptr[i]))
475 break;
476
477 cpbuf=unicode_convert_tobuf(nbuf.bufptr, "utf-8", charset,
478 NULL);
479
480 if (!cpbuf)
481 {
482 const char *errmsg="\"(unknown character set)\"";
483
484 while (*errmsg)
485 (*print_func)(*errmsg++, ptr);
486 need_braces=1;
487 }
488 else
489 {
490 if (i < nbuf.bufsize)
491 {
492 (*print_func)('"', ptr);
493
494 for (i=0; cpbuf[i]; ++i)
495 {
496 if (cpbuf[i] == '\\' ||
497 cpbuf[i] == '"')
498 (*print_func)('\\', ptr);
499 (*print_func)(cpbuf[i], ptr);
500 }
501 (*print_func)('"', ptr);
502 need_braces=1;
503 }
504 else
505 {
506 for (i=0; cpbuf[i]; ++i)
507 {
508 need_braces=1;
509 (*print_func)(cpbuf[i], ptr);
510 }
511 }
512
513 free(cpbuf);
514 }
515 free(nbuf.bufptr);
516
517 if (need_braces)
518 {
519 (*print_func)(' ', ptr);
520 (*print_func)('<', ptr);
521 }
522
523 nbuf.bufptr=0;
524 nbuf.bufsize=1;
525
526 if (rfc822_display_addr(a, n, charset,
527 save_unicode_text, &nbuf) < 0)
528 return -1;
529
530 nbuf.bufptr=malloc(nbuf.bufsize);
531 nbuf.bufsize=0;
532 if (!nbuf.bufptr)
533 return -1;
534
535 if (rfc822_display_addr(a, n, charset,
536 save_unicode_text, &nbuf) < 0)
537 {
538 free(nbuf.bufptr);
539 return -1;
540 }
541 for (i=0; i<nbuf.bufsize; i++)
542 (*print_func)(nbuf.bufptr[i], ptr);
543
544 free(nbuf.bufptr);
545
546 if (need_braces)
547 (*print_func)('>', ptr);
548 sep=", ";
549 }
550
551 return 0;
552 }
553
554 static int rfc2047_print_unicode_addrstr(const char *addrheader,
555 const char *charset,
556 void (*print_func)(char, void *),
557 void (*print_separator)(const char *, void *),
558 void (*err_func)(const char *, int, void *),
559 void *ptr)
560 {
561 struct rfc822t *t;
562 struct rfc822a *a;
563 int rc;
564
565 t=rfc822t_alloc_new(addrheader, err_func, ptr);
566
567 if (!t)
568 return -1;
569
570 a=rfc822a_alloc(t);
571
572 if (!a)
573 {
574 rfc822t_free(t);
575 return -1;
576 }
577 rc=rfc2047_print_unicodeaddr(a, charset, print_func, print_separator,
578 ptr);
579 rfc822a_free(a);
580 rfc822t_free(t);
581 return (rc);
582 }
583
584 struct rfc822_display_hdrvalue_s {
585
586 void (*display_func)(const char *, size_t, void *);
587 void *ptr;
588 };
589
590 static void rfc822_display_hdrvalue_print_func(char c, void *ptr)
591 {
592 struct rfc822_display_hdrvalue_s *s=
593 (struct rfc822_display_hdrvalue_s *)ptr;
594
595 (*s->display_func)(&c, 1, s->ptr);
596 }
597
598 static void rfc822_display_hdrvalue_print_separator(const char *cp, void *ptr)
599 {
600 struct rfc822_display_hdrvalue_s *s=
601 (struct rfc822_display_hdrvalue_s *)ptr;
602
603 (*s->display_func)(cp, strlen(cp), s->ptr);
604 (*s->display_func)("", 0, s->ptr); /* Signal wrap point */
605 }
606
607 int rfc822_display_hdrvalue(const char *hdrname,
608 const char *hdrvalue,
609 const char *charset,
610 void (*display_func)(const char *, size_t,
611 void *),
612 void (*err_func)(const char *, int, void *),
613 void *ptr)
614 {
615 struct rfc822_display_hdrvalue_s s;
616
617 s.display_func=display_func;
618 s.ptr=ptr;
619
620 if (rfc822hdr_is_addr(hdrname))
621 {
622 return rfc2047_print_unicode_addrstr(hdrvalue,
623 charset,
624 rfc822_display_hdrvalue_print_func,
625 rfc822_display_hdrvalue_print_separator,
626 NULL,
627 &s);
628 }
629
630 return rfc2047_decode_unicode(hdrvalue, charset, display_func, ptr);
631 }
632
633 struct rfc822_display_hdrvalue_tobuf_s {
634 void (*orig_err_func)(const char *, int, void *);
635 void *orig_ptr;
636
637 size_t cnt;
638 char *buf;
639 };
640
641 static void rfc822_display_hdrvalue_tobuf_cnt(const char *ptr, size_t cnt,
642 void *s)
643 {
644 ((struct rfc822_display_hdrvalue_tobuf_s *)s)->cnt += cnt;
645 }
646
647 static void rfc822_display_hdrvalue_tobuf_save(const char *ptr, size_t cnt,
648 void *s)
649 {
650 if (cnt)
651 memcpy(((struct rfc822_display_hdrvalue_tobuf_s *)s)->buf,
652 ptr, cnt);
653
654 ((struct rfc822_display_hdrvalue_tobuf_s *)s)->buf += cnt;
655 }
656
657 static void rfc822_display_hdrvalue_tobuf_errfunc(const char *ptr, int index,
658 void *s)
659 {
660 void (*f)(const char *, int, void *)=
661 ((struct rfc822_display_hdrvalue_tobuf_s *)s)->orig_err_func;
662
663 if (f)
664 f(ptr, index,
665 ((struct rfc822_display_hdrvalue_tobuf_s *)s)->orig_ptr);
666 }
667
668 char *rfc822_display_addr_tobuf(const struct rfc822a *rfcp, int index,
669 const char *chset)
670 {
671 struct rfc822_display_hdrvalue_tobuf_s nbuf;
672 int errcode;
673 char *ptr;
674
675 nbuf.buf=0;
676 nbuf.cnt=1;
677
678 errcode=rfc822_display_addr(rfcp, index, chset,
679 rfc822_display_hdrvalue_tobuf_cnt, &nbuf);
680
681 if (errcode < 0)
682 return NULL;
683
684 ptr=nbuf.buf=malloc(nbuf.cnt);
685 nbuf.cnt=0;
686 if (!ptr)
687 return NULL;
688
689 errcode=rfc822_display_addr(rfcp, index, chset,
690 rfc822_display_hdrvalue_tobuf_save, &nbuf);
691
692 if (errcode < 0)
693 {
694 free(nbuf.buf);
695 return NULL;
696 }
697 *nbuf.buf=0;
698 return ptr;
699 }
700
701 char *rfc822_display_hdrvalue_tobuf(const char *hdrname,
702 const char *hdrvalue,
703 const char *charset,
704 void (*err_func)(const char *, int,
705 void *),
706 void *ptr)
707 {
708 struct rfc822_display_hdrvalue_tobuf_s s;
709 int errcode;
710 char *bufptr;
711
712 s.orig_err_func=err_func;
713 s.orig_ptr=ptr;
714 s.cnt=1;
715
716 errcode=rfc822_display_hdrvalue(hdrname, hdrvalue, charset,
717 rfc822_display_hdrvalue_tobuf_cnt,
718 rfc822_display_hdrvalue_tobuf_errfunc,
719 &s);
720
721 if (errcode < 0)
722 return NULL;
723
724 bufptr=s.buf=malloc(s.cnt);
725
726 if (!bufptr)
727 return NULL;
728
729 errcode=rfc822_display_hdrvalue(hdrname, hdrvalue, charset,
730 rfc822_display_hdrvalue_tobuf_save,
731 rfc822_display_hdrvalue_tobuf_errfunc,
732 &s);
733 if (errcode)
734 {
735 free(bufptr);
736 return NULL;
737 }
738 *s.buf=0;
739 return bufptr;
740 }
741
742 char *rfc822_display_addr_str_tobuf(const char *tok, const char *chset)
743 {
744 struct rfc822_display_hdrvalue_tobuf_s s;
745 int errcode;
746 char *bufptr;
747
748 s.cnt=1;
749
750 errcode=rfc822_display_addr_str(tok, chset,
751 rfc822_display_hdrvalue_tobuf_cnt,
752 &s);
753
754 if (errcode < 0)
755 return NULL;
756
757 bufptr=s.buf=malloc(s.cnt);
758
759 if (!bufptr)
760 return NULL;
761
762 errcode=rfc822_display_addr_str(tok, chset,
763 rfc822_display_hdrvalue_tobuf_save,
764 &s);
765 if (errcode < 0)
766 {
767 free(bufptr);
768 return NULL;
769 }
770 *s.buf=0;
771 return bufptr;
772 }
773
774
775 static const char xdigit[]="0123456789ABCDEFabcdef";
776
777 static const unsigned char decode64tab[]={
778 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
779 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
780 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
781 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 99, 0, 0,
782 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
783 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
784 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
785 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0,
786 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
788 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
790 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
794 };
795
796 static int nyb(int c)
797 {
798 const char *p;
799 int n;
800
801 p=strchr(xdigit, c);
802
803 if (!p)
804 return 0;
805
806 n=p-xdigit;
807
808 if (n > 15)
809 n -= 6;
810
811 return n;
812 }
813
814 static size_t decodebase64(const char *ptr, size_t cnt,
815 char *dec_buf)
816 {
817 size_t i, j;
818 char a,b,c;
819 size_t k;
820
821 i=cnt / 4;
822 i=i*4;
823 k=0;
824 for (j=0; j<i; j += 4)
825 {
826 int w=decode64tab[(int)(unsigned char)ptr[j]];
827 int x=decode64tab[(int)(unsigned char)ptr[j+1]];
828 int y=decode64tab[(int)(unsigned char)ptr[j+2]];
829 int z=decode64tab[(int)(unsigned char)ptr[j+3]];
830
831 a= (w << 2) | (x >> 4);
832 b= (x << 4) | (y >> 2);
833 c= (y << 6) | z;
834 dec_buf[k++]=a;
835 if ( ptr[j+2] != '=')
836 dec_buf[k++]=b;
837 if ( ptr[j+3] != '=')
838 dec_buf[k++]=c;
839 }
840 return (k);
841 }
842
843
844 static ssize_t rfc822_decode_rfc2047_atom(const char *str,
845 size_t cnt,
846
847 void (*callback)(const char *,
848 const char *,
849 const char *,
850 size_t,
851 void *),
852 void *ptr)
853 {
854 const char *chset_str;
855 const char *enc_str;
856 const char *content_str;
857
858 char *chset;
859 char *lang;
860
861 char *content;
862
863 size_t i;
864 size_t j;
865 size_t k;
866
867 size_t content_len;
868
869 if (cnt < 2 || str[0] != '=' || str[1] != '?')
870 return 0;
871
872 chset_str=str+2;
873
874 for (i=2; i<cnt; i++)
875 if (str[i] == '?')
876 break;
877
878 if (i >= cnt)
879 return 0;
880
881 enc_str= str + ++i;
882
883 for (; i < cnt; i++)
884 if (str[i] == '?')
885 break;
886
887 if (i >= cnt)
888 return 0;
889
890 content_str= str + ++i;
891
892 while (1)
893 {
894 if (cnt-i < 2)
895 return 0;
896
897 if (str[i] == '?' && str[i+1] == '=')
898 break;
899 ++i;
900 }
901
902 for (j=0; chset_str[j] != '?'; ++j)
903 ;
904
905 chset=malloc(j+1);
906
907 if (!chset)
908 return -1;
909
910 memcpy(chset, chset_str, j);
911 chset[j]=0;
912
913 lang=strchr(chset, '*'); /* RFC 2231 */
914
915 if (lang)
916 *lang++ = 0;
917 else
918 lang="";
919
920 content_len=str + i - content_str;
921
922 content=malloc(content_len+1);
923
924 if (!content)
925 {
926 free(chset);
927 return -1;
928 }
929
930 switch (*enc_str) {
931 case 'q':
932 case 'Q':
933
934 k=0;
935 for (j=0; j<content_len; j++)
936 {
937 char c;
938
939 if (content_str[j] == '=' && i-j >= 3)
940 {
941 content[k]=(char)(nyb(content_str[j+1])*16 +
942 nyb(content_str[j+2]));
943 ++k;
944 j += 2;
945 continue;
946 }
947
948 c=content_str[j];
949 if (c == '_')
950 c=' ';
951 content[k]=c;
952 ++k;
953 }
954 break;
955
956 case 'b':
957 case 'B':
958 k=decodebase64(content_str, content_len, content);
959 break;
960 default:
961 free(content);
962 free(chset);
963 return (0);
964 }
965
966 if (callback)
967 (*callback)(chset, lang, content, k, ptr);
968 free(content);
969 free(chset);
970 return i + 2;
971 }
972
973 int rfc2047_decoder(const char *text,
974 void (*callback)(const char *chset,
975 const char *lang,
976 const char *content,
977 size_t cnt,
978 void *dummy),
979 void *ptr)
980 {
981 ssize_t rc;
982
983 while (text && *text)
984 {
985 size_t i;
986
987 for (i=0; text[i]; i++)
988 {
989 if (text[i] == '=' && text[i+1] == '?')
990 break;
991 }
992
993 if (i)
994 (*callback)("utf-8", "", text, i, ptr);
995
996 text += i;
997
998 if (!*text)
999 continue;
1000
1001 rc=rfc822_decode_rfc2047_atom(text, strlen(text),
1002 callback, ptr);
1003
1004 if (rc < 0)
1005 return -1;
1006
1007 if (rc == 0)
1008 {
1009 (*callback)("utf-8", "", text, 2, ptr);
1010 text += 2;
1011 continue;
1012 }
1013
1014 text += rc;
1015
1016 for (i=0; text[i]; i++)
1017 {
1018 if (strchr(" \t\r\n", text[i]) == NULL)
1019 break;
1020 }
1021
1022 if (text[i] != '=' || text[i+1] != '?')
1023 continue;
1024
1025 rc=rfc822_decode_rfc2047_atom(text+i, strlen(text+i), NULL,
1026 NULL);
1027
1028 if (rc < 0)
1029 return -1;
1030 if (rc > 0)
1031 text += i;
1032 }
1033
1034 return 0;
1035 }
1036
1037 static int rfc2047_decode_unicode(const char *text,
1038 const char *chset,
1039 void (*callback)(const char *, size_t,
1040 void *),
1041 void *ptr)
1042 {
1043 struct rfc822_display_name_s s;
1044
1045 s.chset=chset;
1046 s.print_func=callback;
1047 s.ptr=ptr;
1048
1049 return rfc2047_decoder(text, rfc822_display_addr_cb, &s);
1050 }