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