]>
diplodocus.org Git - nmh/blob - sbr/mf.c
1 /* mf.c -- mail filter subroutines
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
15 static int isat (const char *);
16 static int parse_address (void);
17 static int phrase (char *);
18 static int route_addr (char *);
19 static int local_part (char *);
20 static int domain (char *);
21 static int route (char *);
22 static int my_lex (char *);
29 (p
[1] == 'a' || p
[1] == 'A') &&
30 (p
[2] == 't' || p
[2] == 'T') &&
37 * getadrx() implements a partial 822-style address parser. The parser
38 * is neither complete nor correct. It does however recognize nearly all
39 * of the 822 address syntax. In addition it handles the majority of the
40 * 733 syntax as well. Most problems arise from trying to accommodate both.
42 * In terms of 822, the route-specification in
44 * "<" [route] local-part "@" domain ">"
46 * is parsed and returned unchanged. Multiple at-signs are compressed
47 * via source-routing. Recursive groups are not allowed as per the
50 * In terms of 733, " at " is recognized as equivalent to "@".
52 * In terms of both the parser will not complain about missing hosts.
56 * We should not allow addresses like
58 * Marshall T. Rose <MRose@UCI>
60 * but should insist on
62 * "Marshall T. Rose" <MRose@UCI>
64 * Unfortunately, a lot of mailers stupidly let people get away with this.
68 * We should not allow addresses like
72 * but should insist on
76 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
81 * We should not allow addresses like
85 * but should insist on
87 * Marshall Rose <@UCI:MRose@UCI-750a>
89 * Unfortunately, a lot of mailers stupidly do this.
111 static struct specials special
[] = {
128 static int glevel
= 0;
129 static int ingrp
= 0;
130 static int last_lex
= LX_END
;
132 static char *dp
= NULL
;
133 static char *cp
= NULL
;
134 static char *ap
= NULL
;
135 static char *pers
= NULL
;
136 static char *mbox
= NULL
;
137 static char *host
= NULL
;
138 static char *routepath
= NULL
;
139 static char *grp
= NULL
;
140 static char *note
= NULL
;
141 static char err
[BUFSIZ
];
142 static char adr
[BUFSIZ
];
144 static struct adrx adrxs2
;
147 /* eai = Email Address Internationalization */
149 getadrx (const char *addrs
, int eai
)
153 struct adrx
*adrxp
= &adrxs2
;
161 pers
= mbox
= host
= routepath
= grp
= note
= NULL
;
165 dp
= cp
= strdup (FENDNULL(addrs
));
167 } else if (cp
== NULL
) {
173 parse
= parse_address();
179 if (parse
== OK
&& last_lex
!= LX_COMA
&& last_lex
!= LX_END
) {
180 /* catch trailing comments */
186 /* Reject the address if key fields contain 8bit characters. */
188 (contains8bit(mbox
, NULL
) || contains8bit(host
, NULL
) ||
189 contains8bit(routepath
, NULL
) || contains8bit(grp
, NULL
)))
190 strcpy(err
, "Address contains 8-bit characters");
193 while (last_lex
!= LX_COMA
&& last_lex
!= LX_END
)
196 while (isspace ((unsigned char) *ap
))
199 snprintf(adr
, sizeof adr
, "%.*s", (int)(cp
- ap
), ap
);
202 bp
= adr
+ strlen (adr
) - 1;
203 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
210 adrxp
->path
= routepath
;
212 adrxp
->ingrp
= ingrp
;
214 adrxp
->err
= err
[0] ? err
: NULL
;
227 switch (my_lex (buffer
)) {
230 pers
= strdup (buffer
);
235 strcpy (err
, "extraneous semi-colon");
247 case LX_LBRK
: /* sigh (2) */
250 case LX_AT
: /* sigh (3) */
252 if (route_addr (buffer
) == NOTOK
)
254 return OK
; /* why be choosy? */
257 snprintf(err
, sizeof err
, "illegal address construct (%s)", buffer
);
261 switch (my_lex (buffer
)) {
264 pers
= add (buffer
, add (" ", pers
));
265 more_phrase
: ; /* sigh (1) */
266 if (phrase (buffer
) == NOTOK
)
272 if (route_addr (buffer
) == NOTOK
)
274 if (last_lex
== LX_RBRK
)
276 snprintf(err
, sizeof err
, "missing right-bracket (%s)", buffer
);
282 snprintf(err
, sizeof err
, "nested groups not allowed (%s)", pers
);
285 grp
= add (": ", pers
);
291 switch (my_lex (buffer
)) {
293 case LX_END
: /* tsk, tsk */
302 return parse_address ();
306 case LX_DOT
: /* sigh (1) */
307 pers
= add (".", pers
);
311 snprintf(err
, sizeof err
, "no mailbox in address, only a phrase (%s%s)",
323 mbox
= add (buffer
, pers
);
325 if (route_addr (buffer
) == NOTOK
)
333 if (domain (buffer
) == NOTOK
)
339 strcpy (err
, "extraneous semi-colon");
348 snprintf(err
, sizeof err
, "junk after local@domain (%s)", buffer
);
352 case LX_SEMI
: /* no host */
356 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
357 strcpy (err
, "extraneous semi-colon");
365 snprintf(err
, sizeof err
, "missing mailbox (%s)", buffer
);
372 phrase (char *buffer
)
376 while ((lex
= my_lex(buffer
)) == LX_ATOM
|| lex
== LX_QSTR
)
377 pers
= add(buffer
, add(" ", pers
));
384 route_addr (char *buffer
)
388 if (my_lex (buffer
) == LX_AT
) {
389 if (route (buffer
) == NOTOK
)
395 if (local_part (buffer
) == NOTOK
)
400 return domain (buffer
);
402 case LX_SEMI
: /* if in group */
403 case LX_RBRK
: /* no host */
409 snprintf(err
, sizeof err
, "no at-sign after local-part (%s)", buffer
);
416 local_part (char *buffer
)
421 switch (my_lex (buffer
)) {
424 mbox
= add (buffer
, mbox
);
428 snprintf(err
, sizeof err
, "no mailbox in local-part (%s)", buffer
);
432 switch (my_lex (buffer
)) {
434 mbox
= add (buffer
, mbox
);
445 domain (char *buffer
)
448 switch (my_lex (buffer
)) {
451 host
= add (buffer
, host
);
455 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
459 switch (my_lex (buffer
)) {
461 host
= add (buffer
, host
);
464 case LX_AT
: /* sigh (0) */
465 mbox
= add (host
, add ("%", mbox
));
480 routepath
= mh_xstrdup ("@");
483 switch (my_lex (buffer
)) {
486 routepath
= add (buffer
, routepath
);
490 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
493 switch (my_lex (buffer
)) {
495 routepath
= add (buffer
, routepath
);
497 switch (my_lex (buffer
)) {
502 routepath
= add (buffer
, routepath
);
506 snprintf(err
, sizeof err
, "no at-sign found for next domain in route (%s)",
513 case LX_AT
: /* XXX */
515 routepath
= add (buffer
, routepath
);
519 routepath
= add (buffer
, routepath
);
523 snprintf(err
, sizeof err
, "no colon found to terminate route (%s)", buffer
);
531 my_lex (char *buffer
)
533 /* buffer should be at least BUFSIZ bytes long */
537 /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
538 #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
543 return (last_lex
= LX_END
);
547 while (isspace ((unsigned char) c
))
551 return (last_lex
= LX_END
);
560 return (last_lex
= LX_ERR
);
563 if ((c
= *cp
++) == 0) {
565 return (last_lex
= LX_ERR
);
579 note
= note
? add (buffer
, add (" ", note
))
581 return my_lex (buffer
);
592 return (last_lex
= LX_ERR
);
595 if ((c
= *cp
++) == 0) {
597 return (last_lex
= LX_ERR
);
606 return (last_lex
= LX_QSTR
);
616 return (last_lex
= LX_ERR
);
619 if ((c
= *cp
++) == 0) {
621 return (last_lex
= LX_ERR
);
630 return (last_lex
= LX_DLIT
);
636 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
637 if (c
== special
[i
].lx_chr
)
638 return (last_lex
= special
[i
].lx_val
);
640 if (iscntrl ((unsigned char) c
))
641 return (last_lex
= LX_ERR
);
644 if ((c
= *cp
++) == 0)
646 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
647 if (c
== special
[i
].lx_chr
)
649 if (iscntrl ((unsigned char) c
) || isspace ((unsigned char) c
))
659 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
664 /* Out of buffer space. *bp is the last byte in the buffer */
666 return (last_lex
= LX_ERR
);
671 legal_person (const char *p
)
675 static char buffer
[BUFSIZ
];
679 for (cp
= p
; *cp
; cp
++)
680 for (i
= 0; special
[i
].lx_chr
; i
++)
681 if (*cp
== special
[i
].lx_chr
) {
682 snprintf(buffer
, sizeof buffer
, "\"%s\"", p
);