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_char(char *ptr, int optional)
112 if (ptr[0] >= 0x1 && ptr[0] <= 0x7f)
114 return optional ? ptr : NULL;
118 osmtpd_mheader_skip_ctl(char *ptr, int optional)
120 if ((ptr[0] >= 0x0 && ptr[0] <= 0x1f) || ptr[0] == 0x7f)
122 return optional ? ptr : NULL;
126 osmtpd_mheader_skip_obs_fws(char *ptr, int optional)
128 char *start = ptr, *prev;
130 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
131 return optional ? start : NULL;
133 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
138 if ((ptr = osmtpd_mheader_skip_crlf(ptr, 0)) == NULL)
140 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
143 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
150 osmtpd_mheader_skip_fws(char *ptr, int optional)
152 char *start = ptr, *prev = ptr;
154 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
156 if ((ptr = osmtpd_mheader_skip_crlf(prev, 1)) == prev)
158 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
159 return osmtpd_mheader_skip_obs_fws(start, optional);
161 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
167 osmtpd_mheader_skip_obs_no_ws_ctl(char *ptr, int optional)
169 if ((ptr[0] >= 1 && ptr[0] <= 8) || ptr[0] == 11 || ptr[0] == 12 ||
170 (ptr[0] >= 14 && ptr[0] <= 31) || ptr[0] == 127)
172 return optional ? ptr : NULL;
176 osmtpd_mheader_skip_obs_ctext(char *ptr, int optional)
178 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
182 osmtpd_mheader_skip_ctext(char *ptr, int optional)
186 if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
187 (ptr[0] >= 93 && ptr[0] <= 126))
189 if ((ptr = osmtpd_mheader_skip_obs_ctext(ptr, 0)) != NULL)
191 return optional ? start : NULL;
195 osmtpd_mheader_skip_obs_qp(char *ptr, int optional)
199 if (ptr[0] == '\\' && (
200 (ptr = osmtpd_mheader_skip_obs_no_ws_ctl(start + 1, 0)) != NULL ||
201 (ptr = osmtpd_mheader_skip_lf(start + 1, 0)) != NULL ||
202 (ptr = osmtpd_mheader_skip_cr(start + 1, 0)) != NULL))
204 return optional ? start : NULL;
208 osmtpd_mheader_skip_quoted_pair(char *ptr, int optional)
212 if (ptr[0] == '\\' && (
213 (ptr = osmtpd_mheader_skip_vchar(start + 1, 0)) != NULL ||
214 (ptr = osmtpd_mheader_skip_wsp(start + 1, 0)) != NULL))
216 return osmtpd_mheader_skip_obs_qp(start, optional);
220 osmtpd_mheader_skip_ccontent(char *ptr, int optional)
224 if ((ptr = osmtpd_mheader_skip_ctext(ptr, 0)) != NULL)
226 if ((ptr = osmtpd_mheader_skip_quoted_pair(start, 0)) != NULL)
228 if ((ptr = osmtpd_mheader_skip_comment(start, 0)) != NULL)
230 return optional ? start : NULL;
234 osmtpd_mheader_skip_comment(char *ptr, int optional)
239 return optional ? start : NULL;
241 ptr = osmtpd_mheader_skip_fws(ptr, 1);
244 if ((ptr = osmtpd_mheader_skip_ccontent(ptr, 0)) == NULL)
245 return optional ? start : NULL;
250 osmtpd_mheader_skip_cfws(char *ptr, int optional)
252 char *start = ptr, *prev;
255 ptr = osmtpd_mheader_skip_fws(ptr, 1);
257 if ((ptr = osmtpd_mheader_skip_comment(ptr, 0)) == NULL) {
262 return ptr == start && !optional ? NULL : ptr;
266 osmtpd_mheader_skip_atext(char *ptr, int optional)
270 if ((ptr = osmtpd_mheader_skip_alpha(start, 0)) != NULL ||
271 (ptr = osmtpd_mheader_skip_digit(start, 0)) != NULL)
274 if (ptr[0] == '!' || ptr[0] == '#' || ptr[0] == '$' || ptr[0] == '%' ||
275 ptr[0] == '&' || ptr[0] == '\'' || ptr[0] == '*' || ptr[0] == '+' ||
276 ptr[0] == '-' || ptr[0] == '/' || ptr[0] == '=' || ptr[0] == '?' ||
277 ptr[0] == '^' || ptr[0] == '_' || ptr[0] == '`' || ptr[0] == '{' ||
278 ptr[0] == '|' || ptr[0] == '}' || ptr[0] == '~')
280 return optional ? start : NULL;
284 osmtpd_mheader_skip_atom(char *ptr, int optional)
286 char *start = ptr, *prev;
288 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
289 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
290 return optional ? start : NULL;
293 ptr = osmtpd_mheader_skip_atext(ptr, 1);
294 } while (prev != ptr);
295 return osmtpd_mheader_skip_cfws(ptr, 1);
299 osmtpd_mheader_skip_dot_atom_text(char *ptr, int optional)
301 char *start = ptr, *prev;
303 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
304 return optional ? start : NULL;
307 ptr = osmtpd_mheader_skip_atext(ptr, 1);
308 } while (ptr != prev);
310 while (ptr[0] == '.') {
312 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
316 ptr = osmtpd_mheader_skip_atext(ptr, 1);
317 } while (ptr != prev);
323 osmtpd_mheader_skip_dot_atom(char *ptr, int optional)
327 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
328 if ((ptr = osmtpd_mheader_skip_dot_atom_text(ptr, 0)) == NULL)
329 return optional ? start : NULL;
330 return osmtpd_mheader_skip_cfws(ptr, 1);
335 osmtpd_mheader_skip_obs_qtext(char *ptr, int optional)
337 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
341 osmtpd_mheader_skip_qtext(char *ptr, int optional)
345 if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
346 (ptr[0] >= 93 && ptr[0] <= 126))
348 if ((ptr = osmtpd_mheader_skip_obs_qtext(ptr, 0)) != NULL)
350 return optional ? start : NULL;
354 osmtpd_mheader_skip_qcontent(char *ptr, int optional)
358 if ((ptr = osmtpd_mheader_skip_qtext(ptr, 0)) != NULL)
360 return osmtpd_mheader_skip_quoted_pair(start, optional);
364 osmtpd_mheader_skip_quoted_string(char *ptr, int optional)
366 char *start = ptr, *prev;
368 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
369 if ((ptr = osmtpd_mheader_skip_dquote(ptr, 0)) == NULL)
370 return optional ? start : NULL;
373 ptr = osmtpd_mheader_skip_fws(ptr, 1);
374 if ((ptr = osmtpd_mheader_skip_qcontent(ptr, 0)) == NULL)
378 if ((ptr = osmtpd_mheader_skip_dquote(prev, 0)) == NULL)
379 return optional ? start : NULL;
380 return osmtpd_mheader_skip_cfws(ptr, 1);
384 osmtpd_mheader_skip_word(char *ptr, int optional)
388 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) != NULL)
390 return osmtpd_mheader_skip_quoted_string(start, optional);
394 osmtpd_mheader_skip_obs_phrase(char *ptr, int optional)
396 char *start = ptr, *prev;
398 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
399 return optional ? start : NULL;
402 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) != NULL)
407 if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL)
414 osmtpd_mheader_skip_phrase(char *ptr, int optional)
416 /* obs-phrase is a superset of phrae */
417 return osmtpd_mheader_skip_obs_phrase(ptr, optional);
419 char *start = ptr, *prev;
421 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
422 return optional ? start : NULL;
425 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
432 osmtpd_mheader_skip_obs_local_part(char *ptr, int optional)
434 char *start = ptr, *prev;
436 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
437 return optional ? start : NULL;
439 while (ptr[0] == '.') {
441 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
449 osmtpd_mheader_skip_local_part(char *ptr, int optional)
453 if ((ptr = osmtpd_mheader_skip_dot_atom(ptr, 0)) != NULL)
456 if ((ptr = osmtpd_mheader_skip_quoted_string(ptr, 0)) != NULL)
458 return osmtpd_mheader_skip_obs_local_part(start, optional);
462 osmtpd_mheader_skip_obs_dtext(char *ptr, int optional)
466 if ((ptr = osmtpd_mheader_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
468 return osmtpd_mheader_skip_quoted_pair(start, optional);
472 osmtpd_mheader_skip_dtext(char *ptr, int optional)
474 if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
476 return osmtpd_mheader_skip_obs_dtext(ptr, optional);
481 osmtpd_mheader_skip_domain_literal(char *ptr, int optional)
483 char *start = ptr, *prev;
485 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
487 return optional ? start : NULL;
489 ptr = osmtpd_mheader_skip_fws(ptr, 1);
491 if ((ptr = osmtpd_mheader_skip_dtext(ptr, 0)) == NULL) {
497 return optional ? start : NULL;
498 return osmtpd_mheader_skip_cfws(ptr, 1);
502 osmtpd_mheader_skip_obs_domain(char *ptr, int optional)
504 char *start = ptr, *prev;
506 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
507 return optional ? start : NULL;
512 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
519 osmtpd_mheader_skip_domain(char *ptr, int optional)
523 if ((ptr = osmtpd_mheader_skip_dot_atom(start, 0)) != NULL)
525 if ((ptr = osmtpd_mheader_skip_domain_literal(start, 0)) != NULL)
527 return osmtpd_mheader_skip_obs_domain(start, optional);
531 osmtpd_mheader_skip_display_name(char *ptr, int optional)
533 return osmtpd_mheader_skip_phrase(ptr, optional);
537 osmtpd_mheader_skip_obs_domain_list(char *ptr, int optional)
539 char *start = ptr, *prev;
546 } else if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL) {
555 return optional ? start : NULL;
556 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
557 return optional ? start : NULL;
562 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
566 if ((ptr = osmtpd_mheader_skip_domain(ptr + 1, 0)) == NULL) {
575 osmtpd_mheader_skip_obs_route(char *ptr, int optional)
579 if ((ptr = osmtpd_mheader_skip_obs_domain_list(ptr, 0)) == NULL)
580 return optional ? start : NULL;
582 return optional ? start : NULL;
587 osmtpd_mheader_skip_addr_spec(char *ptr, int optional)
591 if ((ptr = osmtpd_mheader_skip_local_part(ptr, 0)) == NULL)
592 return optional ? start : NULL;
594 return optional ? start : NULL;
595 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
596 return optional ? start : NULL;
601 osmtpd_mheader_skip_obs_angle_addr(char *ptr, int optional)
605 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
607 return optional ? start : NULL;
608 if ((ptr = osmtpd_mheader_skip_obs_route(ptr, 0)) == NULL)
609 return optional ? start : NULL;
610 if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
611 return optional ? start : NULL;
613 return optional ? start : NULL;
614 return osmtpd_mheader_skip_cfws(ptr, 1);
618 osmtpd_mheader_skip_angle_addr(char *ptr, int optional)
622 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
624 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
625 if ((ptr = osmtpd_mheader_skip_addr_spec(ptr, 0)) == NULL)
626 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
628 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
629 return osmtpd_mheader_skip_cfws(ptr, 1);
633 osmtpd_mheader_skip_name_addr(char *ptr, int optional)
637 ptr = osmtpd_mheader_skip_display_name(ptr, 1);
638 if ((ptr = osmtpd_mheader_skip_angle_addr(ptr, 0)) == NULL)
639 return optional ? start : NULL;
645 osmtpd_mheader_skip_tspecials(char *ptr, int optional)
647 if (ptr[0] == '(' || ptr[0] == ')' || ptr[0] == '<' || ptr[0] == '>' ||
648 ptr[0] == '@' || ptr[0] == ',' || ptr[0] == ';' || ptr[0] == ':' ||
649 ptr[0] == '\\' || ptr[0] == '\'' || ptr[0] == '/' ||
650 ptr[0] == '[' || ptr[0] == ']' || ptr[0] == '?' || ptr[0] == '=')
652 return optional ? ptr : NULL;
657 osmtpd_mheader_skip_token(char *ptr, int optional)
659 if (osmtpd_mheader_skip_char(ptr, 0) == NULL)
660 return optional ? ptr : NULL;
661 /* Can't find the official definition for SPACE, so use WSP */
662 if (osmtpd_mheader_skip_wsp(ptr, 0) != NULL)
663 return optional ? ptr : NULL;
664 if (osmtpd_mheader_skip_ctl(ptr, 0) != NULL)
665 return optional ? ptr : NULL;
666 if (osmtpd_mheader_skip_tspecials(ptr, 0) != NULL)
667 return optional ? ptr : NULL;
670 if (osmtpd_mheader_skip_char(ptr, 0) == NULL)
672 if (osmtpd_mheader_skip_wsp(ptr, 0) != NULL)
674 if (osmtpd_mheader_skip_ctl(ptr, 0) != NULL)
676 if (osmtpd_mheader_skip_tspecials(ptr, 0) != NULL)
683 osmtpd_mheader_skip_value(char *ptr, int optional)
687 if ((ptr = osmtpd_mheader_skip_token(ptr, 0)) == NULL)
688 return osmtpd_mheader_skip_quoted_string(start, optional);
692 /* Return the domain component of the first mailbox */
694 osmtpd_mheader_from_domain(char *ptr)
699 if (strncasecmp(ptr, "from:", 5) == 0) {
702 } else if (strncasecmp(ptr, "from", 4) == 0) {
706 } while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL);
715 /* Both from and obs-from use Mailbox-list CRLF */
716 /* obs-mbox-list has just a prefix compared to mailbox-list */
719 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
720 if (ptr++[0] != ',') {
725 /* We're only interested in the first mailbox */
726 if (osmtpd_mheader_skip_name_addr(ptr, 0) != NULL) {
727 ptr = osmtpd_mheader_skip_display_name(ptr, 1);
728 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
732 ptr = osmtpd_mheader_skip_local_part(ptr, 0);
735 tmp = osmtpd_mheader_skip_domain(ptr, 0);
736 return strndup(ptr, tmp - ptr);
738 if (osmtpd_mheader_skip_addr_spec(ptr, 0) != NULL) {
739 ptr = osmtpd_mheader_skip_local_part(ptr, 0);
742 tmp = osmtpd_mheader_skip_domain(ptr, 0);
743 return strndup(ptr, tmp - ptr);