Import Debian package 0.61.0-1+lenny1
[hcoop/debian/courier-authlib.git] / rfc822 / rfc822.c
CommitLineData
d9898ee8 1/*
2** Copyright 1998 - 2007 Double Precision, Inc.
3** See COPYING for distribution information.
4*/
5
6/*
7** $Id: rfc822.c,v 1.21 2007/02/26 04:13:41 mrsam Exp $
8*/
9#include <stdio.h>
10#include <ctype.h>
11#include <stdlib.h>
12#include <string.h>
13#include "rfc822.h"
14
15static void tokenize(const char *p, struct rfc822token *tokp, int *toklen,
16 void (*err_func)(const char *, int, void *), void *voidp)
17{
18const char *addr=p;
19int i=0;
20int 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(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
248static void parseaddr(struct rfc822token *tokens, int ntokens,
249 struct rfc822addr *addrs, int *naddrs)
250{
251int 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
460static void print_token(const struct rfc822token *token,
461 void (*print_func)(char, void *), void *ptr)
462{
463const char *p;
464int 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
497void rfc822tok_print(const struct rfc822token *token,
498 void (*print_func)(char, void *), void *ptr)
499{
500int prev_isatom=0;
501int 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
514void rfc822_print(const struct rfc822a *rfcp, void (*print_func)(char, void *),
515 void (*print_separator)(const char *s, void *), void *ptr)
516{
517 rfc822_print_common(rfcp, 0, 0, print_func, print_separator, ptr);
518}
519
520void rfc822_print_common(const struct rfc822a *rfcp,
521 char *(*decode_func)(const char *, const char *), const char *chset,
522 void (*print_func)(char, void *),
523 void (*print_separator)(const char *, void *), void *ptr)
524{
525const struct rfc822addr *addrs=rfcp->addrs;
526int naddrs=rfcp->naddrs;
527
528 while (naddrs)
529 {
530 if (addrs->tokens == 0)
531 {
532 rfc822tok_print(addrs->name, print_func, ptr);
533 ++addrs;
534 --naddrs;
535 if (addrs[-1].name && naddrs)
536 {
537 struct rfc822token *t;
538
539 for (t=addrs[-1].name; t && t->next; t=t->next)
540 ;
541
542 if (t && (t->token == ':' || t->token == ';'))
543 (*print_separator)(" ", ptr);
544 }
545 continue;
546 }
547 else if (addrs->name && addrs->name->token == '(')
548 { /* old style */
549 char *p;
550
551 rfc822tok_print(addrs->tokens, print_func, ptr);
552 (*print_func)(' ', ptr);
553
554 if (decode_func && (p=rfc822_gettok(addrs->name))!=0)
555 {
556 char *q= (*decode_func)(p, chset);
557 char *r;
558
559 for (r=q; r && *r; r++)
560 (*print_func)( (int)(unsigned char)*r,
561 ptr);
562 if (q) free(q);
563 free(p);
564 }
565 else rfc822tok_print(addrs->name, print_func, ptr);
566 }
567 else
568 {
569 int print_braces=0;
570 char *p;
571
572 if (addrs->name)
573 {
574 if (decode_func &&
575 (p=rfc822_gettok(addrs->name)) != 0)
576 {
577 char *q= (*decode_func)(p, chset);
578 char *r;
579
580 for (r=q; r && *r; r++)
581 (*print_func)(
582 (int)(unsigned char)*r,
583 ptr);
584 if (q) free(q);
585 free(p);
586 }
587 else rfc822tok_print(addrs->name,
588 print_func, ptr);
589 (*print_func)(' ', ptr);
590 print_braces=1;
591 }
592 else
593 {
594 struct rfc822token *p;
595
596 for (p=addrs->tokens; p && p->next; p=p->next)
597 if (rfc822_is_atom(p->token) &&
598 rfc822_is_atom(p->next->token))
599 print_braces=1;
600 }
601 if (print_braces)
602 (*print_func)('<', ptr);
603#if 0
604 rfc822tok_print(addrs->tokens, print_func, ptr);
605#else
606 if (decode_func &&
607 (p=rfc822_gettok(addrs->tokens))!=0)
608 {
609 char *q=(*decode_func)(p, chset);
610 char *r;
611 for (r=q; r && *r; r++)
612 (*print_func)((int)(unsigned char)*r,
613 ptr);
614 if (q) free(q);
615 free(p);
616 }
617 else rfc822tok_print(addrs->tokens, print_func, ptr);
618#endif
619 if (print_braces)
620 {
621 (*print_func)('>', ptr);
622 }
623 }
624 ++addrs;
625 --naddrs;
626 if (naddrs)
627 if (addrs->tokens || (addrs->name &&
628 rfc822_is_atom(addrs->name->token)))
629 (*print_separator)(", ", ptr);
630 }
631}
632
633void rfc822t_free(struct rfc822t *p)
634{
635 if (p->tokens) free(p->tokens);
636 free(p);
637}
638
639void rfc822a_free(struct rfc822a *p)
640{
641 if (p->addrs) free(p->addrs);
642 free(p);
643}
644
645void rfc822_deladdr(struct rfc822a *rfcp, int index)
646{
647int i;
648
649 if (index < 0 || index >= rfcp->naddrs) return;
650
651 for (i=index+1; i<rfcp->naddrs; i++)
652 rfcp->addrs[i-1]=rfcp->addrs[i];
653 if (--rfcp->naddrs == 0)
654 {
655 free(rfcp->addrs);
656 rfcp->addrs=0;
657 }
658}
659
660static void compat_err_func(const char *p, int i, void *voidp)
661{
662 void (*err_func)(const char *, int)=
663 (void (*)(const char *, int))voidp;
664
665 if (err_func)
666 (*err_func)(p, i);
667}
668
669struct rfc822t *rfc822t_alloc(const char *addr,
670 void (*err_func)(const char *, int))
671{
672 return (rfc822t_alloc_new(addr, &compat_err_func, (void *)err_func));
673}
674
675
676struct rfc822t *rfc822t_alloc_new(const char *addr,
677 void (*err_func)(const char *, int, void *), void *voidp)
678{
679struct rfc822t *p=(struct rfc822t *)malloc(sizeof(struct rfc822t));
680
681 if (!p) return (NULL);
682 memset(p, 0, sizeof(*p));
683
684 tokenize(addr, NULL, &p->ntokens, err_func, voidp);
685 p->tokens=p->ntokens ? (struct rfc822token *)
686 calloc(p->ntokens, sizeof(struct rfc822token)):0;
687 if (p->ntokens && !p->tokens)
688 {
689 rfc822t_free(p);
690 return (NULL);
691 }
692 tokenize(addr, p->tokens, &p->ntokens, NULL, NULL);
693 return (p);
694}
695
696struct rfc822a *rfc822a_alloc(struct rfc822t *t)
697{
698struct rfc822a *p=(struct rfc822a *)malloc(sizeof(struct rfc822a));
699
700 if (!p) return (NULL);
701 memset(p, 0, sizeof(*p));
702
703 parseaddr(t->tokens, t->ntokens, NULL, &p->naddrs);
704 p->addrs=p->naddrs ? (struct rfc822addr *)
705 calloc(p->naddrs, sizeof(struct rfc822addr)):0;
706 if (p->naddrs && !p->addrs)
707 {
708 rfc822a_free(p);
709 return (NULL);
710 }
711 parseaddr(t->tokens, t->ntokens, p->addrs, &p->naddrs);
712 return (p);
713}
714
715void rfc822_praddr(const struct rfc822a *rfcp, int index,
716 void (*print_func)(char, void *), void *ptr)
717{
718const struct rfc822addr *addrs;
719
720 if (index < 0 || index >= rfcp->naddrs) return;
721
722 addrs=rfcp->addrs+index;
723 if (addrs->tokens)
724 {
725 rfc822tok_print(addrs->tokens, print_func, ptr);
726 (*print_func)('\n', ptr);
727 }
728}
729
730void rfc822_addrlist(const struct rfc822a *rfcp,
731 void (*print_func)(char, void *), void *ptr)
732{
733int i;
734
735 for (i=0; i<rfcp->naddrs; i++)
736 rfc822_praddr(rfcp, i, print_func, ptr);
737}
738
739void rfc822_prname(const struct rfc822a *rfcp, int index,
740 void (*print_func)(char, void *), void *ptr)
741{
742const struct rfc822addr *addrs;
743
744 if (index < 0 || index >= rfcp->naddrs) return;
745
746 addrs=rfcp->addrs+index;
747
748 if (!addrs->tokens) return;
749 rfc822_prname_orlist(rfcp, index, print_func, ptr);
750}
751
752void rfc822_prname_orlist(const struct rfc822a *rfcp, int index,
753 void (*print_func)(char, void *), void *ptr)
754{
755const struct rfc822addr *addrs;
756
757 if (index < 0 || index >= rfcp->naddrs) return;
758
759 addrs=rfcp->addrs+index;
760
761 if (addrs->name)
762 {
763 struct rfc822token *i;
764 int n;
765 int prev_isatom=0;
766 int isatom=0;
767
768 for (i=addrs->name; i; i=i->next, prev_isatom=isatom)
769 {
770 isatom=rfc822_is_atom(i->token);
771 if (isatom && prev_isatom)
772 (*print_func)(' ', ptr);
773
774 if (i->token == '"')
775 {
776 for (n=0; n<i->len; n++)
777 {
778 if (i->ptr[n] == '\\' &&
779 n + 1 < i->len)
780 ++n;
781 (*print_func)(i->ptr[n], ptr);
782 }
783 continue;
784 }
785
786 if (i->token != '(')
787 {
788 print_token(i, print_func, ptr);
789 continue;
790 }
791
792 for (n=2; n<i->len; n++)
793 (*print_func)(i->ptr[n-1], ptr);
794 }
795 } else
796 rfc822tok_print(addrs->tokens, print_func, ptr);
797 (*print_func)('\n', ptr);
798}
799
800void rfc822_namelist(const struct rfc822a *rfcp,
801 void (*print_func)(char, void *), void *ptr)
802{
803int i;
804
805 for (i=0; i<rfcp->naddrs; i++)
806 rfc822_prname(rfcp, i, print_func, ptr);
807}