]>
diplodocus.org Git - nmh/blob - sbr/mf.c
4fcff0d61c9de60373fdc9eeb6e7e3e49e13ab4d
3 * mf.c -- mail filter subroutines
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
16 static int isat (const char *);
17 static int parse_address (void);
18 static int phrase (char *);
19 static int route_addr (char *);
20 static int local_part (char *);
21 static int domain (char *);
22 static int route (char *);
23 static int my_lex (char *);
29 return has_prefix(p
, " AT ") || has_prefix(p
, " At ") ||
30 has_prefix(p
, " aT ") || has_prefix(p
, " at ");
36 * getadrx() implements a partial 822-style address parser. The parser
37 * is neither complete nor correct. It does however recognize nearly all
38 * of the 822 address syntax. In addition it handles the majority of the
39 * 733 syntax as well. Most problems arise from trying to accommodate both.
41 * In terms of 822, the route-specification in
43 * "<" [route] local-part "@" domain ">"
45 * is parsed and returned unchanged. Multiple at-signs are compressed
46 * via source-routing. Recursive groups are not allowed as per the
49 * In terms of 733, " at " is recognized as equivalent to "@".
51 * In terms of both the parser will not complain about missing hosts.
55 * We should not allow addresses like
57 * Marshall T. Rose <MRose@UCI>
59 * but should insist on
61 * "Marshall T. Rose" <MRose@UCI>
63 * Unfortunately, a lot of mailers stupidly let people get away with this.
67 * We should not allow addresses like
71 * but should insist on
75 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
80 * We should not allow addresses like
84 * but should insist on
86 * Marshall Rose <@UCI:MRose@UCI-750a>
88 * Unfortunately, a lot of mailers stupidly do this.
112 static struct specials special
[] = {
129 static int glevel
= 0;
130 static int ingrp
= 0;
131 static int last_lex
= LX_END
;
133 static char *dp
= NULL
;
134 static char *cp
= NULL
;
135 static char *ap
= NULL
;
136 static char *pers
= NULL
;
137 static char *mbox
= NULL
;
138 static char *host
= NULL
;
139 static char *path
= NULL
;
140 static char *grp
= NULL
;
141 static char *note
= NULL
;
142 static char err
[BUFSIZ
];
143 static char adr
[BUFSIZ
];
145 static struct adrx adrxs2
;
148 /* eai = Email Address Internationalization */
150 getadrx (const char *addrs
, int eai
)
153 struct adrx
*adrxp
= &adrxs2
;
161 pers
= mbox
= host
= path
= grp
= note
= NULL
;
165 dp
= cp
= strdup (addrs
? addrs
: "");
175 switch (parse_address ()) {
187 default: /* catch trailing comments */
201 * Reject the address if key fields contain 8bit characters
204 if (contains8bit(mbox
, NULL
) || contains8bit(host
, NULL
) ||
205 contains8bit(path
, NULL
) || contains8bit(grp
, NULL
)) {
206 strcpy(err
, "Address contains 8-bit characters");
223 while (isspace ((unsigned char) *ap
))
226 snprintf(adr
, sizeof adr
, "%.*s", (int)(cp
- ap
), ap
);
229 bp
= adr
+ strlen (adr
) - 1;
230 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
239 adrxp
->ingrp
= ingrp
;
241 adrxp
->err
= err
[0] ? err
: NULL
;
254 switch (my_lex (buffer
)) {
257 pers
= strdup (buffer
);
262 strcpy (err
, "extraneous semi-colon");
274 case LX_LBRK
: /* sigh (2) */
277 case LX_AT
: /* sigh (3) */
279 if (route_addr (buffer
) == NOTOK
)
281 return OK
; /* why be choosy? */
284 snprintf(err
, sizeof err
, "illegal address construct (%s)", buffer
);
288 switch (my_lex (buffer
)) {
291 pers
= add (buffer
, add (" ", pers
));
292 more_phrase
: ; /* sigh (1) */
293 if (phrase (buffer
) == NOTOK
)
299 if (route_addr (buffer
) == NOTOK
)
301 if (last_lex
== LX_RBRK
)
303 snprintf(err
, sizeof err
, "missing right-bracket (%s)", buffer
);
309 snprintf(err
, sizeof err
, "nested groups not allowed (%s)", pers
);
312 grp
= add (": ", pers
);
318 switch (my_lex (buffer
)) {
320 case LX_END
: /* tsk, tsk */
329 return parse_address ();
333 case LX_DOT
: /* sigh (1) */
334 pers
= add (".", pers
);
338 snprintf(err
, sizeof err
, "no mailbox in address, only a phrase (%s%s)",
350 mbox
= add (buffer
, pers
);
352 if (route_addr (buffer
) == NOTOK
)
360 if (domain (buffer
) == NOTOK
)
366 strcpy (err
, "extraneous semi-colon");
375 snprintf(err
, sizeof err
, "junk after local@domain (%s)", buffer
);
379 case LX_SEMI
: /* no host */
383 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
384 strcpy (err
, "extraneous semi-colon");
392 snprintf(err
, sizeof err
, "missing mailbox (%s)", buffer
);
399 phrase (char *buffer
)
402 switch (my_lex (buffer
)) {
405 pers
= add (buffer
, add (" ", pers
));
415 route_addr (char *buffer
)
419 if (my_lex (buffer
) == LX_AT
) {
420 if (route (buffer
) == NOTOK
)
426 if (local_part (buffer
) == NOTOK
)
431 return domain (buffer
);
433 case LX_SEMI
: /* if in group */
434 case LX_RBRK
: /* no host */
440 snprintf(err
, sizeof err
, "no at-sign after local-part (%s)", buffer
);
447 local_part (char *buffer
)
452 switch (my_lex (buffer
)) {
455 mbox
= add (buffer
, mbox
);
459 snprintf(err
, sizeof err
, "no mailbox in local-part (%s)", buffer
);
463 switch (my_lex (buffer
)) {
465 mbox
= add (buffer
, mbox
);
476 domain (char *buffer
)
479 switch (my_lex (buffer
)) {
482 host
= add (buffer
, host
);
486 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
490 switch (my_lex (buffer
)) {
492 host
= add (buffer
, host
);
495 case LX_AT
: /* sigh (0) */
496 mbox
= add (host
, add ("%", mbox
));
511 path
= mh_xstrdup ("@");
514 switch (my_lex (buffer
)) {
517 path
= add (buffer
, path
);
521 snprintf(err
, sizeof err
, "no sub-domain in domain-part of address (%s)", buffer
);
524 switch (my_lex (buffer
)) {
526 path
= add (buffer
, path
);
528 switch (my_lex (buffer
)) {
533 path
= add (buffer
, path
);
537 snprintf(err
, sizeof err
, "no at-sign found for next domain in route (%s)",
544 case LX_AT
: /* XXX */
546 path
= add (buffer
, path
);
550 path
= add (buffer
, path
);
554 snprintf(err
, sizeof err
, "no colon found to terminate route (%s)", buffer
);
562 my_lex (char *buffer
)
564 /* buffer should be at least BUFSIZ bytes long */
568 /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
569 #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
574 return (last_lex
= LX_END
);
578 while (isspace ((unsigned char) c
))
582 return (last_lex
= LX_END
);
591 return (last_lex
= LX_ERR
);
594 if ((c
= *cp
++) == 0) {
596 return (last_lex
= LX_ERR
);
610 note
= note
? add (buffer
, add (" ", note
))
612 return my_lex (buffer
);
623 return (last_lex
= LX_ERR
);
626 if ((c
= *cp
++) == 0) {
628 return (last_lex
= LX_ERR
);
637 return (last_lex
= LX_QSTR
);
647 return (last_lex
= LX_ERR
);
650 if ((c
= *cp
++) == 0) {
652 return (last_lex
= LX_ERR
);
661 return (last_lex
= LX_DLIT
);
667 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
668 if (c
== special
[i
].lx_chr
)
669 return (last_lex
= special
[i
].lx_val
);
671 if (iscntrl ((unsigned char) c
))
672 return (last_lex
= LX_ERR
);
675 if ((c
= *cp
++) == 0)
677 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
678 if (c
== special
[i
].lx_chr
)
680 if (iscntrl ((unsigned char) c
) || isspace ((unsigned char) c
))
690 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
695 /* Out of buffer space. *bp is the last byte in the buffer */
697 return (last_lex
= LX_ERR
);
702 legal_person (const char *p
)
706 static char buffer
[BUFSIZ
];
710 for (cp
= p
; *cp
; cp
++)
711 for (i
= 0; special
[i
].lx_chr
; i
++)
712 if (*cp
== special
[i
].lx_chr
) {
713 snprintf(buffer
, sizeof buffer
, "\"%s\"", p
);