2 ** mf.c -- mail filter subroutines
4 ** This code is Copyright (c) 2002, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
20 static char *getcpy(char *);
21 static int parse_address(void);
22 static int phrase(char *);
23 static int route_addr(char *);
24 static int local_part(char *);
25 static int domain(char *);
26 static int route(char *);
27 static int my_lex(char *);
37 ** causes compiles to blow up because the symbol _cleanup
38 ** is undefined where did this ever come from?
45 p = mh_xmalloc((size_t) (strlen(s) + 2));
53 ** getadrx() implements a partial 822-style address parser. The parser
54 ** is neither complete nor correct. It does however recognize nearly all
55 ** of the 822 address syntax.
56 ** Historically, it handled the majority (and still handles parts) of the
57 ** 733 syntax as well. Most problems arise from trying to accomodate both.
59 ** In terms of 822, the route-specification in
61 ** "<" [route] local-part "@" domain ">"
63 ** is parsed and returned unchanged. Multiple at-signs are compressed
64 ** via source-routing. Recursive groups are not allowed as per the
67 ** In terms of both the parser will not complain about missing hosts.
71 ** We should not allow addresses like
73 ** Marshall T. Rose <MRose@UCI>
75 ** but should insist on
77 ** "Marshall T. Rose" <MRose@UCI>
79 ** Unfortunately, a lot of mailers stupidly let people get away with this.
83 ** We should not allow addresses like
87 ** but should insist on
91 ** Unfortunately, a lot of mailers stupidly let people's UAs get away with
96 ** We should not allow addresses like
98 ** @UCI:MRose@UCI-750a
100 ** but should insist on
102 ** Marshall Rose <@UCI:MRose@UCI-750a>
104 ** Unfortunately, a lot of mailers stupidly do this.
128 static struct specials special[] = {
145 static int glevel = 0;
146 static int ingrp = 0;
147 static int last_lex = LX_END;
149 static char *dp = NULL;
150 static unsigned char *cp = NULL;
151 static unsigned char *ap = NULL;
152 static char *pers = NULL;
153 static char *mbox = NULL;
154 static char *host = NULL;
155 static char *path = NULL;
156 static char *grp = NULL;
157 static char *note = NULL;
158 static char err[BUFSIZ];
159 static char adr[BUFSIZ];
161 static struct adrx adrxs2;
168 struct adrx *adrxp = &adrxs2;
182 pers = mbox = host = path = grp = note = NULL;
186 dp = cp = getcpy(addrs ? addrs : "");
188 } else if (cp == NULL) {
194 switch (parse_address()) {
206 default: /* catch trailing comments */
234 sprintf(adr, "%.*s", (int)(cp - ap), ap);
237 bp = adr + strlen(adr) - 1;
238 if (*bp == ',' || *bp == ';' || *bp == '\n')
247 adrxp->ingrp = ingrp;
249 adrxp->err = err[0] ? err : NULL;
262 switch (my_lex(buffer)) {
265 pers = getcpy(buffer);
270 strcpy(err, "extraneous semi-colon");
283 case LX_LBRK: /* sigh (2) */
286 case LX_AT: /* sigh (3) */
288 if (route_addr(buffer) == NOTOK)
290 return OK; /* why be choosy? */
293 sprintf(err, "illegal address construct (%s)", buffer);
297 switch (my_lex(buffer)) {
300 pers = add(buffer, add(" ", pers));
301 more_phrase: ; /* sigh (1) */
302 if (phrase(buffer) == NOTOK)
308 if (route_addr(buffer) == NOTOK)
310 if (last_lex == LX_RBRK)
312 sprintf(err, "missing right-bracket (%s)", buffer);
318 sprintf(err, "nested groups not allowed (%s)", pers);
321 grp = add(": ", pers);
327 switch (my_lex(buffer)) {
329 case LX_END: /* tsk, tsk */
338 return parse_address();
342 case LX_DOT: /* sigh (1) */
343 pers = add(".", pers);
347 sprintf(err, "no mailbox in address, only a phrase (%s%s)", pers, buffer);
358 mbox = add(buffer, pers);
360 if (route_addr(buffer) == NOTOK)
368 if (domain(buffer) == NOTOK)
374 strcpy(err, "extraneous semi-colon");
382 sprintf(err, "junk after local@domain (%s)", buffer);
386 case LX_SEMI: /* no host */
390 if (last_lex == LX_SEMI && glevel-- <= 0) {
391 strcpy(err, "extraneous semi-colon");
399 sprintf(err, "missing mailbox (%s)", buffer);
409 switch (my_lex(buffer)) {
412 pers = add(buffer, add(" ", pers));
422 route_addr(char *buffer)
426 if (my_lex(buffer) == LX_AT) {
427 if (route(buffer) == NOTOK)
433 if (local_part(buffer) == NOTOK)
438 return domain(buffer);
440 case LX_SEMI: /* if in group */
441 case LX_RBRK: /* no host */
447 sprintf(err, "no at-sign after local-part (%s)", buffer);
454 local_part(char *buffer)
459 switch (my_lex(buffer)) {
462 mbox = add(buffer, mbox);
466 sprintf(err, "no mailbox in local-part (%s)", buffer);
470 switch (my_lex(buffer)) {
472 mbox = add(buffer, mbox);
486 switch (my_lex(buffer)) {
489 host = add(buffer, host);
493 sprintf(err, "no sub-domain in domain-part of address (%s)", buffer);
497 switch (my_lex(buffer)) {
499 host = add(buffer, host);
502 case LX_AT: /* sigh (0) */
503 mbox = add(host, add("%", mbox));
521 switch (my_lex(buffer)) {
524 path = add(buffer, path);
528 sprintf(err, "no sub-domain in domain-part of address (%s)", buffer);
531 switch (my_lex(buffer)) {
533 path = add(buffer, path);
535 switch (my_lex(buffer)) {
540 path = add(buffer, path);
544 sprintf(err, "no at-sign found for next domain in route (%s)",
551 case LX_AT: /* XXX */
553 path = add(buffer, path);
557 path = add(buffer, path);
561 sprintf(err, "no colon found to terminate route (%s)", buffer);
571 /* buffer should be at least BUFSIZ bytes long */
577 ** Add C to the buffer bp. After use of this macro *bp is guaranteed
578 ** to be within the buffer.
583 if ((bp - buffer) == (BUFSIZ-1)) \
584 goto my_lex_buffull; \
590 return (last_lex = LX_END);
597 return (last_lex = LX_END);
606 return (last_lex = LX_ERR);
609 if ((c = *cp++) == 0) {
611 return (last_lex = LX_ERR);
624 note = note ? add(buffer, add(" ", note)) : getcpy(buffer);
625 return my_lex(buffer);
636 return (last_lex = LX_ERR);
639 if ((c = *cp++) == 0) {
641 return (last_lex = LX_ERR);
649 return (last_lex = LX_QSTR);
659 return (last_lex = LX_ERR);
662 if ((c = *cp++) == 0) {
664 return (last_lex = LX_ERR);
672 return (last_lex = LX_DLIT);
678 for (i = 0; special[i].lx_chr != 0; i++)
679 if (c == special[i].lx_chr)
680 return (last_lex = special[i].lx_val);
683 return (last_lex = LX_ERR);
686 if ((c = *cp++) == 0)
688 for (i = 0; special[i].lx_chr != 0; i++)
689 if (c == special[i].lx_chr)
691 if (iscntrl(c) || isspace(c))
704 /* Out of buffer space. *bp is the last byte in the buffer */
706 return (last_lex = LX_ERR);
711 legal_person(char *p)
715 static char buffer[BUFSIZ];
719 for (cp = p; *cp; cp++)
720 for (i = 0; special[i].lx_chr; i++)
721 if (*cp == special[i].lx_chr) {
722 sprintf(buffer, "\"%s\"", p);