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_xcalloc(strlen(s) + 2, sizeof(char));
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 accommodate 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;
185 dp = cp = getcpy(addrs ? addrs : "");
187 } else if (cp == NULL) {
192 switch (parse_address()) {
204 default: /* catch trailing comments */
232 sprintf(adr, "%.*s", (int)(cp - ap), ap);
235 bp = adr + strlen(adr) - 1;
236 if (*bp == ',' || *bp == ';' || *bp == '\n')
245 adrxp->ingrp = ingrp;
247 adrxp->err = err[0] ? err : NULL;
260 switch (my_lex(buffer)) {
263 pers = getcpy(buffer);
268 strcpy(err, "extraneous semi-colon");
280 case LX_LBRK: /* sigh (2) */
283 case LX_AT: /* sigh (3) */
285 if (route_addr(buffer) == NOTOK)
287 return OK; /* why be choosy? */
290 sprintf(err, "illegal address construct (%s)", buffer);
294 switch (my_lex(buffer)) {
297 pers = add(buffer, add(" ", pers));
298 more_phrase: ; /* sigh (1) */
299 if (phrase(buffer) == NOTOK)
305 if (route_addr(buffer) == NOTOK)
307 if (last_lex == LX_RBRK)
309 sprintf(err, "missing right-bracket (%s)", buffer);
315 sprintf(err, "nested groups not allowed (%s)", pers);
318 grp = add(": ", pers);
324 switch (my_lex(buffer)) {
326 case LX_END: /* tsk, tsk */
335 return parse_address();
339 case LX_DOT: /* sigh (1) */
340 pers = add(".", pers);
344 sprintf(err, "no mailbox in address, only a phrase (%s%s)", pers, buffer);
355 mbox = add(buffer, pers);
357 if (route_addr(buffer) == NOTOK)
365 if (domain(buffer) == NOTOK)
371 strcpy(err, "extraneous semi-colon");
379 sprintf(err, "junk after local@domain (%s)", buffer);
383 case LX_SEMI: /* no host */
387 if (last_lex == LX_SEMI && glevel-- <= 0) {
388 strcpy(err, "extraneous semi-colon");
396 sprintf(err, "missing mailbox (%s)", buffer);
406 switch (my_lex(buffer)) {
409 pers = add(buffer, add(" ", pers));
419 route_addr(char *buffer)
423 if (my_lex(buffer) == LX_AT) {
424 if (route(buffer) == NOTOK)
430 if (local_part(buffer) == NOTOK)
435 return domain(buffer);
437 case LX_SEMI: /* if in group */
438 case LX_RBRK: /* no host */
444 sprintf(err, "no at-sign after local-part (%s)", buffer);
451 local_part(char *buffer)
456 switch (my_lex(buffer)) {
459 mbox = add(buffer, mbox);
463 sprintf(err, "no mailbox in local-part (%s)", buffer);
467 switch (my_lex(buffer)) {
469 mbox = add(buffer, mbox);
483 switch (my_lex(buffer)) {
486 host = add(buffer, host);
490 sprintf(err, "no sub-domain in domain-part of address (%s)", buffer);
494 switch (my_lex(buffer)) {
496 host = add(buffer, host);
499 case LX_AT: /* sigh (0) */
500 mbox = add(host, add("%", mbox));
517 switch (my_lex(buffer)) {
520 path = add(buffer, path);
524 sprintf(err, "no sub-domain in domain-part of address (%s)", buffer);
527 switch (my_lex(buffer)) {
529 path = add(buffer, path);
531 switch (my_lex(buffer)) {
536 path = add(buffer, path);
540 sprintf(err, "no at-sign found for next domain in route (%s)",
547 case LX_AT: /* XXX */
549 path = add(buffer, path);
553 path = add(buffer, path);
557 sprintf(err, "no colon found to terminate route (%s)", buffer);
567 /* buffer should be at least BUFSIZ bytes long */
573 ** Add C to the buffer bp. After use of this macro *bp is guaranteed
574 ** to be within the buffer.
579 if ((bp - buffer) == (BUFSIZ-1)) \
580 goto my_lex_buffull; \
586 return (last_lex = LX_END);
593 return (last_lex = LX_END);
602 return (last_lex = LX_ERR);
605 if ((c = *cp++) == 0) {
607 return (last_lex = LX_ERR);
620 note = note ? add(buffer, add(" ", note)) : getcpy(buffer);
621 return my_lex(buffer);
632 return (last_lex = LX_ERR);
635 if ((c = *cp++) == 0) {
637 return (last_lex = LX_ERR);
645 return (last_lex = LX_QSTR);
655 return (last_lex = LX_ERR);
658 if ((c = *cp++) == 0) {
660 return (last_lex = LX_ERR);
668 return (last_lex = LX_DLIT);
674 for (i = 0; special[i].lx_chr != 0; i++)
675 if (c == special[i].lx_chr)
676 return (last_lex = special[i].lx_val);
679 return (last_lex = LX_ERR);
682 if ((c = *cp++) == 0)
684 for (i = 0; special[i].lx_chr != 0; i++)
685 if (c == special[i].lx_chr)
687 if (iscntrl(c) || isspace(c))
700 /* Out of buffer space. *bp is the last byte in the buffer */
702 return (last_lex = LX_ERR);
707 legal_person(char *p)
711 static char buffer[BUFSIZ];
715 for (cp = p; *cp; cp++)
716 for (i = 0; special[i].lx_chr; i++)
717 if (*cp == special[i].lx_chr) {
718 sprintf(buffer, "\"%s\"", p);