Blob


1 /*
2 * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
3 *
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.
7 *
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.
15 */
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <strings.h>
23 #include "mheader.h"
25 char *
26 osmtpd_mheader_skip_sp(char *ptr, int optional)
27 {
28 if (ptr[0] == 0x20)
29 return ptr + 1;
30 return optional ? ptr : NULL;
31 }
33 char *
34 osmtpd_mheader_skip_htab(char *ptr, int optional)
35 {
36 if (ptr[0] == 0x9)
37 return ptr + 1;
38 return optional ? ptr : NULL;
39 }
41 char *
42 osmtpd_mheader_skip_wsp(char *ptr, int optional)
43 {
44 char *start = ptr;
46 if ((ptr = osmtpd_mheader_skip_sp(start, 0)) != NULL ||
47 (ptr = osmtpd_mheader_skip_htab(start, 0)) != NULL)
48 return ptr;
49 return optional ? ptr : NULL;
50 }
52 char *
53 osmtpd_mheader_skip_crlf(char *ptr, int optional)
54 {
55 if (ptr[0] == 13 && ptr[1] == 10)
56 return ptr + 2;
57 return optional ? ptr : NULL;
58 }
60 char *
61 osmtpd_mheader_skip_vchar(char *ptr, int optional)
62 {
63 if (ptr[0] >= 0x21 && ptr[0] <= 0x7e)
64 return ptr + 1;
65 return optional ? ptr : NULL;
66 }
68 char *
69 osmtpd_mheader_skip_lf(char *ptr, int optional)
70 {
71 if (ptr[0] == 0xa)
72 return ptr + 1;
73 return optional ? ptr : NULL;
74 }
76 char *
77 osmtpd_mheader_skip_cr(char *ptr, int optional)
78 {
79 if (ptr[0] == 0xd)
80 return ptr + 1;
81 return optional ? ptr : NULL;
82 }
84 char *
85 osmtpd_mheader_skip_alpha(char *ptr, int optional)
86 {
87 if ((ptr[0] >= 0x41 && ptr[0] <= 0x5a) ||
88 (ptr[0] >= 0x61 && ptr[0] <= 0x7a))
89 return ptr + 1;
90 return optional ? ptr : NULL;
91 }
93 char *
94 osmtpd_mheader_skip_digit(char *ptr, int optional)
95 {
96 if (ptr[0] >= 0x30 && ptr[0] <= 0x39)
97 return ptr + 1;
98 return optional ? ptr : NULL;
99 }
101 char *
102 osmtpd_mheader_skip_dquote(char *ptr, int optional)
104 if (ptr[0] == 0x22)
105 return ptr + 1;
106 return optional ? ptr : NULL;
109 char *
110 osmtpd_mheader_skip_char(char *ptr, int optional)
112 if (ptr[0] >= 0x1 && ptr[0] <= 0x7f)
113 return ptr + 1;
114 return optional ? ptr : NULL;
117 char *
118 osmtpd_mheader_skip_ctl(char *ptr, int optional)
120 if ((ptr[0] >= 0x0 && ptr[0] <= 0x1f) || ptr[0] == 0x7f)
121 return ptr + 1;
122 return optional ? ptr : NULL;
125 char *
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;
132 prev = ptr;
133 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
134 prev = ptr;
136 ptr = prev;
137 while (1) {
138 if ((ptr = osmtpd_mheader_skip_crlf(ptr, 0)) == NULL)
139 return prev;
140 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
141 return prev;
142 prev = ptr;
143 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
144 prev = ptr;
145 ptr = prev;
149 char *
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)
155 prev = ptr;
156 if ((ptr = osmtpd_mheader_skip_crlf(prev, 1)) == prev)
157 ptr = start;
158 if ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) == NULL)
159 return osmtpd_mheader_skip_obs_fws(start, optional);
160 prev = ptr;
161 while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL)
162 prev = ptr;
163 return prev;
166 char *
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)
171 return ptr + 1;
172 return optional ? ptr : NULL;
175 char *
176 osmtpd_mheader_skip_obs_ctext(char *ptr, int optional)
178 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
181 char *
182 osmtpd_mheader_skip_ctext(char *ptr, int optional)
184 char *start = ptr;
186 if ((ptr[0] >= 33 && ptr[0] <= 39) || (ptr[0] >= 42 && ptr[0] <= 91) ||
187 (ptr[0] >= 93 && ptr[0] <= 126))
188 return ptr + 1;
189 if ((ptr = osmtpd_mheader_skip_obs_ctext(ptr, 0)) != NULL)
190 return ptr;
191 return optional ? start : NULL;
194 char *
195 osmtpd_mheader_skip_obs_qp(char *ptr, int optional)
197 char *start = ptr;
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))
203 return ptr;
204 return optional ? start : NULL;
207 char *
208 osmtpd_mheader_skip_quoted_pair(char *ptr, int optional)
210 char *start = ptr;
212 if (ptr[0] == '\\' && (
213 (ptr = osmtpd_mheader_skip_vchar(start + 1, 0)) != NULL ||
214 (ptr = osmtpd_mheader_skip_wsp(start + 1, 0)) != NULL))
215 return ptr;
216 return osmtpd_mheader_skip_obs_qp(start, optional);
219 char *
220 osmtpd_mheader_skip_ccontent(char *ptr, int optional)
222 char *start = ptr;
224 if ((ptr = osmtpd_mheader_skip_ctext(ptr, 0)) != NULL)
225 return ptr;
226 if ((ptr = osmtpd_mheader_skip_quoted_pair(start, 0)) != NULL)
227 return ptr;
228 if ((ptr = osmtpd_mheader_skip_comment(start, 0)) != NULL)
229 return ptr;
230 return optional ? start : NULL;
233 char *
234 osmtpd_mheader_skip_comment(char *ptr, int optional)
236 char *start = ptr;
238 if (ptr++[0] != '(')
239 return optional ? start : NULL;
240 while (1) {
241 ptr = osmtpd_mheader_skip_fws(ptr, 1);
242 if (ptr[0] == ')')
243 return ptr + 1;
244 if ((ptr = osmtpd_mheader_skip_ccontent(ptr, 0)) == NULL)
245 return optional ? start : NULL;
249 char *
250 osmtpd_mheader_skip_cfws(char *ptr, int optional)
252 char *start = ptr, *prev;
254 while (1) {
255 ptr = osmtpd_mheader_skip_fws(ptr, 1);
256 prev = ptr;
257 if ((ptr = osmtpd_mheader_skip_comment(ptr, 0)) == NULL) {
258 ptr = prev;
259 break;
262 return ptr == start && !optional ? NULL : ptr;
265 char *
266 osmtpd_mheader_skip_atext(char *ptr, int optional)
268 char *start = ptr;
270 if ((ptr = osmtpd_mheader_skip_alpha(start, 0)) != NULL ||
271 (ptr = osmtpd_mheader_skip_digit(start, 0)) != NULL)
272 return ptr;
273 ptr = start;
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] == '~')
279 return ptr + 1;
280 return optional ? start : NULL;
283 char *
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;
291 do {
292 prev = ptr;
293 ptr = osmtpd_mheader_skip_atext(ptr, 1);
294 } while (prev != ptr);
295 return osmtpd_mheader_skip_cfws(ptr, 1);
298 char *
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;
305 do {
306 prev = ptr;
307 ptr = osmtpd_mheader_skip_atext(ptr, 1);
308 } while (ptr != prev);
310 while (ptr[0] == '.') {
311 ptr++;
312 if ((ptr = osmtpd_mheader_skip_atext(ptr, 0)) == NULL)
313 return prev;
314 do {
315 prev = ptr;
316 ptr = osmtpd_mheader_skip_atext(ptr, 1);
317 } while (ptr != prev);
319 return ptr;
322 char *
323 osmtpd_mheader_skip_dot_atom(char *ptr, int optional)
325 char *start = ptr;
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);
334 char *
335 osmtpd_mheader_skip_obs_qtext(char *ptr, int optional)
337 return osmtpd_mheader_skip_obs_no_ws_ctl(ptr, optional);
340 char *
341 osmtpd_mheader_skip_qtext(char *ptr, int optional)
343 char *start = ptr;
345 if (ptr[0] == 33 || (ptr[0] >= 35 && ptr[0] <= 91) ||
346 (ptr[0] >= 93 && ptr[0] <= 126))
347 return ptr + 1;
348 if ((ptr = osmtpd_mheader_skip_obs_qtext(ptr, 0)) != NULL)
349 return ptr;
350 return optional ? start : NULL;
353 char *
354 osmtpd_mheader_skip_qcontent(char *ptr, int optional)
356 char *start = ptr;
358 if ((ptr = osmtpd_mheader_skip_qtext(ptr, 0)) != NULL)
359 return ptr;
360 return osmtpd_mheader_skip_quoted_pair(start, optional);
363 char *
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;
371 prev = ptr;
372 while (1) {
373 ptr = osmtpd_mheader_skip_fws(ptr, 1);
374 if ((ptr = osmtpd_mheader_skip_qcontent(ptr, 0)) == NULL)
375 break;
376 prev = ptr;
378 if ((ptr = osmtpd_mheader_skip_dquote(prev, 0)) == NULL)
379 return optional ? start : NULL;
380 return osmtpd_mheader_skip_cfws(ptr, 1);
383 char *
384 osmtpd_mheader_skip_word(char *ptr, int optional)
386 char *start = ptr;
388 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) != NULL)
389 return ptr;
390 return osmtpd_mheader_skip_quoted_string(start, optional);
393 char *
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;
400 while (1) {
401 prev = ptr;
402 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) != NULL)
403 continue;
404 ptr = prev;
405 if (ptr[0] == '.')
406 continue;
407 if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL)
408 continue;
409 return prev;
413 char *
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);
418 #if 0
419 char *start = ptr, *prev;
421 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
422 return optional ? start : NULL;
423 while (1) {
424 prev = ptr;
425 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
426 return prev;
428 #endif
431 char *
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;
438 prev = ptr;
439 while (ptr[0] == '.') {
440 ptr++;
441 if ((ptr = osmtpd_mheader_skip_word(ptr, 0)) == NULL)
442 return prev;
443 prev = ptr;
445 return ptr;
448 char *
449 osmtpd_mheader_skip_local_part(char *ptr, int optional)
451 char *start = ptr;
453 if ((ptr = osmtpd_mheader_skip_dot_atom(ptr, 0)) != NULL)
454 return ptr;
455 ptr = start;
456 if ((ptr = osmtpd_mheader_skip_quoted_string(ptr, 0)) != NULL)
457 return ptr;
458 return osmtpd_mheader_skip_obs_local_part(start, optional);
461 char *
462 osmtpd_mheader_skip_obs_dtext(char *ptr, int optional)
464 char *start = ptr;
466 if ((ptr = osmtpd_mheader_skip_obs_no_ws_ctl(ptr, 0)) != NULL)
467 return ptr;
468 return osmtpd_mheader_skip_quoted_pair(start, optional);
471 char *
472 osmtpd_mheader_skip_dtext(char *ptr, int optional)
474 if ((ptr[0] >= 33 && ptr[0] <= 90) || (ptr[0] >= 94 && ptr[0] <= 126))
475 return ptr + 1;
476 return osmtpd_mheader_skip_obs_dtext(ptr, optional);
480 char *
481 osmtpd_mheader_skip_domain_literal(char *ptr, int optional)
483 char *start = ptr, *prev;
485 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
486 if (ptr++[0] != '[')
487 return optional ? start : NULL;
488 while (1) {
489 ptr = osmtpd_mheader_skip_fws(ptr, 1);
490 prev = ptr;
491 if ((ptr = osmtpd_mheader_skip_dtext(ptr, 0)) == NULL) {
492 ptr = prev;
493 break;
496 if (ptr[0] != ']')
497 return optional ? start : NULL;
498 return osmtpd_mheader_skip_cfws(ptr, 1);
501 char *
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;
508 prev = ptr;
509 while (1) {
510 if (ptr++[0] != '.')
511 return prev;
512 if ((ptr = osmtpd_mheader_skip_atom(ptr, 0)) == NULL)
513 return prev;
514 prev = ptr;
518 char *
519 osmtpd_mheader_skip_domain(char *ptr, int optional)
521 char *start = ptr;
523 if ((ptr = osmtpd_mheader_skip_dot_atom(start, 0)) != NULL)
524 return ptr;
525 if ((ptr = osmtpd_mheader_skip_domain_literal(start, 0)) != NULL)
526 return ptr;
527 return osmtpd_mheader_skip_obs_domain(start, optional);
530 char *
531 osmtpd_mheader_skip_display_name(char *ptr, int optional)
533 return osmtpd_mheader_skip_phrase(ptr, optional);
536 char *
537 osmtpd_mheader_skip_obs_domain_list(char *ptr, int optional)
539 char *start = ptr, *prev;
541 while (1) {
542 if (ptr[0] == ',') {
543 ptr++;
544 prev = ptr;
545 continue;
546 } else if ((ptr = osmtpd_mheader_skip_cfws(ptr, 0)) != NULL) {
547 prev = ptr;
548 continue;
550 break;
552 ptr = prev;
554 if (ptr++[0] != '@')
555 return optional ? start : NULL;
556 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
557 return optional ? start : NULL;
558 while (1) {
559 if (ptr[0] != ',')
560 break;
561 ptr++;
562 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
563 if (ptr[0] != '@')
564 continue;
565 prev = ptr;
566 if ((ptr = osmtpd_mheader_skip_domain(ptr + 1, 0)) == NULL) {
567 ptr = prev;
568 break;
571 return ptr;
574 char *
575 osmtpd_mheader_skip_obs_route(char *ptr, int optional)
577 char *start = ptr;
579 if ((ptr = osmtpd_mheader_skip_obs_domain_list(ptr, 0)) == NULL)
580 return optional ? start : NULL;
581 if (ptr++[0] != ':')
582 return optional ? start : NULL;
583 return ptr;
586 char *
587 osmtpd_mheader_skip_addr_spec(char *ptr, int optional)
589 char *start = ptr;
591 if ((ptr = osmtpd_mheader_skip_local_part(ptr, 0)) == NULL)
592 return optional ? start : NULL;
593 if (ptr++[0] != '@')
594 return optional ? start : NULL;
595 if ((ptr = osmtpd_mheader_skip_domain(ptr, 0)) == NULL)
596 return optional ? start : NULL;
597 return ptr;
600 char *
601 osmtpd_mheader_skip_obs_angle_addr(char *ptr, int optional)
603 char *start = ptr;
605 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
606 if (ptr++[0] != '<')
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;
612 if (ptr++[0] != '>')
613 return optional ? start : NULL;
614 return osmtpd_mheader_skip_cfws(ptr, 1);
617 char *
618 osmtpd_mheader_skip_angle_addr(char *ptr, int optional)
620 char *start = ptr;
622 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
623 if (ptr++[0] != '<')
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);
627 if (ptr++[0] != '>')
628 return osmtpd_mheader_skip_obs_angle_addr(start, optional);
629 return osmtpd_mheader_skip_cfws(ptr, 1);
632 char *
633 osmtpd_mheader_skip_name_addr(char *ptr, int optional)
635 char *start = ptr;
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;
640 return ptr;
643 /* RFC 2045 */
644 char *
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] == '=')
651 return ptr + 1;
652 return optional ? ptr : NULL;
656 char *
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;
668 ptr++;
669 while (1) {
670 if (osmtpd_mheader_skip_char(ptr, 0) == NULL)
671 return ptr;
672 if (osmtpd_mheader_skip_wsp(ptr, 0) != NULL)
673 return ptr;
674 if (osmtpd_mheader_skip_ctl(ptr, 0) != NULL)
675 return ptr;
676 if (osmtpd_mheader_skip_tspecials(ptr, 0) != NULL)
677 return ptr;
678 ptr++;
682 char *
683 osmtpd_mheader_skip_value(char *ptr, int optional)
685 char *start = ptr;
687 if ((ptr = osmtpd_mheader_skip_token(ptr, 0)) == NULL)
688 return osmtpd_mheader_skip_quoted_string(start, optional);
689 return ptr;
692 /* Return the domain component of the first mailbox */
693 char *
694 osmtpd_mheader_from_domain(char *ptr)
696 char *tmp;
698 /* from */
699 if (strncasecmp(ptr, "from:", 5) == 0) {
700 ptr += 5;
701 /* obs-from */
702 } else if (strncasecmp(ptr, "from", 4) == 0) {
703 ptr += 4;
704 do {
705 tmp = ptr;
706 } while ((ptr = osmtpd_mheader_skip_wsp(ptr, 0)) != NULL);
707 ptr = tmp;
708 if (ptr++[0] != ':')
709 return NULL;
710 } else {
711 errno = EINVAL;
712 return NULL;
715 /* Both from and obs-from use Mailbox-list CRLF */
716 /* obs-mbox-list has just a prefix compared to mailbox-list */
717 while (1) {
718 tmp = ptr;
719 ptr = osmtpd_mheader_skip_cfws(ptr, 1);
720 if (ptr++[0] != ',') {
721 ptr = tmp;
722 break;
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);
729 /* < */
730 ptr++;
731 /* addr-spec */
732 ptr = osmtpd_mheader_skip_local_part(ptr, 0);
733 /* @ */
734 ptr++;
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);
740 /* @ */
741 ptr++;
742 tmp = osmtpd_mheader_skip_domain(ptr, 0);
743 return strndup(ptr, tmp - ptr);
745 errno = EINVAL;
746 return NULL;