]>
diplodocus.org Git - nmh/blob - sbr/mf.c
3 * mf.c -- mail filter subroutines
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
16 static int isat (const char *);
17 static int parse_address (void);
18 static int phrase (char *);
19 static int route_addr (char *);
20 static int local_part (char *);
21 static int domain (char *);
22 static int route (char *);
23 static int my_lex (char *);
27 isfrom(const char *string
)
29 return (HasPrefix(string
, "From ")
30 || HasPrefix(string
, ">From "));
35 lequal (const char *a
, const char *b
)
39 for (; *a
; a
++, b
++) {
42 c1
= toupper((unsigned char)*a
);
43 c2
= toupper((unsigned char)*b
);
55 return HasPrefix(p
, " AT ") || HasPrefix(p
, " At ") ||
56 HasPrefix(p
, " aT ") || HasPrefix(p
, " at ");
62 * getadrx() implements a partial 822-style address parser. The parser
63 * is neither complete nor correct. It does however recognize nearly all
64 * of the 822 address syntax. In addition it handles the majority of the
65 * 733 syntax as well. Most problems arise from trying to accommodate both.
67 * In terms of 822, the route-specification in
69 * "<" [route] local-part "@" domain ">"
71 * is parsed and returned unchanged. Multiple at-signs are compressed
72 * via source-routing. Recursive groups are not allowed as per the
75 * In terms of 733, " at " is recognized as equivalent to "@".
77 * In terms of both the parser will not complain about missing hosts.
81 * We should not allow addresses like
83 * Marshall T. Rose <MRose@UCI>
85 * but should insist on
87 * "Marshall T. Rose" <MRose@UCI>
89 * Unfortunately, a lot of mailers stupidly let people get away with this.
93 * We should not allow addresses like
97 * but should insist on
101 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
106 * We should not allow addresses like
108 * @UCI:MRose@UCI-750a
110 * but should insist on
112 * Marshall Rose <@UCI:MRose@UCI-750a>
114 * Unfortunately, a lot of mailers stupidly do this.
138 static struct specials special
[] = {
155 static int glevel
= 0;
156 static int ingrp
= 0;
157 static int last_lex
= LX_END
;
159 static char *dp
= NULL
;
160 static char *cp
= NULL
;
161 static char *ap
= NULL
;
162 static char *pers
= NULL
;
163 static char *mbox
= NULL
;
164 static char *host
= NULL
;
165 static char *path
= NULL
;
166 static char *grp
= NULL
;
167 static char *note
= NULL
;
168 static char err
[BUFSIZ
];
169 static char adr
[BUFSIZ
];
171 static struct adrx adrxs2
;
174 /* eai = Email Address Internationalization */
176 getadrx (const char *addrs
, int eai
)
179 struct adrx
*adrxp
= &adrxs2
;
187 pers
= mbox
= host
= path
= grp
= note
= NULL
;
191 dp
= cp
= strdup (addrs
? addrs
: "");
201 switch (parse_address ()) {
213 default: /* catch trailing comments */
227 * Reject the address if key fields contain 8bit characters
230 if (contains8bit(mbox
, NULL
) || contains8bit(host
, NULL
) ||
231 contains8bit(path
, NULL
) || contains8bit(grp
, NULL
)) {
232 strcpy(err
, "Address contains 8-bit characters");
249 while (isspace ((unsigned char) *ap
))
252 snprintf(adr
, sizeof adr
, "%.*s", (int)(cp
- ap
), ap
);
255 bp
= adr
+ strlen (adr
) - 1;
256 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
265 adrxp
->ingrp
= ingrp
;
267 adrxp
->err
= err
[0] ? err
: NULL
;
280 switch (my_lex (buffer
)) {
283 pers
= strdup (buffer
);
288 strcpy (err
, "extraneous semi-colon");
299 case LX_LBRK
: /* sigh (2) */
302 case LX_AT
: /* sigh (3) */
304 if (route_addr (buffer
) == NOTOK
)
306 return OK
; /* why be choosy? */
309 snprintf(err
, sizeof err
, "illegal address construct (%s)", buffer
);
313 switch (my_lex (buffer
)) {
316 pers
= add (buffer
, add (" ", pers
));
317 more_phrase
: ; /* sigh (1) */
318 if (phrase (buffer
) == NOTOK
)
324 if (route_addr (buffer
) == NOTOK
)
326 if (last_lex
== LX_RBRK
)
328 snprintf(err
, sizeof err
, "missing right-bracket (%s)", buffer
);
334 snprintf(err
, sizeof err
, "nested groups not allowed (%s)", pers
);
337 grp
= add (": ", pers
);
343 switch (my_lex (buffer
)) {
345 case LX_END
: /* tsk, tsk */
354 return parse_address ();
358 case LX_DOT
: /* sigh (1) */
359 pers
= add (".", pers
);
363 snprintf(err
, sizeof err
, "no mailbox in address, only a phrase (%s%s)",
375 mbox
= add (buffer
, pers
);
377 if (route_addr (buffer
) == NOTOK
)
385 if (domain (buffer
) == NOTOK
)
391 strcpy (err
, "extraneous semi-colon");
399 snprintf(err
, sizeof err
, "junk after local@domain (%s)", buffer
);
403 case LX_SEMI
: /* no host */
407 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
408 strcpy (err
, "extraneous semi-colon");
416 snprintf(err
, sizeof err
, "missing mailbox (%s)", buffer
);
423 phrase (char *buffer
)
426 switch (my_lex (buffer
)) {
429 pers
= add (buffer
, add (" ", pers
));
439 route_addr (char *buffer
)
443 if (my_lex (buffer
) == LX_AT
) {
444 if (route (buffer
) == NOTOK
)
450 if (local_part (buffer
) == NOTOK
)
455 return domain (buffer
);
457 case LX_SEMI
: /* if in group */
458 case LX_RBRK
: /* no host */
464 snprintf(err
, sizeof err
, "no at-sign after local-part (%s)", buffer
);
471 local_part (char *buffer
)
476 switch (my_lex (buffer
)) {
479 mbox
= add (buffer
, mbox
);
483 snprintf(err
, sizeof err
, "no mailbox in local-part (%s)", buffer
);
487 switch (my_lex (buffer
)) {
489 mbox
= add (buffer
, mbox
);
500 domain (char *buffer
)
503 switch (my_lex (buffer
)) {
506 host
= add (buffer
, host
);
510 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
514 switch (my_lex (buffer
)) {
516 host
= add (buffer
, host
);
519 case LX_AT
: /* sigh (0) */
520 mbox
= add (host
, add ("%", mbox
));
538 switch (my_lex (buffer
)) {
541 path
= add (buffer
, path
);
545 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
548 switch (my_lex (buffer
)) {
550 path
= add (buffer
, path
);
552 switch (my_lex (buffer
)) {
557 path
= add (buffer
, path
);
561 snprintf(err
, sizeof err
, "no at-sign found for next domain in route (%s)",
568 case LX_AT
: /* XXX */
570 path
= add (buffer
, path
);
574 path
= add (buffer
, path
);
578 snprintf(err
, sizeof err
, "no colon found to terminate route (%s)", buffer
);
586 my_lex (char *buffer
)
588 /* buffer should be at least BUFSIZ bytes long */
592 /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
593 #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
598 return (last_lex
= LX_END
);
602 while (isspace ((unsigned char) c
))
606 return (last_lex
= LX_END
);
615 return (last_lex
= LX_ERR
);
618 if ((c
= *cp
++) == 0) {
620 return (last_lex
= LX_ERR
);
633 note
= note
? add (buffer
, add (" ", note
))
635 return my_lex (buffer
);
646 return (last_lex
= LX_ERR
);
649 if ((c
= *cp
++) == 0) {
651 return (last_lex
= LX_ERR
);
659 return (last_lex
= LX_QSTR
);
669 return (last_lex
= LX_ERR
);
672 if ((c
= *cp
++) == 0) {
674 return (last_lex
= LX_ERR
);
682 return (last_lex
= LX_DLIT
);
688 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
689 if (c
== special
[i
].lx_chr
)
690 return (last_lex
= special
[i
].lx_val
);
692 if (iscntrl ((unsigned char) c
))
693 return (last_lex
= LX_ERR
);
696 if ((c
= *cp
++) == 0)
698 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
699 if (c
== special
[i
].lx_chr
)
701 if (iscntrl ((unsigned char) c
) || isspace ((unsigned char) c
))
711 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
716 /* Out of buffer space. *bp is the last byte in the buffer */
718 return (last_lex
= LX_ERR
);
723 legal_person (const char *p
)
727 static char buffer
[BUFSIZ
];
731 for (cp
= p
; *cp
; cp
++)
732 for (i
= 0; special
[i
].lx_chr
; i
++)
733 if (*cp
== special
[i
].lx_chr
) {
734 snprintf(buffer
, sizeof buffer
, "\"%s\"", p
);
743 mfgets (FILE *in
, char **bp
)
748 static char *pp
= NULL
;
751 pp
= mh_xmalloc ((size_t) (len
= BUFSIZ
));
753 for (ep
= (cp
= pp
) + len
- 2;;) {
754 switch (i
= getc (in
)) {
772 if (cp
== pp
) /* end of headers, gobble it */
774 switch (i
= getc (in
)) {
775 default: /* end of line */
776 case '\n': /* end of headers, save for next call */
780 case ' ': /* continue headers */
784 } /* fall into default case */
791 dp
= mh_xrealloc (pp
, (size_t) (len
+= BUFSIZ
));
792 cp
+= dp
- pp
, ep
= (pp
= cp
) + len
- 2;