]>
diplodocus.org Git - nmh/blob - zotnet/mf/mf.c
3 * mf.c -- mail filter subroutines
15 static char *getcpy (char *);
16 static char *add (char *, char *);
17 static void compress (char *, char *);
18 static int isat (char *);
19 static int parse_address (void);
20 static int phrase (char *);
21 static int route_addr (char *);
22 static int local_part (char *);
23 static int domain (char *);
24 static int route (char *);
25 static int my_lex (char *);
34 /* causes compiles to blow up because the symbol _cleanup is undefined
35 where did this ever come from? */
41 if ((p
= malloc ((size_t) (strlen (s
) + 2))))
48 add (char *s1
, char *s2
)
55 if ((p
= malloc ((size_t) (strlen (s1
) + strlen (s2
) + 2))))
56 sprintf (p
, "%s%s", s2
, s1
);
64 return (strncmp (string
, "From ", 5) == 0
65 || strncmp (string
, ">From ", 6) == 0);
70 lequal (char *a
, char *b
)
76 char c1
= islower (*a
) ? toupper (*a
) : *a
;
77 char c2
= islower (*b
) ? toupper (*b
) : *b
;
87 * seekadrx() is tricky. We want to cover both UUCP-style and ARPA-style
88 * addresses, so for each list of addresses we see if we can find some
89 * character to give us a hint.
93 #define CHKADR 0 /* undertermined address style */
94 #define UNIXDR 1 /* UNIX-style address */
95 #define ARPADR 2 /* ARPAnet-style address */
98 static char *punctuators
= ";<>.()[]";
99 static char *vp
= NULL
;
100 static char *tp
= NULL
;
102 static struct adrx adrxs1
;
106 seekadrx (char *addrs
)
108 static int state
= CHKADR
;
110 register struct adrx
*adrxp
;
113 for (state
= UNIXDR
, cp
= addrs
; *cp
; cp
++)
114 if (strchr(punctuators
, *cp
)) {
121 adrxp
= uucpadrx (addrs
);
126 adrxp
= getadrx (addrs
);
138 * uucpadrx() implements a partial UUCP-style address parser. It's based
139 * on the UUCP notion that addresses are separated by spaces or commas.
144 uucpadrx (char *addrs
)
146 register char *cp
, *wp
, *xp
, *yp
, *zp
;
147 register struct adrx
*adrxp
= &adrxs1
;
150 vp
= tp
= getcpy (addrs
);
151 compress (addrs
, vp
);
160 for (cp
= tp
; isspace (*cp
); cp
++)
168 if ((wp
= strchr(cp
, ',')) == NULL
) {
169 if ((wp
= strchr(cp
, ' ')) != NULL
) {
171 while (isspace (*xp
))
173 if (*xp
!= 0 && isat (--xp
)) {
175 while (isspace (*yp
))
178 if ((zp
= strchr(yp
, ' ')) != NULL
)
197 adrxp
->text
= getcpy (cp
);
199 adrxp
->host
= adrxp
->path
= NULL
;
200 if ((wp
= strrchr(cp
, '@')) != NULL
) {
202 adrxp
->host
= *wp
? wp
: NULL
;
205 for (wp
= cp
+ strlen (cp
) - 4; wp
>= cp
; wp
--)
208 adrxp
->host
= wp
+ 3;
211 adrxp
->pers
= adrxp
->grp
= adrxp
->note
= adrxp
->err
= NULL
;
219 compress (char *fp
, char *tp
)
221 register char c
, *cp
;
223 for (c
= ' ', cp
= tp
; (*tp
= *fp
++) != 0;)
231 if (c
== ' ' && cp
< tp
)
239 return (strncmp (p
, " AT ", 4)
240 && strncmp (p
, " At ", 4)
241 && strncmp (p
, " aT ", 4)
242 && strncmp (p
, " at ", 4) ? FALSE
: TRUE
);
248 * getadrx() implements a partial 822-style address parser. The parser
249 * is neither complete nor correct. It does however recognize nearly all
250 * of the 822 address syntax. In addition it handles the majority of the
251 * 733 syntax as well. Most problems arise from trying to accomodate both.
253 * In terms of 822, the route-specification in
255 * "<" [route] local-part "@" domain ">"
257 * is parsed and returned unchanged. Multiple at-signs are compressed
258 * via source-routing. Recursive groups are not allowed as per the
261 * In terms of 733, " at " is recognized as equivalent to "@".
263 * In terms of both the parser will not complain about missing hosts.
267 * We should not allow addresses like
269 * Marshall T. Rose <MRose@UCI>
271 * but should insist on
273 * "Marshall T. Rose" <MRose@UCI>
275 * Unfortunately, a lot of mailers stupidly let people get away with this.
279 * We should not allow addresses like
283 * but should insist on
287 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
292 * We should not allow addresses like
294 * @UCI:MRose@UCI-750a
296 * but should insist on
298 * Marshall Rose <@UCI:MRose@UCI-750a>
300 * Unfortunately, a lot of mailers stupidly do this.
324 static struct specials special
[] = {
341 static int glevel
= 0;
342 static int ingrp
= 0;
343 static int last_lex
= LX_END
;
345 static char *dp
= NULL
;
346 static char *cp
= NULL
;
347 static char *ap
= NULL
;
348 static char *pers
= NULL
;
349 static char *mbox
= NULL
;
350 static char *host
= NULL
;
351 static char *path
= NULL
;
352 static char *grp
= NULL
;
353 static char *note
= NULL
;
354 static char err
[BUFSIZ
];
355 static char adr
[BUFSIZ
];
357 static struct adrx adrxs2
;
361 getadrx (char *addrs
)
364 register struct adrx
*adrxp
= &adrxs2
;
378 pers
= mbox
= host
= path
= grp
= note
= NULL
;
382 dp
= cp
= getcpy (addrs
? addrs
: "");
392 switch (parse_address ()) {
404 default: /* catch trailing comments */
429 while (isspace (*ap
))
432 sprintf (adr
, "%.*s", cp
- ap
, ap
);
435 bp
= adr
+ strlen (adr
) - 1;
436 if (*bp
== ',' || *bp
== ';' || *bp
== '\n')
445 adrxp
->ingrp
= ingrp
;
447 adrxp
->err
= err
[0] ? err
: NULL
;
460 switch (my_lex (buffer
)) {
463 pers
= getcpy (buffer
);
468 strcpy (err
, "extraneous semi-colon");
481 case LX_LBRK
: /* sigh (2) */
484 case LX_AT
: /* sigh (3) */
486 if (route_addr (buffer
) == NOTOK
)
488 return OK
; /* why be choosy? */
491 sprintf (err
, "illegal address construct (%s)", buffer
);
495 switch (my_lex (buffer
)) {
498 pers
= add (buffer
, add (" ", pers
));
499 more_phrase
: ; /* sigh (1) */
500 if (phrase (buffer
) == NOTOK
)
506 if (route_addr (buffer
) == NOTOK
)
508 if (last_lex
== LX_RBRK
)
510 sprintf (err
, "missing right-bracket (%s)", buffer
);
516 sprintf (err
, "nested groups not allowed (%s)", pers
);
519 grp
= add (": ", pers
);
525 switch (my_lex (buffer
)) {
527 case LX_END
: /* tsk, tsk */
536 return parse_address ();
540 case LX_DOT
: /* sigh (1) */
541 pers
= add (".", pers
);
545 sprintf (err
, "no mailbox in address, only a phrase (%s%s)",
557 mbox
= add (buffer
, pers
);
559 if (route_addr (buffer
) == NOTOK
)
567 if (domain (buffer
) == NOTOK
)
573 strcpy (err
, "extraneous semi-colon");
581 sprintf (err
, "junk after local@domain (%s)", buffer
);
585 case LX_SEMI
: /* no host */
589 if (last_lex
== LX_SEMI
&& glevel
-- <= 0) {
590 strcpy (err
, "extraneous semi-colon");
598 sprintf (err
, "missing mailbox (%s)", buffer
);
605 phrase (char *buffer
)
608 switch (my_lex (buffer
)) {
611 pers
= add (buffer
, add (" ", pers
));
621 route_addr (char *buffer
)
623 register char *pp
= cp
;
625 if (my_lex (buffer
) == LX_AT
) {
626 if (route (buffer
) == NOTOK
)
632 if (local_part (buffer
) == NOTOK
)
637 return domain (buffer
);
639 case LX_SEMI
: /* if in group */
640 case LX_RBRK
: /* no host */
646 sprintf (err
, "no at-sign after local-part (%s)", buffer
);
653 local_part (char *buffer
)
658 switch (my_lex (buffer
)) {
661 mbox
= add (buffer
, mbox
);
665 sprintf (err
, "no mailbox in local-part (%s)", buffer
);
669 switch (my_lex (buffer
)) {
671 mbox
= add (buffer
, mbox
);
682 domain (char *buffer
)
685 switch (my_lex (buffer
)) {
688 host
= add (buffer
, host
);
692 sprintf (err
, "no sub-domain in domain-part of address (%s)", buffer
);
696 switch (my_lex (buffer
)) {
698 host
= add (buffer
, host
);
701 case LX_AT
: /* sigh (0) */
702 mbox
= add (host
, add ("%", mbox
));
720 switch (my_lex (buffer
)) {
723 path
= add (buffer
, path
);
727 sprintf (err
, "no sub-domain in domain-part of address (%s)", buffer
);
730 switch (my_lex (buffer
)) {
732 path
= add (buffer
, path
);
734 switch (my_lex (buffer
)) {
739 path
= add (buffer
, path
);
743 sprintf (err
, "no at-sign found for next domain in route (%s)",
750 case LX_AT
: /* XXX */
752 path
= add (buffer
, path
);
756 path
= add (buffer
, path
);
760 sprintf (err
, "no colon found to terminate route (%s)", buffer
);
768 my_lex (char *buffer
)
771 register char c
, *bp
;
776 return (last_lex
= LX_END
);
784 return (last_lex
= LX_END
);
788 for (*bp
++ = c
, i
= 0;;)
792 return (last_lex
= LX_ERR
);
795 if ((c
= *cp
++) == 0) {
797 return (last_lex
= LX_ERR
);
810 note
= note
? add (buffer
, add (" ", note
))
812 return my_lex (buffer
);
821 return (last_lex
= LX_ERR
);
824 if ((c
= *cp
++) == 0) {
826 return (last_lex
= LX_ERR
);
834 return (last_lex
= LX_QSTR
);
842 return (last_lex
= LX_ERR
);
845 if ((c
= *cp
++) == 0) {
847 return (last_lex
= LX_ERR
);
855 return (last_lex
= LX_DLIT
);
860 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
861 if (c
== special
[i
].lx_chr
)
862 return (last_lex
= special
[i
].lx_val
);
865 return (last_lex
= LX_ERR
);
868 if ((c
= *cp
++) == 0)
870 for (i
= 0; special
[i
].lx_chr
!= 0; i
++)
871 if (c
== special
[i
].lx_chr
)
873 if (iscntrl (c
) || isspace (c
))
883 last_lex
= !gotat
|| cp
== NULL
|| strchr(cp
, '<') != NULL
890 legal_person (char *p
)
894 static char buffer
[BUFSIZ
];
898 for (cp
= p
; *cp
; cp
++)
899 for (i
= 0; special
[i
].lx_chr
; i
++)
900 if (*cp
== special
[i
].lx_chr
) {
901 sprintf (buffer
, "\"%s\"", p
);
910 mfgets (FILE *in
, char **bp
)
913 register char *cp
, *dp
, *ep
;
915 static char *pp
= NULL
;
918 if (!(pp
= malloc ((size_t) (len
= BUFSIZ
))))
921 for (ep
= (cp
= pp
) + len
- 2;;) {
922 switch (i
= getc (in
)) {
940 if (cp
== pp
) /* end of headers, gobble it */
942 switch (i
= getc (in
)) {
943 default: /* end of line */
944 case '\n': /* end of headers, save for next call */
948 case ' ': /* continue headers */
952 } /* fall into default case */
959 if (!(dp
= realloc (pp
, (size_t) (len
+= BUFSIZ
)))) {
965 cp
+= dp
- pp
, ep
= (pp
= cp
) + len
- 2;