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 
save_unicode_text(const char * p,size_t l,void * ptr)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 
unknown_charset(const char * chset,const char * tochset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc822_display_addr_cb(const char * chset,const char * lang,const char * content,size_t cnt,void * dummy)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
rfc822_display_name_int(const struct rfc822a * rfcp,int index,const char * chset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc822_display_name(const struct rfc822a * rfcp,int index,const char * chset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc822_display_name_tobuf(const struct rfc822a * rfcp,int index,const char * chset)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 
rfc822_display_namelist(const struct rfc822a * rfcp,const char * chset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc822_display_addr_str(const char * tok,const char * chset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc822_display_addr(const struct rfc822a * rfcp,int index,const char * chset,void (* print_func)(const char *,size_t,void *),void * ptr)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 
rfc2047_print_unicodeaddr(const struct rfc822a * a,const char * charset,void (* print_func)(char,void *),void (* print_separator)(const char *,void *),void * ptr)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 
rfc2047_print_unicode_addrstr(const char * addrheader,const char * charset,void (* print_func)(char,void *),void (* print_separator)(const char *,void *),void (* err_func)(const char *,int,void *),void * ptr)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 
rfc822_display_hdrvalue_print_func(char c,void * ptr)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 
rfc822_display_hdrvalue_print_separator(const char * cp,void * ptr)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 
rfc822_display_hdrvalue(const char * hdrname,const char * hdrvalue,const char * charset,void (* display_func)(const char *,size_t,void *),void (* err_func)(const char *,int,void *),void * ptr)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 
rfc822_display_hdrvalue_tobuf_cnt(const char * ptr,size_t cnt,void * s)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 
rfc822_display_hdrvalue_tobuf_save(const char * ptr,size_t cnt,void * s)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 
rfc822_display_hdrvalue_tobuf_errfunc(const char * ptr,int index,void * s)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 
rfc822_display_addr_tobuf(const struct rfc822a * rfcp,int index,const char * chset)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 
rfc822_display_hdrvalue_tobuf(const char * hdrname,const char * hdrvalue,const char * charset,void (* err_func)(const char *,int,void *),void * ptr)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 
rfc822_display_addr_str_tobuf(const char * tok,const char * chset)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 
nyb(int c)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 
decodebase64(const char * ptr,size_t cnt,char * dec_buf)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 
rfc822_decode_rfc2047_atom(const char * str,size_t cnt,void (* callback)(const char *,const char *,const char *,size_t,void *),void * ptr)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 
rfc2047_decoder(const char * text,void (* callback)(const char * chset,const char * lang,const char * content,size_t cnt,void * dummy),void * ptr)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 
rfc2047_decode_unicode(const char * text,const char * chset,void (* callback)(const char *,size_t,void *),void * ptr)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 }
1051