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.
17 static char *getcpy(char *);
18 static int parse_address(void);
19 static int phrase(char *);
20 static int route_addr(char *);
21 static int local_part(char *);
22 static int domain(char *);
23 static int route(char *);
24 static int my_lex(char *);
34 ** causes compiles to blow up because the symbol _cleanup
35 ** is undefined where did this ever come from?
42 p = mh_xmalloc((size_t) (strlen(s) + 2));
50 ** getadrx() implements a partial 822-style address parser. The parser
51 ** is neither complete nor correct. It does however recognize nearly all
52 ** of the 822 address syntax.
53 ** Historically, it handled the majority (and still handles parts) of the
54 ** 733 syntax as well. Most problems arise from trying to accomodate both.
56 ** In terms of 822, the route-specification in
58 ** "<" [route] local-part "@" domain ">"
60 ** is parsed and returned unchanged. Multiple at-signs are compressed
61 ** via source-routing. Recursive groups are not allowed as per the
64 ** In terms of both the parser will not complain about missing hosts.
68 ** We should not allow addresses like
70 ** Marshall T. Rose <MRose@UCI>
72 ** but should insist on
74 ** "Marshall T. Rose" <MRose@UCI>
76 ** Unfortunately, a lot of mailers stupidly let people get away with this.
80 ** We should not allow addresses like
84 ** but should insist on
88 ** Unfortunately, a lot of mailers stupidly let people's UAs get away with
93 ** We should not allow addresses like
95 ** @UCI:MRose@UCI-750a
97 ** but should insist on
99 ** Marshall Rose <@UCI:MRose@UCI-750a>
101 ** Unfortunately, a lot of mailers stupidly do this.
125 static struct specials special[] = {
142 static int glevel = 0;
143 static int ingrp = 0;
144 static int last_lex = LX_END;
146 static char *dp = NULL;
147 static unsigned char *cp = NULL;
148 static unsigned char *ap = NULL;
149 static char *pers = NULL;
150 static char *mbox = NULL;
151 static char *host = NULL;
152 static char *path = NULL;
153 static char *grp = NULL;
154 static char *note = NULL;
155 static char err[BUFSIZ];
156 static char adr[BUFSIZ];
158 static struct adrx adrxs2;
165 register struct adrx *adrxp = &adrxs2;
179 pers = mbox = host = path = grp = note = NULL;
183 dp = cp = getcpy(addrs ? addrs : "");
185 } else if (cp == NULL) {
191 switch (parse_address()) {
203 default: /* catch trailing comments */
231 sprintf(adr, "%.*s", (int)(cp - ap), ap);
234 bp = adr + strlen(adr) - 1;
235 if (*bp == ',' || *bp == ';' || *bp == '\n')
244 adrxp->ingrp = ingrp;
246 adrxp->err = err[0] ? err : NULL;
259 switch (my_lex(buffer)) {
262 pers = getcpy(buffer);
267 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)
421 register char *pp = cp;
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));
518 switch (my_lex(buffer)) {
521 path = add(buffer, path);
525 sprintf(err, "no sub-domain in domain-part of address (%s)", buffer);
528 switch (my_lex(buffer)) {
530 path = add(buffer, path);
532 switch (my_lex(buffer)) {
537 path = add(buffer, path);
541 sprintf(err, "no at-sign found for next domain in route (%s)",
548 case LX_AT: /* XXX */
550 path = add(buffer, path);
554 path = add(buffer, path);
558 sprintf(err, "no colon found to terminate route (%s)", buffer);
568 /* buffer should be at least BUFSIZ bytes long */
570 register unsigned char c;
574 ** Add C to the buffer bp. After use of this macro *bp is guaranteed
575 ** to be within the buffer.
580 if ((bp - buffer) == (BUFSIZ-1)) \
581 goto my_lex_buffull; \
587 return (last_lex = LX_END);
594 return (last_lex = LX_END);
603 return (last_lex = LX_ERR);
606 if ((c = *cp++) == 0) {
608 return (last_lex = LX_ERR);
621 note = note ? add(buffer, add(" ", note)) : getcpy(buffer);
622 return my_lex(buffer);
633 return (last_lex = LX_ERR);
636 if ((c = *cp++) == 0) {
638 return (last_lex = LX_ERR);
646 return (last_lex = LX_QSTR);
656 return (last_lex = LX_ERR);
659 if ((c = *cp++) == 0) {
661 return (last_lex = LX_ERR);
669 return (last_lex = LX_DLIT);
675 for (i = 0; special[i].lx_chr != 0; i++)
676 if (c == special[i].lx_chr)
677 return (last_lex = special[i].lx_val);
680 return (last_lex = LX_ERR);
683 if ((c = *cp++) == 0)
685 for (i = 0; special[i].lx_chr != 0; i++)
686 if (c == special[i].lx_chr)
688 if (iscntrl(c) || isspace(c))
701 /* Out of buffer space. *bp is the last byte in the buffer */
703 return (last_lex = LX_ERR);
708 legal_person(char *p)
712 static char buffer[BUFSIZ];
716 for (cp = p; *cp; cp++)
717 for (i = 0; special[i].lx_chr; i++)
718 if (*cp == special[i].lx_chr) {
719 sprintf(buffer, "\"%s\"", p);