9 date 92.12.15.00.20.22; author jromine; state Exp;
14 date 92.12.11.22.13.12; author jromine; state Exp;
19 date 92.01.31.22.33.19; author jromine; state Exp;
24 date 92.01.30.22.40.35; author jromine; state Exp;
29 date 90.04.05.15.04.19; author sources; state Exp;
34 date 90.02.06.13.39.34; author sources; state Exp;
39 date 90.02.05.15.29.59; author sources; state Exp;
44 date 90.02.05.15.29.16; author sources; state Exp;
49 date 90.01.23.16.06.55; author sources; state Exp;
54 date 90.01.23.15.56.16; author sources; state Exp;
68 @/* mf.c - mail filter subroutines */
70 static char ident[] = "@@(#)$Id: mf.c,v 1.9 1992/12/11 22:13:12 jromine Exp jromine $";
77 static int isat(), parse_address(), phrase();
78 static int route_addr(), local_part(), domain(), route();
80 static void compress();
83 static char *getcpy (s)
88 if (!s) { _cleanup(); abort(); for(;;) pause();}
89 if ((p = malloc ((unsigned) (strlen (s) + 2))) != NULL)
95 static char *add (s1, s2)
104 if ((p = malloc ((unsigned) (strlen (s1) + strlen (s2) + 2))) != NULL)
105 (void) sprintf (p, "%s%s", s2, s1);
113 register char *string;
115 return (strncmp (string, "From ", 5) == 0
116 || strncmp (string, ">From ", 6) == 0);
128 char c1 = islower (*a) ? toupper (*a) : *a;
129 char c2 = islower (*b) ? toupper (*b) : *b;
141 * seekadrx() is tricky. We want to cover both UUCP-style and ARPA-style
142 * addresses, so for each list of addresses we see if we can find some
143 * character to give us a hint.
148 #define CHKADR 0 /* undertermined address style */
149 #define UNIXDR 1 /* UNIX-style address */
150 #define ARPADR 2 /* ARPAnet-style address */
153 static char *punctuators = ";<>.()[]";
154 static char *vp = NULL;
155 static char *tp = NULL;
157 static struct adrx adrxs1;
161 struct adrx *seekadrx (addrs)
162 register char *addrs;
164 static int state = CHKADR;
166 register struct adrx *adrxp;
169 for (state = UNIXDR, cp = addrs; *cp; cp++)
170 if (index (punctuators, *cp)) {
177 adrxp = uucpadrx (addrs);
182 adrxp = getadrx (addrs);
196 * uucpadrx() implements a partial UUCP-style address parser. It's based
197 * on the UUCP notion that addresses are separated by spaces or commas.
202 struct adrx *uucpadrx (addrs)
203 register char *addrs;
210 register struct adrx *adrxp = &adrxs1;
213 vp = tp = getcpy (addrs);
214 compress (addrs, vp);
223 for (cp = tp; isspace (*cp); cp++)
233 if ((wp = index (cp, ',')) == NULL)
234 if ((wp = index (cp, ' ')) != NULL) {
236 while (isspace (*xp))
238 if (*xp != 0 && isat (--xp)) {
240 while (isspace (*yp))
243 if ((zp = index (yp, ' ')) != NULL)
259 free (adrxp -> text);
260 adrxp -> text = getcpy (cp);
262 adrxp -> host = adrxp -> path = NULL;
263 if ((wp = rindex (cp, '@@')) != NULL) {
265 adrxp -> host = *wp ? wp : NULL;
268 for (wp = cp + strlen (cp) - 4; wp >= cp; wp--)
271 adrxp -> host = wp + 3;
274 adrxp -> pers = adrxp -> grp = adrxp -> note = adrxp -> err = NULL;
282 static void compress (fp, tp)
289 for (c = ' ', cp = tp; (*tp = *fp++) != 0;)
297 if (c == ' ' && cp < tp)
305 return (strncmp (p, " AT ", 4)
306 && strncmp (p, " At ", 4)
307 && strncmp (p, " aT ", 4)
308 && strncmp (p, " at ", 4) ? FALSE : TRUE);
315 * getadrx() implements a partial 822-style address parser. The parser
316 * is neither complete nor correct. It does however recognize nearly all
317 * of the 822 address syntax. In addition it handles the majority of the
318 * 733 syntax as well. Most problems arise from trying to accomodate both.
320 * In terms of 822, the route-specification in
322 * "<" [route] local-part "@@" domain ">"
324 * is parsed and returned unchanged. Multiple at-signs are compressed
325 * via source-routing. Recursive groups are not allowed as per the
328 * In terms of 733, " at " is recognized as equivalent to "@@".
330 * In terms of both the parser will not complain about missing hosts.
334 * We should not allow addresses like
336 * Marshall T. Rose <MRose@@UCI>
338 * but should insist on
340 * "Marshall T. Rose" <MRose@@UCI>
342 * Unfortunately, a lot of mailers stupidly let people get away with this.
346 * We should not allow addresses like
350 * but should insist on
354 * Unfortunately, a lot of mailers stupidly let people's UAs get away with
359 * We should not allow addresses like
361 * @@UCI:MRose@@UCI-750a
363 * but should insist on
365 * Marshall Rose <@@UCI:MRose@@UCI-750a>
367 * Unfortunately, a lot of mailers stupidly do this.
410 static int glevel = 0;
411 static int ingrp = 0;
412 static int last_lex = LX_END;
414 static char *dp = NULL;
415 static char *cp = NULL;
416 static char *ap = NULL;
417 static char *pers = NULL;
418 static char *mbox = NULL;
419 static char *host = NULL;
420 static char *path = NULL;
421 static char *grp = NULL;
422 static char *note = NULL;
423 static char err[BUFSIZ];
424 static char adr[BUFSIZ];
426 static struct adrx adrxs2;
430 struct adrx *getadrx (addrs)
431 register char *addrs;
434 register struct adrx *adrxp = &adrxs2;
448 pers = mbox = host = path = grp = note = NULL;
452 dp = cp = getcpy (addrs ? addrs : "");
462 switch (parse_address ()) {
474 default: /* catch trailing comments */
499 while (isspace (*ap))
502 (void) sprintf (adr, "%.*s", cp - ap, ap);
504 (void) strcpy (adr, ap);
505 bp = adr + strlen (adr) - 1;
506 if (*bp == ',' || *bp == ';' || *bp == '\n')
512 adrxp -> pers = pers;
513 adrxp -> mbox = mbox;
514 adrxp -> host = host;
515 adrxp -> path = path;
517 adrxp -> ingrp = ingrp;
518 adrxp -> note = note;
519 adrxp -> err = err[0] ? err : NULL;
526 static int parse_address () {
531 switch (my_lex (buffer)) {
534 pers = getcpy (buffer);
539 (void) strcpy (err, "extraneous semi-colon");
552 case LX_LBRK: /* sigh (2) */
555 case LX_AT: /* sigh (3) */
557 if (route_addr (buffer) == NOTOK)
559 return OK; /* why be choosy? */
562 (void) sprintf (err, "illegal address construct (%s)", buffer);
568 switch (my_lex (buffer)) {
571 pers = add (buffer, add (" ", pers));
572 more_phrase: ; /* sigh (1) */
573 if (phrase (buffer) == NOTOK)
579 if (route_addr (buffer) == NOTOK)
581 if (last_lex == LX_RBRK)
583 (void) sprintf (err, "missing right-bracket (%s)", buffer);
589 (void) sprintf (err, "nested groups not allowed (%s)",
593 grp = add (": ", pers);
599 switch (my_lex (buffer)) {
601 case LX_END: /* tsk, tsk */
610 return parse_address ();
614 case LX_DOT: /* sigh (1) */
615 pers = add (".", pers);
620 "no mailbox in address, only a phrase (%s%s)",
634 mbox = add (buffer, pers);
636 if (route_addr (buffer) == NOTOK)
644 if (domain (buffer) == NOTOK)
650 (void) strcpy (err, "extraneous semi-colon");
658 (void) sprintf (err, "junk after local@@domain (%s)",
663 case LX_SEMI: /* no host */
667 if (last_lex == LX_SEMI && glevel-- <= 0) {
668 (void) strcpy (err, "extraneous semi-colon");
676 (void) sprintf (err, "missing mailbox (%s)", buffer);
683 static int phrase (buffer)
684 register char *buffer;
687 switch (my_lex (buffer)) {
690 pers = add (buffer, add (" ", pers));
700 static int route_addr (buffer)
701 register char *buffer;
703 register char *pp = cp;
705 if (my_lex (buffer) == LX_AT) {
706 if (route (buffer) == NOTOK)
712 if (local_part (buffer) == NOTOK)
717 return domain (buffer);
719 case LX_SEMI: /* if in group */
720 case LX_RBRK: /* no host */
726 (void) sprintf (err, "no at-sign after local-part (%s)", buffer);
733 static int local_part (buffer)
734 register char *buffer;
739 switch (my_lex (buffer)) {
742 mbox = add (buffer, mbox);
746 (void) sprintf (err, "no mailbox in local-part (%s)", buffer);
750 switch (my_lex (buffer)) {
752 mbox = add (buffer, mbox);
763 static int domain (buffer)
764 register char *buffer;
767 switch (my_lex (buffer)) {
770 host = add (buffer, host);
775 "no sub-domain in domain-part of address (%s)",
780 switch (my_lex (buffer)) {
782 host = add (buffer, host);
785 case LX_AT: /* sigh (0) */
786 mbox = add (host, add ("%", mbox));
799 static int route (buffer)
800 register char *buffer;
802 path = getcpy ("@@");
805 switch (my_lex (buffer)) {
808 path = add (buffer, path);
813 "no sub-domain in domain-part of address (%s)",
817 switch (my_lex (buffer)) {
819 path = add (buffer, path);
821 switch (my_lex (buffer)) {
826 path = add (buffer, path);
831 "no at-sign found for next domain in route (%s)",
838 case LX_AT: /* XXX */
840 path = add (buffer, path);
844 path = add (buffer, path);
849 "no colon found to terminate route (%s)", buffer);
857 static int my_lex (buffer)
858 register char *buffer;
867 return (last_lex = LX_END);
875 return (last_lex = LX_END);
879 for (*bp++ = c, i = 0;;)
883 return (last_lex = LX_ERR);
886 if ((c = *cp++) == 0) {
888 return (last_lex = LX_ERR);
901 note = note ? add (buffer, add (" ", note))
903 return my_lex (buffer);
914 return (last_lex = LX_ERR);
917 if ((c = *cp++) == 0) {
919 return (last_lex = LX_ERR);
927 return (last_lex = LX_QSTR);
935 return (last_lex = LX_ERR);
938 if ((c = *cp++) == 0) {
940 return (last_lex = LX_ERR);
948 return (last_lex = LX_DLIT);
955 for (i = 0; special[i].lx_chr != 0; i++)
956 if (c == special[i].lx_chr)
957 return (last_lex = special[i].lx_val);
960 return (last_lex = LX_ERR);
963 if ((c = *cp++) == 0)
965 for (i = 0; special[i].lx_chr != 0; i++)
966 if (c == special[i].lx_chr)
968 if (iscntrl (c) || isspace (c))
978 last_lex = !gotat || cp == NULL || index (cp, '<') != NULL
985 char *legal_person (p)
990 static char buffer[BUFSIZ];
994 for (cp = p; *cp; cp++)
995 for (i = 0; special[i].lx_chr; i++)
996 if (*cp == special[i].lx_chr) {
997 (void) sprintf (buffer, "\"%s\"", p);
1015 static char *pp = NULL;
1018 if ((pp = malloc ((unsigned) (len = BUFSIZ))) == NULL)
1021 for (ep = (cp = pp) + len - 2;;) {
1022 switch (i = getc (in)) {
1040 if (cp == pp) /* end of headers, gobble it */
1042 switch (i = getc (in)) {
1043 default: /* end of line */
1044 case '\n': /* end of headers, save for next call */
1045 (void) ungetc (i, in);
1048 case ' ': /* continue headers */
1052 } /* fall into default case */
1059 if ((dp = realloc (pp, (unsigned) (len += BUFSIZ))) == NULL) {
1065 cp += dp - pp, ep = (pp = cp) + len - 2;
1078 static char ident[] = "@@(#)$Id: mf.c,v 1.8 1992/01/31 22:33:19 jromine Exp jromine $";
1090 static char ident[] = "@@(#)$Id: mf.c,v 1.7 1992/01/30 22:40:35 jromine Exp jromine $";
1093 static int compress(), isat(), parse_address(), phrase();
1097 static int compress (fp, tp)
1108 static char ident[] = "@@(#)$Id: mf.c,v 1.6 1990/04/05 15:04:19 sources Exp jromine $";
1114 return (*b == NULL);
1120 if (*xp != NULL && isat (--xp)) {
1126 *zp = NULL, tp = ++zp;
1129 *wp = NULL, tp = ++wp;
1132 *wp = NULL, tp = ++wp;
1135 *wp = NULL, tp = ++wp;
1144 for (c = ' ', cp = tp; (*tp = *fp++) != NULL;)
1168 if ((c = *cp++) == NULL) {
1177 if ((c = *cp++) == NULL) {
1186 if ((c = *cp++) == NULL) {
1193 for (i = 0; special[i].lx_chr != NULL; i++)
1196 if ((c = *cp++) == NULL)
1199 for (i = 0; special[i].lx_chr != NULL; i++)
1222 static char ident[] = "@@(#)$Id:$";
1242 bp = cp, save_lex = last_lex;
1243 if (my_lex (adr) == LX_WP) {
1247 if (fp = wp_expand (adr, err)) {
1249 ep = concat (dp, fp, cp, (char *) NULL);
1250 cp = ep + strlen (dp), last_lex = save_lex;
1256 ap = bp, save_lex = last_lex;
1261 cp = bp, last_lex = save_lex;
1271 if (do_wp && c == '<' && *cp == '<')
1273 switch (c = *cp++) {
1277 return (last_lex = LX_WP);
1307 @fix for "at" domain names
1321 @Fix for "test: foo.bar;" case. This probably breaks something else,
1322 but it's as good as I can do for now.
1332 last_lex = !lequal (buffer, "at") || cp == NULL || index (cp, '<') != NULL