/[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 - (show 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 /* 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