/[pkg-mixmaster]/trunk/Mix/Src/rfc822.c
ViewVC logotype

Contents of /trunk/Mix/Src/rfc822.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations) (download)
Wed Oct 31 08:19:51 2001 UTC (11 years, 6 months ago) by rabbi
File MIME type: text/plain
File size: 13410 byte(s)
Initial revision
1 rabbi 1 /* Mixmaster version 3 -- (C) 1999 Anonymizer Inc.
2    
3     Mixmaster may be redistributed and modified under certain conditions.
4     This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
5     ANY KIND, either express or implied. See the file COPYRIGHT for
6     details.
7    
8     Parse RFC 822 headers
9     $Id: rfc822.c,v 1.1 2001/10/31 08:19:53 rabbi Exp $ */
10    
11    
12     #include "mix3.h"
13    
14     static int is_specials(int c);
15     static int is_qtext(char c);
16     static int is_ctext(char c);
17     static void wsc(BUFFER *in, BUFFER *xomment);
18     static int word(BUFFER *in, BUFFER *word, BUFFER *x);
19     static int atom(BUFFER *in, BUFFER *atom, BUFFER *x);
20     static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x);
21     static int comment(BUFFER *in, BUFFER *string);
22     static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x);
23     static int domain(BUFFER *in, BUFFER *domain, BUFFER *x);
24     static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x);
25     static int domain_ref(BUFFER *in, BUFFER *dom, BUFFER *x);
26     static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x);
27     static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x);
28     static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x);
29     static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x);
30     static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x);
31     static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x);
32    
33     static void backtrack(BUFFER *b, int len)
34     {
35     if (b) {
36     b->length = len;
37     b->data[b->length] = '\0';
38     }
39     }
40    
41     /* white space and comments */
42     static void wsc(BUFFER *in, BUFFER *string)
43     {
44     char c;
45    
46     for (;;) {
47     c = buf_getc(in);
48     if (c == -1)
49     break;
50     else if (c == '\n') {
51     c = buf_getc(in);
52     if (c != ' ' && c != '\t') {
53     if (c != -1)
54     buf_ungetc(in), buf_ungetc(in);
55     break;
56     }
57     } else {
58     if (c != ' ' && c != '\t') {
59     buf_ungetc(in);
60     if (!comment(in, string))
61     break;
62     }
63     }
64     }
65     }
66    
67     /* specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted-
68     * / "," / ";" / ":" / "\" / <"> ; string, to use
69     * / "." / "[" / "]" ; within a word.
70     */
71    
72     static int is_specials(int c)
73     {
74     return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
75     c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
76     c == '.' || c == '[' || c == ']');
77     }
78    
79     /* qtext = <any CHAR excepting <">, ; => may be folded
80     * "\" & CR, and including
81     * linear-white-space>
82     */
83     static int is_qtext(char c)
84     {
85     return (c != '\"' && c != '\\' && c != '\n');
86     }
87    
88     /* ctext = <any CHAR excluding "(", ; => may be folded
89     * ")", "\" & CR, & including
90     * linear-white-space>
91     */
92     static int is_ctext(char c)
93     {
94     return (c != '(' && c != ')' && c != '\\' && c != '\n');
95     }
96    
97     /* word = atom / quoted-string
98     */
99     static int word(BUFFER *in, BUFFER *word, BUFFER *x)
100     {
101     return (atom(in, word, x) || quoted_string(in, word, x));
102     }
103    
104     /* atom = 1*<any CHAR except specials, SPACE and CTLs>
105     */
106     static int atom(BUFFER *in, BUFFER *atom, BUFFER *x)
107     {
108     int c;
109    
110     buf_clear(atom);
111     wsc(in, x);
112     for (;;) {
113     c = buf_getc(in);
114     if (c == -1)
115     break;
116     else if (is_specials(c) || c == ' ' || c < 32 || c == 127) {
117     buf_ungetc(in);
118     break;
119     } else
120     buf_appendc(atom, c);
121     }
122     if (atom->length)
123     wsc(in, x);
124     return (atom->length);
125     }
126    
127     /* quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
128     * ; quoted chars.
129     */
130     static int quoted_string(BUFFER *in, BUFFER *string, BUFFER *x)
131     {
132     int ptr, xlen;
133     int c;
134    
135     ptr = in->ptr, xlen = x ? x->length : 0;
136     buf_clear(string);
137     wsc(in, NULL);
138     c = buf_getc(in);
139     if (c == '\"') {
140     #if 0
141     buf_appendc(string, c);
142     #endif
143     for (;;) {
144     c = buf_getc(in);
145     if (is_qtext(c))
146     buf_appendc(string, c);
147     else if (c == '\n') {
148     c = buf_getc(in);
149     if (c != ' ' && c != '\n')
150     break;
151     } else if (c == '\\') {
152     c = buf_getc(in);
153     if (c == -1)
154     break;
155     else
156     buf_appendc(string, c);
157     } else if (c == '\"') {
158     #if 0
159     buf_appendc(string, c);
160     #endif
161     wsc(in, NULL);
162     return (1);
163     } else
164     break;
165     }
166     }
167     in->ptr = ptr, backtrack(x, xlen);
168     return (0);
169     }
170    
171     /* comment = "(" *(ctext / quoted-pair / comment) ")"
172     */
173     static int comment(BUFFER *in, BUFFER *string)
174     {
175     int ptr, xlen;
176     int separator = 0;
177     int c;
178    
179     ptr = in->ptr;
180     xlen = string ? string->length : 0;
181     if (xlen)
182     separator = 1;
183     c = buf_getc(in);
184     if (c == '(') {
185     for (;;) {
186     c = buf_getc(in);
187     if (c == -1)
188     return(1); /* unterminated comment, bail out */
189     if (is_ctext(c)) {
190     if (string != NULL) {
191     if (separator)
192     buf_appendc(string, ' '), separator = 0;
193     buf_appendc(string, c);
194     }
195     } else if (c == '\n') {
196     c = buf_getc(in);
197     if (c != ' ' && c != '\n')
198     break;
199     } else if (c == '\\') {
200     c = buf_getc(in);
201     if (c != -1) {
202     if (string != NULL) {
203     if (separator)
204     buf_appendc(string, ' '), separator = 0;
205     buf_appendc(string, c);
206     }
207     }
208     } else if (c == ')')
209     return (1);
210     else {
211     BUFFER *s;
212     int o;
213    
214     s = buf_new();
215     buf_ungetc(in);
216     o = comment(in, s);
217     if (o && string != NULL) {
218     if (separator)
219     buf_appendc(string, ' '), separator = 0;
220     buf_cat(string, s);
221     }
222     buf_free(s);
223     if (!o)
224     break;
225     }
226     }
227     }
228     in->ptr = ptr;
229     backtrack(string, xlen);
230     return (0);
231     }
232    
233     /* local-part = word *("." word) ; uninterpreted
234     * ; case-preserved
235     */
236     static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x)
237     {
238     BUFFER *w;
239     int c;
240    
241     buf_clear(addr);
242     if (!word(in, addr, x))
243     return (0);
244     w = buf_new();
245     for (;;) {
246     c = buf_getc(in);
247     if (c == -1)
248     break;
249     if (c == '.' && (word(in, w, x)))
250     buf_appendc(addr, '.'), buf_cat(addr, w);
251     else {
252     buf_ungetc(in);
253     break;
254     }
255     }
256     buf_free(w);
257     return (addr->length);
258     }
259    
260     /* domain = sub-domain *("." sub-domain)
261     */
262     static int domain(BUFFER *in, BUFFER *domain, BUFFER *x)
263     {
264     BUFFER *sub;
265     int c;
266    
267     if (!sub_domain(in, domain, x))
268     return (0);
269     sub = buf_new();
270     for (;;) {
271     c = buf_getc(in);
272     if (c == -1)
273     break;
274     if (c == '.' && (sub_domain(in, sub, x)))
275     buf_appendc(domain, '.'), buf_cat(domain, sub);
276     else {
277     buf_ungetc(in);
278     break;
279     }
280     }
281     buf_free(sub);
282     return (domain->length);
283     }
284    
285     /* sub-domain = domain-ref / domain-literal
286     */
287     static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x)
288     {
289     return (domain_ref(in, sub, x) || domain_literal(in, sub, x));
290     }
291    
292     /* domain-ref = atom ; symbolic reference
293     */
294     static int domain_ref(BUFFER *in, BUFFER *d, BUFFER *x)
295     {
296     return (atom(in, d, x));
297     }
298    
299     /* addr-spec = local-part "@" domain ; global address
300     */
301     static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x)
302     {
303     BUFFER *dom;
304     int ptr, xlen;
305    
306     ptr = in->ptr, xlen = x ? x->length : 0;
307     dom = buf_new();
308     buf_clear(addr);
309     if (local_part(in, addr, x) && buf_getc(in) == '@' && domain(in, dom, x))
310     buf_appendc(addr, '@'), buf_cat(addr, dom);
311     else
312     buf_clear(addr), in->ptr = ptr, backtrack(x, xlen);
313     buf_free(dom);
314     return (addr->length);
315     }
316    
317     /* route-addr = "<" [route] addr-spec ">"
318     */
319     static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
320     {
321     int c;
322     int ptr, xlen;
323    
324     ptr = in->ptr, xlen = x ? x->length : 0;
325     c = buf_getc(in);
326     if (c == -1)
327     return (0);
328     if (c != '<') {
329     buf_ungetc(in);
330     return (0);
331     }
332     if (addr_spec(in, addr, x) && buf_getc(in) == '>')
333     return (1);
334     in->ptr = ptr, backtrack(x, xlen);
335     return (0);
336     }
337    
338     /* phrase = 1*word ; Sequence of words
339     */
340     static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x)
341     {
342     BUFFER *w;
343    
344     buf_clear(phr);
345     w = buf_new();
346     while (word(in, w, x)) {
347     if (phr->length)
348     buf_appendc(phr, ' ');
349     buf_cat(phr, w);
350     }
351     buf_free(w);
352     return (phr->length);
353     }
354    
355     /* mailbox = addr-spec ; simple address
356     * / [phrase] route-addr ; name & addr-spec
357     * (RFC 1123)
358     */
359     static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x)
360     {
361     int ptr, xlen, ret;
362    
363     buf_clear(name);
364     if (addr_spec(in, mailbox, x))
365     return (1);
366    
367     ptr = in->ptr, xlen = x ? x->length : 0;
368     ret = phrase(in, name, x) && route_addr(in, mailbox, x);
369     if (!ret) {
370     in->ptr = ptr, backtrack(x, xlen);
371     ret = route_addr(in, mailbox, x);
372     }
373    
374     return (ret);
375     }
376    
377     /* address = mailbox ; one addressee
378     * / group ; named list
379     */
380     static int address(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
381     {
382     return (mailbox(in, address, name, x) || group(in, address, name, x));
383     }
384    
385     /* group = phrase ":" [#mailbox] ";"
386     */
387     static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x)
388     {
389     BUFFER *addr, *tmp;
390     int ptr, xlen, ret = 0;
391    
392     ptr = in->ptr, xlen = x ? x->length : 0;
393     addr = buf_new();
394     tmp = buf_new();
395     buf_clear(group);
396     if (phrase(in, name, x) && buf_getc(in) == ':') {
397     while (mailbox(in, addr, tmp, x))
398     buf_cat(group, addr), buf_nl(group);
399     ret = buf_getc(in) == ';';
400     }
401     if (!ret)
402     in->ptr = ptr, backtrack(x, xlen);
403     buf_free(addr);
404     buf_free(tmp);
405     return (ret);
406     }
407    
408     /* domain-literal = "[" *(dtext / quoted-pair) "]"
409     */
410     static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x)
411     {
412     return 0; /* XXX */
413     }
414    
415     /* local address without `@' is not specified in RFC 822 */
416    
417     /* local_addr = "<" atom ">" */
418     static int local_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
419     {
420     int c;
421     int ptr, xlen;
422    
423     ptr = in->ptr, xlen = x ? x->length : 0;
424     c = buf_getc(in);
425     if (c == -1)
426     return (0);
427     if (c != '<') {
428     buf_ungetc(in);
429     return (0);
430     }
431     if (atom(in, addr, x) && buf_getc(in) == '>')
432     return (1);
433     in->ptr = ptr, backtrack(x, xlen);
434     return (0);
435     }
436    
437     static int localaddress(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
438     {
439     int ptr, xlen;
440    
441     buf_clear(name);
442     if (local_addr(in, address, x))
443     return (1);
444     ptr = in->ptr, xlen = x ? x->length : 0;
445     if (phrase(in, name, x) && local_addr(in, address, x))
446     return (1);
447     in->ptr = ptr, backtrack(x, xlen);
448     buf_clear(name);
449     return (atom(in, address, x));
450     }
451    
452     void rfc822_addr(BUFFER *destination, BUFFER *list)
453     {
454     BUFFER *addr, *name;
455    
456     addr = buf_new();
457     name = buf_new();
458    
459     for (;;) {
460     if (!address(destination, addr, name, NULL) &&
461     !localaddress(destination, addr, name, NULL))
462     break;
463     buf_cat(list, addr);
464     buf_nl(list);
465     if (buf_getc(destination) != ',')
466     break;
467     }
468     buf_free(addr);
469     buf_free(name);
470     }
471    
472     void rfc822_name(BUFFER *line, BUFFER *name)
473     {
474     BUFFER *addr, *comment;
475     int ret;
476    
477     addr = buf_new();
478     comment = buf_new();
479     ret = address(line, addr, name, comment);
480     if (ret == 0)
481     ret = localaddress(line, addr, name, comment);
482     if (ret) {
483     if (name->length == 0)
484     buf_set(name, comment);
485     if (name->length == 0)
486     buf_set(name, addr);
487     }
488     if (ret == 0)
489     buf_set(name, line);
490     buf_free(addr);
491     buf_free(comment);
492     }
493    
494     /* MIME extensions. RFC 2045 */
495    
496     /* tspecials := "(" / ")" / "<" / ">" / "@" /
497     * "," / ";" / ":" / "\" / <">
498     * "/" / "[" / "]" / "?" / "="
499     */
500    
501     static int is_tspecials(int c)
502     {
503     return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
504     c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
505     c == '/' || c == '[' || c == ']' || c == '?' || c == '=');
506     }
507    
508     /* token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
509     * or tspecials>
510     */
511     static int token(BUFFER *in, BUFFER *token, BUFFER *x)
512     {
513     int c;
514    
515     buf_clear(token);
516     wsc(in, x);
517     for (;;) {
518     c = buf_getc(in);
519     if (c == -1)
520     break;
521     else if (is_tspecials(c) || c == ' ' || c < 32 || c == 127) {
522     buf_ungetc(in);
523     break;
524     } else
525     buf_appendc(token, c);
526     }
527     if (token->length)
528     wsc(in, x);
529     return (token->length);
530     }
531    
532     /* value := token / quoted-string
533     */
534    
535     static int value(BUFFER *in, BUFFER *value, BUFFER *x)
536     {
537     return (token(in, value, x) || quoted_string(in, value, x));
538     }
539    
540     /* parameter := attribute "=" value
541     */
542    
543     static int parameter(BUFFER *in, BUFFER *attribute, BUFFER *val, BUFFER *x)
544     {
545     int ptr;
546     ptr = in->ptr;
547     token(in, attribute, x);
548     if (buf_getc(in) != '=') {
549     in->ptr = ptr;
550     return(0);
551     }
552     return(value(in, val, x));
553     }
554    
555     /* get type */
556     int get_type(BUFFER *content, BUFFER *type, BUFFER *subtype)
557     {
558     token(content, type, NULL);
559     if (buf_getc(content) == '/')
560     return (token(content, subtype, NULL));
561     buf_ungetc(content);
562     buf_clear(type);
563     return (0);
564     }
565    
566     /* get parameter value */
567     void get_parameter(BUFFER *content, char *attribute, BUFFER *value)
568     {
569     BUFFER *tok;
570     tok = buf_new();
571     buf_clear(value);
572    
573     get_type(content, tok, tok);
574     for (;;) {
575     if (buf_getc(content) != ';')
576     break;
577     if (parameter(content, tok, value, NULL) &&
578     strieq(attribute, tok->data))
579     break; /* found */
580     buf_clear(value);
581     }
582     buf_free(tok);
583     }

  ViewVC Help
Powered by ViewVC 1.1.5