]>
diplodocus.org Git - nmh/blob - sbr/mf.c
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 *);
24 static int contains8bit (const char *);
28 isfrom(const char *string
)
30 return (strncmp (string
, "From ", 5) == 0
31 || strncmp (string
, ">From ", 6) == 0);
36 lequal (const char *a
, const char *b
)
42 char c1
= islower ((unsigned char) *a
) ?
43 toupper ((unsigned char) *a
) : *a
;
44 char c2
= islower ((unsigned char) *b
) ?
45 toupper ((unsigned char) *b
) : *b
;
57 return (strncmp (p
, " AT ", 4)
58 && strncmp (p
, " At ", 4)
59 && strncmp (p
, " aT ", 4)
60 && strncmp (p
, " at ", 4) ? FALSE
: TRUE
);
66 * getadrx() implements a partial 822-style address parser. The parser
67 * is neither complete nor correct. It does however recognize nearly all
68 * of the 822 address syntax. In addition it handles the majority of the
69 * 733 syntax as well. Most problems arise from trying to accomodate both.
71 * In terms of 822, the route-specification in
73 * "<" [route] local-part "@" domain ">"
75 * is parsed and returned unchanged. Multiple at-signs are compressed
76 * via source-routing. Recursive groups are not allowed as per the
79 * In terms of 733, " at " is recognized as equivalent to "@".
81 * In terms of both the parser will not complain about missing hosts.
85 * We should not allow addresses like
87 * Marshall T. Rose <MRose@UCI>
89 * but should insist on
91 * "Marshall T. Rose" <MRose@UCI>
93 * Unfortunately, a lot of mailers stupidly let people get away with this.
97 * We should not allow addresses like
101 * but should insist on
105 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
110 * We should not allow addresses like
112 * @UCI:MRose@UCI-750a
114 * but should insist on
116 * Marshall Rose <@UCI:MRose@UCI-750a>
118 * Unfortunately, a lot of mailers stupidly do this.
142 static struct specials special
[] = {
159 static int glevel
= 0;
160 static int ingrp
= 0;
161 static int last_lex
= LX_END
;
163 static char *dp
= NULL
;
164 static char *cp
= NULL
;
165 static char *ap
= NULL
;
166 static char *pers
= NULL
;
167 static char *mbox
= NULL
;
168 static char *host
= NULL
;
169 static char *path
= NULL
;
170 static char *grp
= NULL
;
171 static char *note
= NULL
;
172 static char err
[BUFSIZ
];
173 static char adr
[BUFSIZ
];
175 static struct adrx adrxs2
;
179 getadrx (const char *addrs
)
182 register struct adrx
*adrxp
= &adrxs2
;
196 pers
= mbox
= host
= path
= grp
= note
= NULL
;
200 dp
= cp
= strdup (addrs
? addrs
: "");
210 switch (parse_address ()) {
222 default: /* catch trailing comments */
235 * Reject the address if key fields contain 8bit characters
238 if (contains8bit(mbox
) || contains8bit(host
) || contains8bit(path
) ||
240 strcpy(err
, "Address contains 8-bit characters");
256 while (isspace ((unsigned char) *ap
))
259 sprintf (adr
, "%.*s", (int)(cp
- ap
), ap
);
262 bp
= adr
+ strlen (adr
) - 1;
263 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
272 adrxp
->ingrp
= ingrp
;
274 adrxp
->err
= err
[0] ? err
: NULL
;
287 switch (my_lex (buffer
)) {
290 pers
= strdup (buffer
);
295 strcpy (err
, "extraneous semi-colon");
308 case LX_LBRK
: /* sigh (2) */
311 case LX_AT
: /* sigh (3) */
313 if (route_addr (buffer
) == NOTOK
)
315 return OK
; /* why be choosy? */
318 sprintf (err
, "illegal address construct (%s)", buffer
);
322 switch (my_lex (buffer
)) {
325 pers
= add (buffer
, add (" ", pers
));
326 more_phrase
: ; /* sigh (1) */
327 if (phrase (buffer
) == NOTOK
)
333 if (route_addr (buffer
) == NOTOK
)
335 if (last_lex
== LX_RBRK
)
337 sprintf (err
, "missing right-bracket (%s)", buffer
);
343 sprintf (err
, "nested groups not allowed (%s)", pers
);
346 grp
= add (": ", pers
);
352 switch (my_lex (buffer
)) {
354 case LX_END
: /* tsk, tsk */
363 return parse_address ();
367 case LX_DOT
: /* sigh (1) */
368 pers
= add (".", pers
);
372 sprintf (err
, "no mailbox in address, only a phrase (%s%s)",
384 mbox
= add (buffer
, pers
);
386 if (route_addr (buffer
) == NOTOK
)
394 if (domain (buffer
) == NOTOK
)
400 strcpy (err
, "extraneous semi-colon");
408 sprintf (err
, "junk after local@domain (%s)", buffer
);
412 case LX_SEMI
: /* no host */
416 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
417 strcpy (err
, "extraneous semi-colon");
425 sprintf (err
, "missing mailbox (%s)", buffer
);
432 phrase (char *buffer
)
435 switch (my_lex (buffer
)) {
438 pers
= add (buffer
, add (" ", pers
));
448 route_addr (char *buffer
)
450 register char *pp
= cp
;
452 if (my_lex (buffer
) == LX_AT
) {
453 if (route (buffer
) == NOTOK
)
459 if (local_part (buffer
) == NOTOK
)
464 return domain (buffer
);
466 case LX_SEMI
: /* if in group */
467 case LX_RBRK
: /* no host */
473 sprintf (err
, "no at-sign after local-part (%s)", buffer
);
480 local_part (char *buffer
)
485 switch (my_lex (buffer
)) {
488 mbox
= add (buffer
, mbox
);
492 sprintf (err
, "no mailbox in local-part (%s)", buffer
);
496 switch (my_lex (buffer
)) {
498 mbox
= add (buffer
, mbox
);
509 domain (char *buffer
)
512 switch (my_lex (buffer
)) {
515 host
= add (buffer
, host
);
519 sprintf (err
, "no sub-domain in domain-part of address (%s)", buffer
);
523 switch (my_lex (buffer
)) {
525 host
= add (buffer
, host
);
528 case LX_AT
: /* sigh (0) */
529 mbox
= add (host
, add ("%", mbox
));
547 switch (my_lex (buffer
)) {
550 path
= add (buffer
, path
);
554 sprintf (err
, "no sub-domain in domain-part of address (%s)", buffer
);
557 switch (my_lex (buffer
)) {
559 path
= add (buffer
, path
);
561 switch (my_lex (buffer
)) {
566 path
= add (buffer
, path
);
570 sprintf (err
, "no at-sign found for next domain in route (%s)",
577 case LX_AT
: /* XXX */
579 path
= add (buffer
, path
);
583 path
= add (buffer
, path
);
587 sprintf (err
, "no colon found to terminate route (%s)", buffer
);
595 my_lex (char *buffer
)
597 /* buffer should be at least BUFSIZ bytes long */
601 /* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
602 #define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
607 return (last_lex
= LX_END
);
611 while (isspace ((unsigned char) c
))
615 return (last_lex
= LX_END
);
624 return (last_lex
= LX_ERR
);
627 if ((c
= *cp
++) == 0) {
629 return (last_lex
= LX_ERR
);
642 note
= note
? add (buffer
, add (" ", note
))
644 return my_lex (buffer
);
655 return (last_lex
= LX_ERR
);
658 if ((c
= *cp
++) == 0) {
660 return (last_lex
= LX_ERR
);
668 return (last_lex
= LX_QSTR
);
678 return (last_lex
= LX_ERR
);
681 if ((c
= *cp
++) == 0) {
683 return (last_lex
= LX_ERR
);
691 return (last_lex
= LX_DLIT
);
697 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
698 if (c
== special
[i
].lx_chr
)
699 return (last_lex
= special
[i
].lx_val
);
701 if (iscntrl ((unsigned char) c
))
702 return (last_lex
= LX_ERR
);
705 if ((c
= *cp
++) == 0)
707 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
708 if (c
== special
[i
].lx_chr
)
710 if (iscntrl ((unsigned char) c
) || isspace ((unsigned char) c
))
720 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
725 /* Out of buffer space. *bp is the last byte in the buffer */
727 return (last_lex
= LX_ERR
);
732 * Return true if the string contains an 8-bit character
736 contains8bit(const char *p
)
742 if (! isascii((unsigned char) *p
))
751 legal_person (const char *p
)
754 register const char *cp
;
755 static char buffer
[BUFSIZ
];
759 for (cp
= p
; *cp
; cp
++)
760 for (i
= 0; special
[i
].lx_chr
; i
++)
761 if (*cp
== special
[i
].lx_chr
) {
762 sprintf (buffer
, "\"%s\"", p
);
771 mfgets (FILE *in
, char **bp
)
774 register char *cp
, *dp
, *ep
;
776 static char *pp
= NULL
;
779 pp
= mh_xmalloc ((size_t) (len
= BUFSIZ
));
781 for (ep
= (cp
= pp
) + len
- 2;;) {
782 switch (i
= getc (in
)) {
800 if (cp
== pp
) /* end of headers, gobble it */
802 switch (i
= getc (in
)) {
803 default: /* end of line */
804 case '\n': /* end of headers, save for next call */
808 case ' ': /* continue headers */
812 } /* fall into default case */
819 dp
= mh_xrealloc (pp
, (size_t) (len
+= BUFSIZ
));
820 cp
+= dp
- pp
, ep
= (pp
= cp
) + len
- 2;