122976Smiriam /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
363589Sbostic * Copyright (c) 1988, 1993
463589Sbostic * The Regents of the University of California. All rights reserved.
533730Sbostic *
642828Sbostic * %sccs.include.redist.c%
733730Sbostic */
822976Smiriam
922976Smiriam #ifndef lint
10*69925Seric static char sccsid[] = "@(#)parseaddr.c 8.73 (Berkeley) 06/19/95";
1133730Sbostic #endif /* not lint */
1222976Smiriam
1356678Seric # include "sendmail.h"
14297Seric
15297Seric /*
169888Seric ** PARSEADDR -- Parse an address
17297Seric **
18297Seric ** Parses an address and breaks it up into three parts: a
19297Seric ** net to transmit the message on, the host to transmit it
20297Seric ** to, and a user on that host. These are loaded into an
212973Seric ** ADDRESS header with the values squirreled away if necessary.
22297Seric ** The "user" part may not be a real user; the process may
23297Seric ** just reoccur on that machine. For example, on a machine
24297Seric ** with an arpanet connection, the address
25297Seric ** csvax.bill@berkeley
26297Seric ** will break up to a "user" of 'csvax.bill' and a host
27297Seric ** of 'berkeley' -- to be transmitted over the arpanet.
28297Seric **
29297Seric ** Parameters:
30297Seric ** addr -- the address to parse.
31297Seric ** a -- a pointer to the address descriptor buffer.
32297Seric ** If NULL, a header will be created.
3364284Seric ** flags -- describe detail for parsing. See RF_ definitions
3464284Seric ** in sendmail.h.
3511445Seric ** delim -- the character to terminate the address, passed
3611445Seric ** to prescan.
3758333Seric ** delimptr -- if non-NULL, set to the location of the
3858333Seric ** delim character that was found.
3956678Seric ** e -- the envelope that will contain this address.
40297Seric **
41297Seric ** Returns:
42297Seric ** A pointer to the address descriptor header (`a' if
43297Seric ** `a' is non-NULL).
44297Seric ** NULL on error.
45297Seric **
46297Seric ** Side Effects:
47297Seric ** none
48297Seric */
49297Seric
509374Seric /* following delimiters are inherent to the internal algorithms */
5159278Seric # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
522091Seric
532973Seric ADDRESS *
parseaddr(addr,a,flags,delim,delimptr,e)5464284Seric parseaddr(addr, a, flags, delim, delimptr, e)
55297Seric char *addr;
562973Seric register ADDRESS *a;
5764284Seric int flags;
5859700Seric int delim;
5958333Seric char **delimptr;
6056678Seric register ENVELOPE *e;
61297Seric {
623149Seric register char **pvp;
6358333Seric auto char *delimptrbuf;
6459084Seric bool queueup;
6516914Seric char pvpbuf[PSBUFSIZE];
6656678Seric extern ADDRESS *buildaddr();
6757388Seric extern bool invalidaddr();
6869748Seric extern void allocaddr __P((ADDRESS *, int, char *));
69297Seric
70297Seric /*
71297Seric ** Initialize and prescan address.
72297Seric */
73297Seric
7456678Seric e->e_to = addr;
757675Seric if (tTd(20, 1))
769888Seric printf("\n--parseaddr(%s)\n", addr);
773188Seric
7858333Seric if (delimptr == NULL)
7958333Seric delimptr = &delimptrbuf;
8058333Seric
8168711Seric pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL);
823149Seric if (pvp == NULL)
8356729Seric {
8456729Seric if (tTd(20, 1))
8556729Seric printf("parseaddr-->NULL\n");
86297Seric return (NULL);
8756729Seric }
88297Seric
8964726Seric if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr))
9064726Seric {
9164726Seric if (tTd(20, 1))
9264726Seric printf("parseaddr-->bad address\n");
9364726Seric return NULL;
9464726Seric }
9564726Seric
96297Seric /*
9764348Seric ** Save addr if we are going to have to.
9864348Seric **
9964348Seric ** We have to do this early because there is a chance that
10064348Seric ** the map lookups in the rewriting rules could clobber
10164348Seric ** static memory somewhere.
10264348Seric */
10364348Seric
10464348Seric if (bitset(RF_COPYPADDR, flags) && addr != NULL)
10564348Seric {
10664348Seric char savec = **delimptr;
10764348Seric
10864348Seric if (savec != '\0')
10964348Seric **delimptr = '\0';
11066794Seric e->e_to = addr = newstr(addr);
11164348Seric if (savec != '\0')
11264348Seric **delimptr = savec;
11364348Seric }
11464348Seric
11564348Seric /*
1163149Seric ** Apply rewriting rules.
1177889Seric ** Ruleset 0 does basic parsing. It must resolve.
118297Seric */
119297Seric
12059084Seric queueup = FALSE;
12165071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
12259084Seric queueup = TRUE;
12365071Seric if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL)
12459084Seric queueup = TRUE;
125297Seric
126297Seric
127297Seric /*
1283149Seric ** Build canonical address from pvp.
129297Seric */
130297Seric
13164284Seric a = buildaddr(pvp, a, flags, e);
132297Seric
133297Seric /*
1343149Seric ** Make local copies of the host & user and then
1353149Seric ** transport them out.
136297Seric */
137297Seric
13864348Seric allocaddr(a, flags, addr);
13964306Seric if (bitset(QBADADDR, a->q_flags))
14064306Seric return a;
14156678Seric
14256678Seric /*
14359084Seric ** If there was a parsing failure, mark it for queueing.
14459084Seric */
14559084Seric
14659084Seric if (queueup)
14759595Seric {
14859734Seric char *msg = "Transient parse error -- message queued for future delivery";
14959734Seric
15059595Seric if (tTd(20, 1))
15159595Seric printf("parseaddr: queuing message\n");
15259734Seric message(msg);
15359734Seric if (e->e_message == NULL)
15460009Seric e->e_message = newstr(msg);
15559084Seric a->q_flags |= QQUEUEUP;
15668358Seric a->q_status = "4.4.3";
15759595Seric }
15859084Seric
15959084Seric /*
16056678Seric ** Compute return value.
16156678Seric */
16256678Seric
16356678Seric if (tTd(20, 1))
1648078Seric {
16556678Seric printf("parseaddr-->");
16656678Seric printaddr(a, FALSE);
16756678Seric }
16856678Seric
16956678Seric return (a);
17056678Seric }
17156678Seric /*
17257388Seric ** INVALIDADDR -- check for address containing meta-characters
17357388Seric **
17457388Seric ** Parameters:
17557388Seric ** addr -- the address to check.
17657388Seric **
17757388Seric ** Returns:
17857388Seric ** TRUE -- if the address has any "wierd" characters
17957388Seric ** FALSE -- otherwise.
18057388Seric */
18157388Seric
18257388Seric bool
invalidaddr(addr,delimptr)18364726Seric invalidaddr(addr, delimptr)
18457388Seric register char *addr;
18564726Seric char *delimptr;
18657388Seric {
18768433Seric char savedelim = '\0';
18864726Seric
18964726Seric if (delimptr != NULL)
19064764Seric {
19164726Seric savedelim = *delimptr;
19264764Seric if (savedelim != '\0')
19364764Seric *delimptr = '\0';
19464764Seric }
19564726Seric #if 0
19664726Seric /* for testing.... */
19764726Seric if (strcmp(addr, "INvalidADDR") == 0)
19857388Seric {
19964726Seric usrerr("553 INvalid ADDRess");
20064764Seric goto addrfailure;
20157388Seric }
20264726Seric #endif
20364726Seric for (; *addr != '\0'; addr++)
20464726Seric {
20564726Seric if ((*addr & 0340) == 0200)
20664726Seric break;
20764726Seric }
20864726Seric if (*addr == '\0')
20964764Seric {
21068400Seric if (delimptr != NULL && savedelim != '\0')
21164764Seric *delimptr = savedelim;
21264726Seric return FALSE;
21364764Seric }
21464726Seric setstat(EX_USAGE);
21564726Seric usrerr("553 Address contained invalid control characters");
21664764Seric addrfailure:
21768446Seric if (delimptr != NULL && savedelim != '\0')
21864764Seric *delimptr = savedelim;
21964726Seric return TRUE;
22057388Seric }
22157388Seric /*
22256678Seric ** ALLOCADDR -- do local allocations of address on demand.
22356678Seric **
22456678Seric ** Also lowercases the host name if requested.
22556678Seric **
22656678Seric ** Parameters:
22756678Seric ** a -- the address to reallocate.
22864284Seric ** flags -- the copy flag (see RF_ definitions in sendmail.h
22964284Seric ** for a description).
23056678Seric ** paddr -- the printname of the address.
23156678Seric **
23256678Seric ** Returns:
23356678Seric ** none.
23456678Seric **
23556678Seric ** Side Effects:
23656678Seric ** Copies portions of a into local buffers as requested.
23756678Seric */
23856678Seric
23969748Seric void
allocaddr(a,flags,paddr)24064348Seric allocaddr(a, flags, paddr)
24156678Seric register ADDRESS *a;
24264284Seric int flags;
24356678Seric char *paddr;
24456678Seric {
24558673Seric if (tTd(24, 4))
24667693Seric printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
24758673Seric
24864348Seric a->q_paddr = paddr;
2498078Seric
25024944Seric if (a->q_user == NULL)
25124944Seric a->q_user = "";
25224944Seric if (a->q_host == NULL)
25324944Seric a->q_host = "";
25424944Seric
25564284Seric if (bitset(RF_COPYPARSE, flags))
256297Seric {
25724944Seric a->q_host = newstr(a->q_host);
2583149Seric if (a->q_user != a->q_paddr)
2593149Seric a->q_user = newstr(a->q_user);
260297Seric }
261297Seric
26256678Seric if (a->q_paddr == NULL)
26356678Seric a->q_paddr = a->q_user;
264297Seric }
265297Seric /*
266297Seric ** PRESCAN -- Prescan name and make it canonical
267297Seric **
2689374Seric ** Scans a name and turns it into a set of tokens. This process
2699374Seric ** deletes blanks and comments (in parentheses).
270297Seric **
271297Seric ** This routine knows about quoted strings and angle brackets.
272297Seric **
273297Seric ** There are certain subtleties to this routine. The one that
274297Seric ** comes to mind now is that backslashes on the ends of names
275297Seric ** are silently stripped off; this is intentional. The problem
276297Seric ** is that some versions of sndmsg (like at LBL) set the kill
277297Seric ** character to something other than @ when reading addresses;
278297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the
279297Seric ** berknet mailer.
280297Seric **
281297Seric ** Parameters:
282297Seric ** addr -- the name to chomp.
283297Seric ** delim -- the delimiter for the address, normally
284297Seric ** '\0' or ','; \0 is accepted in any case.
28515284Seric ** If '\t' then we are reading the .cf file.
28616914Seric ** pvpbuf -- place to put the saved text -- note that
28716914Seric ** the pointers are static.
28865066Seric ** pvpbsize -- size of pvpbuf.
28958333Seric ** delimptr -- if non-NULL, set to the location of the
29058333Seric ** terminating delimiter.
29168711Seric ** toktab -- if set, a token table to use for parsing.
29268711Seric ** If NULL, use the default table.
293297Seric **
294297Seric ** Returns:
2953149Seric ** A pointer to a vector of tokens.
296297Seric ** NULL on error.
297297Seric */
298297Seric
2998078Seric /* states and character types */
3008078Seric # define OPR 0 /* operator */
3018078Seric # define ATM 1 /* atom */
3028078Seric # define QST 2 /* in quoted string */
3038078Seric # define SPC 3 /* chewing up spaces */
3048078Seric # define ONE 4 /* pick up one character */
30568711Seric # define ILL 5 /* illegal character */
3063149Seric
30768711Seric # define NSTATES 6 /* number of states */
3088078Seric # define TYPE 017 /* mask to select state type */
3098078Seric
3108078Seric /* meta bits for table */
3118078Seric # define M 020 /* meta character; don't pass through */
3128078Seric # define B 040 /* cause a break */
3138078Seric # define MB M|B /* meta-break */
3148078Seric
3158078Seric static short StateTab[NSTATES][NSTATES] =
3168078Seric {
31768711Seric /* oldst chtype> OPR ATM QST SPC ONE ILL */
31868711Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB,
31968711Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB,
32068711Seric /*QST*/ QST, QST, OPR, QST, QST, QST,
32168711Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB,
32268711Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB,
32368711Seric /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M,
3248078Seric };
3258078Seric
32665092Seric /* token type table -- it gets modified with $o characters */
32769748Seric static u_char TokTypeTab[256] =
32865092Seric {
32968711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
33068711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
33168711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
33268711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33368711Seric /* sp ! " # $ % & ' ( ) * + , - . / */
33468711Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
33568711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
33668711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33768711Seric /* @ A B C D E F G H I J K L M N O */
33868711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
33968711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */
34068711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
34168711Seric /* ` a b c d e f g h i j k l m n o */
34268711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
34368711Seric /* p q r s t u v w x y z { | } ~ del */
34468711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
34568711Seric
34668711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
34768711Seric OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
34868711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
34968711Seric OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
35068711Seric /* sp ! " # $ % & ' ( ) * + , - . / */
35168711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
35268711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
35368711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
35468711Seric /* @ A B C D E F G H I J K L M N O */
35568711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
35668711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */
35768711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
35868711Seric /* ` a b c d e f g h i j k l m n o */
35968711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
36068711Seric /* p q r s t u v w x y z { | } ~ del */
36168711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
36265092Seric };
36365092Seric
36468711Seric /* token type table for MIME parsing */
36569748Seric u_char MimeTokenTab[256] =
36668711Seric {
36768711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
36868711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
36968711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
37068711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
37168711Seric /* sp ! " # $ % & ' ( ) * + , - . / */
37268711Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
37368711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
37468711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
37568711Seric /* @ A B C D E F G H I J K L M N O */
37668711Seric OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
37768711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */
37868711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
37968711Seric /* ` a b c d e f g h i j k l m n o */
38068711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
38168711Seric /* p q r s t u v w x y z { | } ~ del */
38268711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
38365092Seric
38468711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
38568711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
38668711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
38768711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
38868711Seric /* sp ! " # $ % & ' ( ) * + , - . / */
38968711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
39068711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
39168711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
39268711Seric /* @ A B C D E F G H I J K L M N O */
39368711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
39468711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */
39568711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
39668711Seric /* ` a b c d e f g h i j k l m n o */
39768711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
39868711Seric /* p q r s t u v w x y z { | } ~ del */
39968711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
40068711Seric };
40165092Seric
40268711Seric
4038078Seric # define NOCHAR -1 /* signal nothing in lookahead token */
4048078Seric
4053149Seric char **
prescan(addr,delim,pvpbuf,pvpbsize,delimptr,toktab)40668711Seric prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab)
407297Seric char *addr;
40868353Seric int delim;
40916914Seric char pvpbuf[];
41058333Seric char **delimptr;
41169748Seric u_char *toktab;
412297Seric {
413297Seric register char *p;
4148078Seric register char *q;
4159346Seric register int c;
4163149Seric char **avp;
417297Seric bool bslashmode;
418297Seric int cmntcnt;
4198423Seric int anglecnt;
4203149Seric char *tok;
4218078Seric int state;
4228078Seric int newstate;
42359747Seric char *saveto = CurEnv->e_to;
4248078Seric static char *av[MAXATOM+1];
42565092Seric static char firsttime = TRUE;
42656678Seric extern int errno;
427297Seric
42865092Seric if (firsttime)
42965092Seric {
43065092Seric /* initialize the token type table */
43165092Seric char obuf[50];
43265092Seric
43365092Seric firsttime = FALSE;
43468529Seric expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv);
43565092Seric strcat(obuf, DELIMCHARS);
43665092Seric for (p = obuf; *p != '\0'; p++)
43765092Seric {
43865092Seric if (TokTypeTab[*p & 0xff] == ATM)
43965092Seric TokTypeTab[*p & 0xff] = OPR;
44065092Seric }
44165092Seric }
44268711Seric if (toktab == NULL)
44368711Seric toktab = TokTypeTab;
44465092Seric
44515253Seric /* make sure error messages don't have garbage on them */
44615253Seric errno = 0;
44715253Seric
44816914Seric q = pvpbuf;
4493149Seric bslashmode = FALSE;
4507800Seric cmntcnt = 0;
4518423Seric anglecnt = 0;
4523149Seric avp = av;
45356678Seric state = ATM;
4548078Seric c = NOCHAR;
4558078Seric p = addr;
45659747Seric CurEnv->e_to = p;
45756764Seric if (tTd(22, 11))
458297Seric {
4598078Seric printf("prescan: ");
4608078Seric xputs(p);
46123109Seric (void) putchar('\n');
4628078Seric }
4638078Seric
4648078Seric do
4658078Seric {
4663149Seric /* read a token */
4673149Seric tok = q;
4688078Seric for (;;)
469297Seric {
4708078Seric /* store away any old lookahead character */
47159277Seric if (c != NOCHAR && !bslashmode)
4728078Seric {
47315284Seric /* see if there is room */
47465066Seric if (q >= &pvpbuf[pvpbsize - 5])
4758078Seric {
47658151Seric usrerr("553 Address too long");
47768526Seric if (strlen(addr) > MAXNAME)
47868526Seric addr[MAXNAME] = '\0';
47965015Seric returnnull:
48058333Seric if (delimptr != NULL)
48158333Seric *delimptr = p;
48259747Seric CurEnv->e_to = saveto;
4838078Seric return (NULL);
4848078Seric }
48515284Seric
48615284Seric /* squirrel it away */
4878078Seric *q++ = c;
4888078Seric }
4898078Seric
4908078Seric /* read a new input character */
4918078Seric c = *p++;
49257631Seric if (c == '\0')
49356764Seric {
49456764Seric /* diagnose and patch up bad syntax */
49556764Seric if (state == QST)
49656764Seric {
49764767Seric usrerr("653 Unbalanced '\"'");
49856764Seric c = '"';
49956764Seric }
50056764Seric else if (cmntcnt > 0)
50156764Seric {
50264767Seric usrerr("653 Unbalanced '('");
50356764Seric c = ')';
50456764Seric }
50556764Seric else if (anglecnt > 0)
50656764Seric {
50756764Seric c = '>';
50864767Seric usrerr("653 Unbalanced '<'");
50956764Seric }
51056764Seric else
51156764Seric break;
51215284Seric
51356764Seric p--;
51456764Seric }
51557631Seric else if (c == delim && anglecnt <= 0 &&
51657631Seric cmntcnt <= 0 && state != QST)
51757631Seric break;
51856764Seric
5198078Seric if (tTd(22, 101))
5208078Seric printf("c=%c, s=%d; ", c, state);
5218078Seric
5223149Seric /* chew up special characters */
5233149Seric *q = '\0';
5243149Seric if (bslashmode)
5253149Seric {
52659105Seric bslashmode = FALSE;
52759105Seric
52824944Seric /* kludge \! for naive users */
52958061Seric if (cmntcnt > 0)
53059105Seric {
53158061Seric c = NOCHAR;
53259105Seric continue;
53359105Seric }
53459105Seric else if (c != '!' || state == QST)
53559105Seric {
53656678Seric *q++ = '\\';
53759105Seric continue;
53859105Seric }
5393149Seric }
54056678Seric
54156678Seric if (c == '\\')
5423149Seric {
5433149Seric bslashmode = TRUE;
5443149Seric }
54556678Seric else if (state == QST)
5468514Seric {
5478514Seric /* do nothing, just avoid next clauses */
5488514Seric }
5498078Seric else if (c == '(')
5504100Seric {
5518078Seric cmntcnt++;
5528078Seric c = NOCHAR;
5534100Seric }
5548078Seric else if (c == ')')
5553149Seric {
5568078Seric if (cmntcnt <= 0)
5573149Seric {
55864767Seric usrerr("653 Unbalanced ')'");
55963844Seric c = NOCHAR;
5603149Seric }
5618078Seric else
5628078Seric cmntcnt--;
5638078Seric }
5648078Seric else if (cmntcnt > 0)
5658078Seric c = NOCHAR;
5668423Seric else if (c == '<')
5678423Seric anglecnt++;
5688423Seric else if (c == '>')
5698423Seric {
5708423Seric if (anglecnt <= 0)
5718423Seric {
57264767Seric usrerr("653 Unbalanced '>'");
57363844Seric c = NOCHAR;
5748423Seric }
57563844Seric else
57663844Seric anglecnt--;
5778423Seric }
57858050Seric else if (delim == ' ' && isascii(c) && isspace(c))
57911423Seric c = ' ';
5803149Seric
5818078Seric if (c == NOCHAR)
5828078Seric continue;
5833149Seric
5848078Seric /* see if this is end of input */
58511405Seric if (c == delim && anglecnt <= 0 && state != QST)
5863149Seric break;
5873149Seric
58868711Seric newstate = StateTab[state][toktab[c & 0xff]];
5898078Seric if (tTd(22, 101))
5908078Seric printf("ns=%02o\n", newstate);
5918078Seric state = newstate & TYPE;
59268711Seric if (state == ILL)
59368711Seric {
59468711Seric if (isascii(c) && isprint(c))
59568711Seric usrerr("653 Illegal character %c", c);
59668711Seric else
59768711Seric usrerr("653 Illegal character 0x%02x", c);
59868711Seric }
5998078Seric if (bitset(M, newstate))
6008078Seric c = NOCHAR;
6018078Seric if (bitset(B, newstate))
6024228Seric break;
603297Seric }
6043149Seric
6053149Seric /* new token */
6068078Seric if (tok != q)
6071378Seric {
6088078Seric *q++ = '\0';
6098078Seric if (tTd(22, 36))
610297Seric {
6118078Seric printf("tok=");
6128078Seric xputs(tok);
61323109Seric (void) putchar('\n');
614297Seric }
6158078Seric if (avp >= &av[MAXATOM])
616297Seric {
61758151Seric syserr("553 prescan: too many tokens");
61865015Seric goto returnnull;
619297Seric }
62065015Seric if (q - tok > MAXNAME)
62165015Seric {
62265015Seric syserr("553 prescan: token too long");
62365015Seric goto returnnull;
62465015Seric }
6258078Seric *avp++ = tok;
626297Seric }
6278423Seric } while (c != '\0' && (c != delim || anglecnt > 0));
6283149Seric *avp = NULL;
62958333Seric p--;
63058333Seric if (delimptr != NULL)
63158333Seric *delimptr = p;
63256764Seric if (tTd(22, 12))
63356764Seric {
63456764Seric printf("prescan==>");
63556764Seric printav(av);
63656764Seric }
63759747Seric CurEnv->e_to = saveto;
63858546Seric if (av[0] == NULL)
63964966Seric {
64064966Seric if (tTd(22, 1))
64164966Seric printf("prescan: null leading token\n");
64258546Seric return (NULL);
64364966Seric }
64458403Seric return (av);
6453149Seric }
6463149Seric /*
6473149Seric ** REWRITE -- apply rewrite rules to token vector.
6483149Seric **
6494476Seric ** This routine is an ordered production system. Each rewrite
6504476Seric ** rule has a LHS (called the pattern) and a RHS (called the
6514476Seric ** rewrite); 'rwr' points the the current rewrite rule.
6524476Seric **
6534476Seric ** For each rewrite rule, 'avp' points the address vector we
6544476Seric ** are trying to match against, and 'pvp' points to the pattern.
6558058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY,
6569585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
6579585Seric ** matched is saved away in the match vector (pointed to by 'mvp').
6584476Seric **
6594476Seric ** When a match between avp & pvp does not match, we try to
6609585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
6614476Seric ** we must also back out the match in mvp. If we reach a
6628058Seric ** MATCHANY or MATCHZANY we just extend the match and start
6638058Seric ** over again.
6644476Seric **
6654476Seric ** When we finally match, we rewrite the address vector
6664476Seric ** and try over again.
6674476Seric **
6683149Seric ** Parameters:
6693149Seric ** pvp -- pointer to token vector.
67059027Seric ** ruleset -- the ruleset to use for rewriting.
67165071Seric ** reclevel -- recursion level (to catch loops).
67259027Seric ** e -- the current envelope.
6733149Seric **
6743149Seric ** Returns:
67559084Seric ** A status code. If EX_TEMPFAIL, higher level code should
67659084Seric ** attempt recovery.
6773149Seric **
6783149Seric ** Side Effects:
6793149Seric ** pvp is modified.
6803149Seric */
6812091Seric
6823149Seric struct match
6833149Seric {
6844468Seric char **first; /* first token matched */
6854468Seric char **last; /* last token matched */
68658825Seric char **pattern; /* pointer to pattern */
6873149Seric };
6883149Seric
6894468Seric # define MAXMATCH 9 /* max params per rewrite */
6903149Seric
69165136Seric # ifndef MAXRULERECURSION
69265136Seric # define MAXRULERECURSION 50 /* max recursion depth */
69365136Seric # endif
6943149Seric
69565136Seric
69659084Seric int
rewrite(pvp,ruleset,reclevel,e)69765071Seric rewrite(pvp, ruleset, reclevel, e)
6983149Seric char **pvp;
6994070Seric int ruleset;
70065071Seric int reclevel;
70159027Seric register ENVELOPE *e;
7023149Seric {
7033149Seric register char *ap; /* address pointer */
7043149Seric register char *rp; /* rewrite pointer */
7053149Seric register char **avp; /* address vector pointer */
7063149Seric register char **rvp; /* rewrite vector pointer */
7078058Seric register struct match *mlp; /* cur ptr into mlist */
7088058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */
70958866Seric int ruleno; /* current rule number */
71059084Seric int rstat = EX_OK; /* return status */
71164740Seric int loopcount;
71256678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */
7133149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */
7143149Seric
71567262Seric if (OpMode == MD_TEST || tTd(21, 1))
7163149Seric {
7178959Seric printf("rewrite: ruleset %2d input:", ruleset);
71856678Seric printav(pvp);
7193149Seric }
72056678Seric if (ruleset < 0 || ruleset >= MAXRWSETS)
72156326Seric {
72258151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset);
72359084Seric return EX_CONFIG;
72456326Seric }
72565136Seric if (reclevel++ > MAXRULERECURSION)
72665071Seric {
72765071Seric syserr("rewrite: infinite recursion, ruleset %d", ruleset);
72865071Seric return EX_CONFIG;
72965071Seric }
73056678Seric if (pvp == NULL)
73159084Seric return EX_USAGE;
73256326Seric
7333149Seric /*
73456678Seric ** Run through the list of rewrite rules, applying
73556678Seric ** any that match.
7363149Seric */
7373149Seric
73858866Seric ruleno = 1;
73964740Seric loopcount = 0;
7404070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; )
7413149Seric {
7427675Seric if (tTd(21, 12))
743297Seric {
7448069Seric printf("-----trying rule:");
74556678Seric printav(rwr->r_lhs);
7463149Seric }
7473149Seric
7483149Seric /* try to match on this rule */
7494468Seric mlp = mlist;
7508058Seric rvp = rwr->r_lhs;
7518058Seric avp = pvp;
75258866Seric if (++loopcount > 100)
7533149Seric {
75458866Seric syserr("554 Infinite loop in ruleset %d, rule %d",
75558866Seric ruleset, ruleno);
75658866Seric if (tTd(21, 1))
75752637Seric {
75856678Seric printf("workspace: ");
75956678Seric printav(pvp);
76052637Seric }
76158866Seric break;
76258866Seric }
76358866Seric
76458866Seric while ((ap = *avp) != NULL || *rvp != NULL)
76558866Seric {
7663149Seric rp = *rvp;
7678058Seric if (tTd(21, 35))
7688058Seric {
76958825Seric printf("ADVANCE rp=");
77057531Seric xputs(rp);
77157532Seric printf(", ap=");
7728058Seric xputs(ap);
7738069Seric printf("\n");
7748058Seric }
77556678Seric if (rp == NULL)
77656326Seric {
7773149Seric /* end-of-pattern before end-of-address */
7788058Seric goto backup;
77956678Seric }
78058173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY &&
78158827Seric (*rp & 0377) != MATCHZERO)
78256326Seric {
78358825Seric /* end-of-input with patterns left */
78458825Seric goto backup;
785297Seric }
78656326Seric
78758050Seric switch (*rp & 0377)
7888058Seric {
78958814Seric char buf[MAXLINE];
79056326Seric
79156678Seric case MATCHCLASS:
79258825Seric /* match any phrase in a class */
79358825Seric mlp->pattern = rvp;
79458814Seric mlp->first = avp;
79558814Seric extendclass:
79658825Seric ap = *avp;
79758825Seric if (ap == NULL)
79858814Seric goto backup;
79958814Seric mlp->last = avp++;
80058814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0');
80168199Seric if (!wordinclass(buf, rp[1]))
80256326Seric {
80358825Seric if (tTd(21, 36))
80458825Seric {
80558825Seric printf("EXTEND rp=");
80658825Seric xputs(rp);
80758825Seric printf(", ap=");
80858825Seric xputs(ap);
80958825Seric printf("\n");
81058825Seric }
81158825Seric goto extendclass;
81256326Seric }
81358825Seric if (tTd(21, 36))
81458825Seric printf("CLMATCH\n");
81558814Seric mlp++;
81658814Seric break;
8174060Seric
81858825Seric case MATCHNCLASS:
81958825Seric /* match any token not in a class */
82068199Seric if (wordinclass(ap, rp[1]))
82158825Seric goto backup;
82258825Seric
82358825Seric /* fall through */
82458825Seric
82556678Seric case MATCHONE:
82656678Seric case MATCHANY:
82756678Seric /* match exactly one token */
82858825Seric mlp->pattern = rvp;
82956678Seric mlp->first = avp;
83056678Seric mlp->last = avp++;
8318058Seric mlp++;
83256678Seric break;
8338058Seric
83456678Seric case MATCHZANY:
83556678Seric /* match zero or more tokens */
83658825Seric mlp->pattern = rvp;
83756678Seric mlp->first = avp;
83856678Seric mlp->last = avp - 1;
83956678Seric mlp++;
84056678Seric break;
84156326Seric
84258827Seric case MATCHZERO:
84358173Seric /* match zero tokens */
84458173Seric break;
84558173Seric
84659027Seric case MACRODEXPAND:
84759027Seric /*
84859027Seric ** Match against run-time macro.
84959027Seric ** This algorithm is broken for the
85059027Seric ** general case (no recursive macros,
85159027Seric ** improper tokenization) but should
85259027Seric ** work for the usual cases.
85359027Seric */
85459027Seric
85559027Seric ap = macvalue(rp[1], e);
85659027Seric mlp->first = avp;
85759027Seric if (tTd(21, 2))
85859027Seric printf("rewrite: LHS $&%c => \"%s\"\n",
85959027Seric rp[1],
86059027Seric ap == NULL ? "(NULL)" : ap);
86159027Seric
86259027Seric if (ap == NULL)
86359027Seric break;
86460502Seric while (*ap != '\0')
86559027Seric {
86659027Seric if (*avp == NULL ||
86759027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0)
86859027Seric {
86959027Seric /* no match */
87059027Seric avp = mlp->first;
87159027Seric goto backup;
87259027Seric }
87359027Seric ap += strlen(*avp++);
87459027Seric }
87559027Seric
87659027Seric /* match */
87759027Seric break;
87859027Seric
87956678Seric default:
88056678Seric /* must have exact match */
88156678Seric if (strcasecmp(rp, ap))
8828058Seric goto backup;
8834468Seric avp++;
88456678Seric break;
8853149Seric }
8863149Seric
88756678Seric /* successful match on this token */
8883149Seric rvp++;
8893149Seric continue;
8903149Seric
89158825Seric backup:
89256678Seric /* match failed -- back up */
89358825Seric while (--mlp >= mlist)
8943149Seric {
89558825Seric rvp = mlp->pattern;
89656678Seric rp = *rvp;
89758825Seric avp = mlp->last + 1;
89858825Seric ap = *avp;
89958825Seric
90058825Seric if (tTd(21, 36))
90158825Seric {
90258825Seric printf("BACKUP rp=");
90358825Seric xputs(rp);
90458825Seric printf(", ap=");
90558825Seric xputs(ap);
90658825Seric printf("\n");
90758825Seric }
90858825Seric
90958825Seric if (ap == NULL)
91058825Seric {
91158825Seric /* run off the end -- back up again */
91258825Seric continue;
91358825Seric }
91458050Seric if ((*rp & 0377) == MATCHANY ||
91558050Seric (*rp & 0377) == MATCHZANY)
9164468Seric {
91756678Seric /* extend binding and continue */
91858825Seric mlp->last = avp++;
91956678Seric rvp++;
92058825Seric mlp++;
92156678Seric break;
9224468Seric }
92358825Seric if ((*rp & 0377) == MATCHCLASS)
92456678Seric {
92558814Seric /* extend binding and try again */
92663397Seric mlp->last = avp;
92758814Seric goto extendclass;
92858814Seric }
9293149Seric }
9303149Seric
93158825Seric if (mlp < mlist)
93256678Seric {
93356678Seric /* total failure to match */
93456326Seric break;
9353149Seric }
936297Seric }
9373149Seric
9383149Seric /*
93956678Seric ** See if we successfully matched
9403149Seric */
9413149Seric
94258827Seric if (mlp < mlist || *rvp != NULL)
9433149Seric {
9449374Seric if (tTd(21, 10))
9459374Seric printf("----- rule fails\n");
9469374Seric rwr = rwr->r_next;
94758866Seric ruleno++;
94864740Seric loopcount = 0;
9499374Seric continue;
9509374Seric }
9513149Seric
9529374Seric rvp = rwr->r_rhs;
9539374Seric if (tTd(21, 12))
9549374Seric {
9559374Seric printf("-----rule matches:");
95656678Seric printav(rvp);
9579374Seric }
9589374Seric
9599374Seric rp = *rvp;
96058050Seric if ((*rp & 0377) == CANONUSER)
9619374Seric {
9629374Seric rvp++;
9639374Seric rwr = rwr->r_next;
96458866Seric ruleno++;
96564740Seric loopcount = 0;
9669374Seric }
96758050Seric else if ((*rp & 0377) == CANONHOST)
9689374Seric {
9699374Seric rvp++;
9709374Seric rwr = NULL;
9719374Seric }
97258050Seric else if ((*rp & 0377) == CANONNET)
9739374Seric rwr = NULL;
9749374Seric
9759374Seric /* substitute */
9769374Seric for (avp = npvp; *rvp != NULL; rvp++)
9779374Seric {
9789374Seric register struct match *m;
9799374Seric register char **pp;
9809374Seric
9818058Seric rp = *rvp;
98258050Seric if ((*rp & 0377) == MATCHREPL)
9838058Seric {
98416914Seric /* substitute from LHS */
98516914Seric m = &mlist[rp[1] - '1'];
98656678Seric if (m < mlist || m >= mlp)
9879374Seric {
98858151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds",
98956326Seric ruleset, rp[1]);
99059084Seric return EX_CONFIG;
9919374Seric }
99216914Seric if (tTd(21, 15))
99316914Seric {
99416914Seric printf("$%c:", rp[1]);
99516914Seric pp = m->first;
99656678Seric while (pp <= m->last)
99716914Seric {
99816914Seric printf(" %x=\"", *pp);
99916914Seric (void) fflush(stdout);
100016914Seric printf("%s\"", *pp++);
100116914Seric }
100216914Seric printf("\n");
100316914Seric }
10049374Seric pp = m->first;
100556678Seric while (pp <= m->last)
10063149Seric {
100716914Seric if (avp >= &npvp[MAXATOM])
100856678Seric {
100958151Seric syserr("554 rewrite: expansion too long");
101059084Seric return EX_DATAERR;
101156678Seric }
101216914Seric *avp++ = *pp++;
10133149Seric }
10143149Seric }
101516914Seric else
10168226Seric {
101716914Seric /* vanilla replacement */
10189374Seric if (avp >= &npvp[MAXATOM])
101916889Seric {
102056678Seric toolong:
102158151Seric syserr("554 rewrite: expansion too long");
102259084Seric return EX_DATAERR;
102316889Seric }
102459027Seric if ((*rp & 0377) != MACRODEXPAND)
102559027Seric *avp++ = rp;
102659027Seric else
102759027Seric {
102859027Seric *avp = macvalue(rp[1], e);
102959027Seric if (tTd(21, 2))
103059027Seric printf("rewrite: RHS $&%c => \"%s\"\n",
103159027Seric rp[1],
103259027Seric *avp == NULL ? "(NULL)" : *avp);
103359027Seric if (*avp != NULL)
103459027Seric avp++;
103559027Seric }
10368226Seric }
10379374Seric }
10389374Seric *avp++ = NULL;
103916914Seric
104016914Seric /*
104156678Seric ** Check for any hostname/keyword lookups.
104216914Seric */
104316914Seric
104416914Seric for (rvp = npvp; *rvp != NULL; rvp++)
104516914Seric {
104656678Seric char **hbrvp;
104716914Seric char **xpvp;
104816914Seric int trsize;
104956678Seric char *replac;
105056678Seric int endtoken;
105156678Seric STAB *map;
105256678Seric char *mapname;
105356678Seric char **key_rvp;
105456678Seric char **arg_rvp;
105556678Seric char **default_rvp;
105656678Seric char buf[MAXNAME + 1];
105716914Seric char *pvpb1[MAXATOM + 1];
105856823Seric char *argvect[10];
105917174Seric char pvpbuf[PSBUFSIZE];
106064404Seric char *nullpvp[1];
106116914Seric
106258050Seric if ((**rvp & 0377) != HOSTBEGIN &&
106358050Seric (**rvp & 0377) != LOOKUPBEGIN)
106416914Seric continue;
106516914Seric
106616914Seric /*
106756678Seric ** Got a hostname/keyword lookup.
106816914Seric **
106916914Seric ** This could be optimized fairly easily.
107016914Seric */
107116914Seric
107216914Seric hbrvp = rvp;
107358050Seric if ((**rvp & 0377) == HOSTBEGIN)
107456327Seric {
107556678Seric endtoken = HOSTEND;
107656678Seric mapname = "host";
107756327Seric }
107856326Seric else
107956327Seric {
108056678Seric endtoken = LOOKUPEND;
108156678Seric mapname = *++rvp;
108256327Seric }
108356678Seric map = stab(mapname, ST_MAP, ST_FIND);
108456678Seric if (map == NULL)
108558151Seric syserr("554 rewrite: map %s not found", mapname);
108656678Seric
108756678Seric /* extract the match part */
108856678Seric key_rvp = ++rvp;
108956823Seric default_rvp = NULL;
109056823Seric arg_rvp = argvect;
109156823Seric xpvp = NULL;
109256823Seric replac = pvpbuf;
109358050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken)
109453654Seric {
109558050Seric int nodetype = **rvp & 0377;
109656823Seric
109756823Seric if (nodetype != CANONHOST && nodetype != CANONUSER)
109856678Seric {
109956823Seric rvp++;
110056823Seric continue;
110156823Seric }
110256823Seric
110356823Seric *rvp++ = NULL;
110456823Seric
110556823Seric if (xpvp != NULL)
110656823Seric {
110758814Seric cataddr(xpvp, NULL, replac,
110858082Seric &pvpbuf[sizeof pvpbuf] - replac,
110958082Seric '\0');
111056823Seric *++arg_rvp = replac;
111156823Seric replac += strlen(replac) + 1;
111256823Seric xpvp = NULL;
111356823Seric }
111456823Seric switch (nodetype)
111556823Seric {
111656678Seric case CANONHOST:
111756823Seric xpvp = rvp;
111856678Seric break;
111956678Seric
112056678Seric case CANONUSER:
112156678Seric default_rvp = rvp;
112256678Seric break;
112356678Seric }
112453654Seric }
112516914Seric if (*rvp != NULL)
112616914Seric *rvp++ = NULL;
112756823Seric if (xpvp != NULL)
112856823Seric {
112958814Seric cataddr(xpvp, NULL, replac,
113058082Seric &pvpbuf[sizeof pvpbuf] - replac,
113158082Seric '\0');
113256823Seric *++arg_rvp = replac;
113356823Seric }
113456823Seric *++arg_rvp = NULL;
113516914Seric
113616914Seric /* save the remainder of the input string */
113716914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp;
113816914Seric bcopy((char *) rvp, (char *) pvpb1, trsize);
113916914Seric
114056678Seric /* look it up */
114158814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0');
114256823Seric argvect[0] = buf;
114360538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags))
114456836Seric {
114559084Seric auto int stat = EX_OK;
114656836Seric
114769703Seric if (!bitset(MF_KEEPQUOTES, map->s_map.map_mflags))
114869703Seric stripquotes(buf);
114969703Seric
115060215Seric /* XXX should try to auto-open the map here */
115160215Seric
115258796Seric if (tTd(60, 1))
115358796Seric printf("map_lookup(%s, %s) => ",
115458796Seric mapname, buf);
115556836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map,
115660089Seric buf, argvect, &stat);
115758796Seric if (tTd(60, 1))
115859084Seric printf("%s (%d)\n",
115959084Seric replac ? replac : "NOT FOUND",
116059084Seric stat);
116159084Seric
116259084Seric /* should recover if stat == EX_TEMPFAIL */
116368881Seric if (stat == EX_TEMPFAIL)
116468706Seric {
116568706Seric rstat = EX_TEMPFAIL;
1166*69925Seric if (tTd(60, 1))
116768706Seric printf("map_lookup(%s, %s) failed (stat = %d)\n",
116868706Seric mapname, buf, stat);
116968706Seric if (e->e_message == NULL)
117068706Seric {
117168706Seric char mbuf[300];
117268706Seric
117368706Seric sprintf(mbuf, "map %s: lookup (%s) failed",
117468706Seric mapname, buf);
117568706Seric e->e_message = newstr(mbuf);
117668706Seric }
117768706Seric }
117856836Seric }
117953654Seric else
118056678Seric replac = NULL;
118156678Seric
118256678Seric /* if no replacement, use default */
118356823Seric if (replac == NULL && default_rvp != NULL)
118456823Seric {
118560089Seric /* create the default */
118660089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0');
118756823Seric replac = buf;
118856823Seric }
118956823Seric
119056678Seric if (replac == NULL)
119151317Seric {
119256823Seric xpvp = key_rvp;
119353654Seric }
119464404Seric else if (*replac == '\0')
119564404Seric {
119664404Seric /* null replacement */
119764404Seric nullpvp[0] = NULL;
119864404Seric xpvp = nullpvp;
119964404Seric }
120056678Seric else
120153654Seric {
120256678Seric /* scan the new replacement */
120365066Seric xpvp = prescan(replac, '\0', pvpbuf,
120468711Seric sizeof pvpbuf, NULL, NULL);
120553654Seric if (xpvp == NULL)
120651317Seric {
120758403Seric /* prescan already printed error */
120859084Seric return EX_DATAERR;
120956678Seric }
121051317Seric }
121151317Seric
121216914Seric /* append it to the token list */
121356678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++)
121456678Seric {
121517174Seric *avp++ = newstr(*xpvp);
121616920Seric if (avp >= &npvp[MAXATOM])
121716914Seric goto toolong;
121817174Seric }
121916914Seric
122016914Seric /* restore the old trailing information */
122156678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
122216920Seric if (avp >= &npvp[MAXATOM])
122316914Seric goto toolong;
122417174Seric
122556678Seric break;
122616914Seric }
122716914Seric
122816914Seric /*
122916914Seric ** Check for subroutine calls.
123016914Seric */
123116914Seric
123268559Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR)
123368559Seric {
123468559Seric int stat;
123559084Seric
123668559Seric if (npvp[1] == NULL)
123768559Seric {
123868559Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d",
123968559Seric ruleset, ruleno);
124068559Seric *pvp = NULL;
124168559Seric }
124268559Seric else
124368559Seric {
124468559Seric int ruleset;
124568559Seric STAB *s;
124668385Seric
124768559Seric bcopy((char *) &npvp[2], (char *) pvp,
124868559Seric (int) (avp - npvp - 2) * sizeof *avp);
124968559Seric if (tTd(21, 3))
125068559Seric printf("-----callsubr %s\n", npvp[1]);
125169783Seric ruleset = strtorwset(npvp[1], NULL, ST_FIND);
125268559Seric stat = rewrite(pvp, ruleset, reclevel, e);
125368559Seric if (rstat == EX_OK || stat == EX_TEMPFAIL)
125468559Seric rstat = stat;
125568559Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET)
125668559Seric rwr = NULL;
125768559Seric }
125868559Seric }
125968559Seric else
126068559Seric {
126168559Seric bcopy((char *) npvp, (char *) pvp,
126268559Seric (int) (avp - npvp) * sizeof *avp);
126368559Seric }
12649374Seric if (tTd(21, 4))
12659374Seric {
12669374Seric printf("rewritten as:");
126756678Seric printav(pvp);
12689374Seric }
1269297Seric }
12708069Seric
127167262Seric if (OpMode == MD_TEST || tTd(21, 1))
12728069Seric {
12738959Seric printf("rewrite: ruleset %2d returns:", ruleset);
127456678Seric printav(pvp);
12758069Seric }
127659084Seric
127759084Seric return rstat;
12783149Seric }
12793149Seric /*
12803149Seric ** BUILDADDR -- build address from token vector.
12813149Seric **
12823149Seric ** Parameters:
12833149Seric ** tv -- token vector.
12843149Seric ** a -- pointer to address descriptor to fill.
12853149Seric ** If NULL, one will be allocated.
128664284Seric ** flags -- info regarding whether this is a sender or
128764284Seric ** a recipient.
128858966Seric ** e -- the current envelope.
12893149Seric **
12903149Seric ** Returns:
12914279Seric ** NULL if there was an error.
12924279Seric ** 'a' otherwise.
12933149Seric **
12943149Seric ** Side Effects:
12953149Seric ** fills in 'a'
12963149Seric */
12973149Seric
129857249Seric struct errcodes
129957249Seric {
130057249Seric char *ec_name; /* name of error code */
130157249Seric int ec_code; /* numeric code */
130257249Seric } ErrorCodes[] =
130357249Seric {
130457249Seric "usage", EX_USAGE,
130557249Seric "nouser", EX_NOUSER,
130657249Seric "nohost", EX_NOHOST,
130757249Seric "unavailable", EX_UNAVAILABLE,
130857249Seric "software", EX_SOFTWARE,
130957249Seric "tempfail", EX_TEMPFAIL,
131057249Seric "protocol", EX_PROTOCOL,
131157249Seric #ifdef EX_CONFIG
131257249Seric "config", EX_CONFIG,
131357249Seric #endif
131457249Seric NULL, EX_UNAVAILABLE,
131557249Seric };
131657249Seric
131756678Seric ADDRESS *
buildaddr(tv,a,flags,e)131864284Seric buildaddr(tv, a, flags, e)
13193149Seric register char **tv;
13203149Seric register ADDRESS *a;
132164284Seric int flags;
132258966Seric register ENVELOPE *e;
13233149Seric {
13243149Seric struct mailer **mp;
13253149Seric register struct mailer *m;
132668849Seric register char *p;
132768849Seric char *mname;
132868849Seric char **hostp;
132968849Seric char hbuf[MAXNAME + 1];
133064306Seric static MAILER errormailer;
133164306Seric static char *errorargv[] = { "ERROR", NULL };
133268849Seric static char ubuf[MAXNAME + 1];
13333149Seric
133464791Seric if (tTd(24, 5))
133564791Seric {
133667693Seric printf("buildaddr, flags=%x, tv=", flags);
133764791Seric printav(tv);
133864791Seric }
133964791Seric
13403149Seric if (a == NULL)
13413149Seric a = (ADDRESS *) xalloc(sizeof *a);
134216889Seric bzero((char *) a, sizeof *a);
13433149Seric
134467880Seric /* set up default error return flags */
134567963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY;
134667880Seric
13473149Seric /* figure out what net/mailer to use */
134864306Seric if (*tv == NULL || (**tv & 0377) != CANONNET)
13494279Seric {
135058151Seric syserr("554 buildaddr: no net");
135164306Seric badaddr:
135264306Seric a->q_flags |= QBADADDR;
135364306Seric a->q_mailer = &errormailer;
135464306Seric if (errormailer.m_name == NULL)
135564306Seric {
135664306Seric /* initialize the bogus mailer */
135764306Seric errormailer.m_name = "*error*";
135864306Seric errormailer.m_mailer = "ERROR";
135964306Seric errormailer.m_argv = errorargv;
136064306Seric }
136164306Seric return a;
13624279Seric }
136368849Seric mname = *++tv;
136468849Seric
136568849Seric /* extract host and user portions */
136668849Seric if ((**++tv & 0377) == CANONHOST)
136768849Seric hostp = ++tv;
136868849Seric else
136968849Seric hostp = NULL;
137068849Seric while (*tv != NULL && (**tv & 0377) != CANONUSER)
137168849Seric tv++;
137268849Seric if (*tv == NULL)
13734279Seric {
137468849Seric syserr("554 buildaddr: no user");
137568849Seric goto badaddr;
137668849Seric }
137768849Seric if (hostp != NULL)
137868849Seric cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0');
137968849Seric cataddr(++tv, NULL, ubuf, sizeof ubuf, '\0');
138068849Seric
138168849Seric /* save away the host name */
138268849Seric if (strcasecmp(mname, "error") == 0)
138368849Seric {
138468849Seric if (hostp != NULL)
138510183Seric {
138657249Seric register struct errcodes *ep;
138757249Seric
138868849Seric if (strchr(hbuf, '.') != NULL)
138957249Seric {
139068849Seric a->q_status = newstr(hbuf);
139168849Seric setstat(dsntoexitstat(hbuf));
139257249Seric }
139368849Seric else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
139468849Seric {
139568849Seric setstat(atoi(hbuf));
139668849Seric }
139757249Seric else
139857249Seric {
139957249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
140068849Seric if (strcasecmp(ep->ec_name, hbuf) == 0)
140157249Seric break;
140257249Seric setstat(ep->ec_code);
140357249Seric }
140410183Seric }
140564928Seric else
140664928Seric setstat(EX_UNAVAILABLE);
140768849Seric stripquotes(ubuf);
140868849Seric if (isascii(ubuf[0]) && isdigit(ubuf[0]) &&
140968849Seric isascii(ubuf[1]) && isdigit(ubuf[1]) &&
141068849Seric isascii(ubuf[2]) && isdigit(ubuf[2]) &&
141168849Seric ubuf[3] == ' ')
141264659Seric {
141364659Seric char fmt[10];
141464659Seric
141568849Seric strncpy(fmt, ubuf, 3);
141664659Seric strcpy(&fmt[3], " %s");
141768849Seric usrerr(fmt, ubuf + 4);
141867786Seric
141967786Seric /*
142067786Seric ** If this is a 4xx code and we aren't running
142167786Seric ** SMTP on our input, bounce this message;
142267786Seric ** otherwise it disappears without a trace.
142367786Seric */
142467786Seric
142567786Seric if (fmt[0] == '4' && OpMode != MD_SMTP &&
142667786Seric OpMode != MD_DAEMON)
142767786Seric {
142867786Seric e->e_flags |= EF_FATALERRS;
142967786Seric }
143064659Seric }
143164659Seric else
143264659Seric {
143368849Seric usrerr("553 %s", ubuf);
143464659Seric }
143564306Seric goto badaddr;
14364279Seric }
143757402Seric
14384598Seric for (mp = Mailer; (m = *mp++) != NULL; )
14393149Seric {
144068849Seric if (strcasecmp(m->m_name, mname) == 0)
14413149Seric break;
14423149Seric }
14433149Seric if (m == NULL)
14444279Seric {
144568849Seric syserr("554 buildaddr: unknown mailer %s", mname);
144664306Seric goto badaddr;
14474279Seric }
14484598Seric a->q_mailer = m;
14493149Seric
14503149Seric /* figure out what host (if any) */
145168849Seric if (hostp == NULL)
14523149Seric {
145358509Seric if (!bitnset(M_LOCALMAILER, m->m_flags))
145458509Seric {
145558509Seric syserr("554 buildaddr: no host");
145664306Seric goto badaddr;
145758509Seric }
145857249Seric a->q_host = NULL;
145958509Seric }
146068849Seric else
146168849Seric a->q_host = newstr(hbuf);
14623149Seric
14633149Seric /* figure out the user */
146468849Seric p = ubuf;
146568849Seric if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
14664279Seric {
146768849Seric p++;
146868098Seric tv++;
146968098Seric a->q_flags |= QNOTREMOTE;
147068098Seric }
147168098Seric
147257402Seric /* do special mapping for local mailer */
147368849Seric if (*p == '"')
147468849Seric p++;
147568849Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
147668849Seric a->q_mailer = m = ProgMailer;
147768849Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
147868849Seric a->q_mailer = m = FileMailer;
147968849Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
148057402Seric {
148168849Seric /* may be :include: */
148268849Seric stripquotes(ubuf);
148368849Seric if (strncasecmp(ubuf, ":include:", 9) == 0)
148457402Seric {
148568849Seric /* if :include:, don't need further rewriting */
148668849Seric a->q_mailer = m = InclMailer;
148768849Seric a->q_user = newstr(&ubuf[9]);
148868849Seric return a;
148957402Seric }
149057402Seric }
149157402Seric
149264284Seric /* rewrite according recipient mailer rewriting rules */
149364284Seric define('h', a->q_host, e);
149464284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
149564284Seric {
149664284Seric /* sender addresses done later */
149765071Seric (void) rewrite(tv, 2, 0, e);
149864284Seric if (m->m_re_rwset > 0)
149965071Seric (void) rewrite(tv, m->m_re_rwset, 0, e);
150064284Seric }
150165071Seric (void) rewrite(tv, 4, 0, e);
150219040Seric
150319040Seric /* save the result for the command line/RCPT argument */
150468849Seric cataddr(tv, NULL, ubuf, sizeof ubuf, '\0');
150568849Seric a->q_user = ubuf;
15063149Seric
150758670Seric /*
150858670Seric ** Do mapping to lower case as requested by mailer
150958670Seric */
151058670Seric
151158670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
151258670Seric makelower(a->q_host);
151358670Seric if (!bitnset(M_USR_UPPER, m->m_flags))
151458670Seric makelower(a->q_user);
151558670Seric
151668849Seric return a;
15173149Seric }
15183188Seric /*
15194228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
15204228Seric **
15214228Seric ** Parameters:
15224228Seric ** pvp -- parameter vector to rebuild.
152358814Seric ** evp -- last parameter to include. Can be NULL to
152458814Seric ** use entire pvp.
15254228Seric ** buf -- buffer to build the string into.
15264228Seric ** sz -- size of buf.
152758082Seric ** spacesub -- the space separator character; if null,
152858082Seric ** use SpaceSub.
15294228Seric **
15304228Seric ** Returns:
15314228Seric ** none.
15324228Seric **
15334228Seric ** Side Effects:
15344228Seric ** Destroys buf.
15354228Seric */
15364228Seric
153769748Seric void
cataddr(pvp,evp,buf,sz,spacesub)153858814Seric cataddr(pvp, evp, buf, sz, spacesub)
15394228Seric char **pvp;
154058814Seric char **evp;
15414228Seric char *buf;
15424228Seric register int sz;
154369748Seric int spacesub;
15444228Seric {
15454228Seric bool oatomtok = FALSE;
154656678Seric bool natomtok = FALSE;
15474228Seric register int i;
15484228Seric register char *p;
15494228Seric
155058082Seric if (spacesub == '\0')
155158082Seric spacesub = SpaceSub;
155258082Seric
15538423Seric if (pvp == NULL)
15548423Seric {
155523109Seric (void) strcpy(buf, "");
15568423Seric return;
15578423Seric }
15584228Seric p = buf;
155911156Seric sz -= 2;
15604228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz)
15614228Seric {
156268711Seric natomtok = (TokTypeTab[**pvp & 0xff] == ATM);
15634228Seric if (oatomtok && natomtok)
156458082Seric *p++ = spacesub;
15654228Seric (void) strcpy(p, *pvp);
15664228Seric oatomtok = natomtok;
15674228Seric p += i;
156811156Seric sz -= i + 1;
156958814Seric if (pvp++ == evp)
157058814Seric break;
15714228Seric }
15724228Seric *p = '\0';
15734228Seric }
15744228Seric /*
15753188Seric ** SAMEADDR -- Determine if two addresses are the same
15763188Seric **
15773188Seric ** This is not just a straight comparison -- if the mailer doesn't
15783188Seric ** care about the host we just ignore it, etc.
15793188Seric **
15803188Seric ** Parameters:
15813188Seric ** a, b -- pointers to the internal forms to compare.
15823188Seric **
15833188Seric ** Returns:
15843188Seric ** TRUE -- they represent the same mailbox.
15853188Seric ** FALSE -- they don't.
15863188Seric **
15873188Seric ** Side Effects:
15883188Seric ** none.
15893188Seric */
15903188Seric
15913188Seric bool
sameaddr(a,b)15929374Seric sameaddr(a, b)
15933188Seric register ADDRESS *a;
15943188Seric register ADDRESS *b;
15953188Seric {
159665093Seric register ADDRESS *ca, *cb;
159765093Seric
15983188Seric /* if they don't have the same mailer, forget it */
15993188Seric if (a->q_mailer != b->q_mailer)
16003188Seric return (FALSE);
16013188Seric
16023188Seric /* if the user isn't the same, we can drop out */
160356678Seric if (strcmp(a->q_user, b->q_user) != 0)
16043188Seric return (FALSE);
16053188Seric
160665093Seric /* if we have good uids for both but they differ, these are different */
160765379Seric if (a->q_mailer == ProgMailer)
160865379Seric {
160965379Seric ca = getctladdr(a);
161065379Seric cb = getctladdr(b);
161165379Seric if (ca != NULL && cb != NULL &&
161265379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
161365379Seric ca->q_uid != cb->q_uid)
161465379Seric return (FALSE);
161565379Seric }
161658438Seric
161758509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */
161858509Seric if (a->q_host == b->q_host)
161958509Seric {
162058509Seric /* probably both null pointers */
16213188Seric return (TRUE);
162258509Seric }
16233188Seric if (a->q_host == NULL || b->q_host == NULL)
162458509Seric {
162558509Seric /* only one is a null pointer */
16263188Seric return (FALSE);
162758509Seric }
162856678Seric if (strcmp(a->q_host, b->q_host) != 0)
16293188Seric return (FALSE);
16303188Seric
16313188Seric return (TRUE);
16323188Seric }
16333234Seric /*
16343234Seric ** PRINTADDR -- print address (for debugging)
16353234Seric **
16363234Seric ** Parameters:
16373234Seric ** a -- the address to print
16383234Seric ** follow -- follow the q_next chain.
16393234Seric **
16403234Seric ** Returns:
16413234Seric ** none.
16423234Seric **
16433234Seric ** Side Effects:
16443234Seric ** none.
16453234Seric */
16463234Seric
164767994Seric struct qflags
164867994Seric {
164967994Seric char *qf_name;
165067994Seric u_long qf_bit;
165167994Seric };
165267994Seric
165367994Seric struct qflags AddressFlags[] =
165467994Seric {
165567994Seric "QDONTSEND", QDONTSEND,
165667994Seric "QBADADDR", QBADADDR,
165767994Seric "QGOODUID", QGOODUID,
165867994Seric "QPRIMARY", QPRIMARY,
165967994Seric "QQUEUEUP", QQUEUEUP,
166067994Seric "QSENT", QSENT,
166167994Seric "QNOTREMOTE", QNOTREMOTE,
166267994Seric "QSELFREF", QSELFREF,
166367994Seric "QVERIFIED", QVERIFIED,
166467994Seric "QBOGUSSHELL", QBOGUSSHELL,
166567994Seric "QUNSAFEADDR", QUNSAFEADDR,
166667994Seric "QPINGONSUCCESS", QPINGONSUCCESS,
166767994Seric "QPINGONFAILURE", QPINGONFAILURE,
166867994Seric "QPINGONDELAY", QPINGONDELAY,
166968595Seric "QHASNOTIFY", QHASNOTIFY,
167067994Seric "QRELAYED", QRELAYED,
167168867Seric "QEXPANDED", QEXPANDED,
167268867Seric "QDELIVERED", QDELIVERED,
167368867Seric "QDELAYED", QDELAYED,
167468603Seric "QTHISPASS", QTHISPASS,
167567994Seric NULL
167667994Seric };
167767994Seric
167868433Seric void
printaddr(a,follow)16793234Seric printaddr(a, follow)
16803234Seric register ADDRESS *a;
16813234Seric bool follow;
16823234Seric {
168357731Seric register MAILER *m;
168457731Seric MAILER pseudomailer;
168567994Seric register struct qflags *qfp;
168667994Seric bool firstone;
16875001Seric
168867994Seric if (a == NULL)
168967994Seric {
169067994Seric printf("[NULL]\n");
169167994Seric return;
169267994Seric }
169367994Seric
16943234Seric while (a != NULL)
16953234Seric {
16964443Seric printf("%x=", a);
16974085Seric (void) fflush(stdout);
169857731Seric
169957731Seric /* find the mailer -- carefully */
170057731Seric m = a->q_mailer;
170157731Seric if (m == NULL)
170257731Seric {
170357731Seric m = &pseudomailer;
170457731Seric m->m_mno = -1;
170557731Seric m->m_name = "NULL";
170657731Seric }
170757731Seric
170868603Seric printf("%s:\n\tmailer %d (%s), host `%s'\n",
170957731Seric a->q_paddr, m->m_mno, m->m_name,
171068603Seric a->q_host == NULL ? "<null>" : a->q_host);
171168603Seric printf("\tuser `%s', ruser `%s'\n",
171268603Seric a->q_user,
171367172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser);
171467994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n",
171567994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid);
171667994Seric printf("\tflags=%lx<", a->q_flags);
171767994Seric firstone = TRUE;
171867994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
171967994Seric {
172067994Seric if (!bitset(qfp->qf_bit, a->q_flags))
172167994Seric continue;
172267994Seric if (!firstone)
172367994Seric printf(",");
172467994Seric firstone = FALSE;
172567994Seric printf("%s", qfp->qf_name);
172667994Seric }
172767994Seric printf(">\n");
172859269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n",
172959269Seric a->q_owner == NULL ? "(none)" : a->q_owner,
173063756Seric a->q_home == NULL ? "(none)" : a->q_home,
173163756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname);
173268228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n",
173367987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
173467987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta,
173567990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
17364996Seric
17373234Seric if (!follow)
17383234Seric return;
17394996Seric a = a->q_next;
17403234Seric }
17413234Seric }
174267939Seric /*
174367939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'')
174467939Seric **
174567939Seric ** Parameters:
174667939Seric ** a -- pointer to the address
174767939Seric **
174867939Seric ** Returns:
174967939Seric ** TRUE -- if this address is "empty" (i.e., no one should
175067939Seric ** ever generate replies to it.
175167939Seric ** FALSE -- if it is a "regular" (read: replyable) address.
175267939Seric */
17534317Seric
175467939Seric bool
emptyaddr(a)175567939Seric emptyaddr(a)
175667939Seric register ADDRESS *a;
175767939Seric {
175867939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0;
175967939Seric }
17607682Seric /*
17617682Seric ** REMOTENAME -- return the name relative to the current mailer
17627682Seric **
17637682Seric ** Parameters:
17647682Seric ** name -- the name to translate.
17658069Seric ** m -- the mailer that we want to do rewriting relative
17668069Seric ** to.
176759163Seric ** flags -- fine tune operations.
176859163Seric ** pstat -- pointer to status word.
176958020Seric ** e -- the current envelope.
17707682Seric **
17717682Seric ** Returns:
17727682Seric ** the text string representing this address relative to
17737682Seric ** the receiving mailer.
17747682Seric **
17757682Seric ** Side Effects:
17767682Seric ** none.
17777682Seric **
17787682Seric ** Warnings:
17797682Seric ** The text string returned is tucked away locally;
17807682Seric ** copy it if you intend to save it.
17817682Seric */
17827682Seric
17837682Seric char *
remotename(name,m,flags,pstat,e)178459163Seric remotename(name, m, flags, pstat, e)
17857682Seric char *name;
178656678Seric struct mailer *m;
178759163Seric int flags;
178859163Seric int *pstat;
178956678Seric register ENVELOPE *e;
17907682Seric {
17918069Seric register char **pvp;
17928069Seric char *fancy;
179356678Seric char *oldg = macvalue('g', e);
179458020Seric int rwset;
179568528Seric static char buf[MAXNAME + 1];
179668528Seric char lbuf[MAXNAME + 1];
179716914Seric char pvpbuf[PSBUFSIZE];
179856678Seric extern char *crackaddr();
17997682Seric
18007755Seric if (tTd(12, 1))
18017755Seric printf("remotename(%s)\n", name);
18027755Seric
180310177Seric /* don't do anything if we are tagging it as special */
180459163Seric if (bitset(RF_SENDERADDR, flags))
180559163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
180659163Seric : m->m_se_rwset;
180758020Seric else
180859163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
180959163Seric : m->m_re_rwset;
181058020Seric if (rwset < 0)
181110177Seric return (name);
181210177Seric
18137682Seric /*
18148181Seric ** Do a heuristic crack of this name to extract any comment info.
18158181Seric ** This will leave the name as a comment and a $g macro.
18167889Seric */
18177889Seric
181859163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
181958050Seric fancy = "\201g";
182010310Seric else
182110310Seric fancy = crackaddr(name);
18227889Seric
18238181Seric /*
18248181Seric ** Turn the name into canonical form.
18258181Seric ** Normally this will be RFC 822 style, i.e., "user@domain".
18268181Seric ** If this only resolves to "user", and the "C" flag is
18278181Seric ** specified in the sending mailer, then the sender's
18288181Seric ** domain will be appended.
18298181Seric */
18308181Seric
183168711Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL);
18327889Seric if (pvp == NULL)
18337889Seric return (name);
183465071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
183559163Seric *pstat = EX_TEMPFAIL;
183659163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
18378181Seric {
18388181Seric /* append from domain to this address */
18398181Seric register char **pxp = pvp;
18408181Seric
18419594Seric /* see if there is an "@domain" in the current name */
18428181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0)
18438181Seric pxp++;
18448181Seric if (*pxp == NULL)
18458181Seric {
18469594Seric /* no.... append the "@domain" from the sender */
184756678Seric register char **qxq = e->e_fromdomain;
18488181Seric
18499594Seric while ((*pxp++ = *qxq++) != NULL)
18509594Seric continue;
185165071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL)
185259163Seric *pstat = EX_TEMPFAIL;
18538181Seric }
18548181Seric }
18558181Seric
18568181Seric /*
18578959Seric ** Do more specific rewriting.
185856678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is
185956678Seric ** a sender address or not.
18608181Seric ** Then run it through any receiving-mailer-specific rulesets.
18618181Seric */
18628181Seric
186359163Seric if (bitset(RF_SENDERADDR, flags))
186459541Seric {
186565071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL)
186659163Seric *pstat = EX_TEMPFAIL;
186759541Seric }
18688069Seric else
186959541Seric {
187065071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL)
187159163Seric *pstat = EX_TEMPFAIL;
187259541Seric }
187358020Seric if (rwset > 0)
187459541Seric {
187565071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL)
187659163Seric *pstat = EX_TEMPFAIL;
187759541Seric }
18787682Seric
18798181Seric /*
18808959Seric ** Do any final sanitation the address may require.
18818959Seric ** This will normally be used to turn internal forms
18828959Seric ** (e.g., user@host.LOCAL) into external form. This
18838959Seric ** may be used as a default to the above rules.
18848959Seric */
18858959Seric
188665071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL)
188759163Seric *pstat = EX_TEMPFAIL;
18888959Seric
18898959Seric /*
18908181Seric ** Now restore the comment information we had at the beginning.
18918181Seric */
18928181Seric
189358825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0');
189456678Seric define('g', lbuf, e);
189565494Seric
189665494Seric /* need to make sure route-addrs have <angle brackets> */
189765494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
189868529Seric expand("<\201g>", buf, sizeof buf, e);
189965494Seric else
190068529Seric expand(fancy, buf, sizeof buf, e);
190165494Seric
190256678Seric define('g', oldg, e);
19037682Seric
19047682Seric if (tTd(12, 1))
19057755Seric printf("remotename => `%s'\n", buf);
19067682Seric return (buf);
19077682Seric }
190851317Seric /*
190956678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
191051317Seric **
191151317Seric ** Parameters:
191256678Seric ** a -- the address to map (but just the user name part).
191356678Seric ** sendq -- the sendq in which to install any replacement
191456678Seric ** addresses.
191567982Seric ** aliaslevel -- the alias nesting depth.
191667982Seric ** e -- the envelope.
191751317Seric **
191851317Seric ** Returns:
191951317Seric ** none.
192051317Seric */
192151317Seric
192269748Seric void
maplocaluser(a,sendq,aliaslevel,e)192367982Seric maplocaluser(a, sendq, aliaslevel, e)
192456678Seric register ADDRESS *a;
192556678Seric ADDRESS **sendq;
192667982Seric int aliaslevel;
192756678Seric ENVELOPE *e;
192851317Seric {
192956678Seric register char **pvp;
193056678Seric register ADDRESS *a1 = NULL;
193158333Seric auto char *delimptr;
193256678Seric char pvpbuf[PSBUFSIZE];
193351317Seric
193456678Seric if (tTd(29, 1))
193556678Seric {
193656678Seric printf("maplocaluser: ");
193756678Seric printaddr(a, FALSE);
193856678Seric }
193968711Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL);
194056678Seric if (pvp == NULL)
194156678Seric return;
194251317Seric
194365071Seric (void) rewrite(pvp, 5, 0, e);
194458050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
194556678Seric return;
194651317Seric
194756678Seric /* if non-null, mailer destination specified -- has it changed? */
194864284Seric a1 = buildaddr(pvp, NULL, 0, e);
194956678Seric if (a1 == NULL || sameaddr(a, a1))
195056678Seric return;
195151317Seric
195256678Seric /* mark old address as dead; insert new address */
195356678Seric a->q_flags |= QDONTSEND;
195457731Seric if (tTd(29, 5))
195557731Seric {
195657731Seric printf("maplocaluser: QDONTSEND ");
195757731Seric printaddr(a, FALSE);
195857731Seric }
195956678Seric a1->q_alias = a;
196064348Seric allocaddr(a1, RF_COPYALL, NULL);
196167982Seric (void) recipient(a1, sendq, aliaslevel, e);
196251317Seric }
196358802Seric /*
196458802Seric ** DEQUOTE_INIT -- initialize dequote map
196558802Seric **
196658802Seric ** This is a no-op.
196758802Seric **
196858802Seric ** Parameters:
196958802Seric ** map -- the internal map structure.
197058802Seric ** args -- arguments.
197158802Seric **
197258802Seric ** Returns:
197358802Seric ** TRUE.
197458802Seric */
197558802Seric
197658802Seric bool
dequote_init(map,args)197760219Seric dequote_init(map, args)
197858802Seric MAP *map;
197958802Seric char *args;
198058802Seric {
198158805Seric register char *p = args;
198258805Seric
198369816Seric map->map_mflags |= MF_KEEPQUOTES;
198458805Seric for (;;)
198558805Seric {
198658805Seric while (isascii(*p) && isspace(*p))
198758805Seric p++;
198858805Seric if (*p != '-')
198958805Seric break;
199058805Seric switch (*++p)
199158805Seric {
199258805Seric case 'a':
199358805Seric map->map_app = ++p;
199458805Seric break;
199567824Seric
199667824Seric case 's':
199767824Seric map->map_coldelim = *++p;
199867824Seric break;
199958805Seric }
200058805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p)))
200158805Seric p++;
200258805Seric if (*p != '\0')
200358805Seric *p = '\0';
200458805Seric }
200558805Seric if (map->map_app != NULL)
200658805Seric map->map_app = newstr(map->map_app);
200758805Seric
200858802Seric return TRUE;
200958802Seric }
201058802Seric /*
201158802Seric ** DEQUOTE_MAP -- unquote an address
201258802Seric **
201358802Seric ** Parameters:
201458802Seric ** map -- the internal map structure (ignored).
201560089Seric ** name -- the name to dequote.
201658802Seric ** av -- arguments (ignored).
201759084Seric ** statp -- pointer to status out-parameter.
201858802Seric **
201958802Seric ** Returns:
202058802Seric ** NULL -- if there were no quotes, or if the resulting
202158802Seric ** unquoted buffer would not be acceptable to prescan.
202258802Seric ** else -- The dequoted buffer.
202358802Seric */
202458802Seric
202558802Seric char *
dequote_map(map,name,av,statp)202660089Seric dequote_map(map, name, av, statp)
202758802Seric MAP *map;
202860089Seric char *name;
202958802Seric char **av;
203059084Seric int *statp;
203158802Seric {
203258802Seric register char *p;
203358802Seric register char *q;
203458802Seric register char c;
203567824Seric int anglecnt = 0;
203667824Seric int cmntcnt = 0;
203767824Seric int quotecnt = 0;
203867824Seric int spacecnt = 0;
203967824Seric bool quotemode = FALSE;
204067824Seric bool bslashmode = FALSE;
204167824Seric char spacesub = map->map_coldelim;
204258802Seric
204360089Seric for (p = q = name; (c = *p++) != '\0'; )
204458802Seric {
204558802Seric if (bslashmode)
204658802Seric {
204758802Seric bslashmode = FALSE;
204858802Seric *q++ = c;
204958802Seric continue;
205058802Seric }
205158802Seric
205267824Seric if (c == ' ' && spacesub != '\0')
205367824Seric c = spacesub;
205467764Seric
205558802Seric switch (c)
205658802Seric {
205758802Seric case '\\':
205858802Seric bslashmode = TRUE;
205958802Seric break;
206058802Seric
206158802Seric case '(':
206258802Seric cmntcnt++;
206358802Seric break;
206458802Seric
206558802Seric case ')':
206658802Seric if (cmntcnt-- <= 0)
206758802Seric return NULL;
206858802Seric break;
206959089Seric
207059089Seric case ' ':
207159089Seric spacecnt++;
207259089Seric break;
207358802Seric }
207458802Seric
207558802Seric if (cmntcnt > 0)
207658802Seric {
207758802Seric *q++ = c;
207858802Seric continue;
207958802Seric }
208058802Seric
208158802Seric switch (c)
208258802Seric {
208358802Seric case '"':
208458802Seric quotemode = !quotemode;
208558802Seric quotecnt++;
208658802Seric continue;
208758802Seric
208858802Seric case '<':
208958802Seric anglecnt++;
209058802Seric break;
209158802Seric
209258802Seric case '>':
209358802Seric if (anglecnt-- <= 0)
209458802Seric return NULL;
209558802Seric break;
209658802Seric }
209758802Seric *q++ = c;
209858802Seric }
209958802Seric
210058802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
210159089Seric quotemode || quotecnt <= 0 || spacecnt != 0)
210258802Seric return NULL;
210358802Seric *q++ = '\0';
210460089Seric return name;
210558802Seric }
2106