Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
8d138742 | 2 | ** Copyright 1998 - 2009 Double Precision, Inc. See COPYING for |
d9898ee8 | 3 | ** distribution information. |
4 | */ | |
5 | ||
b0322a85 | 6 | #include "rfc822.h" |
d9898ee8 | 7 | #include <stdio.h> |
8 | #include <ctype.h> | |
9 | #include <string.h> | |
10 | #include <stdlib.h> | |
11 | #include <errno.h> | |
12 | ||
8d138742 | 13 | #include "rfc822hdr.h" |
d9898ee8 | 14 | #include "rfc2047.h" |
8d138742 | 15 | #include "../unicode/unicode.h" |
d9898ee8 | 16 | |
8d138742 CE |
17 | #if LIBIDN |
18 | #include <idna.h> | |
19 | #include <stringprep.h> | |
20 | #endif | |
21 | ||
8d138742 CE |
22 | |
23 | static ssize_t rfc822_decode_rfc2047_atom(const char *str, | |
24 | size_t cnt, | |
d9898ee8 | 25 | |
8d138742 CE |
26 | void (*callback)(const char *, |
27 | const char *, | |
28 | const char *, | |
29 | size_t, | |
30 | void *), | |
31 | void *ptr); | |
d9898ee8 | 32 | |
8d138742 | 33 | static int rfc2047_decode_unicode(const char *text, |
b0322a85 | 34 | const char *chset, |
8d138742 CE |
35 | void (*callback)(const char *, size_t, |
36 | void *), | |
37 | void *ptr); | |
d9898ee8 | 38 | |
39 | struct decode_unicode_s { | |
b0322a85 | 40 | const char *mychset; |
d9898ee8 | 41 | |
42 | char *bufptr; | |
43 | size_t bufsize; | |
44 | } ; | |
45 | ||
8d138742 | 46 | static void save_unicode_text(const char *p, size_t l, void *ptr) |
d9898ee8 | 47 | { |
8d138742 CE |
48 | struct decode_unicode_s *s= |
49 | (struct decode_unicode_s *)ptr; | |
50 | ||
d9898ee8 | 51 | if (s->bufptr) |
52 | memcpy(s->bufptr+s->bufsize, p, l); | |
53 | ||
54 | s->bufsize += l; | |
55 | } | |
56 | ||
8d138742 | 57 | struct rfc822_display_name_s { |
b0322a85 | 58 | const char *chset; |
8d138742 CE |
59 | void (*print_func)(const char *, size_t, void *); |
60 | void *ptr; | |
61 | }; | |
62 | ||
63 | static void unknown_charset(const char *chset, | |
b0322a85 | 64 | const char *tochset, |
8d138742 CE |
65 | void (*print_func)(const char *, size_t, void *), |
66 | void *ptr) | |
d9898ee8 | 67 | { |
8d138742 | 68 | static const char unknown[]="[unknown character set: "; |
d9898ee8 | 69 | |
8d138742 CE |
70 | (*print_func)(unknown, sizeof(unknown)-1, ptr); |
71 | (*print_func)(chset, strlen(chset), ptr); | |
b0322a85 CE |
72 | (*print_func)(" -> ", 4, ptr); |
73 | (*print_func)(tochset, strlen(tochset), ptr); | |
8d138742 CE |
74 | (*print_func)("]", 1, ptr); |
75 | } | |
d9898ee8 | 76 | |
8d138742 CE |
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 | { | |
8d138742 CE |
83 | struct rfc822_display_name_s *s= |
84 | (struct rfc822_display_name_s *)dummy; | |
85 | char *ptr; | |
86 | char *buf; | |
d9898ee8 | 87 | |
8d138742 CE |
88 | buf=malloc(cnt+1); |
89 | ||
90 | if (!buf) | |
91 | return; | |
92 | ||
93 | memcpy(buf, content, cnt); | |
94 | buf[cnt]=0; | |
95 | ||
b0322a85 | 96 | ptr=libmail_u_convert_tobuf(buf, chset, s->chset, NULL); |
8d138742 CE |
97 | free(buf); |
98 | ||
99 | if (ptr) | |
d9898ee8 | 100 | { |
8d138742 CE |
101 | (*s->print_func)(ptr, strlen(ptr), s->ptr); |
102 | free(ptr); | |
d9898ee8 | 103 | } |
b0322a85 CE |
104 | else |
105 | { | |
106 | unknown_charset(chset, s->chset, s->print_func, s->ptr); | |
107 | return; | |
108 | } | |
8d138742 CE |
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; | |
d9898ee8 | 128 | |
8d138742 CE |
129 | if (!addrs->name) |
130 | return rfc822_display_addr(rfcp, index, chset, print_func, ptr); | |
131 | ||
132 | if (chset == NULL) | |
d9898ee8 | 133 | { |
b0322a85 | 134 | s.chset="iso-8859-1"; |
d9898ee8 | 135 | } |
8d138742 CE |
136 | else |
137 | { | |
b0322a85 | 138 | s.chset=chset; |
8d138742 CE |
139 | } |
140 | ||
141 | s.print_func=print_func; | |
142 | s.ptr=ptr; | |
d9898ee8 | 143 | |
8d138742 | 144 | for (i=addrs->name; i; i=i->next, prev_isatom=isatom) |
d9898ee8 | 145 | { |
8d138742 CE |
146 | isatom=rfc822_is_atom(i->token); |
147 | if (isatom && prev_isatom) | |
148 | (*print_func)(" ", 1, ptr); | |
149 | ||
150 | if (i->token == '"' || i->token == '(') | |
d9898ee8 | 151 | { |
8d138742 CE |
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", | |
b0322a85 | 194 | p, s.chset, |
8d138742 CE |
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 */ | |
d9898ee8 | 237 | } |
238 | } | |
8d138742 CE |
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; | |
d9898ee8 | 252 | |
8d138742 CE |
253 | if (!addrs->tokens) |
254 | return 0; | |
d9898ee8 | 255 | |
8d138742 CE |
256 | return rfc822_display_name_int(rfcp, index, chset, |
257 | print_func, ptr); | |
d9898ee8 | 258 | } |
259 | ||
8d138742 CE |
260 | char *rfc822_display_name_tobuf(const struct rfc822a *rfcp, int index, |
261 | const char *chset) | |
d9898ee8 | 262 | { |
263 | struct decode_unicode_s s; | |
8d138742 | 264 | char *p; |
d9898ee8 | 265 | |
266 | s.bufptr=0; | |
267 | s.bufsize=1; | |
268 | ||
8d138742 CE |
269 | if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0) |
270 | return NULL; | |
d9898ee8 | 271 | s.bufptr=p=malloc(s.bufsize); |
8d138742 | 272 | if (!p) |
d9898ee8 | 273 | return (0); |
274 | ||
275 | s.bufsize=0; | |
8d138742 | 276 | if (rfc822_display_name(rfcp, index, chset, save_unicode_text, &s) < 0) |
d9898ee8 | 277 | { |
8d138742 | 278 | free(s.bufptr); |
d9898ee8 | 279 | return (0); |
280 | } | |
8d138742 CE |
281 | save_unicode_text("", 1, &s); |
282 | ||
d9898ee8 | 283 | return (p); |
284 | } | |
285 | ||
8d138742 CE |
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; | |
d9898ee8 | 302 | |
8d138742 CE |
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) | |
d9898ee8 | 313 | { |
8d138742 | 314 | const char *p; |
8d138742 CE |
315 | |
316 | p=strchr(tok,'@'); | |
d9898ee8 | 317 | |
8d138742 CE |
318 | if (!p) |
319 | p=tok; | |
320 | else | |
321 | ++p; | |
d9898ee8 | 322 | |
b0322a85 | 323 | if (chset != NULL) |
8d138742 | 324 | { |
b0322a85 | 325 | int err=0; |
8d138742 CE |
326 | char *utf8_ptr; |
327 | ||
328 | if (p > tok) | |
329 | (*print_func)(tok, p-tok, ptr); | |
330 | ||
331 | #if LIBIDN | |
b0322a85 CE |
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 | ||
8d138742 CE |
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 | { | |
b0322a85 CE |
359 | char *q=libmail_u_convert_tobuf(utf8_ptr, |
360 | "utf-8", | |
361 | chset, NULL); | |
8d138742 CE |
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; | |
d9898ee8 | 379 | } |
380 | ||
8d138742 CE |
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) | |
d9898ee8 | 385 | { |
8d138742 CE |
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; | |
d9898ee8 | 405 | } |
406 | ||
8d138742 CE |
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; | |
d9898ee8 | 415 | |
8d138742 CE |
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 | ||
b0322a85 CE |
477 | cpbuf=libmail_u_convert_tobuf(nbuf.bufptr, "utf-8", charset, |
478 | NULL); | |
479 | ||
480 | if (!cpbuf) | |
8d138742 CE |
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 | { | |
8d138742 CE |
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 | ||
8d138742 CE |
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 | ||
b0322a85 | 630 | return rfc2047_decode_unicode(hdrvalue, charset, display_func, ptr); |
8d138742 CE |
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) | |
b0322a85 | 994 | (*callback)("iso-8859-1", "", text, i, ptr); |
8d138742 CE |
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 | { | |
b0322a85 | 1009 | (*callback)("iso-8859-1", "", text, 2, ptr); |
8d138742 CE |
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, | |
b0322a85 | 1038 | const char *chset, |
8d138742 CE |
1039 | void (*callback)(const char *, size_t, |
1040 | void *), | |
1041 | void *ptr) | |
1042 | { | |
1043 | struct rfc822_display_name_s s; | |
1044 | ||
b0322a85 | 1045 | s.chset=chset; |
8d138742 CE |
1046 | s.print_func=callback; |
1047 | s.ptr=ptr; | |
1048 | ||
1049 | return rfc2047_decoder(text, rfc822_display_addr_cb, &s); | |
1050 | } |