2 ** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for
3 ** distribution information.
12 #include <courier-unicode.h>
14 #include "rfc822hdr.h"
19 #include <stringprep.h>
23 static ssize_t
rfc822_decode_rfc2047_atom(const char *str
,
26 void (*callback
)(const char *,
33 static int rfc2047_decode_unicode(const char *text
,
35 void (*callback
)(const char *, size_t,
39 struct decode_unicode_s
{
46 static void save_unicode_text(const char *p
, size_t l
, void *ptr
)
48 struct decode_unicode_s
*s
=
49 (struct decode_unicode_s
*)ptr
;
52 memcpy(s
->bufptr
+s
->bufsize
, p
, l
);
57 struct rfc822_display_name_s
{
59 void (*print_func
)(const char *, size_t, void *);
63 static void unknown_charset(const char *chset
,
65 void (*print_func
)(const char *, size_t, void *),
68 static const char unknown
[]="[unknown character set: ";
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
);
77 static void rfc822_display_addr_cb(const char *chset
,
83 struct rfc822_display_name_s
*s
=
84 (struct rfc822_display_name_s
*)dummy
;
93 memcpy(buf
, content
, cnt
);
96 ptr
=unicode_convert_tobuf(buf
, chset
, s
->chset
, NULL
);
101 (*s
->print_func
)(ptr
, strlen(ptr
), s
->ptr
);
106 unknown_charset(chset
, s
->chset
, s
->print_func
, s
->ptr
);
112 int rfc822_display_name_int(const struct rfc822a
*rfcp
, int index
,
114 void (*print_func
)(const char *, size_t, void *),
117 struct rfc822_display_name_s s
;
118 const struct rfc822addr
*addrs
;
120 struct rfc822token
*i
;
125 if (index
< 0 || index
>= rfcp
->naddrs
) return 0;
127 addrs
=rfcp
->addrs
+index
;
130 return rfc822_display_addr(rfcp
, index
, chset
, print_func
, ptr
);
134 s
.chset
="iso-8859-1";
141 s
.print_func
=print_func
;
144 for (i
=addrs
->name
; i
; i
=i
->next
, prev_isatom
=isatom
)
146 isatom
=rfc822_is_atom(i
->token
);
147 if (isatom
&& prev_isatom
)
148 (*print_func
)(" ", 1, ptr
);
150 if (i
->token
== '"' || i
->token
== '(')
172 memcpy(p
, i
->ptr
+1, l
);
176 memcpy(p
, i
->ptr
, l
);
183 for (q
=r
=p
; *q
; *r
++ = *q
++)
184 if (*q
== '\\' && q
[1])
191 (*print_func
)(p
, strlen(p
), ptr
);
193 else if (rfc822_display_hdrvalue("subject",
207 char c
= (char)i
->token
;
209 (*print_func
)(&c
, 1, ptr
);
213 rc
=chset
? rfc822_decode_rfc2047_atom(i
->ptr
, i
->len
,
214 rfc822_display_addr_cb
,
222 (*print_func
)(i
->ptr
, i
->len
, ptr
);
226 if (i
->next
&& i
->next
->token
== 0)
228 rc
=rfc822_decode_rfc2047_atom(i
->next
->ptr
,
236 isatom
=0; /* Suppress the separating space */
242 int rfc822_display_name(const struct rfc822a
*rfcp
, int index
,
244 void (*print_func
)(const char *, size_t, void *),
247 const struct rfc822addr
*addrs
;
249 if (index
< 0 || index
>= rfcp
->naddrs
) return 0;
251 addrs
=rfcp
->addrs
+index
;
256 return rfc822_display_name_int(rfcp
, index
, chset
,
260 char *rfc822_display_name_tobuf(const struct rfc822a
*rfcp
, int index
,
263 struct decode_unicode_s s
;
269 if (rfc822_display_name(rfcp
, index
, chset
, save_unicode_text
, &s
) < 0)
271 s
.bufptr
=p
=malloc(s
.bufsize
);
276 if (rfc822_display_name(rfcp
, index
, chset
, save_unicode_text
, &s
) < 0)
281 save_unicode_text("", 1, &s
);
286 int rfc822_display_namelist(const struct rfc822a
*rfcp
,
288 void (*print_func
)(const char *, size_t, void *),
293 for (n
=0; n
<rfcp
->naddrs
; n
++)
295 if (rfcp
->addrs
[n
].tokens
)
297 int err
=rfc822_display_name(rfcp
, n
, chset
,
303 (*print_func
)("\n", 1, ptr
);
309 int rfc822_display_addr_str(const char *tok
,
311 void (*print_func
)(const char *, size_t, void *),
329 (*print_func
)(tok
, p
-tok
, ptr
);
333 ** Invalid UTF-8 can make libidn go off the deep end. Add
334 ** padding as a workaround.
337 size_t s
=strlen(p
)+16;
345 err
=idna_to_unicode_8z8z(cpy
, &utf8_ptr
, 0);
349 if (err
!= IDNA_SUCCESS
)
356 (*print_func
)(p
, strlen(p
), ptr
);
359 char *q
=unicode_convert_tobuf(utf8_ptr
,
364 (*print_func
)(q
, strlen(q
), ptr
);
369 (*print_func
)(p
, strlen(p
), ptr
);
376 (*print_func
)(tok
, strlen(tok
), ptr
);
381 int rfc822_display_addr(const struct rfc822a
*rfcp
, int index
,
383 void (*print_func
)(const char *, size_t, void *),
386 const struct rfc822addr
*addrs
;
390 if (index
< 0 || index
>= rfcp
->naddrs
) return 0;
392 addrs
=rfcp
->addrs
+index
;
397 tok
=rfc822_gettok(addrs
->tokens
);
402 rc
=rfc822_display_addr_str(tok
, chset
, print_func
, ptr
);
407 int rfc2047_print_unicodeaddr(const struct rfc822a
*a
,
409 void (*print_func
)(char, void *),
410 void (*print_separator
)(const char *, void *),
413 const char *sep
=NULL
;
416 for (n
=0; n
<a
->naddrs
; ++n
)
418 struct decode_unicode_s nbuf
;
419 const struct rfc822addr
*addrs
;
429 if (rfc822_display_name_int(a
, n
, charset
,
430 save_unicode_text
, &nbuf
) < 0)
433 nbuf
.bufptr
=malloc(nbuf
.bufsize
);
438 if (rfc822_display_name_int(a
, n
, charset
,
439 save_unicode_text
, &nbuf
) < 0)
444 nbuf
.bufptr
[nbuf
.bufsize
]=0;
446 if (addrs
->tokens
== 0)
450 if (nbuf
.bufsize
== 1) /* ; */
454 (*print_separator
)(sep
, ptr
);
456 for (i
=0; i
<nbuf
.bufsize
; ++i
)
457 (*print_func
)(nbuf
.bufptr
[i
], ptr
);
459 if (nbuf
.bufsize
> 1)
460 (*print_separator
)(" ", ptr
);
465 (*print_separator
)(sep
, ptr
);
473 for (i
=0; i
<nbuf
.bufsize
; i
++)
474 if (strchr(RFC822_SPECIALS
, nbuf
.bufptr
[i
]))
477 cpbuf
=unicode_convert_tobuf(nbuf
.bufptr
, "utf-8", charset
,
482 const char *errmsg
="\"(unknown character set)\"";
485 (*print_func
)(*errmsg
++, ptr
);
490 if (i
< nbuf
.bufsize
)
492 (*print_func
)('"', ptr
);
494 for (i
=0; cpbuf
[i
]; ++i
)
496 if (cpbuf
[i
] == '\\' ||
498 (*print_func
)('\\', ptr
);
499 (*print_func
)(cpbuf
[i
], ptr
);
501 (*print_func
)('"', ptr
);
506 for (i
=0; cpbuf
[i
]; ++i
)
509 (*print_func
)(cpbuf
[i
], ptr
);
519 (*print_func
)(' ', ptr
);
520 (*print_func
)('<', ptr
);
526 if (rfc822_display_addr(a
, n
, charset
,
527 save_unicode_text
, &nbuf
) < 0)
530 nbuf
.bufptr
=malloc(nbuf
.bufsize
);
535 if (rfc822_display_addr(a
, n
, charset
,
536 save_unicode_text
, &nbuf
) < 0)
541 for (i
=0; i
<nbuf
.bufsize
; i
++)
542 (*print_func
)(nbuf
.bufptr
[i
], ptr
);
547 (*print_func
)('>', ptr
);
554 static int rfc2047_print_unicode_addrstr(const char *addrheader
,
556 void (*print_func
)(char, void *),
557 void (*print_separator
)(const char *, void *),
558 void (*err_func
)(const char *, int, void *),
565 t
=rfc822t_alloc_new(addrheader
, err_func
, ptr
);
577 rc
=rfc2047_print_unicodeaddr(a
, charset
, print_func
, print_separator
,
584 struct rfc822_display_hdrvalue_s
{
586 void (*display_func
)(const char *, size_t, void *);
590 static void rfc822_display_hdrvalue_print_func(char c
, void *ptr
)
592 struct rfc822_display_hdrvalue_s
*s
=
593 (struct rfc822_display_hdrvalue_s
*)ptr
;
595 (*s
->display_func
)(&c
, 1, s
->ptr
);
598 static void rfc822_display_hdrvalue_print_separator(const char *cp
, void *ptr
)
600 struct rfc822_display_hdrvalue_s
*s
=
601 (struct rfc822_display_hdrvalue_s
*)ptr
;
603 (*s
->display_func
)(cp
, strlen(cp
), s
->ptr
);
604 (*s
->display_func
)("", 0, s
->ptr
); /* Signal wrap point */
607 int rfc822_display_hdrvalue(const char *hdrname
,
608 const char *hdrvalue
,
610 void (*display_func
)(const char *, size_t,
612 void (*err_func
)(const char *, int, void *),
615 struct rfc822_display_hdrvalue_s s
;
617 s
.display_func
=display_func
;
620 if (rfc822hdr_is_addr(hdrname
))
622 return rfc2047_print_unicode_addrstr(hdrvalue
,
624 rfc822_display_hdrvalue_print_func
,
625 rfc822_display_hdrvalue_print_separator
,
630 return rfc2047_decode_unicode(hdrvalue
, charset
, display_func
, ptr
);
633 struct rfc822_display_hdrvalue_tobuf_s
{
634 void (*orig_err_func
)(const char *, int, void *);
641 static void rfc822_display_hdrvalue_tobuf_cnt(const char *ptr
, size_t cnt
,
644 ((struct rfc822_display_hdrvalue_tobuf_s
*)s
)->cnt
+= cnt
;
647 static void rfc822_display_hdrvalue_tobuf_save(const char *ptr
, size_t cnt
,
651 memcpy(((struct rfc822_display_hdrvalue_tobuf_s
*)s
)->buf
,
654 ((struct rfc822_display_hdrvalue_tobuf_s
*)s
)->buf
+= cnt
;
657 static void rfc822_display_hdrvalue_tobuf_errfunc(const char *ptr
, int index
,
660 void (*f
)(const char *, int, void *)=
661 ((struct rfc822_display_hdrvalue_tobuf_s
*)s
)->orig_err_func
;
665 ((struct rfc822_display_hdrvalue_tobuf_s
*)s
)->orig_ptr
);
668 char *rfc822_display_addr_tobuf(const struct rfc822a
*rfcp
, int index
,
671 struct rfc822_display_hdrvalue_tobuf_s nbuf
;
678 errcode
=rfc822_display_addr(rfcp
, index
, chset
,
679 rfc822_display_hdrvalue_tobuf_cnt
, &nbuf
);
684 ptr
=nbuf
.buf
=malloc(nbuf
.cnt
);
689 errcode
=rfc822_display_addr(rfcp
, index
, chset
,
690 rfc822_display_hdrvalue_tobuf_save
, &nbuf
);
701 char *rfc822_display_hdrvalue_tobuf(const char *hdrname
,
702 const char *hdrvalue
,
704 void (*err_func
)(const char *, int,
708 struct rfc822_display_hdrvalue_tobuf_s s
;
712 s
.orig_err_func
=err_func
;
716 errcode
=rfc822_display_hdrvalue(hdrname
, hdrvalue
, charset
,
717 rfc822_display_hdrvalue_tobuf_cnt
,
718 rfc822_display_hdrvalue_tobuf_errfunc
,
724 bufptr
=s
.buf
=malloc(s
.cnt
);
729 errcode
=rfc822_display_hdrvalue(hdrname
, hdrvalue
, charset
,
730 rfc822_display_hdrvalue_tobuf_save
,
731 rfc822_display_hdrvalue_tobuf_errfunc
,
742 char *rfc822_display_addr_str_tobuf(const char *tok
, const char *chset
)
744 struct rfc822_display_hdrvalue_tobuf_s s
;
750 errcode
=rfc822_display_addr_str(tok
, chset
,
751 rfc822_display_hdrvalue_tobuf_cnt
,
757 bufptr
=s
.buf
=malloc(s
.cnt
);
762 errcode
=rfc822_display_addr_str(tok
, chset
,
763 rfc822_display_hdrvalue_tobuf_save
,
775 static const char xdigit
[]="0123456789ABCDEFabcdef";
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
796 static int nyb(int c
)
814 static size_t decodebase64(const char *ptr
, size_t cnt
,
824 for (j
=0; j
<i
; j
+= 4)
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]];
831 a
= (w
<< 2) | (x
>> 4);
832 b
= (x
<< 4) | (y
>> 2);
835 if ( ptr
[j
+2] != '=')
837 if ( ptr
[j
+3] != '=')
844 static ssize_t
rfc822_decode_rfc2047_atom(const char *str
,
847 void (*callback
)(const char *,
854 const char *chset_str
;
856 const char *content_str
;
869 if (cnt
< 2 || str
[0] != '=' || str
[1] != '?')
874 for (i
=2; i
<cnt
; i
++)
890 content_str
= str
+ ++i
;
897 if (str
[i
] == '?' && str
[i
+1] == '=')
902 for (j
=0; chset_str
[j
] != '?'; ++j
)
910 memcpy(chset
, chset_str
, j
);
913 lang
=strchr(chset
, '*'); /* RFC 2231 */
920 content_len
=str
+ i
- content_str
;
922 content
=malloc(content_len
+1);
935 for (j
=0; j
<content_len
; j
++)
939 if (content_str
[j
] == '=' && i
-j
>= 3)
941 content
[k
]=(char)(nyb(content_str
[j
+1])*16 +
942 nyb(content_str
[j
+2]));
958 k
=decodebase64(content_str
, content_len
, content
);
967 (*callback
)(chset
, lang
, content
, k
, ptr
);
973 int rfc2047_decoder(const char *text
,
974 void (*callback
)(const char *chset
,
983 while (text
&& *text
)
987 for (i
=0; text
[i
]; i
++)
989 if (text
[i
] == '=' && text
[i
+1] == '?')
994 (*callback
)("iso-8859-1", "", text
, i
, ptr
);
1001 rc
=rfc822_decode_rfc2047_atom(text
, strlen(text
),
1009 (*callback
)("iso-8859-1", "", text
, 2, ptr
);
1016 for (i
=0; text
[i
]; i
++)
1018 if (strchr(" \t\r\n", text
[i
]) == NULL
)
1022 if (text
[i
] != '=' || text
[i
+1] != '?')
1025 rc
=rfc822_decode_rfc2047_atom(text
+i
, strlen(text
+i
), NULL
,
1037 static int rfc2047_decode_unicode(const char *text
,
1039 void (*callback
)(const char *, size_t,
1043 struct rfc822_display_name_s s
;
1046 s
.print_func
=callback
;
1049 return rfc2047_decoder(text
, rfc822_display_addr_cb
, &s
);