2 * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 osmtpd_mheader_skip_sp(char *ptr, int optional)
30 return optional ? ptr : NULL;
34 osmtpd_mheader_skip_htab(char *ptr, int optional)
38 return optional ? ptr : NULL;
42 osmtpd_mheader_skip_wsp(char *ptr, int optional)
46 if ((ptr = osmtpd_mheader_skip_sp(start, 0)) != NULL ||
47 (ptr = osmtpd_mheader_skip_htab(start, 0)) != NULL)
49 return optional ? ptr : NULL;
53 osmtpd_mheader_skip_crlf(char *ptr, int optional)
55 if (ptr[0] == 13 && ptr[1] == 10)
57 return optional ? ptr : NULL;
61 osmtpd_mheader_skip_vchar(char *ptr, int optional)
63 if (ptr[0] >= 0x21 && ptr[0] <= 0x7e)
65 return optional ? ptr : NULL;
69 osmtpd_mheader_skip_lf(char *ptr, int optional)
73 return optional ? ptr : NULL;
77 osmtpd_mheader_skip_cr(char *ptr, int optional)
81 return optional ? ptr : NULL;
85 osmtpd_mheader_skip_alpha(char *ptr, int optional)
87 if ((ptr[0] >= 0x41 && ptr[0] <= 0x5a) ||
88 (ptr[0] >= 0x61 && ptr[0] <= 0x7a))
90 return optional ? ptr : NULL;
94 osmtpd_mheader_skip_digit(char *ptr, int optional)
96 if (ptr[0] >= 0x30 && ptr[0] <= 0x39)
98 return optional ? ptr : NULL;
102 osmtpd_mheader_skip_dquote(char *ptr, int optional)
106 return optional ? ptr : NULL;
110 osmtpd_mheader_skip_obs_fws(char *ptr, int optional)
112 char *start = ptr, *prev;
114 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
115 return optional ? start : NULL;
117 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
122 if ((ptr = osmtpd_mheader_skip_crlf(ptr, 0)) == NULL)
124 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
127 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
134 osmtpd_mheader_skip_fws(char *ptr, int optional)
136 char *start = ptr, *prev = ptr;
138 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
140 if ((ptr = osmtpd_mheader_skip_crlf(prev, 1)) == prev)
142 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
143 return osmtpd_mheader_skip_obs_fws(start, optional);
145 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
151 osmtpd_mheader_skip_obs_no_ws_ctl(char *ptr, int optional)
153 if ((ptr[0] >= 1 && ptr[0] <= 8) || ptr[0] == 11 || ptr[0] == 12 ||
154 (ptr[0] >= 14 && ptr[0] <= 31) || ptr[0] == 127)
156 return optional ? ptr : NULL;
160 osmtpd_mheader_skip_obs_ctext(char *ptr, int optional)
162 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
166 osmtpd_mheader_skip_ctext(char *ptr, int optional)
170 if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
171 (ptr[0] >= 93 && ptr[0] <= 126))
173 if ((ptr = osmtpd_mheader_skip_obs_ctext(ptr, 0)) != NULL)
175 return optional ? start : NULL;
179 osmtpd_mheader_skip_obs_qp(char *ptr, int optional)
183 if (ptr[0] == '\\' && (
184 (ptr = osmtpd_mheader_skip_obs_no_ws_ctl(start + 1, 0)) != NULL ||
185 (ptr = osmtpd_mheader_skip_lf(start + 1, 0)) != NULL ||
186 (ptr = osmtpd_mheader_skip_cr(start + 1, 0)) != NULL))
188 return optional ? start : NULL;
192 osmtpd_mheader_skip_quoted_pair(char *ptr, int optional)
196 if (ptr[0] == '\\' && (
197 (ptr = osmtpd_mheader_skip_vchar(start + 1, 0)) != NULL ||
198 (ptr = osmtpd_mheader_skip_wsp(start + 1, 0)) != NULL))
200 return osmtpd_mheader_skip_obs_qp(start, optional);
204 osmtpd_mheader_skip_ccontent(char *ptr, int optional)
208 if ((ptr = osmtpd_mheader_skip_ctext(ptr, 0)) != NULL)
210 if ((ptr = osmtpd_mheader_skip_quoted_pair(start, 0)) != NULL)
212 if ((ptr = osmtpd_mheader_skip_comment(start, 0)) != NULL)
214 return optional ? start : NULL;
218 osmtpd_mheader_skip_comment(char *ptr, int optional)
223 return optional ? start : NULL;
225 ptr = osmtpd_mheader_skip_fws(ptr, 1);
228 if ((ptr = osmtpd_mheader_skip_ccontent(ptr, 0)) == NULL)
229 return optional ? start : NULL;
234 osmtpd_mheader_skip_cfws(char *ptr, int optional)
236 char *start = ptr, *prev;
239 ptr = osmtpd_mheader_skip_fws(ptr, 1);
241 if ((ptr = osmtpd_mheader_skip_comment(ptr, 0)) == NULL) {
246 return ptr == start && !optional ? NULL : ptr;
250 osmtpd_mheader_skip_atext(char *ptr, int optional)
254 if ((ptr = osmtpd_mheader_skip_alpha(start, 0)) != NULL ||
255 (ptr = osmtpd_mheader_skip_digit(start, 0)) != NULL)
258 if (ptr[0] == '!' || ptr[0] == '#' || ptr[0] == '$' || ptr[0] == '%' ||
259 ptr[0] == '&' || ptr[0] == '\'' || ptr[0] == '*' || ptr[0] == '+' ||
260 ptr[0] == '-' || ptr[0] == '/' || ptr[0] == '=' || ptr[0] == '?' ||
261 ptr[0] == '^' || ptr[0] == '_' || ptr[0] == '`' || ptr[0] == '{' ||
262 ptr[0] == '|' || ptr[0] == '}' || ptr[0] == '~')
264 return optional ? start : NULL;
268 osmtpd_mheader_skip_atom(char *ptr, int optional)
270 char *start = ptr, *prev;
272 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
273 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
274 return optional ? start : NULL;
277 ptr = osmtpd_mheader_skip_atext(ptr, 1);
278 } while (prev != ptr);
279 return osmtpd_mheader_skip_cfws(ptr, 1);
283 osmtpd_mheader_skip_dot_atom_text(char *ptr, int optional)
285 char *start = ptr, *prev;
287 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
288 return optional ? start : NULL;
291 ptr = osmtpd_mheader_skip_atext(ptr, 1);
292 } while (ptr != prev);
294 while (ptr[0] == '.') {
296 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
300 ptr = osmtpd_mheader_skip_atext(ptr, 1);
301 } while (ptr != prev);
307 osmtpd_mheader_skip_dot_atom(char *ptr, int optional)
311 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
312 if ((ptr = osmtpd_mheader_skip_dot_atom_text(ptr, 0)) == NULL)
313 return optional ? start : NULL;
314 return osmtpd_mheader_skip_cfws(ptr, 1);
319 osmtpd_mheader_skip_obs_qtext(char *ptr, int optional)
321 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
325 osmtpd_mheader_skip_qtext(char *ptr, int optional)
329 if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
330 (ptr[0] >= 93 && ptr[0] <= 126))
332 if ((ptr = osmtpd_mheader_skip_obs_qtext(ptr, 0)) != NULL)
334 return optional ? start : NULL;
338 osmtpd_mheader_skip_qcontent(char *ptr, int optional)
342 if ((ptr = osmtpd_mheader_skip_qtext(ptr, 0)) != NULL)
344 return osmtpd_mheader_skip_quoted_pair(start, optional);
348 osmtpd_mheader_skip_quoted_string(char *ptr, int optional)
350 char *start = ptr, *prev;
352 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
353 if ((ptr = osmtpd_mheader_skip_dquote(ptr, 0)) == NULL)
354 return optional ? start : NULL;
357 ptr = osmtpd_mheader_skip_fws(ptr, 1);
358 if ((ptr = osmtpd_mheader_skip_qcontent(ptr, 0)) == NULL)
362 if ((ptr = osmtpd_mheader_skip_dquote(prev, 0)) == NULL)
363 return optional ? start : NULL;
364 return osmtpd_mheader_skip_cfws(ptr, 1);
368 osmtpd_mheader_skip_word(char *ptr, int optional)
372 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) != NULL)
374 return osmtpd_mheader_skip_quoted_string(start, optional);
378 osmtpd_mheader_skip_obs_phrase(char *ptr, int optional)
380 char *start = ptr, *prev;
382 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
383 return optional ? start : NULL;
386 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) != NULL)
391 if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL)
398 osmtpd_mheader_skip_phrase(char *ptr, int optional)
400 /* obs-phrase is a superset of phrae */
401 return osmtpd_mheader_skip_obs_phrase(ptr, optional);
403 char *start = ptr, *prev;
405 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
406 return optional ? start : NULL;
409 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
416 osmtpd_mheader_skip_obs_local_part(char *ptr, int optional)
418 char *start = ptr, *prev;
420 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
421 return optional ? start : NULL;
423 while (ptr[0] == '.') {
425 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
433 osmtpd_mheader_skip_local_part(char *ptr, int optional)
437 if ((ptr = osmtpd_mheader_skip_dot_atom(ptr, 0)) != NULL)
440 if ((ptr = osmtpd_mheader_skip_quoted_string(ptr, 0)) != NULL)
442 return osmtpd_mheader_skip_obs_local_part(start, optional);
446 osmtpd_mheader_skip_obs_dtext(char *ptr, int optional)
450 if ((ptr = osmtpd_mheader_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
452 return osmtpd_mheader_skip_quoted_pair(start, optional);
456 osmtpd_mheader_skip_dtext(char *ptr, int optional)
458 if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
460 return osmtpd_mheader_skip_obs_dtext(ptr, optional);
465 osmtpd_mheader_skip_domain_literal(char *ptr, int optional)
467 char *start = ptr, *prev;
469 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
471 return optional ? start : NULL;
473 ptr = osmtpd_mheader_skip_fws(ptr, 1);
475 if ((ptr = osmtpd_mheader_skip_dtext(ptr, 0)) == NULL) {
481 return optional ? start : NULL;
482 return osmtpd_mheader_skip_cfws(ptr, 1);
486 osmtpd_mheader_skip_obs_domain(char *ptr, int optional)
488 char *start = ptr, *prev;
490 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
491 return optional ? start : NULL;
496 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
503 osmtpd_mheader_skip_domain(char *ptr, int optional)
507 if ((ptr = osmtpd_mheader_skip_dot_atom(start, 0)) != NULL)
509 if ((ptr = osmtpd_mheader_skip_domain_literal(start, 0)) != NULL)
511 return osmtpd_mheader_skip_obs_domain(start, optional);
515 osmtpd_mheader_skip_display_name(char *ptr, int optional)
517 return osmtpd_mheader_skip_phrase(ptr, optional);
521 osmtpd_mheader_skip_obs_domain_list(char *ptr, int optional)
523 char *start = ptr, *prev;
530 } else if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL) {
539 return optional ? start : NULL;
540 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
541 return optional ? start : NULL;
546 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
550 if ((ptr = osmtpd_mheader_skip_domain(ptr + 1, 0)) == NULL) {
559 osmtpd_mheader_skip_obs_route(char *ptr, int optional)
563 if ((ptr = osmtpd_mheader_skip_obs_domain_list(ptr, 0)) == NULL)
564 return optional ? start : NULL;
566 return optional ? start : NULL;
571 osmtpd_mheader_skip_addr_spec(char *ptr, int optional)
575 if ((ptr = osmtpd_mheader_skip_local_part(ptr, 0)) == NULL)
576 return optional ? start : NULL;
578 return optional ? start : NULL;
579 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
580 return optional ? start : NULL;
585 osmtpd_mheader_skip_obs_angle_addr(char *ptr, int optional)
589 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
591 return optional ? start : NULL;
592 if ((ptr = osmtpd_mheader_skip_obs_route(ptr, 0)) == NULL)
593 return optional ? start : NULL;
594 if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
595 return optional ? start : NULL;
597 return optional ? start : NULL;
598 return osmtpd_mheader_skip_cfws(ptr, 1);
602 osmtpd_mheader_skip_angle_addr(char *ptr, int optional)
606 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
608 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
609 if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
610 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
612 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
613 return osmtpd_mheader_skip_cfws(ptr, 1);
617 osmtpd_mheader_skip_name_addr(char *ptr, int optional)
621 ptr = osmtpd_mheader_skip_display_name(ptr, 1);
622 if ((ptr = osmtpd_mheader_skip_angle_addr(ptr, 0)) == NULL)
623 return optional ? start : NULL;
627 /* Return the domain component of the first mailbox */
629 osmtpd_mheader_from_domain(char *ptr)
634 if (strncasecmp(ptr, "from:", 5) == 0) {
637 } else if (strncasecmp(ptr, "from", 4) == 0) {
641 } while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL);
650 /* Both from and obs-from use Mailbox-list CRLF */
651 /* obs-mbox-list has just a prefix compared to mailbox-list */
654 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
655 if (ptr++[0] != ',') {
660 /* We're only interested in the first mailbox */
661 if (osmtpd_mheader_skip_name_addr(ptr, 0) != NULL) {
662 ptr = osmtpd_mheader_skip_display_name(ptr, 1);
663 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
667 ptr = osmtpd_mheader_skip_local_part(ptr, 0);
670 tmp = osmtpd_mheader_skip_domain(ptr, 0);
671 return strndup(ptr, tmp - ptr);
673 if (osmtpd_mheader_skip_addr_spec(ptr, 0) != NULL) {
674 ptr = osmtpd_mheader_skip_local_part(ptr, 0);
677 tmp = osmtpd_mheader_skip_domain(ptr, 0);
678 return strndup(ptr, tmp - ptr);