parseaddr.c revision 132943
138032Speter/* 2111823Sgshapiro * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 16132943SgshapiroSM_RCSID("@(#)$Id: parseaddr.c,v 8.378 2004/05/18 20:01:54 ca Exp $") 1790792Sgshapiro 1890792Sgshapirostatic void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); 1964562Sgshapirostatic int callsubr __P((char**, int, ENVELOPE *)); 2064562Sgshapirostatic char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2164562Sgshapirostatic ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 2294334Sgshapirostatic bool hasctrlchar __P((register char *, bool, bool)); 2364562Sgshapiro 2494334Sgshapiro/* replacement for illegal characters in addresses */ 2594334Sgshapiro#define BAD_CHAR_REPLACEMENT '?' 2694334Sgshapiro 2738032Speter/* 2838032Speter** PARSEADDR -- Parse an address 2938032Speter** 3038032Speter** Parses an address and breaks it up into three parts: a 3138032Speter** net to transmit the message on, the host to transmit it 3238032Speter** to, and a user on that host. These are loaded into an 3338032Speter** ADDRESS header with the values squirreled away if necessary. 3438032Speter** The "user" part may not be a real user; the process may 3538032Speter** just reoccur on that machine. For example, on a machine 3638032Speter** with an arpanet connection, the address 3738032Speter** csvax.bill@berkeley 3838032Speter** will break up to a "user" of 'csvax.bill' and a host 3938032Speter** of 'berkeley' -- to be transmitted over the arpanet. 4038032Speter** 4138032Speter** Parameters: 4238032Speter** addr -- the address to parse. 4338032Speter** a -- a pointer to the address descriptor buffer. 4490792Sgshapiro** If NULL, an address will be created. 4538032Speter** flags -- describe detail for parsing. See RF_ definitions 4638032Speter** in sendmail.h. 4738032Speter** delim -- the character to terminate the address, passed 4838032Speter** to prescan. 4938032Speter** delimptr -- if non-NULL, set to the location of the 5038032Speter** delim character that was found. 5138032Speter** e -- the envelope that will contain this address. 5290792Sgshapiro** isrcpt -- true if the address denotes a recipient; false 5390792Sgshapiro** indicates a sender. 5438032Speter** 5538032Speter** Returns: 5638032Speter** A pointer to the address descriptor header (`a' if 5738032Speter** `a' is non-NULL). 5838032Speter** NULL on error. 5938032Speter** 6038032Speter** Side Effects: 6190792Sgshapiro** e->e_to = addr 6238032Speter*/ 6338032Speter 6438032Speter/* following delimiters are inherent to the internal algorithms */ 6564562Sgshapiro#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 6638032Speter 6738032SpeterADDRESS * 6890792Sgshapiroparseaddr(addr, a, flags, delim, delimptr, e, isrcpt) 6938032Speter char *addr; 7038032Speter register ADDRESS *a; 7138032Speter int flags; 7238032Speter int delim; 7338032Speter char **delimptr; 7438032Speter register ENVELOPE *e; 7590792Sgshapiro bool isrcpt; 7638032Speter{ 7790792Sgshapiro char **pvp; 7838032Speter auto char *delimptrbuf; 7964562Sgshapiro bool qup; 8038032Speter char pvpbuf[PSBUFSIZE]; 8138032Speter 8238032Speter /* 8338032Speter ** Initialize and prescan address. 8438032Speter */ 8538032Speter 8638032Speter e->e_to = addr; 8738032Speter if (tTd(20, 1)) 8890792Sgshapiro sm_dprintf("\n--parseaddr(%s)\n", addr); 8938032Speter 9038032Speter if (delimptr == NULL) 9138032Speter delimptr = &delimptrbuf; 9238032Speter 93132943Sgshapiro pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL, false); 9438032Speter if (pvp == NULL) 9538032Speter { 9638032Speter if (tTd(20, 1)) 9790792Sgshapiro sm_dprintf("parseaddr-->NULL\n"); 9864562Sgshapiro return NULL; 9938032Speter } 10038032Speter 10190792Sgshapiro if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt)) 10238032Speter { 10338032Speter if (tTd(20, 1)) 10490792Sgshapiro sm_dprintf("parseaddr-->bad address\n"); 10538032Speter return NULL; 10638032Speter } 10738032Speter 10838032Speter /* 10938032Speter ** Save addr if we are going to have to. 11038032Speter ** 11138032Speter ** We have to do this early because there is a chance that 11238032Speter ** the map lookups in the rewriting rules could clobber 11338032Speter ** static memory somewhere. 11438032Speter */ 11538032Speter 11638032Speter if (bitset(RF_COPYPADDR, flags) && addr != NULL) 11738032Speter { 11838032Speter char savec = **delimptr; 11938032Speter 12038032Speter if (savec != '\0') 12138032Speter **delimptr = '\0'; 12290792Sgshapiro e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr); 12338032Speter if (savec != '\0') 12438032Speter **delimptr = savec; 12538032Speter } 12638032Speter 12738032Speter /* 12838032Speter ** Apply rewriting rules. 12938032Speter ** Ruleset 0 does basic parsing. It must resolve. 13038032Speter */ 13138032Speter 13290792Sgshapiro qup = false; 13390792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 13490792Sgshapiro qup = true; 13590792Sgshapiro if (REWRITE(pvp, 0, e) == EX_TEMPFAIL) 13690792Sgshapiro qup = true; 13738032Speter 13838032Speter /* 13938032Speter ** Build canonical address from pvp. 14038032Speter */ 14138032Speter 14238032Speter a = buildaddr(pvp, a, flags, e); 14338032Speter 14494334Sgshapiro if (hasctrlchar(a->q_user, isrcpt, true)) 14590792Sgshapiro { 14690792Sgshapiro if (tTd(20, 1)) 14790792Sgshapiro sm_dprintf("parseaddr-->bad q_user\n"); 14894334Sgshapiro 14994334Sgshapiro /* 15094334Sgshapiro ** Just mark the address as bad so DSNs work. 15194334Sgshapiro ** hasctrlchar() has to make sure that the address 15294334Sgshapiro ** has been sanitized, e.g., shortened. 15394334Sgshapiro */ 15494334Sgshapiro 15594334Sgshapiro a->q_state = QS_BADADDR; 15690792Sgshapiro } 15790792Sgshapiro 15838032Speter /* 15938032Speter ** Make local copies of the host & user and then 16038032Speter ** transport them out. 16138032Speter */ 16238032Speter 16390792Sgshapiro allocaddr(a, flags, addr, e); 16464562Sgshapiro if (QS_IS_BADADDR(a->q_state)) 16594334Sgshapiro { 16694334Sgshapiro /* weed out bad characters in the printable address too */ 16794334Sgshapiro (void) hasctrlchar(a->q_paddr, isrcpt, false); 16838032Speter return a; 16994334Sgshapiro } 17038032Speter 17138032Speter /* 17290792Sgshapiro ** Select a queue directory for recipient addresses. 17390792Sgshapiro ** This is done here and in split_across_queue_groups(), 17490792Sgshapiro ** but the latter applies to addresses after aliasing, 17590792Sgshapiro ** and only if splitting is done. 17690792Sgshapiro */ 17790792Sgshapiro 17890792Sgshapiro if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) && 17990792Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags) && 18090792Sgshapiro OpMode != MD_INITALIAS) 18190792Sgshapiro { 18290792Sgshapiro int r; 18390792Sgshapiro 18490792Sgshapiro /* call ruleset which should return a queue group name */ 18590792Sgshapiro r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf, 18690792Sgshapiro sizeof(pvpbuf)); 18790792Sgshapiro if (r == EX_OK && 18890792Sgshapiro pvp != NULL && pvp[0] != NULL && 18990792Sgshapiro (pvp[0][0] & 0377) == CANONNET && 19090792Sgshapiro pvp[1] != NULL && pvp[1][0] != '\0') 19190792Sgshapiro { 19290792Sgshapiro r = name2qid(pvp[1]); 19390792Sgshapiro if (r == NOQGRP && LogLevel > 10) 19490792Sgshapiro sm_syslog(LOG_INFO, NOQID, 19590792Sgshapiro "can't find queue group name %s, selection ignored", 19690792Sgshapiro pvp[1]); 19790792Sgshapiro if (tTd(20, 4) && r != NOQGRP) 19890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 19990792Sgshapiro "queue group name %s -> %d", 20090792Sgshapiro pvp[1], r); 20190792Sgshapiro a->q_qgrp = r == NOQGRP ? ENVQGRP : r; 20290792Sgshapiro } 20390792Sgshapiro } 20490792Sgshapiro 20590792Sgshapiro /* 20638032Speter ** If there was a parsing failure, mark it for queueing. 20738032Speter */ 20838032Speter 20964562Sgshapiro if (qup && OpMode != MD_INITALIAS) 21038032Speter { 21138032Speter char *msg = "Transient parse error -- message queued for future delivery"; 21238032Speter 21338032Speter if (e->e_sendmode == SM_DEFER) 21438032Speter msg = "Deferring message until queue run"; 21538032Speter if (tTd(20, 1)) 21690792Sgshapiro sm_dprintf("parseaddr: queuing message\n"); 21738032Speter message(msg); 21838032Speter if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 21990792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, msg); 22064562Sgshapiro a->q_state = QS_QUEUEUP; 22138032Speter a->q_status = "4.4.3"; 22238032Speter } 22338032Speter 22438032Speter /* 22538032Speter ** Compute return value. 22638032Speter */ 22738032Speter 22838032Speter if (tTd(20, 1)) 22938032Speter { 23090792Sgshapiro sm_dprintf("parseaddr-->"); 231132943Sgshapiro printaddr(sm_debug_file(), a, false); 23238032Speter } 23338032Speter 23464562Sgshapiro return a; 23538032Speter} 23690792Sgshapiro/* 23790792Sgshapiro** INVALIDADDR -- check for address containing characters used for macros 23838032Speter** 23938032Speter** Parameters: 24038032Speter** addr -- the address to check. 24190792Sgshapiro** delimptr -- if non-NULL: end of address to check, i.e., 24290792Sgshapiro** a pointer in the address string. 24390792Sgshapiro** isrcpt -- true iff the address is for a recipient. 24438032Speter** 24538032Speter** Returns: 24690792Sgshapiro** true -- if the address has characters that are reservered 24790792Sgshapiro** for macros or is too long. 24890792Sgshapiro** false -- otherwise. 24938032Speter*/ 25038032Speter 25138032Speterbool 25290792Sgshapiroinvalidaddr(addr, delimptr, isrcpt) 25338032Speter register char *addr; 25438032Speter char *delimptr; 25590792Sgshapiro bool isrcpt; 25638032Speter{ 25790792Sgshapiro bool result = false; 25838032Speter char savedelim = '\0'; 25994334Sgshapiro char *b = addr; 26090792Sgshapiro int len = 0; 26138032Speter 26238032Speter if (delimptr != NULL) 26338032Speter { 26490792Sgshapiro /* delimptr points to the end of the address to test */ 26538032Speter savedelim = *delimptr; 26690792Sgshapiro if (savedelim != '\0') /* if that isn't '\0' already: */ 26790792Sgshapiro *delimptr = '\0'; /* set it */ 26838032Speter } 26990792Sgshapiro for (; *addr != '\0'; addr++) 27038032Speter { 27190792Sgshapiro if ((*addr & 0340) == 0200) 27290792Sgshapiro { 27390792Sgshapiro setstat(EX_USAGE); 27490792Sgshapiro result = true; 27594334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 27690792Sgshapiro } 27790792Sgshapiro if (++len > MAXNAME - 1) 27890792Sgshapiro { 27994334Sgshapiro char saved = *addr; 28094334Sgshapiro 28194334Sgshapiro *addr = '\0'; 28294334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 28394334Sgshapiro b, MAXNAME - 1); 28494334Sgshapiro *addr = saved; 28590792Sgshapiro result = true; 28690792Sgshapiro goto delim; 28790792Sgshapiro } 28838032Speter } 28990792Sgshapiro if (result) 29090792Sgshapiro { 29190792Sgshapiro if (isrcpt) 29294334Sgshapiro usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"", 29394334Sgshapiro b); 29490792Sgshapiro else 29594334Sgshapiro usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"", 29694334Sgshapiro b); 29790792Sgshapiro } 29890792Sgshapirodelim: 29990792Sgshapiro if (delimptr != NULL && savedelim != '\0') 30090792Sgshapiro *delimptr = savedelim; /* restore old character at delimptr */ 30190792Sgshapiro return result; 30290792Sgshapiro} 30390792Sgshapiro/* 30490792Sgshapiro** HASCTRLCHAR -- check for address containing meta-characters 30590792Sgshapiro** 30690792Sgshapiro** Checks that the address contains no meta-characters, and contains 30790792Sgshapiro** no "non-printable" characters unless they are quoted or escaped. 30890792Sgshapiro** Quoted or escaped characters are literals. 30990792Sgshapiro** 31090792Sgshapiro** Parameters: 31190792Sgshapiro** addr -- the address to check. 31290792Sgshapiro** isrcpt -- true if the address is for a recipient; false 31390792Sgshapiro** indicates a from. 31494334Sgshapiro** complain -- true if an error should issued if the address 31594334Sgshapiro** is invalid and should be "repaired". 31690792Sgshapiro** 31790792Sgshapiro** Returns: 31890792Sgshapiro** true -- if the address has any "wierd" characters or 31990792Sgshapiro** non-printable characters or if a quote is unbalanced. 32090792Sgshapiro** false -- otherwise. 32190792Sgshapiro*/ 32290792Sgshapiro 32390792Sgshapirostatic bool 32494334Sgshapirohasctrlchar(addr, isrcpt, complain) 32590792Sgshapiro register char *addr; 32694334Sgshapiro bool isrcpt, complain; 32790792Sgshapiro{ 32894334Sgshapiro bool quoted = false; 32990792Sgshapiro int len = 0; 33094334Sgshapiro char *result = NULL; 33194334Sgshapiro char *b = addr; 33290792Sgshapiro 33390792Sgshapiro if (addr == NULL) 33490792Sgshapiro return false; 33538032Speter for (; *addr != '\0'; addr++) 33638032Speter { 33794334Sgshapiro if (++len > MAXNAME - 1) 33894334Sgshapiro { 33994334Sgshapiro if (complain) 34094334Sgshapiro { 34194334Sgshapiro (void) shorten_rfc822_string(b, MAXNAME - 1); 34294334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 34394334Sgshapiro b, MAXNAME - 1); 34494334Sgshapiro return true; 34594334Sgshapiro } 34694334Sgshapiro result = "too long"; 34794334Sgshapiro } 34890792Sgshapiro if (!quoted && (*addr < 32 || *addr == 127)) 34990792Sgshapiro { 35094334Sgshapiro result = "non-printable character"; 35194334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 35294334Sgshapiro continue; 35390792Sgshapiro } 35490792Sgshapiro if (*addr == '"') 35590792Sgshapiro quoted = !quoted; 35690792Sgshapiro else if (*addr == '\\') 35790792Sgshapiro { 35890792Sgshapiro /* XXX Generic problem: no '\0' in strings. */ 35990792Sgshapiro if (*++addr == '\0') 36090792Sgshapiro { 36194334Sgshapiro result = "trailing \\ character"; 36294334Sgshapiro *--addr = BAD_CHAR_REPLACEMENT; 36390792Sgshapiro break; 36490792Sgshapiro } 36590792Sgshapiro } 36638032Speter if ((*addr & 0340) == 0200) 36790792Sgshapiro { 36890792Sgshapiro setstat(EX_USAGE); 36994334Sgshapiro result = "8-bit character"; 37094334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 37194334Sgshapiro continue; 37290792Sgshapiro } 37338032Speter } 37490792Sgshapiro if (quoted) 37594334Sgshapiro result = "unbalanced quote"; /* unbalanced quote */ 37694334Sgshapiro if (result != NULL && complain) 37738032Speter { 37890792Sgshapiro if (isrcpt) 37994334Sgshapiro usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)", 38094334Sgshapiro b, result); 38190792Sgshapiro else 38294334Sgshapiro usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)", 38394334Sgshapiro b, result); 38438032Speter } 38594334Sgshapiro return result != NULL; 38638032Speter} 38790792Sgshapiro/* 38838032Speter** ALLOCADDR -- do local allocations of address on demand. 38938032Speter** 39038032Speter** Also lowercases the host name if requested. 39138032Speter** 39238032Speter** Parameters: 39338032Speter** a -- the address to reallocate. 39438032Speter** flags -- the copy flag (see RF_ definitions in sendmail.h 39538032Speter** for a description). 39638032Speter** paddr -- the printname of the address. 39790792Sgshapiro** e -- envelope 39838032Speter** 39938032Speter** Returns: 40038032Speter** none. 40138032Speter** 40238032Speter** Side Effects: 40338032Speter** Copies portions of a into local buffers as requested. 40438032Speter*/ 40538032Speter 40664562Sgshapirostatic void 40790792Sgshapiroallocaddr(a, flags, paddr, e) 40838032Speter register ADDRESS *a; 40938032Speter int flags; 41038032Speter char *paddr; 41190792Sgshapiro ENVELOPE *e; 41238032Speter{ 41338032Speter if (tTd(24, 4)) 41490792Sgshapiro sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 41538032Speter 41638032Speter a->q_paddr = paddr; 41738032Speter 41838032Speter if (a->q_user == NULL) 41990792Sgshapiro a->q_user = ""; 42038032Speter if (a->q_host == NULL) 42190792Sgshapiro a->q_host = ""; 42238032Speter 42338032Speter if (bitset(RF_COPYPARSE, flags)) 42438032Speter { 42590792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host); 42638032Speter if (a->q_user != a->q_paddr) 42790792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user); 42838032Speter } 42938032Speter 43038032Speter if (a->q_paddr == NULL) 43190792Sgshapiro a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 43290792Sgshapiro a->q_qgrp = NOAQGRP; 43338032Speter} 43490792Sgshapiro/* 43538032Speter** PRESCAN -- Prescan name and make it canonical 43638032Speter** 43738032Speter** Scans a name and turns it into a set of tokens. This process 43864562Sgshapiro** deletes blanks and comments (in parentheses) (if the token type 43964562Sgshapiro** for left paren is SPC). 44038032Speter** 44138032Speter** This routine knows about quoted strings and angle brackets. 44238032Speter** 44338032Speter** There are certain subtleties to this routine. The one that 44438032Speter** comes to mind now is that backslashes on the ends of names 44538032Speter** are silently stripped off; this is intentional. The problem 44638032Speter** is that some versions of sndmsg (like at LBL) set the kill 44738032Speter** character to something other than @ when reading addresses; 44838032Speter** so people type "csvax.eric\@berkeley" -- which screws up the 44938032Speter** berknet mailer. 45038032Speter** 45138032Speter** Parameters: 45238032Speter** addr -- the name to chomp. 45338032Speter** delim -- the delimiter for the address, normally 45438032Speter** '\0' or ','; \0 is accepted in any case. 45538032Speter** If '\t' then we are reading the .cf file. 45638032Speter** pvpbuf -- place to put the saved text -- note that 45738032Speter** the pointers are static. 45838032Speter** pvpbsize -- size of pvpbuf. 45938032Speter** delimptr -- if non-NULL, set to the location of the 46038032Speter** terminating delimiter. 46138032Speter** toktab -- if set, a token table to use for parsing. 46238032Speter** If NULL, use the default table. 463132943Sgshapiro** ignore -- if true, ignore unbalanced addresses 46438032Speter** 46538032Speter** Returns: 46638032Speter** A pointer to a vector of tokens. 46738032Speter** NULL on error. 46838032Speter*/ 46938032Speter 47038032Speter/* states and character types */ 47164562Sgshapiro#define OPR 0 /* operator */ 47264562Sgshapiro#define ATM 1 /* atom */ 47364562Sgshapiro#define QST 2 /* in quoted string */ 47464562Sgshapiro#define SPC 3 /* chewing up spaces */ 47564562Sgshapiro#define ONE 4 /* pick up one character */ 47664562Sgshapiro#define ILL 5 /* illegal character */ 47738032Speter 47864562Sgshapiro#define NSTATES 6 /* number of states */ 47964562Sgshapiro#define TYPE 017 /* mask to select state type */ 48038032Speter 48138032Speter/* meta bits for table */ 48264562Sgshapiro#define M 020 /* meta character; don't pass through */ 48364562Sgshapiro#define B 040 /* cause a break */ 48464562Sgshapiro#define MB M|B /* meta-break */ 48538032Speter 48638032Speterstatic short StateTab[NSTATES][NSTATES] = 48738032Speter{ 48838032Speter /* oldst chtype> OPR ATM QST SPC ONE ILL */ 48938032Speter /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 49038032Speter /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 49138032Speter /*QST*/ { QST, QST, OPR, QST, QST, QST }, 49238032Speter /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 49338032Speter /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 49438032Speter /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 49538032Speter}; 49638032Speter 49738032Speter/* token type table -- it gets modified with $o characters */ 49890792Sgshapirostatic unsigned char TokTypeTab[256] = 49938032Speter{ 50038032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 50138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 50238032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 50338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50438032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 50564562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 50638032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 50738032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50838032Speter /* @ A B C D E F G H I J K L M N O */ 50938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51038032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 51138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51238032Speter /* ` a b c d e f g h i j k l m n o */ 51338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51438032Speter /* p q r s t u v w x y z { | } ~ del */ 51538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51638032Speter 51738032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 51838032Speter OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 51938032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 52038032Speter OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 52138032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 52238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52338032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 52438032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52538032Speter /* @ A B C D E F G H I J K L M N O */ 52638032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52738032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 52838032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52938032Speter /* ` a b c d e f g h i j k l m n o */ 53038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53138032Speter /* p q r s t u v w x y z { | } ~ del */ 53238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53338032Speter}; 53438032Speter 53538032Speter/* token type table for MIME parsing */ 53690792Sgshapirounsigned char MimeTokenTab[256] = 53738032Speter{ 53838032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 53938032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 54038032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 54138032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 54238032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 54364562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 54438032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 54538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 54638032Speter /* @ A B C D E F G H I J K L M N O */ 54738032Speter OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 54838032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 54938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 55038032Speter /* ` a b c d e f g h i j k l m n o */ 55138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55238032Speter /* p q r s t u v w x y z { | } ~ del */ 55338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55438032Speter 55538032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 55638032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55738032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 55838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55938032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 56038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56138032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 56238032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56338032Speter /* @ A B C D E F G H I J K L M N O */ 56438032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56538032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 56638032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56738032Speter /* ` a b c d e f g h i j k l m n o */ 56838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56938032Speter /* p q r s t u v w x y z { | } ~ del */ 57038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 57138032Speter}; 57238032Speter 57364562Sgshapiro/* token type table: don't strip comments */ 57490792Sgshapirounsigned char TokTypeNoC[256] = 57564562Sgshapiro{ 57664562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 57764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 57864562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 57964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58064562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 58164562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 58264562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 58364562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58464562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 58564562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58664562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 58764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58864562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 58964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59064562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 59164562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59238032Speter 59364562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 59464562Sgshapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59564562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 59664562Sgshapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59764562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 59864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59964562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 60064562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60164562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 60264562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60364562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 60464562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60564562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 60664562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60764562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 60864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60964562Sgshapiro}; 61038032Speter 61164562Sgshapiro 612112810Sgshapiro#define NOCHAR (-1) /* signal nothing in lookahead token */ 61364562Sgshapiro 61438032Speterchar ** 615132943Sgshapiroprescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) 61638032Speter char *addr; 61738032Speter int delim; 61838032Speter char pvpbuf[]; 61938032Speter int pvpbsize; 62038032Speter char **delimptr; 62190792Sgshapiro unsigned char *toktab; 622132943Sgshapiro bool ignore; 62338032Speter{ 62438032Speter register char *p; 62538032Speter register char *q; 62638032Speter register int c; 62738032Speter char **avp; 62838032Speter bool bslashmode; 62938032Speter bool route_syntax; 63038032Speter int cmntcnt; 63138032Speter int anglecnt; 63238032Speter char *tok; 63338032Speter int state; 63438032Speter int newstate; 63538032Speter char *saveto = CurEnv->e_to; 63664562Sgshapiro static char *av[MAXATOM + 1]; 63790792Sgshapiro static bool firsttime = true; 63838032Speter 63938032Speter if (firsttime) 64038032Speter { 64138032Speter /* initialize the token type table */ 64238032Speter char obuf[50]; 64338032Speter 64490792Sgshapiro firsttime = false; 64538032Speter if (OperatorChars == NULL) 64638032Speter { 64738032Speter if (ConfigLevel < 7) 64838032Speter OperatorChars = macvalue('o', CurEnv); 64938032Speter if (OperatorChars == NULL) 65038032Speter OperatorChars = ".:@[]"; 65138032Speter } 65264562Sgshapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 65364562Sgshapiro CurEnv); 65490792Sgshapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf); 65538032Speter for (p = obuf; *p != '\0'; p++) 65638032Speter { 65738032Speter if (TokTypeTab[*p & 0xff] == ATM) 65838032Speter TokTypeTab[*p & 0xff] = OPR; 65964562Sgshapiro if (TokTypeNoC[*p & 0xff] == ATM) 66064562Sgshapiro TokTypeNoC[*p & 0xff] = OPR; 66138032Speter } 66238032Speter } 66338032Speter if (toktab == NULL) 66438032Speter toktab = TokTypeTab; 66538032Speter 66638032Speter /* make sure error messages don't have garbage on them */ 66738032Speter errno = 0; 66838032Speter 66938032Speter q = pvpbuf; 67090792Sgshapiro bslashmode = false; 67190792Sgshapiro route_syntax = false; 67238032Speter cmntcnt = 0; 67338032Speter anglecnt = 0; 67438032Speter avp = av; 67538032Speter state = ATM; 67638032Speter c = NOCHAR; 67738032Speter p = addr; 67838032Speter CurEnv->e_to = p; 67938032Speter if (tTd(22, 11)) 68038032Speter { 68190792Sgshapiro sm_dprintf("prescan: "); 682132943Sgshapiro xputs(sm_debug_file(), p); 68390792Sgshapiro sm_dprintf("\n"); 68438032Speter } 68538032Speter 68638032Speter do 68738032Speter { 68838032Speter /* read a token */ 68938032Speter tok = q; 69038032Speter for (;;) 69138032Speter { 69238032Speter /* store away any old lookahead character */ 69338032Speter if (c != NOCHAR && !bslashmode) 69438032Speter { 69538032Speter /* see if there is room */ 69638032Speter if (q >= &pvpbuf[pvpbsize - 5]) 69738032Speter { 698112810Sgshapiro addrtoolong: 69964562Sgshapiro usrerr("553 5.1.1 Address too long"); 70090792Sgshapiro if (strlen(addr) > MAXNAME) 70138032Speter addr[MAXNAME] = '\0'; 70238032Speter returnnull: 70338032Speter if (delimptr != NULL) 704120169Snectar { 705120169Snectar if (p > addr) 706120256Sgshapiro --p; 70738032Speter *delimptr = p; 708120169Snectar } 70938032Speter CurEnv->e_to = saveto; 71064562Sgshapiro return NULL; 71138032Speter } 71238032Speter 71338032Speter /* squirrel it away */ 714112810Sgshapiro#if !ALLOW_255 715112810Sgshapiro if ((char) c == (char) -1 && !tTd(82, 101)) 716112810Sgshapiro c &= 0x7f; 717112810Sgshapiro#endif /* !ALLOW_255 */ 71838032Speter *q++ = c; 71938032Speter } 72038032Speter 72138032Speter /* read a new input character */ 722112810Sgshapiro c = (*p++) & 0x00ff; 72338032Speter if (c == '\0') 72438032Speter { 72538032Speter /* diagnose and patch up bad syntax */ 726132943Sgshapiro if (ignore) 727132943Sgshapiro break; 728132943Sgshapiro else if (state == QST) 72938032Speter { 73090792Sgshapiro usrerr("553 Unbalanced '\"'"); 73138032Speter c = '"'; 73238032Speter } 73338032Speter else if (cmntcnt > 0) 73438032Speter { 73590792Sgshapiro usrerr("553 Unbalanced '('"); 73638032Speter c = ')'; 73738032Speter } 73838032Speter else if (anglecnt > 0) 73938032Speter { 74038032Speter c = '>'; 74190792Sgshapiro usrerr("553 Unbalanced '<'"); 74238032Speter } 74338032Speter else 74438032Speter break; 74538032Speter 74638032Speter p--; 74738032Speter } 74838032Speter else if (c == delim && cmntcnt <= 0 && state != QST) 74938032Speter { 75038032Speter if (anglecnt <= 0) 75138032Speter break; 75238032Speter 75338032Speter /* special case for better error management */ 754132943Sgshapiro if (delim == ',' && !route_syntax && !ignore) 75538032Speter { 75690792Sgshapiro usrerr("553 Unbalanced '<'"); 75738032Speter c = '>'; 75838032Speter p--; 75938032Speter } 76038032Speter } 76138032Speter 76238032Speter if (tTd(22, 101)) 76390792Sgshapiro sm_dprintf("c=%c, s=%d; ", c, state); 76438032Speter 76538032Speter /* chew up special characters */ 76638032Speter *q = '\0'; 76738032Speter if (bslashmode) 76838032Speter { 76990792Sgshapiro bslashmode = false; 77038032Speter 77138032Speter /* kludge \! for naive users */ 77238032Speter if (cmntcnt > 0) 77338032Speter { 77438032Speter c = NOCHAR; 77538032Speter continue; 77638032Speter } 77738032Speter else if (c != '!' || state == QST) 77838032Speter { 779112810Sgshapiro /* see if there is room */ 780112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 781112810Sgshapiro goto addrtoolong; 78238032Speter *q++ = '\\'; 78338032Speter continue; 78438032Speter } 78538032Speter } 78638032Speter 78738032Speter if (c == '\\') 78838032Speter { 78990792Sgshapiro bslashmode = true; 79038032Speter } 79138032Speter else if (state == QST) 79238032Speter { 79364562Sgshapiro /* EMPTY */ 79438032Speter /* do nothing, just avoid next clauses */ 79538032Speter } 79664562Sgshapiro else if (c == '(' && toktab['('] == SPC) 79738032Speter { 79838032Speter cmntcnt++; 79938032Speter c = NOCHAR; 80038032Speter } 80164562Sgshapiro else if (c == ')' && toktab['('] == SPC) 80238032Speter { 80338032Speter if (cmntcnt <= 0) 80438032Speter { 805132943Sgshapiro if (!ignore) 806132943Sgshapiro { 807132943Sgshapiro usrerr("553 Unbalanced ')'"); 808132943Sgshapiro c = NOCHAR; 809132943Sgshapiro } 81038032Speter } 81138032Speter else 81238032Speter cmntcnt--; 81338032Speter } 81438032Speter else if (cmntcnt > 0) 81564562Sgshapiro { 81638032Speter c = NOCHAR; 81764562Sgshapiro } 81838032Speter else if (c == '<') 81938032Speter { 82064562Sgshapiro char *ptr = p; 82138032Speter 82238032Speter anglecnt++; 82364562Sgshapiro while (isascii(*ptr) && isspace(*ptr)) 82464562Sgshapiro ptr++; 82564562Sgshapiro if (*ptr == '@') 82690792Sgshapiro route_syntax = true; 82738032Speter } 82838032Speter else if (c == '>') 82938032Speter { 83038032Speter if (anglecnt <= 0) 83138032Speter { 832132943Sgshapiro if (!ignore) 833132943Sgshapiro { 834132943Sgshapiro usrerr("553 Unbalanced '>'"); 835132943Sgshapiro c = NOCHAR; 836132943Sgshapiro } 83738032Speter } 83838032Speter else 83938032Speter anglecnt--; 84090792Sgshapiro route_syntax = false; 84138032Speter } 84238032Speter else if (delim == ' ' && isascii(c) && isspace(c)) 84338032Speter c = ' '; 84438032Speter 84538032Speter if (c == NOCHAR) 84638032Speter continue; 84738032Speter 84838032Speter /* see if this is end of input */ 84938032Speter if (c == delim && anglecnt <= 0 && state != QST) 85038032Speter break; 85138032Speter 85238032Speter newstate = StateTab[state][toktab[c & 0xff]]; 85338032Speter if (tTd(22, 101)) 85490792Sgshapiro sm_dprintf("ns=%02o\n", newstate); 85538032Speter state = newstate & TYPE; 85638032Speter if (state == ILL) 85738032Speter { 85838032Speter if (isascii(c) && isprint(c)) 85990792Sgshapiro usrerr("553 Illegal character %c", c); 86038032Speter else 86190792Sgshapiro usrerr("553 Illegal character 0x%02x", 86290792Sgshapiro c & 0x0ff); 86338032Speter } 86438032Speter if (bitset(M, newstate)) 86538032Speter c = NOCHAR; 86638032Speter if (bitset(B, newstate)) 86738032Speter break; 86838032Speter } 86938032Speter 87038032Speter /* new token */ 87138032Speter if (tok != q) 87238032Speter { 873112810Sgshapiro /* see if there is room */ 874112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 875112810Sgshapiro goto addrtoolong; 87638032Speter *q++ = '\0'; 87738032Speter if (tTd(22, 36)) 87838032Speter { 87990792Sgshapiro sm_dprintf("tok="); 880132943Sgshapiro xputs(sm_debug_file(), tok); 88190792Sgshapiro sm_dprintf("\n"); 88238032Speter } 88338032Speter if (avp >= &av[MAXATOM]) 88438032Speter { 88564562Sgshapiro usrerr("553 5.1.0 prescan: too many tokens"); 88638032Speter goto returnnull; 88738032Speter } 88838032Speter if (q - tok > MAXNAME) 88938032Speter { 89064562Sgshapiro usrerr("553 5.1.0 prescan: token too long"); 89138032Speter goto returnnull; 89238032Speter } 89338032Speter *avp++ = tok; 89438032Speter } 89538032Speter } while (c != '\0' && (c != delim || anglecnt > 0)); 89638032Speter *avp = NULL; 89738032Speter if (delimptr != NULL) 898120256Sgshapiro { 899120256Sgshapiro if (p > addr) 900120256Sgshapiro p--; 90138032Speter *delimptr = p; 902120256Sgshapiro } 90338032Speter if (tTd(22, 12)) 90438032Speter { 90590792Sgshapiro sm_dprintf("prescan==>"); 906132943Sgshapiro printav(sm_debug_file(), av); 90738032Speter } 90838032Speter CurEnv->e_to = saveto; 90938032Speter if (av[0] == NULL) 91038032Speter { 91138032Speter if (tTd(22, 1)) 91290792Sgshapiro sm_dprintf("prescan: null leading token\n"); 91364562Sgshapiro return NULL; 91438032Speter } 91564562Sgshapiro return av; 91638032Speter} 91790792Sgshapiro/* 91838032Speter** REWRITE -- apply rewrite rules to token vector. 91938032Speter** 92038032Speter** This routine is an ordered production system. Each rewrite 92138032Speter** rule has a LHS (called the pattern) and a RHS (called the 92238032Speter** rewrite); 'rwr' points the the current rewrite rule. 92338032Speter** 92438032Speter** For each rewrite rule, 'avp' points the address vector we 92538032Speter** are trying to match against, and 'pvp' points to the pattern. 92638032Speter** If pvp points to a special match value (MATCHZANY, MATCHANY, 92738032Speter** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 92838032Speter** matched is saved away in the match vector (pointed to by 'mvp'). 92938032Speter** 93038032Speter** When a match between avp & pvp does not match, we try to 93138032Speter** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 93238032Speter** we must also back out the match in mvp. If we reach a 93338032Speter** MATCHANY or MATCHZANY we just extend the match and start 93438032Speter** over again. 93538032Speter** 93638032Speter** When we finally match, we rewrite the address vector 93738032Speter** and try over again. 93838032Speter** 93938032Speter** Parameters: 94038032Speter** pvp -- pointer to token vector. 94138032Speter** ruleset -- the ruleset to use for rewriting. 94238032Speter** reclevel -- recursion level (to catch loops). 94338032Speter** e -- the current envelope. 94490792Sgshapiro** maxatom -- maximum length of buffer (usually MAXATOM) 94538032Speter** 94638032Speter** Returns: 94738032Speter** A status code. If EX_TEMPFAIL, higher level code should 94838032Speter** attempt recovery. 94938032Speter** 95038032Speter** Side Effects: 95138032Speter** pvp is modified. 95238032Speter*/ 95338032Speter 95438032Speterstruct match 95538032Speter{ 95664562Sgshapiro char **match_first; /* first token matched */ 95764562Sgshapiro char **match_last; /* last token matched */ 95864562Sgshapiro char **match_pattern; /* pointer to pattern */ 95938032Speter}; 96038032Speter 96138032Speterint 96290792Sgshapirorewrite(pvp, ruleset, reclevel, e, maxatom) 96338032Speter char **pvp; 96438032Speter int ruleset; 96538032Speter int reclevel; 96638032Speter register ENVELOPE *e; 96790792Sgshapiro int maxatom; 96838032Speter{ 96938032Speter register char *ap; /* address pointer */ 97038032Speter register char *rp; /* rewrite pointer */ 97164562Sgshapiro register char *rulename; /* ruleset name */ 97264562Sgshapiro register char *prefix; 97338032Speter register char **avp; /* address vector pointer */ 97438032Speter register char **rvp; /* rewrite vector pointer */ 97538032Speter register struct match *mlp; /* cur ptr into mlist */ 97638032Speter register struct rewrite *rwr; /* pointer to current rewrite rule */ 97738032Speter int ruleno; /* current rule number */ 97838032Speter int rstat = EX_OK; /* return status */ 97938032Speter int loopcount; 98038032Speter struct match mlist[MAXMATCH]; /* stores match on LHS */ 98164562Sgshapiro char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 98238032Speter char buf[MAXLINE]; 98364562Sgshapiro char name[6]; 98438032Speter 985120256Sgshapiro /* 986120256Sgshapiro ** mlp will not exceed mlist[] because readcf enforces 987120256Sgshapiro ** the upper limit of entries when reading rulesets. 988120256Sgshapiro */ 989120256Sgshapiro 99064562Sgshapiro if (ruleset < 0 || ruleset >= MAXRWSETS) 99138032Speter { 99264562Sgshapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 99364562Sgshapiro return EX_CONFIG; 99464562Sgshapiro } 99564562Sgshapiro rulename = RuleSetNames[ruleset]; 99664562Sgshapiro if (rulename == NULL) 99764562Sgshapiro { 99890792Sgshapiro (void) sm_snprintf(name, sizeof name, "%d", ruleset); 99964562Sgshapiro rulename = name; 100064562Sgshapiro } 100164562Sgshapiro if (OpMode == MD_TEST) 100264562Sgshapiro prefix = ""; 100364562Sgshapiro else 100464562Sgshapiro prefix = "rewrite: ruleset "; 100564562Sgshapiro if (OpMode == MD_TEST) 100664562Sgshapiro { 100790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 100890792Sgshapiro "%s%-16.16s input:", prefix, rulename); 1009132943Sgshapiro printav(smioout, pvp); 101038032Speter } 101164562Sgshapiro else if (tTd(21, 1)) 101238032Speter { 101390792Sgshapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 1014132943Sgshapiro printav(sm_debug_file(), pvp); 101538032Speter } 101638032Speter if (reclevel++ > MaxRuleRecursion) 101738032Speter { 101864562Sgshapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 101964562Sgshapiro MaxRuleRecursion, rulename); 102038032Speter return EX_CONFIG; 102138032Speter } 102238032Speter if (pvp == NULL) 102338032Speter return EX_USAGE; 1024120256Sgshapiro if (maxatom <= 0) 1025120256Sgshapiro return EX_USAGE; 102638032Speter 102738032Speter /* 102838032Speter ** Run through the list of rewrite rules, applying 102938032Speter ** any that match. 103038032Speter */ 103138032Speter 103238032Speter ruleno = 1; 103338032Speter loopcount = 0; 103438032Speter for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 103538032Speter { 103664562Sgshapiro int status; 103738032Speter 103838032Speter /* if already canonical, quit now */ 103938032Speter if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 104038032Speter break; 104138032Speter 104238032Speter if (tTd(21, 12)) 104338032Speter { 104464562Sgshapiro if (tTd(21, 15)) 104590792Sgshapiro sm_dprintf("-----trying rule (line %d):", 104664562Sgshapiro rwr->r_line); 104764562Sgshapiro else 104890792Sgshapiro sm_dprintf("-----trying rule:"); 1049132943Sgshapiro printav(sm_debug_file(), rwr->r_lhs); 105038032Speter } 105138032Speter 105238032Speter /* try to match on this rule */ 105338032Speter mlp = mlist; 105438032Speter rvp = rwr->r_lhs; 105538032Speter avp = pvp; 105638032Speter if (++loopcount > 100) 105738032Speter { 105864562Sgshapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 105964562Sgshapiro rulename, ruleno); 106038032Speter if (tTd(21, 1)) 106138032Speter { 106290792Sgshapiro sm_dprintf("workspace: "); 1063132943Sgshapiro printav(sm_debug_file(), pvp); 106438032Speter } 106538032Speter break; 106638032Speter } 106738032Speter 106838032Speter while ((ap = *avp) != NULL || *rvp != NULL) 106938032Speter { 107038032Speter rp = *rvp; 107138032Speter if (tTd(21, 35)) 107238032Speter { 107390792Sgshapiro sm_dprintf("ADVANCE rp="); 1074132943Sgshapiro xputs(sm_debug_file(), rp); 107590792Sgshapiro sm_dprintf(", ap="); 1076132943Sgshapiro xputs(sm_debug_file(), ap); 107790792Sgshapiro sm_dprintf("\n"); 107838032Speter } 107938032Speter if (rp == NULL) 108038032Speter { 108138032Speter /* end-of-pattern before end-of-address */ 108238032Speter goto backup; 108338032Speter } 108438032Speter if (ap == NULL && (*rp & 0377) != MATCHZANY && 108538032Speter (*rp & 0377) != MATCHZERO) 108638032Speter { 108738032Speter /* end-of-input with patterns left */ 108838032Speter goto backup; 108938032Speter } 109038032Speter 109138032Speter switch (*rp & 0377) 109238032Speter { 109338032Speter case MATCHCLASS: 109438032Speter /* match any phrase in a class */ 109564562Sgshapiro mlp->match_pattern = rvp; 109664562Sgshapiro mlp->match_first = avp; 109738032Speter extendclass: 109838032Speter ap = *avp; 109938032Speter if (ap == NULL) 110038032Speter goto backup; 110164562Sgshapiro mlp->match_last = avp++; 110264562Sgshapiro cataddr(mlp->match_first, mlp->match_last, 110364562Sgshapiro buf, sizeof buf, '\0'); 110438032Speter if (!wordinclass(buf, rp[1])) 110538032Speter { 110638032Speter if (tTd(21, 36)) 110738032Speter { 110890792Sgshapiro sm_dprintf("EXTEND rp="); 1109132943Sgshapiro xputs(sm_debug_file(), rp); 111090792Sgshapiro sm_dprintf(", ap="); 1111132943Sgshapiro xputs(sm_debug_file(), ap); 111290792Sgshapiro sm_dprintf("\n"); 111338032Speter } 111438032Speter goto extendclass; 111538032Speter } 111638032Speter if (tTd(21, 36)) 111790792Sgshapiro sm_dprintf("CLMATCH\n"); 111838032Speter mlp++; 111938032Speter break; 112038032Speter 112138032Speter case MATCHNCLASS: 112238032Speter /* match any token not in a class */ 112338032Speter if (wordinclass(ap, rp[1])) 112438032Speter goto backup; 112538032Speter 112664562Sgshapiro /* FALLTHROUGH */ 112738032Speter 112838032Speter case MATCHONE: 112938032Speter case MATCHANY: 113038032Speter /* match exactly one token */ 113164562Sgshapiro mlp->match_pattern = rvp; 113264562Sgshapiro mlp->match_first = avp; 113364562Sgshapiro mlp->match_last = avp++; 113438032Speter mlp++; 113538032Speter break; 113638032Speter 113738032Speter case MATCHZANY: 113838032Speter /* match zero or more tokens */ 113964562Sgshapiro mlp->match_pattern = rvp; 114064562Sgshapiro mlp->match_first = avp; 114164562Sgshapiro mlp->match_last = avp - 1; 114238032Speter mlp++; 114338032Speter break; 114438032Speter 114538032Speter case MATCHZERO: 114638032Speter /* match zero tokens */ 114738032Speter break; 114838032Speter 114938032Speter case MACRODEXPAND: 115038032Speter /* 115138032Speter ** Match against run-time macro. 115238032Speter ** This algorithm is broken for the 115338032Speter ** general case (no recursive macros, 115438032Speter ** improper tokenization) but should 115538032Speter ** work for the usual cases. 115638032Speter */ 115738032Speter 115838032Speter ap = macvalue(rp[1], e); 115964562Sgshapiro mlp->match_first = avp; 116038032Speter if (tTd(21, 2)) 116198841Sgshapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 116238032Speter macname(rp[1]), 116338032Speter ap == NULL ? "(NULL)" : ap); 116438032Speter 116538032Speter if (ap == NULL) 116638032Speter break; 116738032Speter while (*ap != '\0') 116838032Speter { 116938032Speter if (*avp == NULL || 117090792Sgshapiro sm_strncasecmp(ap, *avp, 117190792Sgshapiro strlen(*avp)) != 0) 117238032Speter { 117338032Speter /* no match */ 117464562Sgshapiro avp = mlp->match_first; 117538032Speter goto backup; 117638032Speter } 117738032Speter ap += strlen(*avp++); 117838032Speter } 117938032Speter 118038032Speter /* match */ 118138032Speter break; 118238032Speter 118338032Speter default: 118438032Speter /* must have exact match */ 118538032Speter if (sm_strcasecmp(rp, ap)) 118638032Speter goto backup; 118738032Speter avp++; 118838032Speter break; 118938032Speter } 119038032Speter 119138032Speter /* successful match on this token */ 119238032Speter rvp++; 119338032Speter continue; 119438032Speter 119538032Speter backup: 119638032Speter /* match failed -- back up */ 119738032Speter while (--mlp >= mlist) 119838032Speter { 119964562Sgshapiro rvp = mlp->match_pattern; 120038032Speter rp = *rvp; 120164562Sgshapiro avp = mlp->match_last + 1; 120238032Speter ap = *avp; 120338032Speter 120438032Speter if (tTd(21, 36)) 120538032Speter { 120690792Sgshapiro sm_dprintf("BACKUP rp="); 1207132943Sgshapiro xputs(sm_debug_file(), rp); 120890792Sgshapiro sm_dprintf(", ap="); 1209132943Sgshapiro xputs(sm_debug_file(), ap); 121090792Sgshapiro sm_dprintf("\n"); 121138032Speter } 121238032Speter 121338032Speter if (ap == NULL) 121438032Speter { 121538032Speter /* run off the end -- back up again */ 121638032Speter continue; 121738032Speter } 121838032Speter if ((*rp & 0377) == MATCHANY || 121938032Speter (*rp & 0377) == MATCHZANY) 122038032Speter { 122138032Speter /* extend binding and continue */ 122264562Sgshapiro mlp->match_last = avp++; 122338032Speter rvp++; 122438032Speter mlp++; 122538032Speter break; 122638032Speter } 122738032Speter if ((*rp & 0377) == MATCHCLASS) 122838032Speter { 122938032Speter /* extend binding and try again */ 123064562Sgshapiro mlp->match_last = avp; 123138032Speter goto extendclass; 123238032Speter } 123338032Speter } 123438032Speter 123538032Speter if (mlp < mlist) 123638032Speter { 123738032Speter /* total failure to match */ 123838032Speter break; 123938032Speter } 124038032Speter } 124138032Speter 124238032Speter /* 124338032Speter ** See if we successfully matched 124438032Speter */ 124538032Speter 124638032Speter if (mlp < mlist || *rvp != NULL) 124738032Speter { 124838032Speter if (tTd(21, 10)) 124990792Sgshapiro sm_dprintf("----- rule fails\n"); 125038032Speter rwr = rwr->r_next; 125138032Speter ruleno++; 125238032Speter loopcount = 0; 125338032Speter continue; 125438032Speter } 125538032Speter 125638032Speter rvp = rwr->r_rhs; 125738032Speter if (tTd(21, 12)) 125838032Speter { 125990792Sgshapiro sm_dprintf("-----rule matches:"); 1260132943Sgshapiro printav(sm_debug_file(), rvp); 126138032Speter } 126238032Speter 126338032Speter rp = *rvp; 126464562Sgshapiro if (rp != NULL) 126538032Speter { 126664562Sgshapiro if ((*rp & 0377) == CANONUSER) 126764562Sgshapiro { 126864562Sgshapiro rvp++; 126964562Sgshapiro rwr = rwr->r_next; 127064562Sgshapiro ruleno++; 127164562Sgshapiro loopcount = 0; 127264562Sgshapiro } 127364562Sgshapiro else if ((*rp & 0377) == CANONHOST) 127464562Sgshapiro { 127564562Sgshapiro rvp++; 127664562Sgshapiro rwr = NULL; 127764562Sgshapiro } 127838032Speter } 127938032Speter 128038032Speter /* substitute */ 128138032Speter for (avp = npvp; *rvp != NULL; rvp++) 128238032Speter { 128338032Speter register struct match *m; 128438032Speter register char **pp; 128538032Speter 128638032Speter rp = *rvp; 128738032Speter if ((*rp & 0377) == MATCHREPL) 128838032Speter { 128938032Speter /* substitute from LHS */ 129038032Speter m = &mlist[rp[1] - '1']; 129138032Speter if (m < mlist || m >= mlp) 129238032Speter { 129364562Sgshapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 129464562Sgshapiro rulename, rp[1]); 129538032Speter return EX_CONFIG; 129638032Speter } 129738032Speter if (tTd(21, 15)) 129838032Speter { 129990792Sgshapiro sm_dprintf("$%c:", rp[1]); 130064562Sgshapiro pp = m->match_first; 130164562Sgshapiro while (pp <= m->match_last) 130238032Speter { 130390792Sgshapiro sm_dprintf(" %p=\"", *pp); 130490792Sgshapiro sm_dflush(); 130590792Sgshapiro sm_dprintf("%s\"", *pp++); 130638032Speter } 130790792Sgshapiro sm_dprintf("\n"); 130838032Speter } 130964562Sgshapiro pp = m->match_first; 131064562Sgshapiro while (pp <= m->match_last) 131138032Speter { 131290792Sgshapiro if (avp >= &npvp[maxatom]) 1313120256Sgshapiro goto toolong; 131438032Speter *avp++ = *pp++; 131538032Speter } 131638032Speter } 131738032Speter else 131838032Speter { 131938032Speter /* some sort of replacement */ 132090792Sgshapiro if (avp >= &npvp[maxatom]) 132138032Speter { 132238032Speter toolong: 132364562Sgshapiro syserr("554 5.3.0 rewrite: expansion too long"); 132490792Sgshapiro if (LogLevel > 9) 132590792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 132690792Sgshapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 132790792Sgshapiro rulename, ruleno); 132838032Speter return EX_DATAERR; 132938032Speter } 133038032Speter if ((*rp & 0377) != MACRODEXPAND) 133138032Speter { 133238032Speter /* vanilla replacement */ 133338032Speter *avp++ = rp; 133438032Speter } 133538032Speter else 133638032Speter { 133798841Sgshapiro /* $&{x} replacement */ 133838032Speter char *mval = macvalue(rp[1], e); 133938032Speter char **xpvp; 134038032Speter int trsize = 0; 134138032Speter static size_t pvpb1_size = 0; 134238032Speter static char **pvpb1 = NULL; 134338032Speter char pvpbuf[PSBUFSIZE]; 134438032Speter 134538032Speter if (tTd(21, 2)) 134698841Sgshapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 134738032Speter macname(rp[1]), 134838032Speter mval == NULL ? "(NULL)" : mval); 134938032Speter if (mval == NULL || *mval == '\0') 135038032Speter continue; 135138032Speter 135238032Speter /* save the remainder of the input */ 135338032Speter for (xpvp = pvp; *xpvp != NULL; xpvp++) 135438032Speter trsize += sizeof *xpvp; 135564562Sgshapiro if ((size_t) trsize > pvpb1_size) 135638032Speter { 135738032Speter if (pvpb1 != NULL) 135877349Sgshapiro sm_free(pvpb1); 135990792Sgshapiro pvpb1 = (char **) 136090792Sgshapiro sm_pmalloc_x(trsize); 136138032Speter pvpb1_size = trsize; 136238032Speter } 136338032Speter 136464562Sgshapiro memmove((char *) pvpb1, 136564562Sgshapiro (char *) pvp, 136664562Sgshapiro trsize); 136738032Speter 136838032Speter /* scan the new replacement */ 136938032Speter xpvp = prescan(mval, '\0', pvpbuf, 137064562Sgshapiro sizeof pvpbuf, NULL, 1371132943Sgshapiro NULL, false); 137238032Speter if (xpvp == NULL) 137338032Speter { 137438032Speter /* prescan pre-printed error */ 137538032Speter return EX_DATAERR; 137638032Speter } 137738032Speter 137838032Speter /* insert it into the output stream */ 137938032Speter while (*xpvp != NULL) 138038032Speter { 138138032Speter if (tTd(21, 19)) 138290792Sgshapiro sm_dprintf(" ... %s\n", 138364562Sgshapiro *xpvp); 138490792Sgshapiro *avp++ = sm_rpool_strdup_x( 138590792Sgshapiro e->e_rpool, *xpvp); 138690792Sgshapiro if (avp >= &npvp[maxatom]) 138738032Speter goto toolong; 138838032Speter xpvp++; 138938032Speter } 139038032Speter if (tTd(21, 19)) 139190792Sgshapiro sm_dprintf(" ... DONE\n"); 139238032Speter 139338032Speter /* restore the old trailing input */ 139464562Sgshapiro memmove((char *) pvp, 139564562Sgshapiro (char *) pvpb1, 139664562Sgshapiro trsize); 139738032Speter } 139838032Speter } 139938032Speter } 140038032Speter *avp++ = NULL; 140138032Speter 140238032Speter /* 140338032Speter ** Check for any hostname/keyword lookups. 140438032Speter */ 140538032Speter 140638032Speter for (rvp = npvp; *rvp != NULL; rvp++) 140738032Speter { 140838032Speter char **hbrvp; 140938032Speter char **xpvp; 141038032Speter int trsize; 141138032Speter char *replac; 141238032Speter int endtoken; 141338032Speter STAB *map; 141438032Speter char *mapname; 141538032Speter char **key_rvp; 141638032Speter char **arg_rvp; 141738032Speter char **default_rvp; 141864562Sgshapiro char cbuf[MAXNAME + 1]; 141938032Speter char *pvpb1[MAXATOM + 1]; 1420120256Sgshapiro char *argvect[MAX_MAP_ARGS]; 142138032Speter char pvpbuf[PSBUFSIZE]; 142238032Speter char *nullpvp[1]; 142338032Speter 142438032Speter if ((**rvp & 0377) != HOSTBEGIN && 142538032Speter (**rvp & 0377) != LOOKUPBEGIN) 142638032Speter continue; 142738032Speter 142838032Speter /* 142938032Speter ** Got a hostname/keyword lookup. 143038032Speter ** 143138032Speter ** This could be optimized fairly easily. 143238032Speter */ 143338032Speter 143438032Speter hbrvp = rvp; 143538032Speter if ((**rvp & 0377) == HOSTBEGIN) 143638032Speter { 143738032Speter endtoken = HOSTEND; 143838032Speter mapname = "host"; 143938032Speter } 144038032Speter else 144138032Speter { 144238032Speter endtoken = LOOKUPEND; 144338032Speter mapname = *++rvp; 1444120256Sgshapiro if (mapname == NULL) 1445120256Sgshapiro syserr("554 5.3.0 rewrite: missing mapname"); 144638032Speter } 144738032Speter map = stab(mapname, ST_MAP, ST_FIND); 144838032Speter if (map == NULL) 1449120256Sgshapiro syserr("554 5.3.0 rewrite: map %s not found", 1450120256Sgshapiro mapname); 145138032Speter 145238032Speter /* extract the match part */ 145338032Speter key_rvp = ++rvp; 1454120256Sgshapiro if (key_rvp == NULL) 1455120256Sgshapiro syserr("554 5.3.0 rewrite: missing key for map %s", 1456120256Sgshapiro mapname); 145738032Speter default_rvp = NULL; 145838032Speter arg_rvp = argvect; 145938032Speter xpvp = NULL; 146038032Speter replac = pvpbuf; 146138032Speter while (*rvp != NULL && (**rvp & 0377) != endtoken) 146238032Speter { 146338032Speter int nodetype = **rvp & 0377; 146438032Speter 1465120256Sgshapiro if (nodetype != CANONHOST && 1466120256Sgshapiro nodetype != CANONUSER) 146738032Speter { 146838032Speter rvp++; 146938032Speter continue; 147038032Speter } 147138032Speter 147238032Speter *rvp++ = NULL; 147338032Speter 147438032Speter if (xpvp != NULL) 147538032Speter { 147638032Speter cataddr(xpvp, NULL, replac, 147738032Speter &pvpbuf[sizeof pvpbuf] - replac, 147838032Speter '\0'); 1479120256Sgshapiro if (arg_rvp < 1480120256Sgshapiro &argvect[MAX_MAP_ARGS - 1]) 1481120256Sgshapiro *++arg_rvp = replac; 148238032Speter replac += strlen(replac) + 1; 148338032Speter xpvp = NULL; 148438032Speter } 148538032Speter switch (nodetype) 148638032Speter { 148738032Speter case CANONHOST: 148838032Speter xpvp = rvp; 148938032Speter break; 149038032Speter 149138032Speter case CANONUSER: 149238032Speter default_rvp = rvp; 149338032Speter break; 149438032Speter } 149538032Speter } 149638032Speter if (*rvp != NULL) 149738032Speter *rvp++ = NULL; 149838032Speter if (xpvp != NULL) 149938032Speter { 150038032Speter cataddr(xpvp, NULL, replac, 150138032Speter &pvpbuf[sizeof pvpbuf] - replac, 150238032Speter '\0'); 1503120256Sgshapiro if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1504120256Sgshapiro *++arg_rvp = replac; 150538032Speter } 1506120256Sgshapiro if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1507120256Sgshapiro argvect[MAX_MAP_ARGS - 1] = NULL; 1508120256Sgshapiro else 1509120256Sgshapiro *++arg_rvp = NULL; 151038032Speter 151138032Speter /* save the remainder of the input string */ 151238032Speter trsize = (int) (avp - rvp + 1) * sizeof *rvp; 151364562Sgshapiro memmove((char *) pvpb1, (char *) rvp, trsize); 151438032Speter 151538032Speter /* look it up */ 151664562Sgshapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 151764562Sgshapiro map == NULL ? '\0' : map->s_map.map_spacesub); 151864562Sgshapiro argvect[0] = cbuf; 151964562Sgshapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 152038032Speter 152138032Speter /* if no replacement, use default */ 152238032Speter if (replac == NULL && default_rvp != NULL) 152338032Speter { 152438032Speter /* create the default */ 152564562Sgshapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 152664562Sgshapiro replac = cbuf; 152738032Speter } 152838032Speter 152938032Speter if (replac == NULL) 153038032Speter { 153138032Speter xpvp = key_rvp; 153238032Speter } 153338032Speter else if (*replac == '\0') 153438032Speter { 153538032Speter /* null replacement */ 153638032Speter nullpvp[0] = NULL; 153738032Speter xpvp = nullpvp; 153838032Speter } 153938032Speter else 154038032Speter { 154138032Speter /* scan the new replacement */ 154238032Speter xpvp = prescan(replac, '\0', pvpbuf, 1543132943Sgshapiro sizeof pvpbuf, NULL, NULL, false); 154438032Speter if (xpvp == NULL) 154538032Speter { 154638032Speter /* prescan already printed error */ 154738032Speter return EX_DATAERR; 154838032Speter } 154938032Speter } 155038032Speter 155138032Speter /* append it to the token list */ 155238032Speter for (avp = hbrvp; *xpvp != NULL; xpvp++) 155338032Speter { 155490792Sgshapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 155590792Sgshapiro if (avp >= &npvp[maxatom]) 155638032Speter goto toolong; 155738032Speter } 155838032Speter 155938032Speter /* restore the old trailing information */ 156038032Speter rvp = avp - 1; 156138032Speter for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 156290792Sgshapiro if (avp >= &npvp[maxatom]) 156338032Speter goto toolong; 156438032Speter } 156538032Speter 156638032Speter /* 156738032Speter ** Check for subroutine calls. 156838032Speter */ 156938032Speter 157064562Sgshapiro status = callsubr(npvp, reclevel, e); 157164562Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 157264562Sgshapiro rstat = status; 157338032Speter 157438032Speter /* copy vector back into original space. */ 157538032Speter for (avp = npvp; *avp++ != NULL;) 157638032Speter continue; 157764562Sgshapiro memmove((char *) pvp, (char *) npvp, 157838032Speter (int) (avp - npvp) * sizeof *avp); 157964562Sgshapiro 158038032Speter if (tTd(21, 4)) 158138032Speter { 158290792Sgshapiro sm_dprintf("rewritten as:"); 1583132943Sgshapiro printav(sm_debug_file(), pvp); 158438032Speter } 158538032Speter } 158638032Speter 158764562Sgshapiro if (OpMode == MD_TEST) 158838032Speter { 158990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 159090792Sgshapiro "%s%-16.16s returns:", prefix, rulename); 1591132943Sgshapiro printav(smioout, pvp); 159238032Speter } 159364562Sgshapiro else if (tTd(21, 1)) 159464562Sgshapiro { 159590792Sgshapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1596132943Sgshapiro printav(sm_debug_file(), pvp); 159764562Sgshapiro } 159838032Speter return rstat; 159938032Speter} 160090792Sgshapiro/* 160138032Speter** CALLSUBR -- call subroutines in rewrite vector 160238032Speter** 160338032Speter** Parameters: 160438032Speter** pvp -- pointer to token vector. 160538032Speter** reclevel -- the current recursion level. 160638032Speter** e -- the current envelope. 160738032Speter** 160838032Speter** Returns: 160938032Speter** The status from the subroutine call. 161038032Speter** 161138032Speter** Side Effects: 161238032Speter** pvp is modified. 161338032Speter*/ 161438032Speter 161564562Sgshapirostatic int 161638032Spetercallsubr(pvp, reclevel, e) 161738032Speter char **pvp; 161838032Speter int reclevel; 161938032Speter ENVELOPE *e; 162038032Speter{ 162164562Sgshapiro char **avp; 162238032Speter register int i; 162390792Sgshapiro int subr, j; 162490792Sgshapiro int nsubr; 162564562Sgshapiro int status; 162638032Speter int rstat = EX_OK; 162790792Sgshapiro#define MAX_SUBR 16 162890792Sgshapiro int subrnumber[MAX_SUBR]; 162990792Sgshapiro int subrindex[MAX_SUBR]; 163038032Speter 163190792Sgshapiro nsubr = 0; 163290792Sgshapiro 163390792Sgshapiro /* 163490792Sgshapiro ** Look for subroutine calls in pvp, collect them into subr*[] 163590792Sgshapiro ** We will perform the calls in the next loop, because we will 163690792Sgshapiro ** call the "last" subroutine first to avoid recursive calls 163790792Sgshapiro ** and too much copying. 163890792Sgshapiro */ 163990792Sgshapiro 164090792Sgshapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 164138032Speter { 164238032Speter if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 164338032Speter { 164438032Speter stripquotes(avp[1]); 164538032Speter subr = strtorwset(avp[1], NULL, ST_FIND); 164638032Speter if (subr < 0) 164738032Speter { 164890792Sgshapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 164938032Speter return EX_CONFIG; 165038032Speter } 165138032Speter 165238032Speter /* 165390792Sgshapiro ** XXX instead of doing this we could optimize 165490792Sgshapiro ** the rules after reading them: just remove 165590792Sgshapiro ** calls to empty rulesets 165638032Speter */ 165738032Speter 165890792Sgshapiro /* subroutine is an empty ruleset? don't call it */ 165990792Sgshapiro if (RewriteRules[subr] == NULL) 166090792Sgshapiro { 166190792Sgshapiro if (tTd(21, 3)) 166290792Sgshapiro sm_dprintf("-----skip subr %s (%d)\n", 166390792Sgshapiro avp[1], subr); 166490792Sgshapiro for (i = 2; avp[i] != NULL; i++) 166590792Sgshapiro avp[i - 2] = avp[i]; 166690792Sgshapiro avp[i - 2] = NULL; 166738032Speter continue; 166890792Sgshapiro } 166990792Sgshapiro if (++nsubr >= MAX_SUBR) 167038032Speter { 167190792Sgshapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 167290792Sgshapiro MAX_SUBR); 167390792Sgshapiro return EX_CONFIG; 167438032Speter } 167590792Sgshapiro subrnumber[nsubr] = subr; 167690792Sgshapiro subrindex[nsubr] = j; 167790792Sgshapiro } 167890792Sgshapiro } 167938032Speter 168090792Sgshapiro /* 168190792Sgshapiro ** Perform the actual subroutines calls, "last" one first, i.e., 168290792Sgshapiro ** go from the right to the left through all calls, 168390792Sgshapiro ** do the rewriting in place. 168490792Sgshapiro */ 168538032Speter 168690792Sgshapiro for (; nsubr > 0; nsubr--) 168790792Sgshapiro { 168890792Sgshapiro subr = subrnumber[nsubr]; 168990792Sgshapiro avp = pvp + subrindex[nsubr]; 169038032Speter 169190792Sgshapiro /* remove the subroutine call and name */ 169290792Sgshapiro for (i = 2; avp[i] != NULL; i++) 169390792Sgshapiro avp[i - 2] = avp[i]; 169490792Sgshapiro avp[i - 2] = NULL; 169538032Speter 169690792Sgshapiro /* 169790792Sgshapiro ** Now we need to call the ruleset specified for 1698120256Sgshapiro ** the subroutine. We can do this in place since 169990792Sgshapiro ** we call the "last" subroutine first. 170090792Sgshapiro */ 170190792Sgshapiro 170290792Sgshapiro status = rewrite(avp, subr, reclevel, e, 170390792Sgshapiro MAXATOM - subrindex[nsubr]); 170490792Sgshapiro if (status != EX_OK && status != EX_TEMPFAIL) 170590792Sgshapiro return status; 170690792Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 170790792Sgshapiro rstat = status; 170838032Speter } 170938032Speter return rstat; 171038032Speter} 171190792Sgshapiro/* 171238032Speter** MAP_LOOKUP -- do lookup in map 171338032Speter** 171438032Speter** Parameters: 171590792Sgshapiro** smap -- the map to use for the lookup. 171638032Speter** key -- the key to look up. 171738032Speter** argvect -- arguments to pass to the map lookup. 171838032Speter** pstat -- a pointer to an integer in which to store the 171938032Speter** status from the lookup. 172038032Speter** e -- the current envelope. 172138032Speter** 172238032Speter** Returns: 172338032Speter** The result of the lookup. 172438032Speter** NULL -- if there was no data for the given key. 172538032Speter*/ 172638032Speter 172764562Sgshapirostatic char * 172864562Sgshapiromap_lookup(smap, key, argvect, pstat, e) 172964562Sgshapiro STAB *smap; 173038032Speter char key[]; 173138032Speter char **argvect; 173238032Speter int *pstat; 173338032Speter ENVELOPE *e; 173438032Speter{ 173564562Sgshapiro auto int status = EX_OK; 173664562Sgshapiro MAP *map; 173738032Speter char *replac; 173838032Speter 173964562Sgshapiro if (smap == NULL) 174064562Sgshapiro return NULL; 174164562Sgshapiro 174264562Sgshapiro map = &smap->s_map; 174364562Sgshapiro DYNOPENMAP(map); 174464562Sgshapiro 174564562Sgshapiro if (e->e_sendmode == SM_DEFER && 174664562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 174738032Speter { 174838032Speter /* don't do any map lookups */ 174938032Speter if (tTd(60, 1)) 175090792Sgshapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 175164562Sgshapiro smap->s_name, key); 175238032Speter *pstat = EX_TEMPFAIL; 175338032Speter return NULL; 175438032Speter } 175538032Speter 175664562Sgshapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 175738032Speter stripquotes(key); 175838032Speter 175938032Speter if (tTd(60, 1)) 176042575Speter { 176190792Sgshapiro sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 176242575Speter if (tTd(60, 5)) 176342575Speter { 176442575Speter int i; 176542575Speter 176642575Speter for (i = 0; argvect[i] != NULL; i++) 176790792Sgshapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 176842575Speter } 176990792Sgshapiro sm_dprintf(") => "); 177042575Speter } 177164562Sgshapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 177238032Speter if (tTd(60, 1)) 177390792Sgshapiro sm_dprintf("%s (%d)\n", 177438032Speter replac != NULL ? replac : "NOT FOUND", 177564562Sgshapiro status); 177638032Speter 177764562Sgshapiro /* should recover if status == EX_TEMPFAIL */ 177864562Sgshapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 177938032Speter { 178038032Speter *pstat = EX_TEMPFAIL; 178138032Speter if (tTd(60, 1)) 178290792Sgshapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 178364562Sgshapiro smap->s_name, key, errno); 178438032Speter if (e->e_message == NULL) 178538032Speter { 178638032Speter char mbuf[320]; 178738032Speter 178890792Sgshapiro (void) sm_snprintf(mbuf, sizeof mbuf, 178938032Speter "%.80s map: lookup (%s): deferred", 179064562Sgshapiro smap->s_name, 179138032Speter shortenstring(key, MAXSHORTSTR)); 179290792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 179338032Speter } 179438032Speter } 179564562Sgshapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 179638032Speter { 179764562Sgshapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 179838032Speter static char *rwbuf = NULL; 179938032Speter static size_t rwbuflen = 0; 180038032Speter 180138032Speter if (i > rwbuflen) 180238032Speter { 180338032Speter if (rwbuf != NULL) 180477349Sgshapiro sm_free(rwbuf); 180538032Speter rwbuflen = i; 180690792Sgshapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 180738032Speter } 180890792Sgshapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 180938032Speter if (tTd(60, 4)) 181090792Sgshapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 181138032Speter rwbuf); 181238032Speter return rwbuf; 181338032Speter } 181438032Speter return replac; 181538032Speter} 181690792Sgshapiro/* 181764562Sgshapiro** INITERRMAILERS -- initialize error and discard mailers 181864562Sgshapiro** 181964562Sgshapiro** Parameters: 182064562Sgshapiro** none. 182164562Sgshapiro** 182264562Sgshapiro** Returns: 182364562Sgshapiro** none. 182464562Sgshapiro** 182564562Sgshapiro** Side Effects: 182664562Sgshapiro** initializes error and discard mailers. 182764562Sgshapiro*/ 182864562Sgshapiro 182964562Sgshapirostatic MAILER discardmailer; 183064562Sgshapirostatic MAILER errormailer; 183164562Sgshapirostatic char *discardargv[] = { "DISCARD", NULL }; 183264562Sgshapirostatic char *errorargv[] = { "ERROR", NULL }; 183364562Sgshapiro 183464562Sgshapirovoid 183564562Sgshapiroiniterrmailers() 183664562Sgshapiro{ 183764562Sgshapiro if (discardmailer.m_name == NULL) 183864562Sgshapiro { 183964562Sgshapiro /* initialize the discard mailer */ 184064562Sgshapiro discardmailer.m_name = "*discard*"; 184164562Sgshapiro discardmailer.m_mailer = "DISCARD"; 184264562Sgshapiro discardmailer.m_argv = discardargv; 184364562Sgshapiro } 184464562Sgshapiro if (errormailer.m_name == NULL) 184564562Sgshapiro { 184664562Sgshapiro /* initialize the bogus mailer */ 184764562Sgshapiro errormailer.m_name = "*error*"; 184864562Sgshapiro errormailer.m_mailer = "ERROR"; 184964562Sgshapiro errormailer.m_argv = errorargv; 185064562Sgshapiro } 185164562Sgshapiro} 185290792Sgshapiro/* 185338032Speter** BUILDADDR -- build address from token vector. 185438032Speter** 185538032Speter** Parameters: 185638032Speter** tv -- token vector. 185738032Speter** a -- pointer to address descriptor to fill. 185838032Speter** If NULL, one will be allocated. 185938032Speter** flags -- info regarding whether this is a sender or 186038032Speter** a recipient. 186138032Speter** e -- the current envelope. 186238032Speter** 186338032Speter** Returns: 186438032Speter** NULL if there was an error. 186538032Speter** 'a' otherwise. 186638032Speter** 186738032Speter** Side Effects: 186838032Speter** fills in 'a' 186938032Speter*/ 187038032Speter 187164562Sgshapirostatic struct errcodes 187238032Speter{ 187338032Speter char *ec_name; /* name of error code */ 187438032Speter int ec_code; /* numeric code */ 187538032Speter} ErrorCodes[] = 187638032Speter{ 187738032Speter { "usage", EX_USAGE }, 187838032Speter { "nouser", EX_NOUSER }, 187938032Speter { "nohost", EX_NOHOST }, 188038032Speter { "unavailable", EX_UNAVAILABLE }, 188138032Speter { "software", EX_SOFTWARE }, 188238032Speter { "tempfail", EX_TEMPFAIL }, 188338032Speter { "protocol", EX_PROTOCOL }, 188438032Speter { "config", EX_CONFIG }, 188538032Speter { NULL, EX_UNAVAILABLE } 188638032Speter}; 188738032Speter 188864562Sgshapirostatic ADDRESS * 188938032Speterbuildaddr(tv, a, flags, e) 189038032Speter register char **tv; 189138032Speter register ADDRESS *a; 189238032Speter int flags; 189338032Speter register ENVELOPE *e; 189438032Speter{ 189594334Sgshapiro bool tempfail = false; 1896120256Sgshapiro int maxatom; 189738032Speter struct mailer **mp; 189838032Speter register struct mailer *m; 189938032Speter register char *p; 190038032Speter char *mname; 190138032Speter char **hostp; 190238032Speter char hbuf[MAXNAME + 1]; 190342575Speter static char ubuf[MAXNAME + 2]; 190438032Speter 190538032Speter if (tTd(24, 5)) 190638032Speter { 190790792Sgshapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1908132943Sgshapiro printav(sm_debug_file(), tv); 190938032Speter } 191038032Speter 1911120256Sgshapiro maxatom = MAXATOM; 191238032Speter if (a == NULL) 191390792Sgshapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 191464562Sgshapiro memset((char *) a, '\0', sizeof *a); 191564562Sgshapiro hbuf[0] = '\0'; 191638032Speter 191738032Speter /* set up default error return flags */ 191838032Speter a->q_flags |= DefaultNotify; 191938032Speter 192038032Speter /* figure out what net/mailer to use */ 192138032Speter if (*tv == NULL || (**tv & 0377) != CANONNET) 192238032Speter { 192364562Sgshapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 192438032Speterbadaddr: 192594334Sgshapiro /* 192694334Sgshapiro ** ExitStat may have been set by an earlier map open 192794334Sgshapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 192894334Sgshapiro ** so we also need to check if this particular $#error 192994334Sgshapiro ** return wanted a 4XX failure. 193094334Sgshapiro ** 193194334Sgshapiro ** XXX the real fix is probably to set ExitStat correctly, 193294334Sgshapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 193394334Sgshapiro ** error. 193494334Sgshapiro */ 193594334Sgshapiro 193694334Sgshapiro if (ExitStat == EX_TEMPFAIL || tempfail) 193764562Sgshapiro a->q_state = QS_QUEUEUP; 193864562Sgshapiro else 193938032Speter { 194064562Sgshapiro a->q_state = QS_BADADDR; 194164562Sgshapiro a->q_mailer = &errormailer; 194238032Speter } 194338032Speter return a; 194438032Speter } 194538032Speter mname = *++tv; 1946120256Sgshapiro --maxatom; 194738032Speter 194838032Speter /* extract host and user portions */ 194938032Speter if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1950120256Sgshapiro { 195138032Speter hostp = ++tv; 1952120256Sgshapiro --maxatom; 1953120256Sgshapiro } 195438032Speter else 195538032Speter hostp = NULL; 1956120256Sgshapiro --maxatom; 195738032Speter while (*tv != NULL && (**tv & 0377) != CANONUSER) 1958120256Sgshapiro { 195938032Speter tv++; 1960120256Sgshapiro --maxatom; 1961120256Sgshapiro } 196238032Speter if (*tv == NULL) 196338032Speter { 196464562Sgshapiro syserr("554 5.3.5 buildaddr: no user"); 196538032Speter goto badaddr; 196638032Speter } 196738032Speter if (tv == hostp) 196838032Speter hostp = NULL; 196938032Speter else if (hostp != NULL) 197038032Speter cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 197138032Speter cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1972120256Sgshapiro --maxatom; 197338032Speter 197438032Speter /* save away the host name */ 197590792Sgshapiro if (sm_strcasecmp(mname, "error") == 0) 197638032Speter { 197764562Sgshapiro /* Set up triplet for use by -bv */ 197864562Sgshapiro a->q_mailer = &errormailer; 197990792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 198090792Sgshapiro /* XXX wrong place? */ 198164562Sgshapiro 198238032Speter if (hostp != NULL) 198338032Speter { 198438032Speter register struct errcodes *ep; 198538032Speter 198690792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 198738032Speter if (strchr(hbuf, '.') != NULL) 198838032Speter { 198990792Sgshapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 199090792Sgshapiro hbuf); 199138032Speter setstat(dsntoexitstat(hbuf)); 199238032Speter } 199338032Speter else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 199438032Speter { 199538032Speter setstat(atoi(hbuf)); 199638032Speter } 199738032Speter else 199838032Speter { 199938032Speter for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 200090792Sgshapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 200138032Speter break; 200238032Speter setstat(ep->ec_code); 200338032Speter } 200438032Speter } 200538032Speter else 200664562Sgshapiro { 200764562Sgshapiro a->q_host = NULL; 200838032Speter setstat(EX_UNAVAILABLE); 200964562Sgshapiro } 201038032Speter stripquotes(ubuf); 201164562Sgshapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 201238032Speter { 201364562Sgshapiro char fmt[16]; 201464562Sgshapiro int off; 201538032Speter 201664562Sgshapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 201738032Speter { 201864562Sgshapiro ubuf[off + 4] = '\0'; 201964562Sgshapiro off += 5; 202038032Speter } 202164562Sgshapiro else 202264562Sgshapiro { 202364562Sgshapiro off = 4; 202464562Sgshapiro ubuf[3] = '\0'; 202564562Sgshapiro } 202690792Sgshapiro (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 202764562Sgshapiro if (off > 4) 202864562Sgshapiro usrerr(fmt, ubuf + off); 202964562Sgshapiro else if (isenhsc(hbuf, '\0') > 0) 203064562Sgshapiro usrerrenh(hbuf, fmt, ubuf + off); 203164562Sgshapiro else 203264562Sgshapiro usrerr(fmt, ubuf + off); 203364562Sgshapiro /* XXX ubuf[off - 1] = ' '; */ 203494334Sgshapiro if (ubuf[0] == '4') 203594334Sgshapiro tempfail = true; 203638032Speter } 203738032Speter else 203838032Speter { 203964562Sgshapiro usrerr("553 5.3.0 %s", ubuf); 204038032Speter } 204138032Speter goto badaddr; 204238032Speter } 204338032Speter 204438032Speter for (mp = Mailer; (m = *mp++) != NULL; ) 204538032Speter { 204690792Sgshapiro if (sm_strcasecmp(m->m_name, mname) == 0) 204738032Speter break; 204838032Speter } 204938032Speter if (m == NULL) 205038032Speter { 205164562Sgshapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 205238032Speter goto badaddr; 205338032Speter } 205438032Speter a->q_mailer = m; 205538032Speter 205638032Speter /* figure out what host (if any) */ 205738032Speter if (hostp == NULL) 205838032Speter { 205938032Speter if (!bitnset(M_LOCALMAILER, m->m_flags)) 206038032Speter { 206164562Sgshapiro syserr("554 5.3.5 buildaddr: no host"); 206238032Speter goto badaddr; 206338032Speter } 206438032Speter a->q_host = NULL; 206538032Speter } 206638032Speter else 206790792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 206838032Speter 206938032Speter /* figure out the user */ 207038032Speter p = ubuf; 207138032Speter if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 207238032Speter { 207338032Speter p++; 207438032Speter tv++; 2075120256Sgshapiro --maxatom; 207638032Speter a->q_flags |= QNOTREMOTE; 207738032Speter } 207838032Speter 207938032Speter /* do special mapping for local mailer */ 208038032Speter if (*p == '"') 208138032Speter p++; 208238032Speter if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 208338032Speter a->q_mailer = m = ProgMailer; 208438032Speter else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 208538032Speter a->q_mailer = m = FileMailer; 208638032Speter else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 208738032Speter { 208838032Speter /* may be :include: */ 208938032Speter stripquotes(ubuf); 209090792Sgshapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 209138032Speter { 209238032Speter /* if :include:, don't need further rewriting */ 209338032Speter a->q_mailer = m = InclMailer; 209490792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 209538032Speter return a; 209638032Speter } 209738032Speter } 209838032Speter 209938032Speter /* rewrite according recipient mailer rewriting rules */ 210090792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 210164562Sgshapiro 210290792Sgshapiro if (ConfigLevel >= 10 || 210364562Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 210438032Speter { 210538032Speter /* sender addresses done later */ 2106120256Sgshapiro (void) rewrite(tv, 2, 0, e, maxatom); 210738032Speter if (m->m_re_rwset > 0) 2108120256Sgshapiro (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 210938032Speter } 2110120256Sgshapiro (void) rewrite(tv, 4, 0, e, maxatom); 211138032Speter 211238032Speter /* save the result for the command line/RCPT argument */ 211338032Speter cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 211490792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 211538032Speter 211638032Speter /* 211738032Speter ** Do mapping to lower case as requested by mailer 211838032Speter */ 211938032Speter 212038032Speter if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 212138032Speter makelower(a->q_host); 212238032Speter if (!bitnset(M_USR_UPPER, m->m_flags)) 212338032Speter makelower(a->q_user); 212438032Speter 212538032Speter if (tTd(24, 6)) 212638032Speter { 212790792Sgshapiro sm_dprintf("buildaddr => "); 2128132943Sgshapiro printaddr(sm_debug_file(), a, false); 212938032Speter } 213038032Speter return a; 213138032Speter} 2132110560Sgshapiro 213390792Sgshapiro/* 213438032Speter** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 213538032Speter** 213638032Speter** Parameters: 213738032Speter** pvp -- parameter vector to rebuild. 213838032Speter** evp -- last parameter to include. Can be NULL to 213938032Speter** use entire pvp. 214038032Speter** buf -- buffer to build the string into. 214138032Speter** sz -- size of buf. 214290792Sgshapiro** spacesub -- the space separator character; if '\0', 214338032Speter** use SpaceSub. 214438032Speter** 214538032Speter** Returns: 214638032Speter** none. 214738032Speter** 214838032Speter** Side Effects: 214938032Speter** Destroys buf. 215038032Speter*/ 215138032Speter 215238032Spetervoid 215338032Spetercataddr(pvp, evp, buf, sz, spacesub) 215438032Speter char **pvp; 215538032Speter char **evp; 215638032Speter char *buf; 215738032Speter register int sz; 215838032Speter int spacesub; 215938032Speter{ 216090792Sgshapiro bool oatomtok = false; 216190792Sgshapiro bool natomtok = false; 216238032Speter register int i; 216338032Speter register char *p; 216438032Speter 216564562Sgshapiro if (sz <= 0) 216664562Sgshapiro return; 216764562Sgshapiro 216838032Speter if (spacesub == '\0') 216938032Speter spacesub = SpaceSub; 217038032Speter 217138032Speter if (pvp == NULL) 217238032Speter { 217364562Sgshapiro *buf = '\0'; 217438032Speter return; 217538032Speter } 217638032Speter p = buf; 217738032Speter sz -= 2; 217890792Sgshapiro while (*pvp != NULL && sz > 0) 217938032Speter { 218038032Speter natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 218138032Speter if (oatomtok && natomtok) 218264562Sgshapiro { 218338032Speter *p++ = spacesub; 218490792Sgshapiro if (--sz <= 0) 218590792Sgshapiro break; 218664562Sgshapiro } 2187132943Sgshapiro i = sm_strlcpy(p, *pvp, sz); 2188132943Sgshapiro sz -= i; 2189132943Sgshapiro if (sz <= 0) 219090792Sgshapiro break; 219138032Speter oatomtok = natomtok; 219238032Speter p += i; 219338032Speter if (pvp++ == evp) 219438032Speter break; 219538032Speter } 2196132943Sgshapiro 2197132943Sgshapiro /* Don't silently truncate long strings */ 2198132943Sgshapiro if (sz <= 0) 219994334Sgshapiro syserr("cataddr: string too long"); 220038032Speter *p = '\0'; 220138032Speter} 220290792Sgshapiro/* 220338032Speter** SAMEADDR -- Determine if two addresses are the same 220438032Speter** 220538032Speter** This is not just a straight comparison -- if the mailer doesn't 220638032Speter** care about the host we just ignore it, etc. 220738032Speter** 220838032Speter** Parameters: 220938032Speter** a, b -- pointers to the internal forms to compare. 221038032Speter** 221138032Speter** Returns: 221290792Sgshapiro** true -- they represent the same mailbox. 221390792Sgshapiro** false -- they don't. 221438032Speter** 221538032Speter** Side Effects: 221638032Speter** none. 221738032Speter*/ 221838032Speter 221938032Speterbool 222038032Spetersameaddr(a, b) 222138032Speter register ADDRESS *a; 222238032Speter register ADDRESS *b; 222338032Speter{ 222438032Speter register ADDRESS *ca, *cb; 222538032Speter 222638032Speter /* if they don't have the same mailer, forget it */ 222738032Speter if (a->q_mailer != b->q_mailer) 222890792Sgshapiro return false; 222938032Speter 223038032Speter /* if the user isn't the same, we can drop out */ 223138032Speter if (strcmp(a->q_user, b->q_user) != 0) 223290792Sgshapiro return false; 223338032Speter 223438032Speter /* if we have good uids for both but they differ, these are different */ 223538032Speter if (a->q_mailer == ProgMailer) 223638032Speter { 223738032Speter ca = getctladdr(a); 223838032Speter cb = getctladdr(b); 223938032Speter if (ca != NULL && cb != NULL && 224038032Speter bitset(QGOODUID, ca->q_flags & cb->q_flags) && 224138032Speter ca->q_uid != cb->q_uid) 224290792Sgshapiro return false; 224338032Speter } 224438032Speter 224538032Speter /* otherwise compare hosts (but be careful for NULL ptrs) */ 224638032Speter if (a->q_host == b->q_host) 224738032Speter { 224838032Speter /* probably both null pointers */ 224990792Sgshapiro return true; 225038032Speter } 225138032Speter if (a->q_host == NULL || b->q_host == NULL) 225238032Speter { 225338032Speter /* only one is a null pointer */ 225490792Sgshapiro return false; 225538032Speter } 225638032Speter if (strcmp(a->q_host, b->q_host) != 0) 225790792Sgshapiro return false; 225838032Speter 225990792Sgshapiro return true; 226038032Speter} 226190792Sgshapiro/* 226238032Speter** PRINTADDR -- print address (for debugging) 226338032Speter** 226438032Speter** Parameters: 226538032Speter** a -- the address to print 226638032Speter** follow -- follow the q_next chain. 226738032Speter** 226838032Speter** Returns: 226938032Speter** none. 227038032Speter** 227138032Speter** Side Effects: 227238032Speter** none. 227338032Speter*/ 227438032Speter 227538032Speterstruct qflags 227638032Speter{ 227790792Sgshapiro char *qf_name; 227890792Sgshapiro unsigned long qf_bit; 227938032Speter}; 228038032Speter 228164562Sgshapirostatic struct qflags AddressFlags[] = 228238032Speter{ 228338032Speter { "QGOODUID", QGOODUID }, 228438032Speter { "QPRIMARY", QPRIMARY }, 228538032Speter { "QNOTREMOTE", QNOTREMOTE }, 228638032Speter { "QSELFREF", QSELFREF }, 228738032Speter { "QBOGUSSHELL", QBOGUSSHELL }, 228838032Speter { "QUNSAFEADDR", QUNSAFEADDR }, 228938032Speter { "QPINGONSUCCESS", QPINGONSUCCESS }, 229038032Speter { "QPINGONFAILURE", QPINGONFAILURE }, 229138032Speter { "QPINGONDELAY", QPINGONDELAY }, 229238032Speter { "QHASNOTIFY", QHASNOTIFY }, 229338032Speter { "QRELAYED", QRELAYED }, 229438032Speter { "QEXPANDED", QEXPANDED }, 229538032Speter { "QDELIVERED", QDELIVERED }, 229638032Speter { "QDELAYED", QDELAYED }, 229738032Speter { "QTHISPASS", QTHISPASS }, 229838032Speter { "QRCPTOK", QRCPTOK }, 229971345Sgshapiro { NULL, 0 } 230038032Speter}; 230138032Speter 230238032Spetervoid 2303132943Sgshapiroprintaddr(fp, a, follow) 2304132943Sgshapiro SM_FILE_T *fp; 230538032Speter register ADDRESS *a; 230638032Speter bool follow; 230738032Speter{ 230838032Speter register MAILER *m; 230938032Speter MAILER pseudomailer; 231038032Speter register struct qflags *qfp; 231138032Speter bool firstone; 231238032Speter 231338032Speter if (a == NULL) 231438032Speter { 2315132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 231638032Speter return; 231738032Speter } 231838032Speter 231938032Speter while (a != NULL) 232038032Speter { 2321132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2322132943Sgshapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 232338032Speter 232438032Speter /* find the mailer -- carefully */ 232538032Speter m = a->q_mailer; 232638032Speter if (m == NULL) 232738032Speter { 232838032Speter m = &pseudomailer; 232938032Speter m->m_mno = -1; 233038032Speter m->m_name = "NULL"; 233138032Speter } 233238032Speter 2333132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 233490792Sgshapiro "%s:\n\tmailer %d (%s), host `%s'\n", 233590792Sgshapiro a->q_paddr == NULL ? "<null>" : a->q_paddr, 233690792Sgshapiro m->m_mno, m->m_name, 233790792Sgshapiro a->q_host == NULL ? "<null>" : a->q_host); 2338132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 233990792Sgshapiro "\tuser `%s', ruser `%s'\n", 234090792Sgshapiro a->q_user, 234190792Sgshapiro a->q_ruser == NULL ? "<null>" : a->q_ruser); 2342132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 234364562Sgshapiro switch (a->q_state) 234464562Sgshapiro { 234564562Sgshapiro case QS_OK: 2346132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 234764562Sgshapiro break; 234864562Sgshapiro 234964562Sgshapiro case QS_DONTSEND: 2350132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 235190792Sgshapiro "DONTSEND"); 235264562Sgshapiro break; 235364562Sgshapiro 235464562Sgshapiro case QS_BADADDR: 2355132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 235690792Sgshapiro "BADADDR"); 235764562Sgshapiro break; 235864562Sgshapiro 235964562Sgshapiro case QS_QUEUEUP: 2360132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 236190792Sgshapiro "QUEUEUP"); 236264562Sgshapiro break; 236364562Sgshapiro 236490792Sgshapiro case QS_RETRY: 2365132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 236690792Sgshapiro break; 236790792Sgshapiro 236864562Sgshapiro case QS_SENT: 2369132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 237064562Sgshapiro break; 237164562Sgshapiro 237264562Sgshapiro case QS_VERIFIED: 2373132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 237490792Sgshapiro "VERIFIED"); 237564562Sgshapiro break; 237664562Sgshapiro 237764562Sgshapiro case QS_EXPANDED: 2378132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 237990792Sgshapiro "EXPANDED"); 238064562Sgshapiro break; 238164562Sgshapiro 238264562Sgshapiro case QS_SENDER: 2383132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 238490792Sgshapiro "SENDER"); 238564562Sgshapiro break; 238664562Sgshapiro 238764562Sgshapiro case QS_CLONED: 2388132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 238990792Sgshapiro "CLONED"); 239064562Sgshapiro break; 239164562Sgshapiro 239264562Sgshapiro case QS_DISCARDED: 2393132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 239490792Sgshapiro "DISCARDED"); 239564562Sgshapiro break; 239664562Sgshapiro 239764562Sgshapiro case QS_REPLACED: 2398132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 239990792Sgshapiro "REPLACED"); 240064562Sgshapiro break; 240164562Sgshapiro 240264562Sgshapiro case QS_REMOVED: 2403132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240490792Sgshapiro "REMOVED"); 240564562Sgshapiro break; 240664562Sgshapiro 240764562Sgshapiro case QS_DUPLICATE: 2408132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240990792Sgshapiro "DUPLICATE"); 241064562Sgshapiro break; 241164562Sgshapiro 241264562Sgshapiro case QS_INCLUDED: 2413132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241490792Sgshapiro "INCLUDED"); 241564562Sgshapiro break; 241664562Sgshapiro 241764562Sgshapiro default: 2418132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241990792Sgshapiro "%d", a->q_state); 242064562Sgshapiro break; 242164562Sgshapiro } 2422132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 242390792Sgshapiro ", next=%p, alias %p, uid %d, gid %d\n", 242490792Sgshapiro a->q_next, a->q_alias, 242590792Sgshapiro (int) a->q_uid, (int) a->q_gid); 2426132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 242790792Sgshapiro a->q_flags); 242890792Sgshapiro firstone = true; 242938032Speter for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 243038032Speter { 243138032Speter if (!bitset(qfp->qf_bit, a->q_flags)) 243238032Speter continue; 243338032Speter if (!firstone) 2434132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 243590792Sgshapiro ","); 243690792Sgshapiro firstone = false; 2437132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 243890792Sgshapiro qfp->qf_name); 243938032Speter } 2440132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2441132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 244290792Sgshapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 244390792Sgshapiro a->q_owner == NULL ? "(none)" : a->q_owner, 244490792Sgshapiro a->q_home == NULL ? "(none)" : a->q_home, 244590792Sgshapiro a->q_fullname == NULL ? "(none)" : a->q_fullname); 2446132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 244790792Sgshapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 244890792Sgshapiro a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 244990792Sgshapiro a->q_statmta == NULL ? "(none)" : a->q_statmta, 245090792Sgshapiro a->q_status == NULL ? "(none)" : a->q_status); 2451132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 245290792Sgshapiro "\tfinalrcpt=\"%s\"\n", 245390792Sgshapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2454132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 245590792Sgshapiro "\trstatus=\"%s\"\n", 245690792Sgshapiro a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2457132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 245890792Sgshapiro "\tstatdate=%s\n", 245990792Sgshapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 246038032Speter 246138032Speter if (!follow) 246238032Speter return; 246338032Speter a = a->q_next; 246438032Speter } 246538032Speter} 246690792Sgshapiro/* 246790792Sgshapiro** EMPTYADDR -- return true if this address is empty (``<>'') 246838032Speter** 246938032Speter** Parameters: 247038032Speter** a -- pointer to the address 247138032Speter** 247238032Speter** Returns: 247390792Sgshapiro** true -- if this address is "empty" (i.e., no one should 247438032Speter** ever generate replies to it. 247590792Sgshapiro** false -- if it is a "regular" (read: replyable) address. 247638032Speter*/ 247738032Speter 247838032Speterbool 247938032Speteremptyaddr(a) 248038032Speter register ADDRESS *a; 248138032Speter{ 248238032Speter return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 248338032Speter a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 248438032Speter} 248590792Sgshapiro/* 248638032Speter** REMOTENAME -- return the name relative to the current mailer 248738032Speter** 248838032Speter** Parameters: 248938032Speter** name -- the name to translate. 2490120256Sgshapiro** m -- the mailer that we want to do rewriting relative to. 249138032Speter** flags -- fine tune operations. 249238032Speter** pstat -- pointer to status word. 249338032Speter** e -- the current envelope. 249438032Speter** 249538032Speter** Returns: 249638032Speter** the text string representing this address relative to 249738032Speter** the receiving mailer. 249838032Speter** 249938032Speter** Side Effects: 250038032Speter** none. 250138032Speter** 250238032Speter** Warnings: 250338032Speter** The text string returned is tucked away locally; 250438032Speter** copy it if you intend to save it. 250538032Speter*/ 250638032Speter 250738032Speterchar * 250838032Speterremotename(name, m, flags, pstat, e) 250938032Speter char *name; 251038032Speter struct mailer *m; 251138032Speter int flags; 251238032Speter int *pstat; 251338032Speter register ENVELOPE *e; 251438032Speter{ 251538032Speter register char **pvp; 251690792Sgshapiro char *SM_NONVOLATILE fancy; 251790792Sgshapiro char *oldg; 251838032Speter int rwset; 251938032Speter static char buf[MAXNAME + 1]; 252038032Speter char lbuf[MAXNAME + 1]; 252138032Speter char pvpbuf[PSBUFSIZE]; 252264562Sgshapiro char addrtype[4]; 252338032Speter 252438032Speter if (tTd(12, 1)) 252590792Sgshapiro sm_dprintf("remotename(%s)\n", name); 252638032Speter 252738032Speter /* don't do anything if we are tagging it as special */ 252838032Speter if (bitset(RF_SENDERADDR, flags)) 252964562Sgshapiro { 253038032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 253138032Speter : m->m_se_rwset; 253264562Sgshapiro addrtype[2] = 's'; 253364562Sgshapiro } 253438032Speter else 253564562Sgshapiro { 253638032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 253738032Speter : m->m_re_rwset; 253864562Sgshapiro addrtype[2] = 'r'; 253964562Sgshapiro } 254038032Speter if (rwset < 0) 254164562Sgshapiro return name; 254264562Sgshapiro addrtype[1] = ' '; 254364562Sgshapiro addrtype[3] = '\0'; 254464562Sgshapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 254590792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 254638032Speter 254738032Speter /* 254838032Speter ** Do a heuristic crack of this name to extract any comment info. 254938032Speter ** This will leave the name as a comment and a $g macro. 255038032Speter */ 255138032Speter 255238032Speter if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 255338032Speter fancy = "\201g"; 255438032Speter else 2555111823Sgshapiro fancy = crackaddr(name, e); 255638032Speter 255738032Speter /* 255838032Speter ** Turn the name into canonical form. 255938032Speter ** Normally this will be RFC 822 style, i.e., "user@domain". 256038032Speter ** If this only resolves to "user", and the "C" flag is 256138032Speter ** specified in the sending mailer, then the sender's 256238032Speter ** domain will be appended. 256338032Speter */ 256438032Speter 2565132943Sgshapiro pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 256638032Speter if (pvp == NULL) 256764562Sgshapiro return name; 256890792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 256938032Speter *pstat = EX_TEMPFAIL; 257038032Speter if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 257138032Speter { 257238032Speter /* append from domain to this address */ 257338032Speter register char **pxp = pvp; 257464562Sgshapiro int l = MAXATOM; /* size of buffer for pvp */ 257538032Speter 257638032Speter /* see if there is an "@domain" in the current name */ 257738032Speter while (*pxp != NULL && strcmp(*pxp, "@") != 0) 257864562Sgshapiro { 257938032Speter pxp++; 258064562Sgshapiro --l; 258164562Sgshapiro } 258238032Speter if (*pxp == NULL) 258338032Speter { 258438032Speter /* no.... append the "@domain" from the sender */ 258538032Speter register char **qxq = e->e_fromdomain; 258638032Speter 258738032Speter while ((*pxp++ = *qxq++) != NULL) 258864562Sgshapiro { 258964562Sgshapiro if (--l <= 0) 259064562Sgshapiro { 259164562Sgshapiro *--pxp = NULL; 259264562Sgshapiro usrerr("553 5.1.0 remotename: too many tokens"); 259364562Sgshapiro *pstat = EX_UNAVAILABLE; 259464562Sgshapiro break; 259564562Sgshapiro } 259664562Sgshapiro } 259790792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 259838032Speter *pstat = EX_TEMPFAIL; 259938032Speter } 260038032Speter } 260138032Speter 260238032Speter /* 260338032Speter ** Do more specific rewriting. 260438032Speter ** Rewrite using ruleset 1 or 2 depending on whether this is 260538032Speter ** a sender address or not. 260638032Speter ** Then run it through any receiving-mailer-specific rulesets. 260738032Speter */ 260838032Speter 260938032Speter if (bitset(RF_SENDERADDR, flags)) 261038032Speter { 261190792Sgshapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 261238032Speter *pstat = EX_TEMPFAIL; 261338032Speter } 261438032Speter else 261538032Speter { 261690792Sgshapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 261738032Speter *pstat = EX_TEMPFAIL; 261838032Speter } 261938032Speter if (rwset > 0) 262038032Speter { 262190792Sgshapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 262238032Speter *pstat = EX_TEMPFAIL; 262338032Speter } 262438032Speter 262538032Speter /* 262638032Speter ** Do any final sanitation the address may require. 262738032Speter ** This will normally be used to turn internal forms 262838032Speter ** (e.g., user@host.LOCAL) into external form. This 262938032Speter ** may be used as a default to the above rules. 263038032Speter */ 263138032Speter 263290792Sgshapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 263338032Speter *pstat = EX_TEMPFAIL; 263438032Speter 263538032Speter /* 263638032Speter ** Now restore the comment information we had at the beginning. 263738032Speter */ 263838032Speter 263938032Speter cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 264090792Sgshapiro oldg = macget(&e->e_macro, 'g'); 264190792Sgshapiro macset(&e->e_macro, 'g', lbuf); 264238032Speter 264390792Sgshapiro SM_TRY 264490792Sgshapiro /* need to make sure route-addrs have <angle brackets> */ 264590792Sgshapiro if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 264690792Sgshapiro expand("<\201g>", buf, sizeof buf, e); 264790792Sgshapiro else 264890792Sgshapiro expand(fancy, buf, sizeof buf, e); 264990792Sgshapiro SM_FINALLY 265090792Sgshapiro macset(&e->e_macro, 'g', oldg); 265190792Sgshapiro SM_END_TRY 265238032Speter 265338032Speter if (tTd(12, 1)) 265490792Sgshapiro sm_dprintf("remotename => `%s'\n", buf); 265564562Sgshapiro return buf; 265638032Speter} 265790792Sgshapiro/* 265838032Speter** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 265938032Speter** 266038032Speter** Parameters: 266138032Speter** a -- the address to map (but just the user name part). 266238032Speter** sendq -- the sendq in which to install any replacement 266338032Speter** addresses. 266438032Speter** aliaslevel -- the alias nesting depth. 266538032Speter** e -- the envelope. 266638032Speter** 266738032Speter** Returns: 266838032Speter** none. 266938032Speter*/ 267038032Speter 267138032Speter#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 267238032Speter Q_PINGFLAGS|QHASNOTIFY|\ 267390792Sgshapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 267490792Sgshapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 267538032Speter 267638032Spetervoid 267738032Spetermaplocaluser(a, sendq, aliaslevel, e) 267838032Speter register ADDRESS *a; 267938032Speter ADDRESS **sendq; 268038032Speter int aliaslevel; 268138032Speter ENVELOPE *e; 268238032Speter{ 268338032Speter register char **pvp; 268490792Sgshapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 268538032Speter char pvpbuf[PSBUFSIZE]; 268638032Speter 268738032Speter if (tTd(29, 1)) 268838032Speter { 268990792Sgshapiro sm_dprintf("maplocaluser: "); 2690132943Sgshapiro printaddr(sm_debug_file(), a, false); 269138032Speter } 2692132943Sgshapiro pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 269338032Speter if (pvp == NULL) 269438032Speter { 269538032Speter if (tTd(29, 9)) 269690792Sgshapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 269764562Sgshapiro a->q_user); 269838032Speter return; 269938032Speter } 270038032Speter 270190792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 270290792Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 270390792Sgshapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 270464562Sgshapiro 270590792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 270690792Sgshapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 270738032Speter { 270838032Speter if (tTd(29, 9)) 270990792Sgshapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 271064562Sgshapiro a->q_state = QS_QUEUEUP; 271138032Speter a->q_status = "4.4.3"; 271238032Speter return; 271338032Speter } 271438032Speter if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 271538032Speter { 271638032Speter if (tTd(29, 9)) 271790792Sgshapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 271838032Speter return; 271938032Speter } 272038032Speter 272190792Sgshapiro SM_TRY 272290792Sgshapiro a1 = buildaddr(pvp, NULL, 0, e); 272390792Sgshapiro SM_EXCEPT(exc, "E:mta.quickabort") 272490792Sgshapiro 272590792Sgshapiro /* 272690792Sgshapiro ** mark address as bad, S5 returned an error 272790792Sgshapiro ** and we gave that back to the SMTP client. 272890792Sgshapiro */ 272990792Sgshapiro 273090792Sgshapiro a->q_state = QS_DONTSEND; 273190792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 273290792Sgshapiro SM_END_TRY 273390792Sgshapiro 273438032Speter /* if non-null, mailer destination specified -- has it changed? */ 273538032Speter if (a1 == NULL || sameaddr(a, a1)) 273638032Speter { 273738032Speter if (tTd(29, 9)) 273890792Sgshapiro sm_dprintf("maplocaluser: address unchanged\n"); 273938032Speter return; 274038032Speter } 274138032Speter 274238032Speter /* make new address take on flags and print attributes of old */ 274338032Speter a1->q_flags &= ~Q_COPYFLAGS; 274438032Speter a1->q_flags |= a->q_flags & Q_COPYFLAGS; 274590792Sgshapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 274690792Sgshapiro a1->q_finalrcpt = a->q_finalrcpt; 274764562Sgshapiro a1->q_orcpt = a->q_orcpt; 274838032Speter 274938032Speter /* mark old address as dead; insert new address */ 275064562Sgshapiro a->q_state = QS_REPLACED; 275138032Speter if (tTd(29, 5)) 275238032Speter { 275390792Sgshapiro sm_dprintf("maplocaluser: QS_REPLACED "); 2754132943Sgshapiro printaddr(sm_debug_file(), a, false); 275538032Speter } 275638032Speter a1->q_alias = a; 275790792Sgshapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 275838032Speter (void) recipient(a1, sendq, aliaslevel, e); 275938032Speter} 276090792Sgshapiro/* 276138032Speter** DEQUOTE_INIT -- initialize dequote map 276238032Speter** 276338032Speter** Parameters: 276438032Speter** map -- the internal map structure. 276538032Speter** args -- arguments. 276638032Speter** 276738032Speter** Returns: 276890792Sgshapiro** true. 276938032Speter*/ 277038032Speter 277138032Speterbool 277238032Speterdequote_init(map, args) 277338032Speter MAP *map; 277438032Speter char *args; 277538032Speter{ 277638032Speter register char *p = args; 277738032Speter 277864562Sgshapiro /* there is no check whether there is really an argument */ 277938032Speter map->map_mflags |= MF_KEEPQUOTES; 278038032Speter for (;;) 278138032Speter { 278238032Speter while (isascii(*p) && isspace(*p)) 278338032Speter p++; 278438032Speter if (*p != '-') 278538032Speter break; 278638032Speter switch (*++p) 278738032Speter { 278838032Speter case 'a': 278938032Speter map->map_app = ++p; 279038032Speter break; 279138032Speter 279264562Sgshapiro case 'D': 279364562Sgshapiro map->map_mflags |= MF_DEFER; 279464562Sgshapiro break; 279564562Sgshapiro 279664562Sgshapiro case 'S': 279738032Speter case 's': 279864562Sgshapiro map->map_spacesub = *++p; 279938032Speter break; 280038032Speter } 280138032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 280238032Speter p++; 280338032Speter if (*p != '\0') 280438032Speter *p = '\0'; 280538032Speter } 280638032Speter if (map->map_app != NULL) 280738032Speter map->map_app = newstr(map->map_app); 280838032Speter 280990792Sgshapiro return true; 281038032Speter} 281190792Sgshapiro/* 281238032Speter** DEQUOTE_MAP -- unquote an address 281338032Speter** 281438032Speter** Parameters: 281538032Speter** map -- the internal map structure (ignored). 281638032Speter** name -- the name to dequote. 281738032Speter** av -- arguments (ignored). 281838032Speter** statp -- pointer to status out-parameter. 281938032Speter** 282038032Speter** Returns: 282138032Speter** NULL -- if there were no quotes, or if the resulting 282238032Speter** unquoted buffer would not be acceptable to prescan. 282338032Speter** else -- The dequoted buffer. 282438032Speter*/ 282538032Speter 282638032Speter/* ARGSUSED2 */ 282738032Speterchar * 282838032Speterdequote_map(map, name, av, statp) 282938032Speter MAP *map; 283038032Speter char *name; 283138032Speter char **av; 283238032Speter int *statp; 283338032Speter{ 283438032Speter register char *p; 283538032Speter register char *q; 283638032Speter register char c; 283738032Speter int anglecnt = 0; 283838032Speter int cmntcnt = 0; 283938032Speter int quotecnt = 0; 284038032Speter int spacecnt = 0; 284190792Sgshapiro bool quotemode = false; 284290792Sgshapiro bool bslashmode = false; 284364562Sgshapiro char spacesub = map->map_spacesub; 284438032Speter 284538032Speter for (p = q = name; (c = *p++) != '\0'; ) 284638032Speter { 284738032Speter if (bslashmode) 284838032Speter { 284990792Sgshapiro bslashmode = false; 285038032Speter *q++ = c; 285138032Speter continue; 285238032Speter } 285338032Speter 285438032Speter if (c == ' ' && spacesub != '\0') 285538032Speter c = spacesub; 285638032Speter 285738032Speter switch (c) 285838032Speter { 285938032Speter case '\\': 286090792Sgshapiro bslashmode = true; 286138032Speter break; 286238032Speter 286338032Speter case '(': 286438032Speter cmntcnt++; 286538032Speter break; 286638032Speter 286738032Speter case ')': 286838032Speter if (cmntcnt-- <= 0) 286938032Speter return NULL; 287038032Speter break; 287138032Speter 287238032Speter case ' ': 287364562Sgshapiro case '\t': 287438032Speter spacecnt++; 287538032Speter break; 287638032Speter } 287738032Speter 287838032Speter if (cmntcnt > 0) 287938032Speter { 288038032Speter *q++ = c; 288138032Speter continue; 288238032Speter } 288338032Speter 288438032Speter switch (c) 288538032Speter { 288638032Speter case '"': 288738032Speter quotemode = !quotemode; 288838032Speter quotecnt++; 288938032Speter continue; 289038032Speter 289138032Speter case '<': 289238032Speter anglecnt++; 289338032Speter break; 289438032Speter 289538032Speter case '>': 289638032Speter if (anglecnt-- <= 0) 289738032Speter return NULL; 289838032Speter break; 289938032Speter } 290038032Speter *q++ = c; 290138032Speter } 290238032Speter 290338032Speter if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 290438032Speter quotemode || quotecnt <= 0 || spacecnt != 0) 290538032Speter return NULL; 290638032Speter *q++ = '\0'; 290738032Speter return map_rewrite(map, name, strlen(name), NULL); 290838032Speter} 290990792Sgshapiro/* 291038032Speter** RSCHECK -- check string(s) for validity using rewriting sets 291138032Speter** 291238032Speter** Parameters: 291338032Speter** rwset -- the rewriting set to use. 291438032Speter** p1 -- the first string to check. 291538032Speter** p2 -- the second string to check -- may be null. 291638032Speter** e -- the current envelope. 2917102528Sgshapiro** flags -- control some behavior, see RSF_ in sendmail.h 291890792Sgshapiro** logl -- logging level. 291971345Sgshapiro** host -- NULL or relay host. 292090792Sgshapiro** logid -- id for sm_syslog. 292138032Speter** 292238032Speter** Returns: 292338032Speter** EX_OK -- if the rwset doesn't resolve to $#error 292438032Speter** else -- the failure status (message printed) 292538032Speter*/ 292638032Speter 292738032Speterint 2928102528Sgshapirorscheck(rwset, p1, p2, e, flags, logl, host, logid) 292938032Speter char *rwset; 293038032Speter char *p1; 293138032Speter char *p2; 293238032Speter ENVELOPE *e; 2933102528Sgshapiro int flags; 293464562Sgshapiro int logl; 293571345Sgshapiro char *host; 293690792Sgshapiro char *logid; 293738032Speter{ 293890792Sgshapiro char *volatile buf; 293938032Speter int bufsize; 294038032Speter int saveexitstat; 294190792Sgshapiro int volatile rstat = EX_OK; 294238032Speter char **pvp; 294338032Speter int rsno; 294490792Sgshapiro bool volatile discard = false; 294538032Speter auto ADDRESS a1; 294638032Speter bool saveQuickAbort = QuickAbort; 294738032Speter bool saveSuprErrs = SuprErrs; 294890792Sgshapiro bool quarantine = false; 294990792Sgshapiro char ubuf[BUFSIZ * 2]; 295038032Speter char buf0[MAXLINE]; 295138032Speter char pvpbuf[PSBUFSIZE]; 295238032Speter extern char MsgBuf[]; 295338032Speter 295438032Speter if (tTd(48, 2)) 295590792Sgshapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 295638032Speter p2 == NULL ? "(NULL)" : p2); 295738032Speter 295838032Speter rsno = strtorwset(rwset, NULL, ST_FIND); 295938032Speter if (rsno < 0) 296038032Speter return EX_OK; 296138032Speter 296238032Speter if (p2 != NULL) 296338032Speter { 296438032Speter bufsize = strlen(p1) + strlen(p2) + 2; 296538032Speter if (bufsize > sizeof buf0) 296690792Sgshapiro buf = sm_malloc_x(bufsize); 296738032Speter else 296838032Speter { 296938032Speter buf = buf0; 297038032Speter bufsize = sizeof buf0; 297138032Speter } 297290792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 297338032Speter } 297438032Speter else 297538032Speter { 297638032Speter bufsize = strlen(p1) + 1; 297738032Speter if (bufsize > sizeof buf0) 297890792Sgshapiro buf = sm_malloc_x(bufsize); 297938032Speter else 298038032Speter { 298138032Speter buf = buf0; 298238032Speter bufsize = sizeof buf0; 298338032Speter } 298490792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 298538032Speter } 298690792Sgshapiro SM_TRY 298738032Speter { 298890792Sgshapiro SuprErrs = true; 298990792Sgshapiro QuickAbort = false; 299090792Sgshapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 2991132943Sgshapiro bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, 2992132943Sgshapiro bitset(RSF_RMCOMM, flags) ? false : true); 299390792Sgshapiro SuprErrs = saveSuprErrs; 299490792Sgshapiro if (pvp == NULL) 299590792Sgshapiro { 299690792Sgshapiro if (tTd(48, 2)) 299790792Sgshapiro sm_dprintf("rscheck: cannot prescan input\n"); 299890792Sgshapiro /* 299990792Sgshapiro syserr("rscheck: cannot prescan input: \"%s\"", 300090792Sgshapiro shortenstring(buf, MAXSHORTSTR)); 300190792Sgshapiro rstat = EX_DATAERR; 300290792Sgshapiro */ 300390792Sgshapiro goto finis; 300490792Sgshapiro } 3005102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3006102528Sgshapiro SuprErrs = true; 300790792Sgshapiro (void) REWRITE(pvp, rsno, e); 3008102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3009102528Sgshapiro SuprErrs = saveSuprErrs; 301090792Sgshapiro if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 301190792Sgshapiro pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 301290792Sgshapiro strcmp(pvp[1], "discard") != 0)) 301390792Sgshapiro { 301490792Sgshapiro goto finis; 301590792Sgshapiro } 301666494Sgshapiro 301790792Sgshapiro if (strcmp(pvp[1], "discard") == 0) 301890792Sgshapiro { 301990792Sgshapiro if (tTd(48, 2)) 302090792Sgshapiro sm_dprintf("rscheck: discard mailer selected\n"); 302190792Sgshapiro e->e_flags |= EF_DISCARD; 302290792Sgshapiro discard = true; 302390792Sgshapiro } 302490792Sgshapiro else if (strcmp(pvp[1], "error") == 0 && 302590792Sgshapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 302690792Sgshapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 302790792Sgshapiro { 302890792Sgshapiro if (pvp[4] == NULL || 302990792Sgshapiro (pvp[4][0] & 0377) != CANONUSER || 303090792Sgshapiro pvp[5] == NULL) 303190792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 303290792Sgshapiro rwset); 303390792Sgshapiro else 303490792Sgshapiro { 303590792Sgshapiro cataddr(&(pvp[5]), NULL, ubuf, 303690792Sgshapiro sizeof ubuf, ' '); 303790792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 303890792Sgshapiro ubuf); 303990792Sgshapiro } 304090792Sgshapiro macdefine(&e->e_macro, A_PERM, 304190792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 304290792Sgshapiro quarantine = true; 304390792Sgshapiro } 304490792Sgshapiro else 304590792Sgshapiro { 304690792Sgshapiro int savelogusrerrs = LogUsrErrs; 304790792Sgshapiro static bool logged = false; 304890792Sgshapiro 304990792Sgshapiro /* got an error -- process it */ 305090792Sgshapiro saveexitstat = ExitStat; 305190792Sgshapiro LogUsrErrs = false; 305290792Sgshapiro (void) buildaddr(pvp, &a1, 0, e); 305390792Sgshapiro LogUsrErrs = savelogusrerrs; 305490792Sgshapiro rstat = ExitStat; 305590792Sgshapiro ExitStat = saveexitstat; 305690792Sgshapiro if (!logged) 305790792Sgshapiro { 3058102528Sgshapiro if (bitset(RSF_COUNT, flags)) 305990792Sgshapiro markstats(e, &a1, STATS_REJECT); 306090792Sgshapiro logged = true; 306190792Sgshapiro } 306290792Sgshapiro } 306390792Sgshapiro 306490792Sgshapiro if (LogLevel > logl) 306590792Sgshapiro { 306690792Sgshapiro char *relay; 306790792Sgshapiro char *p; 306890792Sgshapiro char lbuf[MAXLINE]; 306990792Sgshapiro 307090792Sgshapiro p = lbuf; 307190792Sgshapiro if (p2 != NULL) 307290792Sgshapiro { 307390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 307490792Sgshapiro ", arg2=%s", 307590792Sgshapiro p2); 307690792Sgshapiro p += strlen(p); 307790792Sgshapiro } 307890792Sgshapiro 307990792Sgshapiro if (host != NULL) 308090792Sgshapiro relay = host; 308190792Sgshapiro else 308290792Sgshapiro relay = macvalue('_', e); 308390792Sgshapiro if (relay != NULL) 308490792Sgshapiro { 308590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 308690792Sgshapiro ", relay=%s", relay); 308790792Sgshapiro p += strlen(p); 308890792Sgshapiro } 308990792Sgshapiro *p = '\0'; 309090792Sgshapiro if (discard) 309190792Sgshapiro sm_syslog(LOG_NOTICE, logid, 309290792Sgshapiro "ruleset=%s, arg1=%s%s, discard", 309390792Sgshapiro rwset, p1, lbuf); 309490792Sgshapiro else if (quarantine) 309590792Sgshapiro sm_syslog(LOG_NOTICE, logid, 309690792Sgshapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 309790792Sgshapiro rwset, p1, lbuf, ubuf); 309890792Sgshapiro else 309990792Sgshapiro sm_syslog(LOG_NOTICE, logid, 310090792Sgshapiro "ruleset=%s, arg1=%s%s, reject=%s", 310190792Sgshapiro rwset, p1, lbuf, MsgBuf); 310290792Sgshapiro } 310390792Sgshapiro 310490792Sgshapiro finis: ; 310573188Sgshapiro } 310690792Sgshapiro SM_FINALLY 310738032Speter { 310890792Sgshapiro /* clean up */ 310990792Sgshapiro if (buf != buf0) 311090792Sgshapiro sm_free(buf); 311190792Sgshapiro QuickAbort = saveQuickAbort; 311238032Speter } 311390792Sgshapiro SM_END_TRY 311438032Speter 311590792Sgshapiro setstat(rstat); 311690792Sgshapiro 311790792Sgshapiro /* rulesets don't set errno */ 311890792Sgshapiro errno = 0; 311990792Sgshapiro if (rstat != EX_OK && QuickAbort) 312090792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 312190792Sgshapiro return rstat; 312290792Sgshapiro} 312390792Sgshapiro/* 312490792Sgshapiro** RSCAP -- call rewriting set to return capabilities 312590792Sgshapiro** 312690792Sgshapiro** Parameters: 312790792Sgshapiro** rwset -- the rewriting set to use. 312890792Sgshapiro** p1 -- the first string to check. 312990792Sgshapiro** p2 -- the second string to check -- may be null. 313090792Sgshapiro** e -- the current envelope. 313190792Sgshapiro** pvp -- pointer to token vector. 313290792Sgshapiro** pvpbuf -- buffer space. 3133120256Sgshapiro** size -- size of buffer space. 313490792Sgshapiro** 313590792Sgshapiro** Returns: 313690792Sgshapiro** EX_UNAVAILABLE -- ruleset doesn't exist. 313790792Sgshapiro** EX_DATAERR -- prescan() failed. 313890792Sgshapiro** EX_OK -- rewrite() was successful. 313990792Sgshapiro** else -- return status from rewrite(). 314090792Sgshapiro*/ 314190792Sgshapiro 314290792Sgshapiroint 314390792Sgshapirorscap(rwset, p1, p2, e, pvp, pvpbuf, size) 314490792Sgshapiro char *rwset; 314590792Sgshapiro char *p1; 314690792Sgshapiro char *p2; 314790792Sgshapiro ENVELOPE *e; 314890792Sgshapiro char ***pvp; 314990792Sgshapiro char *pvpbuf; 315090792Sgshapiro int size; 315190792Sgshapiro{ 315290792Sgshapiro char *volatile buf; 315390792Sgshapiro int bufsize; 315490792Sgshapiro int volatile rstat = EX_OK; 315590792Sgshapiro int rsno; 315690792Sgshapiro bool saveQuickAbort = QuickAbort; 315790792Sgshapiro bool saveSuprErrs = SuprErrs; 315890792Sgshapiro char buf0[MAXLINE]; 315990792Sgshapiro extern char MsgBuf[]; 316090792Sgshapiro 316190792Sgshapiro if (tTd(48, 2)) 316290792Sgshapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 316390792Sgshapiro p2 == NULL ? "(NULL)" : p2); 316490792Sgshapiro 316590792Sgshapiro if (pvp != NULL) 316690792Sgshapiro *pvp = NULL; 316790792Sgshapiro rsno = strtorwset(rwset, NULL, ST_FIND); 316890792Sgshapiro if (rsno < 0) 316990792Sgshapiro return EX_UNAVAILABLE; 317090792Sgshapiro 317190792Sgshapiro if (p2 != NULL) 317238032Speter { 317390792Sgshapiro bufsize = strlen(p1) + strlen(p2) + 2; 317490792Sgshapiro if (bufsize > sizeof buf0) 317590792Sgshapiro buf = sm_malloc_x(bufsize); 317690792Sgshapiro else 317790792Sgshapiro { 317890792Sgshapiro buf = buf0; 317990792Sgshapiro bufsize = sizeof buf0; 318090792Sgshapiro } 318190792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 318238032Speter } 318364562Sgshapiro else 318438032Speter { 318590792Sgshapiro bufsize = strlen(p1) + 1; 318690792Sgshapiro if (bufsize > sizeof buf0) 318790792Sgshapiro buf = sm_malloc_x(bufsize); 318890792Sgshapiro else 318938032Speter { 319090792Sgshapiro buf = buf0; 319190792Sgshapiro bufsize = sizeof buf0; 319238032Speter } 319390792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 319438032Speter } 319590792Sgshapiro SM_TRY 319638032Speter { 319790792Sgshapiro SuprErrs = true; 319890792Sgshapiro QuickAbort = false; 3199132943Sgshapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); 320090792Sgshapiro if (*pvp != NULL) 3201120256Sgshapiro rstat = rewrite(*pvp, rsno, 0, e, size); 320271345Sgshapiro else 320338032Speter { 320490792Sgshapiro if (tTd(48, 2)) 320590792Sgshapiro sm_dprintf("rscap: cannot prescan input\n"); 320690792Sgshapiro rstat = EX_DATAERR; 320738032Speter } 320838032Speter } 320990792Sgshapiro SM_FINALLY 321090792Sgshapiro { 321190792Sgshapiro /* clean up */ 321290792Sgshapiro if (buf != buf0) 321390792Sgshapiro sm_free(buf); 321490792Sgshapiro SuprErrs = saveSuprErrs; 321590792Sgshapiro QuickAbort = saveQuickAbort; 321638032Speter 321790792Sgshapiro /* prevent information leak, this may contain rewrite error */ 321890792Sgshapiro MsgBuf[0] = '\0'; 321990792Sgshapiro } 322090792Sgshapiro SM_END_TRY 322138032Speter return rstat; 322238032Speter} 3223