trfc822.c - mixmaster - mixmaster 3.0 patched for libressl
HTML git clone git://parazyd.org/mixmaster.git
DIR Log
DIR Files
DIR Refs
DIR README
---
trfc822.c (13497B)
---
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others.
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 934 2006-06-24 13:40:39Z rabbi $ */
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 int 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 (c == -1) /* catch unterminated quoted string */
146 break;
147 if (is_qtext(c))
148 buf_appendc(string, c);
149 else if (c == '\n') {
150 c = buf_getc(in);
151 if (c != ' ' && c != '\n')
152 break;
153 } else if (c == '\\') {
154 c = buf_getc(in);
155 if (c == -1)
156 break;
157 else
158 buf_appendc(string, c);
159 } else if (c == '\"') {
160 #if 0
161 buf_appendc(string, c);
162 #endif
163 wsc(in, NULL);
164 return (1);
165 } else
166 break;
167 }
168 }
169 in->ptr = ptr, backtrack(x, xlen);
170 return (0);
171 }
172
173 /* comment = "(" *(ctext / quoted-pair / comment) ")"
174 */
175 static int comment(BUFFER *in, BUFFER *string)
176 {
177 int ptr, xlen;
178 int separator = 0;
179 int c;
180
181 ptr = in->ptr;
182 xlen = string ? string->length : 0;
183 if (xlen)
184 separator = 1;
185 c = buf_getc(in);
186 if (c == '(') {
187 for (;;) {
188 c = buf_getc(in);
189 if (c == -1)
190 return(1); /* unterminated comment, bail out */
191 if (is_ctext(c)) {
192 if (string != NULL) {
193 if (separator)
194 buf_appendc(string, ' '), separator = 0;
195 buf_appendc(string, c);
196 }
197 } else if (c == '\n') {
198 c = buf_getc(in);
199 if (c != ' ' && c != '\n')
200 break;
201 } else if (c == '\\') {
202 c = buf_getc(in);
203 if (c != -1) {
204 if (string != NULL) {
205 if (separator)
206 buf_appendc(string, ' '), separator = 0;
207 buf_appendc(string, c);
208 }
209 }
210 } else if (c == ')')
211 return (1);
212 else {
213 BUFFER *s;
214 int o;
215
216 s = buf_new();
217 buf_ungetc(in);
218 o = comment(in, s);
219 if (o && string != NULL) {
220 if (separator)
221 buf_appendc(string, ' '), separator = 0;
222 buf_cat(string, s);
223 }
224 buf_free(s);
225 if (!o)
226 break;
227 }
228 }
229 }
230 in->ptr = ptr;
231 backtrack(string, xlen);
232 return (0);
233 }
234
235 /* local-part = word *("." word) ; uninterpreted
236 * ; case-preserved
237 */
238 static int local_part(BUFFER *in, BUFFER *addr, BUFFER *x)
239 {
240 BUFFER *w;
241 int c;
242
243 buf_clear(addr);
244 if (!word(in, addr, x))
245 return (0);
246 w = buf_new();
247 for (;;) {
248 c = buf_getc(in);
249 if (c == -1)
250 break;
251 if (c == '.' && (word(in, w, x)))
252 buf_appendc(addr, '.'), buf_cat(addr, w);
253 else {
254 buf_ungetc(in);
255 break;
256 }
257 }
258 buf_free(w);
259 return (addr->length);
260 }
261
262 /* domain = sub-domain *("." sub-domain)
263 */
264 static int domain(BUFFER *in, BUFFER *domain, BUFFER *x)
265 {
266 BUFFER *sub;
267 int c;
268
269 if (!sub_domain(in, domain, x))
270 return (0);
271 sub = buf_new();
272 for (;;) {
273 c = buf_getc(in);
274 if (c == -1)
275 break;
276 if (c == '.' && (sub_domain(in, sub, x)))
277 buf_appendc(domain, '.'), buf_cat(domain, sub);
278 else {
279 buf_ungetc(in);
280 break;
281 }
282 }
283 buf_free(sub);
284 return (domain->length);
285 }
286
287 /* sub-domain = domain-ref / domain-literal
288 */
289 static int sub_domain(BUFFER *in, BUFFER *sub, BUFFER *x)
290 {
291 return (domain_ref(in, sub, x) || domain_literal(in, sub, x));
292 }
293
294 /* domain-ref = atom ; symbolic reference
295 */
296 static int domain_ref(BUFFER *in, BUFFER *d, BUFFER *x)
297 {
298 return (atom(in, d, x));
299 }
300
301 /* addr-spec = local-part "@" domain ; global address
302 */
303 static int addr_spec(BUFFER *in, BUFFER *addr, BUFFER *x)
304 {
305 BUFFER *dom;
306 int ptr, xlen;
307
308 ptr = in->ptr, xlen = x ? x->length : 0;
309 dom = buf_new();
310 buf_clear(addr);
311 if (local_part(in, addr, x) && buf_getc(in) == '@' && domain(in, dom, x))
312 buf_appendc(addr, '@'), buf_cat(addr, dom);
313 else
314 buf_clear(addr), in->ptr = ptr, backtrack(x, xlen);
315 buf_free(dom);
316 return (addr->length);
317 }
318
319 /* route-addr = "<" [route] addr-spec ">"
320 */
321 static int route_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
322 {
323 int c;
324 int ptr, xlen;
325
326 ptr = in->ptr, xlen = x ? x->length : 0;
327 c = buf_getc(in);
328 if (c == -1)
329 return (0);
330 if (c != '<') {
331 buf_ungetc(in);
332 return (0);
333 }
334 if (addr_spec(in, addr, x) && buf_getc(in) == '>')
335 return (1);
336 in->ptr = ptr, backtrack(x, xlen);
337 return (0);
338 }
339
340 /* phrase = 1*word ; Sequence of words
341 */
342 static int phrase(BUFFER *in, BUFFER *phr, BUFFER *x)
343 {
344 BUFFER *w;
345
346 buf_clear(phr);
347 w = buf_new();
348 while (word(in, w, x)) {
349 if (phr->length)
350 buf_appendc(phr, ' ');
351 buf_cat(phr, w);
352 }
353 buf_free(w);
354 return (phr->length);
355 }
356
357 /* mailbox = addr-spec ; simple address
358 * / [phrase] route-addr ; name & addr-spec
359 * (RFC 1123)
360 */
361 static int mailbox(BUFFER *in, BUFFER *mailbox, BUFFER *name, BUFFER *x)
362 {
363 int ptr, xlen, ret;
364
365 buf_clear(name);
366 if (addr_spec(in, mailbox, x))
367 return (1);
368
369 ptr = in->ptr, xlen = x ? x->length : 0;
370 ret = phrase(in, name, x) && route_addr(in, mailbox, x);
371 if (!ret) {
372 in->ptr = ptr, backtrack(x, xlen);
373 ret = route_addr(in, mailbox, x);
374 }
375
376 return (ret);
377 }
378
379 /* address = mailbox ; one addressee
380 * / group ; named list
381 */
382 static int address(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
383 {
384 return (mailbox(in, address, name, x) || group(in, address, name, x));
385 }
386
387 /* group = phrase ":" [#mailbox] ";"
388 */
389 static int group(BUFFER *in, BUFFER *group, BUFFER *name, BUFFER *x)
390 {
391 BUFFER *addr, *tmp;
392 int ptr, xlen, ret = 0;
393
394 ptr = in->ptr, xlen = x ? x->length : 0;
395 addr = buf_new();
396 tmp = buf_new();
397 buf_clear(group);
398 if (phrase(in, name, x) && buf_getc(in) == ':') {
399 while (mailbox(in, addr, tmp, x))
400 buf_cat(group, addr), buf_nl(group);
401 ret = buf_getc(in) == ';';
402 }
403 if (!ret)
404 in->ptr = ptr, backtrack(x, xlen);
405 buf_free(addr);
406 buf_free(tmp);
407 return (ret);
408 }
409
410 /* domain-literal = "[" *(dtext / quoted-pair) "]"
411 */
412 static int domain_literal(BUFFER *in, BUFFER *dom, BUFFER *x)
413 {
414 return 0; /* XXX */
415 }
416
417 /* local address without `@' is not specified in RFC 822 */
418
419 /* local_addr = "<" atom ">" */
420 static int local_addr(BUFFER *in, BUFFER *addr, BUFFER *x)
421 {
422 int c;
423 int ptr, xlen;
424
425 ptr = in->ptr, xlen = x ? x->length : 0;
426 c = buf_getc(in);
427 if (c == -1)
428 return (0);
429 if (c != '<') {
430 buf_ungetc(in);
431 return (0);
432 }
433 if (atom(in, addr, x) && buf_getc(in) == '>')
434 return (1);
435 in->ptr = ptr, backtrack(x, xlen);
436 return (0);
437 }
438
439 static int localaddress(BUFFER *in, BUFFER *address, BUFFER *name, BUFFER *x)
440 {
441 int ptr, xlen;
442
443 buf_clear(name);
444 if (local_addr(in, address, x))
445 return (1);
446 ptr = in->ptr, xlen = x ? x->length : 0;
447 if (phrase(in, name, x) && local_addr(in, address, x))
448 return (1);
449 in->ptr = ptr, backtrack(x, xlen);
450 buf_clear(name);
451 return (atom(in, address, x));
452 }
453
454 void rfc822_addr(BUFFER *destination, BUFFER *list)
455 {
456 BUFFER *addr, *name;
457
458 addr = buf_new();
459 name = buf_new();
460
461 for (;;) {
462 if (!address(destination, addr, name, NULL) &&
463 !localaddress(destination, addr, name, NULL))
464 break;
465 buf_cat(list, addr);
466 buf_nl(list);
467 if (buf_getc(destination) != ',')
468 break;
469 }
470 buf_free(addr);
471 buf_free(name);
472 }
473
474 void rfc822_name(BUFFER *line, BUFFER *name)
475 {
476 BUFFER *addr, *comment;
477 int ret;
478
479 addr = buf_new();
480 comment = buf_new();
481 ret = address(line, addr, name, comment);
482 if (ret == 0)
483 ret = localaddress(line, addr, name, comment);
484 if (ret) {
485 if (name->length == 0)
486 buf_set(name, comment);
487 if (name->length == 0)
488 buf_set(name, addr);
489 }
490 if (ret == 0)
491 buf_set(name, line);
492 buf_free(addr);
493 buf_free(comment);
494 }
495
496 /* MIME extensions. RFC 2045 */
497
498 /* tspecials := "(" / ")" / "<" / ">" / "@" /
499 * "," / ";" / ":" / "\" / <">
500 * "/" / "[" / "]" / "?" / "="
501 */
502
503 static int is_tspecials(int c)
504 {
505 return (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
506 c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
507 c == '/' || c == '[' || c == ']' || c == '?' || c == '=');
508 }
509
510 /* token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
511 * or tspecials>
512 */
513 static int token(BUFFER *in, BUFFER *token, BUFFER *x)
514 {
515 int c;
516
517 buf_clear(token);
518 wsc(in, x);
519 for (;;) {
520 c = buf_getc(in);
521 if (c == -1)
522 break;
523 else if (is_tspecials(c) || c == ' ' || c < 32 || c == 127) {
524 buf_ungetc(in);
525 break;
526 } else
527 buf_appendc(token, c);
528 }
529 if (token->length)
530 wsc(in, x);
531 return (token->length);
532 }
533
534 /* value := token / quoted-string
535 */
536
537 static int value(BUFFER *in, BUFFER *value, BUFFER *x)
538 {
539 return (token(in, value, x) || quoted_string(in, value, x));
540 }
541
542 /* parameter := attribute "=" value
543 */
544
545 static int parameter(BUFFER *in, BUFFER *attribute, BUFFER *val, BUFFER *x)
546 {
547 int ptr;
548 ptr = in->ptr;
549 token(in, attribute, x);
550 if (buf_getc(in) != '=') {
551 in->ptr = ptr;
552 return(0);
553 }
554 return(value(in, val, x));
555 }
556
557 /* get type */
558 int get_type(BUFFER *content, BUFFER *type, BUFFER *subtype)
559 {
560 token(content, type, NULL);
561 if (buf_getc(content) == '/')
562 return (token(content, subtype, NULL));
563 buf_ungetc(content);
564 buf_clear(type);
565 return (0);
566 }
567
568 /* get parameter value */
569 void get_parameter(BUFFER *content, char *attribute, BUFFER *value)
570 {
571 BUFFER *tok;
572 tok = buf_new();
573 buf_clear(value);
574
575 get_type(content, tok, tok);
576 for (;;) {
577 if (buf_getc(content) != ';')
578 break;
579 if (parameter(content, tok, value, NULL) &&
580 strieq(attribute, tok->data))
581 break; /* found */
582 buf_clear(value);
583 }
584 buf_free(tok);
585 }