Imported Upstream version 0.66.1
[hcoop/debian/courier-authlib.git] / libs / rfc822 / rfc822.c
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
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
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
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
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
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
552 static void rfc822_print_common_nameaddr_cntlen(char c, void *p)
553 {
554 ++ *(size_t *)p;
555 }
556
557 static void rfc822_print_common_nameaddr_saveaddr(char c, void *p)
558 {
559 char **cp=(char **)p;
560
561 *(*cp)++=c;
562 }
563
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
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
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
762 void rfc822t_free(struct rfc822t *p)
763 {
764 if (p->tokens) free(p->tokens);
765 free(p);
766 }
767
768 void rfc822a_free(struct rfc822a *p)
769 {
770 if (p->addrs) free(p->addrs);
771 free(p);
772 }
773
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
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
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 }