]>
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.
14 static int isat (const char *);
15 static int parse_address (void);
16 static int phrase (char *);
17 static int route_addr (char *);
18 static int local_part (char *);
19 static int domain (char *);
20 static int route (char *);
21 static int my_lex (char *);
27 return has_prefix(p
, " AT ") || has_prefix(p
, " At ") ||
28 has_prefix(p
, " aT ") || has_prefix(p
, " at ");
34 * getadrx() implements a partial 822-style address parser. The parser
35 * is neither complete nor correct. It does however recognize nearly all
36 * of the 822 address syntax. In addition it handles the majority of the
37 * 733 syntax as well. Most problems arise from trying to accommodate both.
39 * In terms of 822, the route-specification in
41 * "<" [route] local-part "@" domain ">"
43 * is parsed and returned unchanged. Multiple at-signs are compressed
44 * via source-routing. Recursive groups are not allowed as per the
47 * In terms of 733, " at " is recognized as equivalent to "@".
49 * In terms of both the parser will not complain about missing hosts.
53 * We should not allow addresses like
55 * Marshall T. Rose <MRose@UCI>
57 * but should insist on
59 * "Marshall T. Rose" <MRose@UCI>
61 * Unfortunately, a lot of mailers stupidly let people get away with this.
65 * We should not allow addresses like
69 * but should insist on
73 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
78 * We should not allow addresses like
82 * but should insist on
84 * Marshall Rose <@UCI:MRose@UCI-750a>
86 * Unfortunately, a lot of mailers stupidly do this.
110 static struct specials special
[] = {
127 static int glevel
= 0;
128 static int ingrp
= 0;
129 static int last_lex
= LX_END
;
131 static char *dp
= NULL
;
132 static char *cp
= NULL
;
133 static char *ap
= NULL
;
134 static char *pers
= NULL
;
135 static char *mbox
= NULL
;
136 static char *host
= NULL
;
137 static char *path
= NULL
;
138 static char *grp
= NULL
;
139 static char *note
= NULL
;
140 static char err
[BUFSIZ
];
141 static char adr
[BUFSIZ
];
143 static struct adrx adrxs2
;
146 /* eai = Email Address Internationalization */
148 getadrx (const char *addrs
, int eai
)
151 struct adrx
*adrxp
= &adrxs2
;
159 pers
= mbox
= host
= path
= grp
= note
= NULL
;
163 dp
= cp
= strdup (addrs
? addrs
: "");
173 switch (parse_address ()) {
185 default: /* catch trailing comments */
199 * Reject the address if key fields contain 8bit characters
202 if (contains8bit(mbox
, NULL
) || contains8bit(host
, NULL
) ||
203 contains8bit(path
, NULL
) || contains8bit(grp
, NULL
)) {
204 strcpy(err
, "Address contains 8-bit characters");
221 while (isspace ((unsigned char) *ap
))
224 snprintf(adr
, sizeof adr
, "%.*s", (int)(cp
- ap
), ap
);
227 bp
= adr
+ strlen (adr
) - 1;
228 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
237 adrxp
->ingrp
= ingrp
;
239 adrxp
->err
= err
[0] ? err
: NULL
;
252 switch (my_lex (buffer
)) {
255 pers
= strdup (buffer
);
260 strcpy (err
, "extraneous semi-colon");
272 case LX_LBRK
: /* sigh (2) */
275 case LX_AT
: /* sigh (3) */
277 if (route_addr (buffer
) == NOTOK
)
279 return OK
; /* why be choosy? */
282 snprintf(err
, sizeof err
, "illegal address construct (%s)", buffer
);
286 switch (my_lex (buffer
)) {
289 pers
= add (buffer
, add (" ", pers
));
290 more_phrase
: ; /* sigh (1) */
291 if (phrase (buffer
) == NOTOK
)
297 if (route_addr (buffer
) == NOTOK
)
299 if (last_lex
== LX_RBRK
)
301 snprintf(err
, sizeof err
, "missing right-bracket (%s)", buffer
);
307 snprintf(err
, sizeof err
, "nested groups not allowed (%s)", pers
);
310 grp
= add (": ", pers
);
316 switch (my_lex (buffer
)) {
318 case LX_END
: /* tsk, tsk */
327 return parse_address ();
331 case LX_DOT
: /* sigh (1) */
332 pers
= add (".", pers
);
336 snprintf(err
, sizeof err
, "no mailbox in address, only a phrase (%s%s)",
348 mbox
= add (buffer
, pers
);
350 if (route_addr (buffer
) == NOTOK
)
358 if (domain (buffer
) == NOTOK
)
364 strcpy (err
, "extraneous semi-colon");
373 snprintf(err
, sizeof err
, "junk after local@domain (%s)", buffer
);
377 case LX_SEMI
: /* no host */
381 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
382 strcpy (err
, "extraneous semi-colon");
390 snprintf(err
, sizeof err
, "missing mailbox (%s)", buffer
);
397 phrase (char *buffer
)
400 switch (my_lex (buffer
)) {
403 pers
= add (buffer
, add (" ", pers
));
413 route_addr (char *buffer
)
417 if (my_lex (buffer
) == LX_AT
) {
418 if (route (buffer
) == NOTOK
)
424 if (local_part (buffer
) == NOTOK
)
429 return domain (buffer
);
431 case LX_SEMI
: /* if in group */
432 case LX_RBRK
: /* no host */
438 snprintf(err
, sizeof err
, "no at-sign after local-part (%s)", buffer
);
445 local_part (char *buffer
)
450 switch (my_lex (buffer
)) {
453 mbox
= add (buffer
, mbox
);
457 snprintf(err
, sizeof err
, "no mailbox in local-part (%s)", buffer
);
461 switch (my_lex (buffer
)) {
463 mbox
= add (buffer
, mbox
);
474 domain (char *buffer
)
477 switch (my_lex (buffer
)) {
480 host
= add (buffer
, host
);
484 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
488 switch (my_lex (buffer
)) {
490 host
= add (buffer
, host
);
493 case LX_AT
: /* sigh (0) */
494 mbox
= add (host
, add ("%", mbox
));
509 path
= mh_xstrdup ("@");
512 switch (my_lex (buffer
)) {
515 path
= add (buffer
, path
);
519 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
522 switch (my_lex (buffer
)) {
524 path
= add (buffer
, path
);
526 switch (my_lex (buffer
)) {
531 path
= add (buffer
, path
);
535 snprintf(err
, sizeof err
, "no at-sign found for next domain in route (%s)",
542 case LX_AT
: /* XXX */
544 path
= add (buffer
, path
);
548 path
= add (buffer
, path
);
552 snprintf(err
, sizeof err
, "no colon found to terminate route (%s)", buffer
);
560 my_lex (char *buffer
)
562 /* buffer should be at least BUFSIZ bytes long */
566 /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
567 #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
572 return (last_lex
= LX_END
);
576 while (isspace ((unsigned char) c
))
580 return (last_lex
= LX_END
);
589 return (last_lex
= LX_ERR
);
592 if ((c
= *cp
++) == 0) {
594 return (last_lex
= LX_ERR
);
608 note
= note
? add (buffer
, add (" ", note
))
610 return my_lex (buffer
);
621 return (last_lex
= LX_ERR
);
624 if ((c
= *cp
++) == 0) {
626 return (last_lex
= LX_ERR
);
635 return (last_lex
= LX_QSTR
);
645 return (last_lex
= LX_ERR
);
648 if ((c
= *cp
++) == 0) {
650 return (last_lex
= LX_ERR
);
659 return (last_lex
= LX_DLIT
);
665 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
666 if (c
== special
[i
].lx_chr
)
667 return (last_lex
= special
[i
].lx_val
);
669 if (iscntrl ((unsigned char) c
))
670 return (last_lex
= LX_ERR
);
673 if ((c
= *cp
++) == 0)
675 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
676 if (c
== special
[i
].lx_chr
)
678 if (iscntrl ((unsigned char) c
) || isspace ((unsigned char) c
))
688 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
693 /* Out of buffer space. *bp is the last byte in the buffer */
695 return (last_lex
= LX_ERR
);
700 legal_person (const char *p
)
704 static char buffer
[BUFSIZ
];
708 for (cp
= p
; *cp
; cp
++)
709 for (i
= 0; special
[i
].lx_chr
; i
++)
710 if (*cp
== special
[i
].lx_chr
) {
711 snprintf(buffer
, sizeof buffer
, "\"%s\"", p
);