1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 /*
7 */
8 #include	"rfc822.h"
9 #include	<stdio.h>
10 #include	<ctype.h>
11 #include	<stdlib.h>
12 #include	<string.h>
13 
tokenize(const char * p,struct rfc822token * tokp,int * toklen,void (* err_func)(const char *,int,void *),void * voidp)14 static void tokenize(const char *p, struct rfc822token *tokp, int *toklen,
15 	void (*err_func)(const char *, int, void *), void *voidp)
16 {
17 const char *addr=p;
18 int	i=0;
19 int	inbracket=0;
20 
21 	*toklen=0;
22 	while (*p)
23 	{
24 		if (isspace((int)(unsigned char)*p))
25 		{
26 			p++;
27 			i++;
28 			continue;
29 		}
30 
31 #define SPECIALS "<>@,;:.[]()%!\"\\?=/"
32 
33 		switch (*p)	{
34 		int	level;
35 
36 		case '(':
37 			if (tokp)
38 			{
39 				tokp->token='(';
40 				tokp->ptr=p;
41 				tokp->len=0;
42 			}
43 			level=0;
44 			for (;;)
45 			{
46 				if (!*p)
47 				{
48 					if (err_func) (*err_func)(addr, i,
49 								  voidp);
50 					if (tokp) tokp->token='"';
51 					++*toklen;
52 					return;
53 				}
54 				if (*p == '(')
55 					++level;
56 				if (*p == ')' && --level == 0)
57 				{
58 					p++;
59 					i++;
60 					if (tokp)	tokp->len++;
61 					break;
62 				}
63 				if (*p == '\\' && p[1])
64 				{
65 					p++;
66 					i++;
67 					if (tokp)	tokp->len++;
68 				}
69 
70 				i++;
71 				if (tokp)	tokp->len++;
72 				p++;
73 			}
74 			if (tokp)	++tokp;
75 			++*toklen;
76 			continue;
77 
78 		case '"':
79 			p++;
80 			i++;
81 
82 			if (tokp)
83 			{
84 				tokp->token='"';
85 				tokp->ptr=p;
86 			}
87 			while (*p != '"')
88 			{
89 				if (!*p)
90 				{
91 					if (err_func) (*err_func)(addr, i,
92 								  voidp);
93 					++*toklen;
94 					return;
95 				}
96 				if (*p == '\\' && p[1])
97 				{
98 					if (tokp)	tokp->len++;
99 					p++;
100 					i++;
101 				}
102 				if (tokp)	tokp->len++;
103 				p++;
104 				i++;
105 			}
106 			++*toklen;
107 			if (tokp)	++tokp;
108 			p++;
109 			i++;
110 			continue;
111 		case '\\':
112 		case ')':
113 			if (err_func) (*err_func)(addr, i, voidp);
114 			++p;
115 			++i;
116 			continue;
117 
118 		case '=':
119 
120 			if (p[1] == '?')
121 			{
122 				int j;
123 
124 			/* exception: =? ... ?= */
125 
126 				for (j=2; p[j]; j++)
127 				{
128 					if (p[j] == '?' && p[j+1] == '=')
129 						break;
130 
131 					if (p[j] == '?' || p[j] == '=')
132 						continue;
133 
134 					if (strchr(RFC822_SPECIALS, p[j]) ||
135 					    isspace(p[j]))
136 						break;
137 				}
138 
139 				if (p[j] == '?' && p[j+1] == '=')
140 				{
141 					j += 2;
142 					if (tokp)
143 					{
144 						tokp->token=0;
145 						tokp->ptr=p;
146 						tokp->len=j;
147 						++tokp;
148 					}
149 					++*toklen;
150 
151 					p += j;
152 					i += j;
153 					continue;
154 				}
155 			}
156 			/* FALLTHROUGH */
157 
158 		case '<':
159 		case '>':
160 		case '@':
161 		case ',':
162 		case ';':
163 		case ':':
164 		case '.':
165 		case '[':
166 		case ']':
167 		case '%':
168 		case '!':
169 		case '?':
170 		case '/':
171 
172 			if ( (*p == '<' && inbracket) ||
173 				(*p == '>' && !inbracket))
174 			{
175 				if (err_func) (*err_func)(addr, i, voidp);
176 				++p;
177 				++i;
178 				continue;
179 			}
180 
181 			if (*p == '<')
182 				inbracket=1;
183 
184 			if (*p == '>')
185 				inbracket=0;
186 
187 			if (tokp)
188 			{
189 				tokp->token= *p;
190 				tokp->ptr=p;
191 				tokp->len=1;
192 				++tokp;
193 			}
194 			++*toklen;
195 
196 			if (*p == '<' && p[1] == '>')
197 					/* Fake a null address */
198 			{
199 				if (tokp)
200 				{
201 					tokp->token=0;
202 					tokp->ptr="";
203 					tokp->len=0;
204 					++tokp;
205 				}
206 				++*toklen;
207 			}
208 			++p;
209 			++i;
210 			continue;
211 		default:
212 
213 			if (tokp)
214 			{
215 				tokp->token=0;
216 				tokp->ptr=p;
217 				tokp->len=0;
218 			}
219 			while (*p && !isspace((int)(unsigned char)*p) && strchr(
220 				SPECIALS, *p) == 0)
221 			{
222 				if (tokp)	++tokp->len;
223 				++p;
224 				++i;
225 			}
226 			if (i == 0)	/* Idiot check */
227 			{
228 				if (err_func) (*err_func)(addr, i, voidp);
229 				if (tokp)
230 				{
231 					tokp->token='"';
232 					tokp->ptr=p;
233 					tokp->len=1;
234 					++tokp;
235 				}
236 				++*toklen;
237 				++p;
238 				++i;
239 				continue;
240 			}
241 			if (tokp)	++tokp;
242 			++*toklen;
243 		}
244 	}
245 }
246 
parseaddr(struct rfc822token * tokens,int ntokens,struct rfc822addr * addrs,int * naddrs)247 static void parseaddr(struct rfc822token *tokens, int ntokens,
248 		struct rfc822addr *addrs, int *naddrs)
249 {
250 int	flag, j, k;
251 
252 	*naddrs=0;
253 
254 	while (ntokens)
255 	{
256 	int	i;
257 
258 		/* atoms (token=0) or quoted strings, followed by a : token
259 		is a list name. */
260 
261 		for (i=0; i<ntokens; i++)
262 			if (tokens[i].token && tokens[i].token != '"')
263 				break;
264 		if (i < ntokens && tokens[i].token == ':')
265 		{
266 			++i;
267 			if (addrs)
268 			{
269 				addrs->tokens=0;
270 				addrs->name=i ? tokens:0;
271 				for (j=1; j<i; j++)
272 					addrs->name[j-1].next=addrs->name+j;
273 				if (i)
274 					addrs->name[i-1].next=0;
275 				addrs++;
276 			}
277 			++*naddrs;
278 			tokens += i;
279 			ntokens -= i;
280 			continue;  /* Group=phrase ":" */
281 		}
282 
283 		/* Spurious commas are skipped, ;s are recorded */
284 
285 		if (tokens->token == ',' || tokens->token == ';')
286 		{
287 			if (tokens->token == ';')
288 			{
289 				if (addrs)
290 				{
291 					addrs->tokens=0;
292 					addrs->name=tokens;
293 					addrs->name->next=0;
294 					addrs++;
295 				}
296 				++*naddrs;
297 			}
298 			++tokens;
299 			--ntokens;
300 			continue;
301 		}
302 
303 		/* If we can find a '<' before the next comma or semicolon,
304 		we have new style RFC path address */
305 
306 		for (i=0; i<ntokens && tokens[i].token != ';' &&
307 				tokens[i].token != ',' &&
308 					tokens[i].token != '<'; i++)
309 			;
310 
311 		if (i < ntokens && tokens[i].token == '<')
312 		{
313 		int	j;
314 
315 			/* Ok -- what to do with the stuff before '>'???
316 			If it consists exclusively of atoms, leave them alone.
317 			Else, make them all a quoted string. */
318 
319                         for (j=0; j<i && (tokens[j].token == 0 ||
320                                           tokens[j].token == '('); j++)
321                                 ;
322 
323 			if (j == i)
324 			{
325 				if (addrs)
326 				{
327 					addrs->name= i ? tokens:0;
328 					for (k=1; k<i; k++)
329 						addrs->name[k-1].next=addrs->name+k;
330 					if (i)
331 						addrs->name[i-1].next=0;
332 				}
333 			}
334 			else	/* Intentionally corrupt the original toks */
335 			{
336 				if (addrs)
337 				{
338 					tokens->len= tokens[i-1].ptr
339 							+ tokens[i-1].len
340 							- tokens->ptr;
341 					/* We know that all the ptrs point
342 					to parts of the same string. */
343 					tokens->token='"';
344 						/* Quoted string. */
345 					addrs->name=tokens;
346 					addrs->name->next=0;
347 				}
348 			}
349 
350 		/* Any comments in the name part are changed to quotes */
351 
352 			if (addrs)
353 			{
354 			struct rfc822token *t;
355 
356 				for (t=addrs->name; t; t=t->next)
357 					if (t->token == '(')
358 						t->token='"';
359 			}
360 
361 			/* Now that's done and over with, see what can
362 			be done with the <...> part. */
363 
364 			++i;
365 			tokens += i;
366 			ntokens -= i;
367 			for (i=0; i<ntokens && tokens[i].token != '>'; i++)
368 				;
369 			if (addrs)
370 			{
371 				addrs->tokens=i ? tokens:0;
372 				for (k=1; k<i; k++)
373 					addrs->tokens[k-1].next=addrs->tokens+k;
374 				if (i)
375 					addrs->tokens[i-1].next=0;
376 				++addrs;
377 			}
378 			++*naddrs;
379 			tokens += i;
380 			ntokens -= i;
381 			if (ntokens)	/* Skip the '>' token */
382 			{
383 				--ntokens;
384 				++tokens;
385 			}
386 			continue;
387 		}
388 
389 		/* Ok - old style address.  Assume the worst */
390 
391 		/* Try to figure out where the address ends.  It ends upon:
392 		a comma, semicolon, or two consecutive atoms. */
393 
394 		flag=0;
395 		for (i=0; i<ntokens && tokens[i].token != ',' &&
396 			tokens[i].token != ';'; i++)
397 		{
398 			if (tokens[i].token == '(')	continue;
399 					/* Ignore comments */
400 			if (tokens[i].token == 0 || tokens[i].token == '"')
401 								/* Atom */
402 			{
403 				if (flag)	break;
404 				flag=1;
405 			}
406 			else	flag=0;
407 		}
408 		if (i == 0)	/* Must be spurious comma, or something */
409 		{
410 			++tokens;
411 			--ntokens;
412 			continue;
413 		}
414 
415 		if (addrs)
416 		{
417 			addrs->name=0;
418 		}
419 
420 		/* Ok, now get rid of embedded comments in the address.
421 		Consider the last comment to be the real name */
422 
423 		if (addrs)
424 		{
425 			struct	rfc822token	save_token;
426 
427 			memset(&save_token, 0, sizeof(save_token));
428 
429 			for (j=k=0; j<i; j++)
430 			{
431 				if (tokens[j].token == '(')
432 				{
433 					save_token=tokens[j];
434 					continue;
435 				}
436 				tokens[k]=tokens[j];
437 				k++;
438 			}
439 
440 			if (save_token.ptr)
441 			{
442 				tokens[i-1]=save_token;
443 				addrs->name=tokens+i-1;
444 				addrs->name->next=0;
445 			}
446 			addrs->tokens=k ? tokens:NULL;
447 			for (j=1; j<k; j++)
448 				addrs->tokens[j-1].next=addrs->tokens+j;
449 			if (k)
450 				addrs->tokens[k-1].next=0;
451 			++addrs;
452 		}
453 		++*naddrs;
454 		tokens += i;
455 		ntokens -= i;
456 	}
457 }
458 
print_token(const struct rfc822token * token,void (* print_func)(char,void *),void * ptr)459 static void print_token(const struct rfc822token *token,
460 		void (*print_func)(char, void *), void *ptr)
461 {
462 const char *p;
463 int	n;
464 
465 	if (token->token == 0 || token->token == '(')
466 	{
467 		for (n=token->len, p=token->ptr; n; --n, ++p)
468 			(*print_func)(*p, ptr);
469 		return;
470 	}
471 
472 	if (token->token != '"')
473 	{
474 		(*print_func)(token->token, ptr);
475 		return;
476 	}
477 
478 	(*print_func)('"', ptr);
479 	n=token->len;
480 	p=token->ptr;
481 	while (n)
482 	{
483 		if (*p == '"' || (*p == '\\' && n == 1)) (*print_func)('\\', ptr);
484 		if (*p == '\\' && n > 1)
485 		{
486 			(*print_func)('\\', ptr);
487 			++p;
488 			--n;
489 		}
490 		(*print_func)(*p++, ptr);
491 		--n;
492 	}
493 	(*print_func)('"', ptr);
494 }
495 
rfc822tok_print(const struct rfc822token * token,void (* print_func)(char,void *),void * ptr)496 void rfc822tok_print(const struct rfc822token *token,
497 		void (*print_func)(char, void *), void *ptr)
498 {
499 int	prev_isatom=0;
500 int	isatom;
501 
502 	while (token)
503 	{
504 		isatom=rfc822_is_atom(token->token);
505 		if (prev_isatom && isatom)
506 			(*print_func)(' ', ptr);
507 		print_token(token, print_func, ptr);
508 		prev_isatom=isatom;
509 		token=token->next;
510 	}
511 }
512 
rfc822_prname_int(const struct rfc822addr * addrs,void (* print_func)(char,void *),void * ptr)513 static void rfc822_prname_int(const struct rfc822addr *addrs,
514 			      void (*print_func)(char, void *),
515 			      void *ptr)
516 
517 {
518 	struct rfc822token *i;
519 	int n;
520 	int	prev_isatom=0;
521 	int	isatom=0;
522 
523 	for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
524 	{
525 		isatom=rfc822_is_atom(i->token);
526 		if (isatom && prev_isatom)
527 			(*print_func)(' ', ptr);
528 
529 		if (i->token == '"')
530 		{
531 			for (n=0; n<i->len; n++)
532 			{
533 				if (i->ptr[n] == '\\' &&
534 				    n + 1 < i->len)
535 					++n;
536 				(*print_func)(i->ptr[n], ptr);
537 			}
538 			continue;
539 		}
540 
541 		if (i->token != '(')
542 		{
543 			print_token(i, print_func, ptr);
544 			continue;
545 		}
546 
547 		for (n=2; n<i->len; n++)
548 			(*print_func)(i->ptr[n-1], ptr);
549 	}
550 }
551 
rfc822_print_common_nameaddr_cntlen(char c,void * p)552 static void rfc822_print_common_nameaddr_cntlen(char c, void *p)
553 {
554 	++ *(size_t *)p;
555 }
556 
rfc822_print_common_nameaddr_saveaddr(char c,void * p)557 static void rfc822_print_common_nameaddr_saveaddr(char c, void *p)
558 {
559 	char **cp=(char **)p;
560 
561 	*(*cp)++=c;
562 }
563 
rfc822_print_common_nameaddr(const struct rfc822addr * addrs,char * (* decode_func)(const char *,const char *,int),const char * chset,void (* print_func)(char,void *),void * ptr)564 static int rfc822_print_common_nameaddr(const struct rfc822addr *addrs,
565 					char *(*decode_func)(const char *,
566 							     const char *, int),
567 					const char *chset,
568 					void (*print_func)(char, void *),
569 					void *ptr)
570 {
571 	size_t n=1;
572 	char *addrbuf, *namebuf;
573 	char *p, *q;
574 	int print_braces=0;
575 
576 	if (addrs->tokens)
577 		rfc822tok_print(addrs->tokens,
578 				rfc822_print_common_nameaddr_cntlen, &n);
579 
580 
581 	p=addrbuf=malloc(n);
582 
583 	if (!addrbuf)
584 		return -1;
585 
586 	if (addrs->tokens)
587 		rfc822tok_print(addrs->tokens,
588 				rfc822_print_common_nameaddr_saveaddr, &p);
589 
590 	*p=0;
591 
592 	n=1;
593 
594 	rfc822_prname_int(addrs,
595 			  rfc822_print_common_nameaddr_cntlen, &n);
596 
597 	p=namebuf=malloc(n);
598 
599 	if (!p)
600 	{
601 		free(addrbuf);
602 		return -1;
603 	}
604 
605 	rfc822_prname_int(addrs,
606 			  rfc822_print_common_nameaddr_saveaddr, &p);
607 
608 	*p=0;
609 
610 	p=(*decode_func)(namebuf, chset, 0);
611 
612 	free(namebuf);
613 	if (!p)
614 	{
615 		free(addrbuf);
616 		return -1;
617 	}
618 
619 	for (namebuf=p; *p; p++)
620 	{
621 		print_braces=1;
622 		(*print_func)(*p, ptr);
623 	}
624 	free(namebuf);
625 
626 	p=(*decode_func)(addrbuf, chset, 1);
627 	free(addrbuf);
628 
629 	if (!p)
630 		return -1;
631 
632 	if (print_braces)
633 		(*print_func)(' ', ptr);
634 
635 	for (q=p; *q; ++q)
636 		if (*q != '.' && *q != '@' && strchr(RFC822_SPECIALS, *q))
637 		{
638 			print_braces=1;
639 			break;
640 		}
641 
642 	if (print_braces)
643 		(*print_func)('<', ptr);
644 
645 	for (addrbuf=p; *p; p++)
646 		(*print_func)(*p, ptr);
647 
648 	if (print_braces)
649 		(*print_func)('>', ptr);
650 
651 	free(addrbuf);
652 	return (0);
653 }
654 
rfc822_print(const struct rfc822a * rfcp,void (* print_func)(char,void *),void (* print_separator)(const char * s,void *),void * ptr)655 int rfc822_print(const struct rfc822a *rfcp, void (*print_func)(char, void *),
656 	void (*print_separator)(const char *s, void *), void *ptr)
657 {
658 	return rfc822_print_common(rfcp, 0, 0, print_func, print_separator, ptr);
659 }
660 
rfc822_print_common(const struct rfc822a * rfcp,char * (* decode_func)(const char *,const char *,int),const char * chset,void (* print_func)(char,void *),void (* print_separator)(const char *,void *),void * ptr)661 int rfc822_print_common(const struct rfc822a *rfcp,
662 			char *(*decode_func)(const char *, const char *, int),
663 			const char *chset,
664 			void (*print_func)(char, void *),
665 			void (*print_separator)(const char *, void *),
666 			void *ptr)
667 {
668 const struct rfc822addr *addrs=rfcp->addrs;
669 int naddrs=rfcp->naddrs;
670 
671 	while (naddrs)
672 	{
673 		if (addrs->tokens == 0)
674 		{
675 			rfc822tok_print(addrs->name, print_func, ptr);
676 			++addrs;
677 			--naddrs;
678 			if (addrs[-1].name && naddrs)
679 			{
680 			struct	rfc822token *t;
681 
682 				for (t=addrs[-1].name; t && t->next; t=t->next)
683 					;
684 
685 				if (t && (t->token == ':' || t->token == ';'))
686 					(*print_separator)(" ", ptr);
687 			}
688 			continue;
689 		}
690 		else if (addrs->name && addrs->name->token == '(')
691 		{	/* old style */
692 
693 			if (!decode_func)
694 			{
695 				rfc822tok_print(addrs->tokens, print_func, ptr);
696 				(*print_func)(' ', ptr);
697 				rfc822tok_print(addrs->name, print_func, ptr);
698 			}
699 			else
700 			{
701 				if (rfc822_print_common_nameaddr(addrs,
702 								 decode_func,
703 								 chset,
704 								 print_func,
705 								 ptr) < 0)
706 					return -1;
707 			}
708 		}
709 		else
710 		{
711 			if (!decode_func)
712 			{
713 				int	print_braces=0;
714 
715 				if (addrs->name)
716 				{
717 					rfc822tok_print(addrs->name,
718 							print_func, ptr);
719 					(*print_func)(' ', ptr);
720 					print_braces=1;
721 				}
722 #if 1
723 				else
724 				{
725 					struct rfc822token *p;
726 
727 					for (p=addrs->tokens; p && p->next; p=p->next)
728 						if (rfc822_is_atom(p->token) &&
729 						    rfc822_is_atom(p->next->token))
730 							print_braces=1;
731 				}
732 #endif
733 
734 				if (print_braces)
735 					(*print_func)('<', ptr);
736 
737 				rfc822tok_print(addrs->tokens, print_func, ptr);
738 
739 				if (print_braces)
740 					(*print_func)('>', ptr);
741 			}
742 			else
743 			{
744 				if (rfc822_print_common_nameaddr(addrs,
745 								 decode_func,
746 								 chset,
747 								 print_func,
748 								 ptr) < 0)
749 					return -1;
750 			}
751 		}
752 		++addrs;
753 		--naddrs;
754 		if (naddrs)
755 			if (addrs->tokens || (addrs->name &&
756 				rfc822_is_atom(addrs->name->token)))
757 				(*print_separator)(", ", ptr);
758 	}
759 	return 0;
760 }
761 
rfc822t_free(struct rfc822t * p)762 void rfc822t_free(struct rfc822t *p)
763 {
764 	if (p->tokens)	free(p->tokens);
765 	free(p);
766 }
767 
rfc822a_free(struct rfc822a * p)768 void rfc822a_free(struct rfc822a *p)
769 {
770 	if (p->addrs)	free(p->addrs);
771 	free(p);
772 }
773 
rfc822_deladdr(struct rfc822a * rfcp,int index)774 void rfc822_deladdr(struct rfc822a *rfcp, int index)
775 {
776 int	i;
777 
778 	if (index < 0 || index >= rfcp->naddrs)	return;
779 
780 	for (i=index+1; i<rfcp->naddrs; i++)
781 		rfcp->addrs[i-1]=rfcp->addrs[i];
782 	if (--rfcp->naddrs == 0)
783 	{
784 		free(rfcp->addrs);
785 		rfcp->addrs=0;
786 	}
787 }
788 
rfc822t_alloc_new(const char * addr,void (* err_func)(const char *,int,void *),void * voidp)789 struct rfc822t *rfc822t_alloc_new(const char *addr,
790 	void (*err_func)(const char *, int, void *), void *voidp)
791 {
792 struct rfc822t *p=(struct rfc822t *)malloc(sizeof(struct rfc822t));
793 
794 	if (!p)	return (NULL);
795 	memset(p, 0, sizeof(*p));
796 
797 	tokenize(addr, NULL, &p->ntokens, err_func, voidp);
798 	p->tokens=p->ntokens ? (struct rfc822token *)
799 			calloc(p->ntokens, sizeof(struct rfc822token)):0;
800 	if (p->ntokens && !p->tokens)
801 	{
802 		rfc822t_free(p);
803 		return (NULL);
804 	}
805 	tokenize(addr, p->tokens, &p->ntokens, NULL, NULL);
806 	return (p);
807 }
808 
rfc822a_alloc(struct rfc822t * t)809 struct rfc822a *rfc822a_alloc(struct rfc822t *t)
810 {
811 struct rfc822a *p=(struct rfc822a *)malloc(sizeof(struct rfc822a));
812 
813 	if (!p)	return (NULL);
814 	memset(p, 0, sizeof(*p));
815 
816 	parseaddr(t->tokens, t->ntokens, NULL, &p->naddrs);
817 	p->addrs=p->naddrs ? (struct rfc822addr *)
818 			calloc(p->naddrs, sizeof(struct rfc822addr)):0;
819 	if (p->naddrs && !p->addrs)
820 	{
821 		rfc822a_free(p);
822 		return (NULL);
823 	}
824 	parseaddr(t->tokens, t->ntokens, p->addrs, &p->naddrs);
825 	return (p);
826 }
827