1c2aa98e2SPeter Wemm /* 206f25ae9SGregory Neil Shapiro * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 14c2aa98e2SPeter Wemm #ifndef lint 1506f25ae9SGregory Neil Shapiro static char id[] = "@(#)$Id: parseaddr.c,v 8.234.4.1 2000/05/25 18:56:16 gshapiro Exp $"; 1606f25ae9SGregory Neil Shapiro #endif /* ! lint */ 17c2aa98e2SPeter Wemm 1806f25ae9SGregory Neil Shapiro #include <sendmail.h> 1906f25ae9SGregory Neil Shapiro 2006f25ae9SGregory Neil Shapiro static void allocaddr __P((ADDRESS *, int, char *)); 2106f25ae9SGregory Neil Shapiro static int callsubr __P((char**, int, ENVELOPE *)); 2206f25ae9SGregory Neil Shapiro static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2306f25ae9SGregory Neil Shapiro static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 24c2aa98e2SPeter Wemm 25c2aa98e2SPeter Wemm /* 26c2aa98e2SPeter Wemm ** PARSEADDR -- Parse an address 27c2aa98e2SPeter Wemm ** 28c2aa98e2SPeter Wemm ** Parses an address and breaks it up into three parts: a 29c2aa98e2SPeter Wemm ** net to transmit the message on, the host to transmit it 30c2aa98e2SPeter Wemm ** to, and a user on that host. These are loaded into an 31c2aa98e2SPeter Wemm ** ADDRESS header with the values squirreled away if necessary. 32c2aa98e2SPeter Wemm ** The "user" part may not be a real user; the process may 33c2aa98e2SPeter Wemm ** just reoccur on that machine. For example, on a machine 34c2aa98e2SPeter Wemm ** with an arpanet connection, the address 35c2aa98e2SPeter Wemm ** csvax.bill@berkeley 36c2aa98e2SPeter Wemm ** will break up to a "user" of 'csvax.bill' and a host 37c2aa98e2SPeter Wemm ** of 'berkeley' -- to be transmitted over the arpanet. 38c2aa98e2SPeter Wemm ** 39c2aa98e2SPeter Wemm ** Parameters: 40c2aa98e2SPeter Wemm ** addr -- the address to parse. 41c2aa98e2SPeter Wemm ** a -- a pointer to the address descriptor buffer. 42c2aa98e2SPeter Wemm ** If NULL, a header will be created. 43c2aa98e2SPeter Wemm ** flags -- describe detail for parsing. See RF_ definitions 44c2aa98e2SPeter Wemm ** in sendmail.h. 45c2aa98e2SPeter Wemm ** delim -- the character to terminate the address, passed 46c2aa98e2SPeter Wemm ** to prescan. 47c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 48c2aa98e2SPeter Wemm ** delim character that was found. 49c2aa98e2SPeter Wemm ** e -- the envelope that will contain this address. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** Returns: 52c2aa98e2SPeter Wemm ** A pointer to the address descriptor header (`a' if 53c2aa98e2SPeter Wemm ** `a' is non-NULL). 54c2aa98e2SPeter Wemm ** NULL on error. 55c2aa98e2SPeter Wemm ** 56c2aa98e2SPeter Wemm ** Side Effects: 57c2aa98e2SPeter Wemm ** none 58c2aa98e2SPeter Wemm */ 59c2aa98e2SPeter Wemm 60c2aa98e2SPeter Wemm /* following delimiters are inherent to the internal algorithms */ 61c2aa98e2SPeter Wemm #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 62c2aa98e2SPeter Wemm 63c2aa98e2SPeter Wemm ADDRESS * 64c2aa98e2SPeter Wemm parseaddr(addr, a, flags, delim, delimptr, e) 65c2aa98e2SPeter Wemm char *addr; 66c2aa98e2SPeter Wemm register ADDRESS *a; 67c2aa98e2SPeter Wemm int flags; 68c2aa98e2SPeter Wemm int delim; 69c2aa98e2SPeter Wemm char **delimptr; 70c2aa98e2SPeter Wemm register ENVELOPE *e; 71c2aa98e2SPeter Wemm { 72c2aa98e2SPeter Wemm register char **pvp; 73c2aa98e2SPeter Wemm auto char *delimptrbuf; 7406f25ae9SGregory Neil Shapiro bool qup; 75c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 76c2aa98e2SPeter Wemm 77c2aa98e2SPeter Wemm /* 78c2aa98e2SPeter Wemm ** Initialize and prescan address. 79c2aa98e2SPeter Wemm */ 80c2aa98e2SPeter Wemm 81c2aa98e2SPeter Wemm e->e_to = addr; 82c2aa98e2SPeter Wemm if (tTd(20, 1)) 8306f25ae9SGregory Neil Shapiro dprintf("\n--parseaddr(%s)\n", addr); 84c2aa98e2SPeter Wemm 85c2aa98e2SPeter Wemm if (delimptr == NULL) 86c2aa98e2SPeter Wemm delimptr = &delimptrbuf; 87c2aa98e2SPeter Wemm 88c2aa98e2SPeter Wemm pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 89c2aa98e2SPeter Wemm if (pvp == NULL) 90c2aa98e2SPeter Wemm { 91c2aa98e2SPeter Wemm if (tTd(20, 1)) 9206f25ae9SGregory Neil Shapiro dprintf("parseaddr-->NULL\n"); 9306f25ae9SGregory Neil Shapiro return NULL; 94c2aa98e2SPeter Wemm } 95c2aa98e2SPeter Wemm 96c2aa98e2SPeter Wemm if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 97c2aa98e2SPeter Wemm { 98c2aa98e2SPeter Wemm if (tTd(20, 1)) 9906f25ae9SGregory Neil Shapiro dprintf("parseaddr-->bad address\n"); 100c2aa98e2SPeter Wemm return NULL; 101c2aa98e2SPeter Wemm } 102c2aa98e2SPeter Wemm 103c2aa98e2SPeter Wemm /* 104c2aa98e2SPeter Wemm ** Save addr if we are going to have to. 105c2aa98e2SPeter Wemm ** 106c2aa98e2SPeter Wemm ** We have to do this early because there is a chance that 107c2aa98e2SPeter Wemm ** the map lookups in the rewriting rules could clobber 108c2aa98e2SPeter Wemm ** static memory somewhere. 109c2aa98e2SPeter Wemm */ 110c2aa98e2SPeter Wemm 111c2aa98e2SPeter Wemm if (bitset(RF_COPYPADDR, flags) && addr != NULL) 112c2aa98e2SPeter Wemm { 113c2aa98e2SPeter Wemm char savec = **delimptr; 114c2aa98e2SPeter Wemm 115c2aa98e2SPeter Wemm if (savec != '\0') 116c2aa98e2SPeter Wemm **delimptr = '\0'; 117c2aa98e2SPeter Wemm e->e_to = addr = newstr(addr); 118c2aa98e2SPeter Wemm if (savec != '\0') 119c2aa98e2SPeter Wemm **delimptr = savec; 120c2aa98e2SPeter Wemm } 121c2aa98e2SPeter Wemm 122c2aa98e2SPeter Wemm /* 123c2aa98e2SPeter Wemm ** Apply rewriting rules. 124c2aa98e2SPeter Wemm ** Ruleset 0 does basic parsing. It must resolve. 125c2aa98e2SPeter Wemm */ 126c2aa98e2SPeter Wemm 12706f25ae9SGregory Neil Shapiro qup = FALSE; 128c2aa98e2SPeter Wemm if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 12906f25ae9SGregory Neil Shapiro qup = TRUE; 130c2aa98e2SPeter Wemm if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 13106f25ae9SGregory Neil Shapiro qup = TRUE; 132c2aa98e2SPeter Wemm 133c2aa98e2SPeter Wemm 134c2aa98e2SPeter Wemm /* 135c2aa98e2SPeter Wemm ** Build canonical address from pvp. 136c2aa98e2SPeter Wemm */ 137c2aa98e2SPeter Wemm 138c2aa98e2SPeter Wemm a = buildaddr(pvp, a, flags, e); 139c2aa98e2SPeter Wemm 140c2aa98e2SPeter Wemm /* 141c2aa98e2SPeter Wemm ** Make local copies of the host & user and then 142c2aa98e2SPeter Wemm ** transport them out. 143c2aa98e2SPeter Wemm */ 144c2aa98e2SPeter Wemm 145c2aa98e2SPeter Wemm allocaddr(a, flags, addr); 14606f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(a->q_state)) 147c2aa98e2SPeter Wemm return a; 148c2aa98e2SPeter Wemm 149c2aa98e2SPeter Wemm /* 150c2aa98e2SPeter Wemm ** If there was a parsing failure, mark it for queueing. 151c2aa98e2SPeter Wemm */ 152c2aa98e2SPeter Wemm 15306f25ae9SGregory Neil Shapiro if (qup && OpMode != MD_INITALIAS) 154c2aa98e2SPeter Wemm { 155c2aa98e2SPeter Wemm char *msg = "Transient parse error -- message queued for future delivery"; 156c2aa98e2SPeter Wemm 157c2aa98e2SPeter Wemm if (e->e_sendmode == SM_DEFER) 158c2aa98e2SPeter Wemm msg = "Deferring message until queue run"; 159c2aa98e2SPeter Wemm if (tTd(20, 1)) 16006f25ae9SGregory Neil Shapiro dprintf("parseaddr: queuing message\n"); 161c2aa98e2SPeter Wemm message(msg); 162c2aa98e2SPeter Wemm if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 163c2aa98e2SPeter Wemm e->e_message = newstr(msg); 16406f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 165c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 166c2aa98e2SPeter Wemm } 167c2aa98e2SPeter Wemm 168c2aa98e2SPeter Wemm /* 169c2aa98e2SPeter Wemm ** Compute return value. 170c2aa98e2SPeter Wemm */ 171c2aa98e2SPeter Wemm 172c2aa98e2SPeter Wemm if (tTd(20, 1)) 173c2aa98e2SPeter Wemm { 17406f25ae9SGregory Neil Shapiro dprintf("parseaddr-->"); 175c2aa98e2SPeter Wemm printaddr(a, FALSE); 176c2aa98e2SPeter Wemm } 177c2aa98e2SPeter Wemm 17806f25ae9SGregory Neil Shapiro return a; 179c2aa98e2SPeter Wemm } 180c2aa98e2SPeter Wemm /* 181c2aa98e2SPeter Wemm ** INVALIDADDR -- check for address containing meta-characters 182c2aa98e2SPeter Wemm ** 183c2aa98e2SPeter Wemm ** Parameters: 184c2aa98e2SPeter Wemm ** addr -- the address to check. 185c2aa98e2SPeter Wemm ** 186c2aa98e2SPeter Wemm ** Returns: 187c2aa98e2SPeter Wemm ** TRUE -- if the address has any "wierd" characters 188c2aa98e2SPeter Wemm ** FALSE -- otherwise. 189c2aa98e2SPeter Wemm */ 190c2aa98e2SPeter Wemm 191c2aa98e2SPeter Wemm bool 192c2aa98e2SPeter Wemm invalidaddr(addr, delimptr) 193c2aa98e2SPeter Wemm register char *addr; 194c2aa98e2SPeter Wemm char *delimptr; 195c2aa98e2SPeter Wemm { 196c2aa98e2SPeter Wemm char savedelim = '\0'; 197c2aa98e2SPeter Wemm 198c2aa98e2SPeter Wemm if (delimptr != NULL) 199c2aa98e2SPeter Wemm { 200c2aa98e2SPeter Wemm savedelim = *delimptr; 201c2aa98e2SPeter Wemm if (savedelim != '\0') 202c2aa98e2SPeter Wemm *delimptr = '\0'; 203c2aa98e2SPeter Wemm } 20406f25ae9SGregory Neil Shapiro if (strlen(addr) > MAXNAME - 1) 205c2aa98e2SPeter Wemm { 20606f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address too long (%d bytes max)", 20706f25ae9SGregory Neil Shapiro MAXNAME - 1); 208c2aa98e2SPeter Wemm goto failure; 209c2aa98e2SPeter Wemm } 210c2aa98e2SPeter Wemm for (; *addr != '\0'; addr++) 211c2aa98e2SPeter Wemm { 212c2aa98e2SPeter Wemm if ((*addr & 0340) == 0200) 213c2aa98e2SPeter Wemm break; 214c2aa98e2SPeter Wemm } 215c2aa98e2SPeter Wemm if (*addr == '\0') 216c2aa98e2SPeter Wemm { 217c2aa98e2SPeter Wemm if (delimptr != NULL && savedelim != '\0') 218c2aa98e2SPeter Wemm *delimptr = savedelim; 219c2aa98e2SPeter Wemm return FALSE; 220c2aa98e2SPeter Wemm } 221c2aa98e2SPeter Wemm setstat(EX_USAGE); 22206f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address contained invalid control characters"); 223c2aa98e2SPeter Wemm failure: 224c2aa98e2SPeter Wemm if (delimptr != NULL && savedelim != '\0') 225c2aa98e2SPeter Wemm *delimptr = savedelim; 226c2aa98e2SPeter Wemm return TRUE; 227c2aa98e2SPeter Wemm } 228c2aa98e2SPeter Wemm /* 229c2aa98e2SPeter Wemm ** ALLOCADDR -- do local allocations of address on demand. 230c2aa98e2SPeter Wemm ** 231c2aa98e2SPeter Wemm ** Also lowercases the host name if requested. 232c2aa98e2SPeter Wemm ** 233c2aa98e2SPeter Wemm ** Parameters: 234c2aa98e2SPeter Wemm ** a -- the address to reallocate. 235c2aa98e2SPeter Wemm ** flags -- the copy flag (see RF_ definitions in sendmail.h 236c2aa98e2SPeter Wemm ** for a description). 237c2aa98e2SPeter Wemm ** paddr -- the printname of the address. 238c2aa98e2SPeter Wemm ** 239c2aa98e2SPeter Wemm ** Returns: 240c2aa98e2SPeter Wemm ** none. 241c2aa98e2SPeter Wemm ** 242c2aa98e2SPeter Wemm ** Side Effects: 243c2aa98e2SPeter Wemm ** Copies portions of a into local buffers as requested. 244c2aa98e2SPeter Wemm */ 245c2aa98e2SPeter Wemm 24606f25ae9SGregory Neil Shapiro static void 247c2aa98e2SPeter Wemm allocaddr(a, flags, paddr) 248c2aa98e2SPeter Wemm register ADDRESS *a; 249c2aa98e2SPeter Wemm int flags; 250c2aa98e2SPeter Wemm char *paddr; 251c2aa98e2SPeter Wemm { 252c2aa98e2SPeter Wemm if (tTd(24, 4)) 25306f25ae9SGregory Neil Shapiro dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 254c2aa98e2SPeter Wemm 255c2aa98e2SPeter Wemm a->q_paddr = paddr; 256c2aa98e2SPeter Wemm 257c2aa98e2SPeter Wemm if (a->q_user == NULL) 25806f25ae9SGregory Neil Shapiro a->q_user = newstr(""); 259c2aa98e2SPeter Wemm if (a->q_host == NULL) 26006f25ae9SGregory Neil Shapiro a->q_host = newstr(""); 261c2aa98e2SPeter Wemm 262c2aa98e2SPeter Wemm if (bitset(RF_COPYPARSE, flags)) 263c2aa98e2SPeter Wemm { 264c2aa98e2SPeter Wemm a->q_host = newstr(a->q_host); 265c2aa98e2SPeter Wemm if (a->q_user != a->q_paddr) 266c2aa98e2SPeter Wemm a->q_user = newstr(a->q_user); 267c2aa98e2SPeter Wemm } 268c2aa98e2SPeter Wemm 269c2aa98e2SPeter Wemm if (a->q_paddr == NULL) 27006f25ae9SGregory Neil Shapiro a->q_paddr = newstr(a->q_user); 271c2aa98e2SPeter Wemm } 272c2aa98e2SPeter Wemm /* 273c2aa98e2SPeter Wemm ** PRESCAN -- Prescan name and make it canonical 274c2aa98e2SPeter Wemm ** 275c2aa98e2SPeter Wemm ** Scans a name and turns it into a set of tokens. This process 27606f25ae9SGregory Neil Shapiro ** deletes blanks and comments (in parentheses) (if the token type 27706f25ae9SGregory Neil Shapiro ** for left paren is SPC). 278c2aa98e2SPeter Wemm ** 279c2aa98e2SPeter Wemm ** This routine knows about quoted strings and angle brackets. 280c2aa98e2SPeter Wemm ** 281c2aa98e2SPeter Wemm ** There are certain subtleties to this routine. The one that 282c2aa98e2SPeter Wemm ** comes to mind now is that backslashes on the ends of names 283c2aa98e2SPeter Wemm ** are silently stripped off; this is intentional. The problem 284c2aa98e2SPeter Wemm ** is that some versions of sndmsg (like at LBL) set the kill 285c2aa98e2SPeter Wemm ** character to something other than @ when reading addresses; 286c2aa98e2SPeter Wemm ** so people type "csvax.eric\@berkeley" -- which screws up the 287c2aa98e2SPeter Wemm ** berknet mailer. 288c2aa98e2SPeter Wemm ** 289c2aa98e2SPeter Wemm ** Parameters: 290c2aa98e2SPeter Wemm ** addr -- the name to chomp. 291c2aa98e2SPeter Wemm ** delim -- the delimiter for the address, normally 292c2aa98e2SPeter Wemm ** '\0' or ','; \0 is accepted in any case. 293c2aa98e2SPeter Wemm ** If '\t' then we are reading the .cf file. 294c2aa98e2SPeter Wemm ** pvpbuf -- place to put the saved text -- note that 295c2aa98e2SPeter Wemm ** the pointers are static. 296c2aa98e2SPeter Wemm ** pvpbsize -- size of pvpbuf. 297c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 298c2aa98e2SPeter Wemm ** terminating delimiter. 299c2aa98e2SPeter Wemm ** toktab -- if set, a token table to use for parsing. 300c2aa98e2SPeter Wemm ** If NULL, use the default table. 301c2aa98e2SPeter Wemm ** 302c2aa98e2SPeter Wemm ** Returns: 303c2aa98e2SPeter Wemm ** A pointer to a vector of tokens. 304c2aa98e2SPeter Wemm ** NULL on error. 305c2aa98e2SPeter Wemm */ 306c2aa98e2SPeter Wemm 307c2aa98e2SPeter Wemm /* states and character types */ 308c2aa98e2SPeter Wemm #define OPR 0 /* operator */ 309c2aa98e2SPeter Wemm #define ATM 1 /* atom */ 310c2aa98e2SPeter Wemm #define QST 2 /* in quoted string */ 311c2aa98e2SPeter Wemm #define SPC 3 /* chewing up spaces */ 312c2aa98e2SPeter Wemm #define ONE 4 /* pick up one character */ 313c2aa98e2SPeter Wemm #define ILL 5 /* illegal character */ 314c2aa98e2SPeter Wemm 315c2aa98e2SPeter Wemm #define NSTATES 6 /* number of states */ 316c2aa98e2SPeter Wemm #define TYPE 017 /* mask to select state type */ 317c2aa98e2SPeter Wemm 318c2aa98e2SPeter Wemm /* meta bits for table */ 319c2aa98e2SPeter Wemm #define M 020 /* meta character; don't pass through */ 320c2aa98e2SPeter Wemm #define B 040 /* cause a break */ 321c2aa98e2SPeter Wemm #define MB M|B /* meta-break */ 322c2aa98e2SPeter Wemm 323c2aa98e2SPeter Wemm static short StateTab[NSTATES][NSTATES] = 324c2aa98e2SPeter Wemm { 325c2aa98e2SPeter Wemm /* oldst chtype> OPR ATM QST SPC ONE ILL */ 326c2aa98e2SPeter Wemm /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 327c2aa98e2SPeter Wemm /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 328c2aa98e2SPeter Wemm /*QST*/ { QST, QST, OPR, QST, QST, QST }, 329c2aa98e2SPeter Wemm /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 330c2aa98e2SPeter Wemm /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 331c2aa98e2SPeter Wemm /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 332c2aa98e2SPeter Wemm }; 333c2aa98e2SPeter Wemm 334c2aa98e2SPeter Wemm /* token type table -- it gets modified with $o characters */ 335c2aa98e2SPeter Wemm static u_char TokTypeTab[256] = 336c2aa98e2SPeter Wemm { 337c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 338c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 339c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 340c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 341c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 34206f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 343c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 344c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 345c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 346c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 347c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 348c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 349c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 350c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 351c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 352c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 353c2aa98e2SPeter Wemm 354c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 355c2aa98e2SPeter Wemm OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 356c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 357c2aa98e2SPeter Wemm OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 358c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 359c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 360c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 361c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 362c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 363c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 364c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 365c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 366c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 367c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 368c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 369c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 370c2aa98e2SPeter Wemm }; 371c2aa98e2SPeter Wemm 372c2aa98e2SPeter Wemm /* token type table for MIME parsing */ 373c2aa98e2SPeter Wemm u_char MimeTokenTab[256] = 374c2aa98e2SPeter Wemm { 375c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 376c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 377c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 378c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 379c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 38006f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 381c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 382c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 383c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 384c2aa98e2SPeter Wemm OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 385c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 386c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 387c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 388c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 389c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 390c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 391c2aa98e2SPeter Wemm 392c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 393c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 394c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 395c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 396c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 397c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 398c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 399c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 400c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 401c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 402c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 403c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 404c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 405c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 406c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 407c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 408c2aa98e2SPeter Wemm }; 409c2aa98e2SPeter Wemm 41006f25ae9SGregory Neil Shapiro /* token type table: don't strip comments */ 41106f25ae9SGregory Neil Shapiro u_char TokTypeNoC[256] = 41206f25ae9SGregory Neil Shapiro { 41306f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 41406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 41506f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 41606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 41706f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 41806f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 41906f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 42006f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 42106f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 42206f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 42306f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 42406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 42506f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 42606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 42706f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 42806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 42906f25ae9SGregory Neil Shapiro 43006f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 43106f25ae9SGregory Neil Shapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 43206f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 43306f25ae9SGregory Neil Shapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 43406f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 43506f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 43606f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 43706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 43806f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 43906f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 44006f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 44106f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 44206f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 44306f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 44406f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 44506f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 44606f25ae9SGregory Neil Shapiro }; 44706f25ae9SGregory Neil Shapiro 448c2aa98e2SPeter Wemm 449c2aa98e2SPeter Wemm #define NOCHAR -1 /* signal nothing in lookahead token */ 450c2aa98e2SPeter Wemm 451c2aa98e2SPeter Wemm char ** 452c2aa98e2SPeter Wemm prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 453c2aa98e2SPeter Wemm char *addr; 454c2aa98e2SPeter Wemm int delim; 455c2aa98e2SPeter Wemm char pvpbuf[]; 456c2aa98e2SPeter Wemm int pvpbsize; 457c2aa98e2SPeter Wemm char **delimptr; 458c2aa98e2SPeter Wemm u_char *toktab; 459c2aa98e2SPeter Wemm { 460c2aa98e2SPeter Wemm register char *p; 461c2aa98e2SPeter Wemm register char *q; 462c2aa98e2SPeter Wemm register int c; 463c2aa98e2SPeter Wemm char **avp; 464c2aa98e2SPeter Wemm bool bslashmode; 465c2aa98e2SPeter Wemm bool route_syntax; 466c2aa98e2SPeter Wemm int cmntcnt; 467c2aa98e2SPeter Wemm int anglecnt; 468c2aa98e2SPeter Wemm char *tok; 469c2aa98e2SPeter Wemm int state; 470c2aa98e2SPeter Wemm int newstate; 471c2aa98e2SPeter Wemm char *saveto = CurEnv->e_to; 472c2aa98e2SPeter Wemm static char *av[MAXATOM + 1]; 473c2aa98e2SPeter Wemm static char firsttime = TRUE; 474c2aa98e2SPeter Wemm extern int errno; 475c2aa98e2SPeter Wemm 476c2aa98e2SPeter Wemm if (firsttime) 477c2aa98e2SPeter Wemm { 478c2aa98e2SPeter Wemm /* initialize the token type table */ 479c2aa98e2SPeter Wemm char obuf[50]; 480c2aa98e2SPeter Wemm 481c2aa98e2SPeter Wemm firsttime = FALSE; 482c2aa98e2SPeter Wemm if (OperatorChars == NULL) 483c2aa98e2SPeter Wemm { 484c2aa98e2SPeter Wemm if (ConfigLevel < 7) 485c2aa98e2SPeter Wemm OperatorChars = macvalue('o', CurEnv); 486c2aa98e2SPeter Wemm if (OperatorChars == NULL) 487c2aa98e2SPeter Wemm OperatorChars = ".:@[]"; 488c2aa98e2SPeter Wemm } 48906f25ae9SGregory Neil Shapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 49006f25ae9SGregory Neil Shapiro CurEnv); 49106f25ae9SGregory Neil Shapiro (void) strlcat(obuf, DELIMCHARS, sizeof obuf); 492c2aa98e2SPeter Wemm for (p = obuf; *p != '\0'; p++) 493c2aa98e2SPeter Wemm { 494c2aa98e2SPeter Wemm if (TokTypeTab[*p & 0xff] == ATM) 495c2aa98e2SPeter Wemm TokTypeTab[*p & 0xff] = OPR; 49606f25ae9SGregory Neil Shapiro if (TokTypeNoC[*p & 0xff] == ATM) 49706f25ae9SGregory Neil Shapiro TokTypeNoC[*p & 0xff] = OPR; 498c2aa98e2SPeter Wemm } 499c2aa98e2SPeter Wemm } 500c2aa98e2SPeter Wemm if (toktab == NULL) 501c2aa98e2SPeter Wemm toktab = TokTypeTab; 502c2aa98e2SPeter Wemm 503c2aa98e2SPeter Wemm /* make sure error messages don't have garbage on them */ 504c2aa98e2SPeter Wemm errno = 0; 505c2aa98e2SPeter Wemm 506c2aa98e2SPeter Wemm q = pvpbuf; 507c2aa98e2SPeter Wemm bslashmode = FALSE; 508c2aa98e2SPeter Wemm route_syntax = FALSE; 509c2aa98e2SPeter Wemm cmntcnt = 0; 510c2aa98e2SPeter Wemm anglecnt = 0; 511c2aa98e2SPeter Wemm avp = av; 512c2aa98e2SPeter Wemm state = ATM; 513c2aa98e2SPeter Wemm c = NOCHAR; 514c2aa98e2SPeter Wemm p = addr; 515c2aa98e2SPeter Wemm CurEnv->e_to = p; 516c2aa98e2SPeter Wemm if (tTd(22, 11)) 517c2aa98e2SPeter Wemm { 51806f25ae9SGregory Neil Shapiro dprintf("prescan: "); 519c2aa98e2SPeter Wemm xputs(p); 52006f25ae9SGregory Neil Shapiro dprintf("\n"); 521c2aa98e2SPeter Wemm } 522c2aa98e2SPeter Wemm 523c2aa98e2SPeter Wemm do 524c2aa98e2SPeter Wemm { 525c2aa98e2SPeter Wemm /* read a token */ 526c2aa98e2SPeter Wemm tok = q; 527c2aa98e2SPeter Wemm for (;;) 528c2aa98e2SPeter Wemm { 529c2aa98e2SPeter Wemm /* store away any old lookahead character */ 530c2aa98e2SPeter Wemm if (c != NOCHAR && !bslashmode) 531c2aa98e2SPeter Wemm { 532c2aa98e2SPeter Wemm /* see if there is room */ 533c2aa98e2SPeter Wemm if (q >= &pvpbuf[pvpbsize - 5]) 534c2aa98e2SPeter Wemm { 53506f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address too long"); 536c2aa98e2SPeter Wemm if (strlen(addr) > (SIZE_T) MAXNAME) 537c2aa98e2SPeter Wemm addr[MAXNAME] = '\0'; 538c2aa98e2SPeter Wemm returnnull: 539c2aa98e2SPeter Wemm if (delimptr != NULL) 540c2aa98e2SPeter Wemm *delimptr = p; 541c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 54206f25ae9SGregory Neil Shapiro return NULL; 543c2aa98e2SPeter Wemm } 544c2aa98e2SPeter Wemm 545c2aa98e2SPeter Wemm /* squirrel it away */ 546c2aa98e2SPeter Wemm *q++ = c; 547c2aa98e2SPeter Wemm } 548c2aa98e2SPeter Wemm 549c2aa98e2SPeter Wemm /* read a new input character */ 550c2aa98e2SPeter Wemm c = *p++; 551c2aa98e2SPeter Wemm if (c == '\0') 552c2aa98e2SPeter Wemm { 553c2aa98e2SPeter Wemm /* diagnose and patch up bad syntax */ 554c2aa98e2SPeter Wemm if (state == QST) 555c2aa98e2SPeter Wemm { 556c2aa98e2SPeter Wemm usrerr("653 Unbalanced '\"'"); 557c2aa98e2SPeter Wemm c = '"'; 558c2aa98e2SPeter Wemm } 559c2aa98e2SPeter Wemm else if (cmntcnt > 0) 560c2aa98e2SPeter Wemm { 561c2aa98e2SPeter Wemm usrerr("653 Unbalanced '('"); 562c2aa98e2SPeter Wemm c = ')'; 563c2aa98e2SPeter Wemm } 564c2aa98e2SPeter Wemm else if (anglecnt > 0) 565c2aa98e2SPeter Wemm { 566c2aa98e2SPeter Wemm c = '>'; 567c2aa98e2SPeter Wemm usrerr("653 Unbalanced '<'"); 568c2aa98e2SPeter Wemm } 569c2aa98e2SPeter Wemm else 570c2aa98e2SPeter Wemm break; 571c2aa98e2SPeter Wemm 572c2aa98e2SPeter Wemm p--; 573c2aa98e2SPeter Wemm } 574c2aa98e2SPeter Wemm else if (c == delim && cmntcnt <= 0 && state != QST) 575c2aa98e2SPeter Wemm { 576c2aa98e2SPeter Wemm if (anglecnt <= 0) 577c2aa98e2SPeter Wemm break; 578c2aa98e2SPeter Wemm 579c2aa98e2SPeter Wemm /* special case for better error management */ 580c2aa98e2SPeter Wemm if (delim == ',' && !route_syntax) 581c2aa98e2SPeter Wemm { 582c2aa98e2SPeter Wemm usrerr("653 Unbalanced '<'"); 583c2aa98e2SPeter Wemm c = '>'; 584c2aa98e2SPeter Wemm p--; 585c2aa98e2SPeter Wemm } 586c2aa98e2SPeter Wemm } 587c2aa98e2SPeter Wemm 588c2aa98e2SPeter Wemm if (tTd(22, 101)) 58906f25ae9SGregory Neil Shapiro dprintf("c=%c, s=%d; ", c, state); 590c2aa98e2SPeter Wemm 591c2aa98e2SPeter Wemm /* chew up special characters */ 592c2aa98e2SPeter Wemm *q = '\0'; 593c2aa98e2SPeter Wemm if (bslashmode) 594c2aa98e2SPeter Wemm { 595c2aa98e2SPeter Wemm bslashmode = FALSE; 596c2aa98e2SPeter Wemm 597c2aa98e2SPeter Wemm /* kludge \! for naive users */ 598c2aa98e2SPeter Wemm if (cmntcnt > 0) 599c2aa98e2SPeter Wemm { 600c2aa98e2SPeter Wemm c = NOCHAR; 601c2aa98e2SPeter Wemm continue; 602c2aa98e2SPeter Wemm } 603c2aa98e2SPeter Wemm else if (c != '!' || state == QST) 604c2aa98e2SPeter Wemm { 605c2aa98e2SPeter Wemm *q++ = '\\'; 606c2aa98e2SPeter Wemm continue; 607c2aa98e2SPeter Wemm } 608c2aa98e2SPeter Wemm } 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm if (c == '\\') 611c2aa98e2SPeter Wemm { 612c2aa98e2SPeter Wemm bslashmode = TRUE; 613c2aa98e2SPeter Wemm } 614c2aa98e2SPeter Wemm else if (state == QST) 615c2aa98e2SPeter Wemm { 61606f25ae9SGregory Neil Shapiro /* EMPTY */ 617c2aa98e2SPeter Wemm /* do nothing, just avoid next clauses */ 618c2aa98e2SPeter Wemm } 61906f25ae9SGregory Neil Shapiro else if (c == '(' && toktab['('] == SPC) 620c2aa98e2SPeter Wemm { 621c2aa98e2SPeter Wemm cmntcnt++; 622c2aa98e2SPeter Wemm c = NOCHAR; 623c2aa98e2SPeter Wemm } 62406f25ae9SGregory Neil Shapiro else if (c == ')' && toktab['('] == SPC) 625c2aa98e2SPeter Wemm { 626c2aa98e2SPeter Wemm if (cmntcnt <= 0) 627c2aa98e2SPeter Wemm { 628c2aa98e2SPeter Wemm usrerr("653 Unbalanced ')'"); 629c2aa98e2SPeter Wemm c = NOCHAR; 630c2aa98e2SPeter Wemm } 631c2aa98e2SPeter Wemm else 632c2aa98e2SPeter Wemm cmntcnt--; 633c2aa98e2SPeter Wemm } 634c2aa98e2SPeter Wemm else if (cmntcnt > 0) 63506f25ae9SGregory Neil Shapiro { 636c2aa98e2SPeter Wemm c = NOCHAR; 63706f25ae9SGregory Neil Shapiro } 638c2aa98e2SPeter Wemm else if (c == '<') 639c2aa98e2SPeter Wemm { 64006f25ae9SGregory Neil Shapiro char *ptr = p; 641c2aa98e2SPeter Wemm 642c2aa98e2SPeter Wemm anglecnt++; 64306f25ae9SGregory Neil Shapiro while (isascii(*ptr) && isspace(*ptr)) 64406f25ae9SGregory Neil Shapiro ptr++; 64506f25ae9SGregory Neil Shapiro if (*ptr == '@') 646c2aa98e2SPeter Wemm route_syntax = TRUE; 647c2aa98e2SPeter Wemm } 648c2aa98e2SPeter Wemm else if (c == '>') 649c2aa98e2SPeter Wemm { 650c2aa98e2SPeter Wemm if (anglecnt <= 0) 651c2aa98e2SPeter Wemm { 652c2aa98e2SPeter Wemm usrerr("653 Unbalanced '>'"); 653c2aa98e2SPeter Wemm c = NOCHAR; 654c2aa98e2SPeter Wemm } 655c2aa98e2SPeter Wemm else 656c2aa98e2SPeter Wemm anglecnt--; 657c2aa98e2SPeter Wemm route_syntax = FALSE; 658c2aa98e2SPeter Wemm } 659c2aa98e2SPeter Wemm else if (delim == ' ' && isascii(c) && isspace(c)) 660c2aa98e2SPeter Wemm c = ' '; 661c2aa98e2SPeter Wemm 662c2aa98e2SPeter Wemm if (c == NOCHAR) 663c2aa98e2SPeter Wemm continue; 664c2aa98e2SPeter Wemm 665c2aa98e2SPeter Wemm /* see if this is end of input */ 666c2aa98e2SPeter Wemm if (c == delim && anglecnt <= 0 && state != QST) 667c2aa98e2SPeter Wemm break; 668c2aa98e2SPeter Wemm 669c2aa98e2SPeter Wemm newstate = StateTab[state][toktab[c & 0xff]]; 670c2aa98e2SPeter Wemm if (tTd(22, 101)) 67106f25ae9SGregory Neil Shapiro dprintf("ns=%02o\n", newstate); 672c2aa98e2SPeter Wemm state = newstate & TYPE; 673c2aa98e2SPeter Wemm if (state == ILL) 674c2aa98e2SPeter Wemm { 675c2aa98e2SPeter Wemm if (isascii(c) && isprint(c)) 676c2aa98e2SPeter Wemm usrerr("653 Illegal character %c", c); 677c2aa98e2SPeter Wemm else 678c2aa98e2SPeter Wemm usrerr("653 Illegal character 0x%02x", c); 679c2aa98e2SPeter Wemm } 680c2aa98e2SPeter Wemm if (bitset(M, newstate)) 681c2aa98e2SPeter Wemm c = NOCHAR; 682c2aa98e2SPeter Wemm if (bitset(B, newstate)) 683c2aa98e2SPeter Wemm break; 684c2aa98e2SPeter Wemm } 685c2aa98e2SPeter Wemm 686c2aa98e2SPeter Wemm /* new token */ 687c2aa98e2SPeter Wemm if (tok != q) 688c2aa98e2SPeter Wemm { 689c2aa98e2SPeter Wemm *q++ = '\0'; 690c2aa98e2SPeter Wemm if (tTd(22, 36)) 691c2aa98e2SPeter Wemm { 69206f25ae9SGregory Neil Shapiro dprintf("tok="); 693c2aa98e2SPeter Wemm xputs(tok); 69406f25ae9SGregory Neil Shapiro dprintf("\n"); 695c2aa98e2SPeter Wemm } 696c2aa98e2SPeter Wemm if (avp >= &av[MAXATOM]) 697c2aa98e2SPeter Wemm { 69806f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: too many tokens"); 699c2aa98e2SPeter Wemm goto returnnull; 700c2aa98e2SPeter Wemm } 701c2aa98e2SPeter Wemm if (q - tok > MAXNAME) 702c2aa98e2SPeter Wemm { 70306f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: token too long"); 704c2aa98e2SPeter Wemm goto returnnull; 705c2aa98e2SPeter Wemm } 706c2aa98e2SPeter Wemm *avp++ = tok; 707c2aa98e2SPeter Wemm } 708c2aa98e2SPeter Wemm } while (c != '\0' && (c != delim || anglecnt > 0)); 709c2aa98e2SPeter Wemm *avp = NULL; 710c2aa98e2SPeter Wemm p--; 711c2aa98e2SPeter Wemm if (delimptr != NULL) 712c2aa98e2SPeter Wemm *delimptr = p; 713c2aa98e2SPeter Wemm if (tTd(22, 12)) 714c2aa98e2SPeter Wemm { 71506f25ae9SGregory Neil Shapiro dprintf("prescan==>"); 716c2aa98e2SPeter Wemm printav(av); 717c2aa98e2SPeter Wemm } 718c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 719c2aa98e2SPeter Wemm if (av[0] == NULL) 720c2aa98e2SPeter Wemm { 721c2aa98e2SPeter Wemm if (tTd(22, 1)) 72206f25ae9SGregory Neil Shapiro dprintf("prescan: null leading token\n"); 72306f25ae9SGregory Neil Shapiro return NULL; 724c2aa98e2SPeter Wemm } 72506f25ae9SGregory Neil Shapiro return av; 726c2aa98e2SPeter Wemm } 727c2aa98e2SPeter Wemm /* 728c2aa98e2SPeter Wemm ** REWRITE -- apply rewrite rules to token vector. 729c2aa98e2SPeter Wemm ** 730c2aa98e2SPeter Wemm ** This routine is an ordered production system. Each rewrite 731c2aa98e2SPeter Wemm ** rule has a LHS (called the pattern) and a RHS (called the 732c2aa98e2SPeter Wemm ** rewrite); 'rwr' points the the current rewrite rule. 733c2aa98e2SPeter Wemm ** 734c2aa98e2SPeter Wemm ** For each rewrite rule, 'avp' points the address vector we 735c2aa98e2SPeter Wemm ** are trying to match against, and 'pvp' points to the pattern. 736c2aa98e2SPeter Wemm ** If pvp points to a special match value (MATCHZANY, MATCHANY, 737c2aa98e2SPeter Wemm ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 738c2aa98e2SPeter Wemm ** matched is saved away in the match vector (pointed to by 'mvp'). 739c2aa98e2SPeter Wemm ** 740c2aa98e2SPeter Wemm ** When a match between avp & pvp does not match, we try to 741c2aa98e2SPeter Wemm ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 742c2aa98e2SPeter Wemm ** we must also back out the match in mvp. If we reach a 743c2aa98e2SPeter Wemm ** MATCHANY or MATCHZANY we just extend the match and start 744c2aa98e2SPeter Wemm ** over again. 745c2aa98e2SPeter Wemm ** 746c2aa98e2SPeter Wemm ** When we finally match, we rewrite the address vector 747c2aa98e2SPeter Wemm ** and try over again. 748c2aa98e2SPeter Wemm ** 749c2aa98e2SPeter Wemm ** Parameters: 750c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 751c2aa98e2SPeter Wemm ** ruleset -- the ruleset to use for rewriting. 752c2aa98e2SPeter Wemm ** reclevel -- recursion level (to catch loops). 753c2aa98e2SPeter Wemm ** e -- the current envelope. 754c2aa98e2SPeter Wemm ** 755c2aa98e2SPeter Wemm ** Returns: 756c2aa98e2SPeter Wemm ** A status code. If EX_TEMPFAIL, higher level code should 757c2aa98e2SPeter Wemm ** attempt recovery. 758c2aa98e2SPeter Wemm ** 759c2aa98e2SPeter Wemm ** Side Effects: 760c2aa98e2SPeter Wemm ** pvp is modified. 761c2aa98e2SPeter Wemm */ 762c2aa98e2SPeter Wemm 763c2aa98e2SPeter Wemm struct match 764c2aa98e2SPeter Wemm { 76506f25ae9SGregory Neil Shapiro char **match_first; /* first token matched */ 76606f25ae9SGregory Neil Shapiro char **match_last; /* last token matched */ 76706f25ae9SGregory Neil Shapiro char **match_pattern; /* pointer to pattern */ 768c2aa98e2SPeter Wemm }; 769c2aa98e2SPeter Wemm 770c2aa98e2SPeter Wemm #define MAXMATCH 9 /* max params per rewrite */ 771c2aa98e2SPeter Wemm 772c2aa98e2SPeter Wemm 773c2aa98e2SPeter Wemm int 774c2aa98e2SPeter Wemm rewrite(pvp, ruleset, reclevel, e) 775c2aa98e2SPeter Wemm char **pvp; 776c2aa98e2SPeter Wemm int ruleset; 777c2aa98e2SPeter Wemm int reclevel; 778c2aa98e2SPeter Wemm register ENVELOPE *e; 779c2aa98e2SPeter Wemm { 780c2aa98e2SPeter Wemm register char *ap; /* address pointer */ 781c2aa98e2SPeter Wemm register char *rp; /* rewrite pointer */ 78206f25ae9SGregory Neil Shapiro register char *rulename; /* ruleset name */ 78306f25ae9SGregory Neil Shapiro register char *prefix; 784c2aa98e2SPeter Wemm register char **avp; /* address vector pointer */ 785c2aa98e2SPeter Wemm register char **rvp; /* rewrite vector pointer */ 786c2aa98e2SPeter Wemm register struct match *mlp; /* cur ptr into mlist */ 787c2aa98e2SPeter Wemm register struct rewrite *rwr; /* pointer to current rewrite rule */ 788c2aa98e2SPeter Wemm int ruleno; /* current rule number */ 789c2aa98e2SPeter Wemm int rstat = EX_OK; /* return status */ 790c2aa98e2SPeter Wemm int loopcount; 791c2aa98e2SPeter Wemm struct match mlist[MAXMATCH]; /* stores match on LHS */ 792c2aa98e2SPeter Wemm char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 793c2aa98e2SPeter Wemm char buf[MAXLINE]; 79406f25ae9SGregory Neil Shapiro char name[6]; 795c2aa98e2SPeter Wemm 796c2aa98e2SPeter Wemm if (ruleset < 0 || ruleset >= MAXRWSETS) 797c2aa98e2SPeter Wemm { 79806f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 799c2aa98e2SPeter Wemm return EX_CONFIG; 800c2aa98e2SPeter Wemm } 80106f25ae9SGregory Neil Shapiro rulename = RuleSetNames[ruleset]; 80206f25ae9SGregory Neil Shapiro if (rulename == NULL) 80306f25ae9SGregory Neil Shapiro { 80406f25ae9SGregory Neil Shapiro snprintf(name, sizeof name, "%d", ruleset); 80506f25ae9SGregory Neil Shapiro rulename = name; 80606f25ae9SGregory Neil Shapiro } 80706f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 80806f25ae9SGregory Neil Shapiro prefix = ""; 80906f25ae9SGregory Neil Shapiro else 81006f25ae9SGregory Neil Shapiro prefix = "rewrite: ruleset "; 81106f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 81206f25ae9SGregory Neil Shapiro { 81306f25ae9SGregory Neil Shapiro printf("%s%-16.16s input:", prefix, rulename); 81406f25ae9SGregory Neil Shapiro printav(pvp); 81506f25ae9SGregory Neil Shapiro } 81606f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 81706f25ae9SGregory Neil Shapiro { 81806f25ae9SGregory Neil Shapiro dprintf("%s%-16.16s input:", prefix, rulename); 81906f25ae9SGregory Neil Shapiro printav(pvp); 82006f25ae9SGregory Neil Shapiro } 821c2aa98e2SPeter Wemm if (reclevel++ > MaxRuleRecursion) 822c2aa98e2SPeter Wemm { 82306f25ae9SGregory Neil Shapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 82406f25ae9SGregory Neil Shapiro MaxRuleRecursion, rulename); 825c2aa98e2SPeter Wemm return EX_CONFIG; 826c2aa98e2SPeter Wemm } 827c2aa98e2SPeter Wemm if (pvp == NULL) 828c2aa98e2SPeter Wemm return EX_USAGE; 829c2aa98e2SPeter Wemm 830c2aa98e2SPeter Wemm /* 831c2aa98e2SPeter Wemm ** Run through the list of rewrite rules, applying 832c2aa98e2SPeter Wemm ** any that match. 833c2aa98e2SPeter Wemm */ 834c2aa98e2SPeter Wemm 835c2aa98e2SPeter Wemm ruleno = 1; 836c2aa98e2SPeter Wemm loopcount = 0; 837c2aa98e2SPeter Wemm for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 838c2aa98e2SPeter Wemm { 83906f25ae9SGregory Neil Shapiro int status; 840c2aa98e2SPeter Wemm 841c2aa98e2SPeter Wemm /* if already canonical, quit now */ 842c2aa98e2SPeter Wemm if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 843c2aa98e2SPeter Wemm break; 844c2aa98e2SPeter Wemm 845c2aa98e2SPeter Wemm if (tTd(21, 12)) 846c2aa98e2SPeter Wemm { 84706f25ae9SGregory Neil Shapiro if (tTd(21, 15)) 84806f25ae9SGregory Neil Shapiro dprintf("-----trying rule (line %d):", 84906f25ae9SGregory Neil Shapiro rwr->r_line); 85006f25ae9SGregory Neil Shapiro else 85106f25ae9SGregory Neil Shapiro dprintf("-----trying rule:"); 852c2aa98e2SPeter Wemm printav(rwr->r_lhs); 853c2aa98e2SPeter Wemm } 854c2aa98e2SPeter Wemm 855c2aa98e2SPeter Wemm /* try to match on this rule */ 856c2aa98e2SPeter Wemm mlp = mlist; 857c2aa98e2SPeter Wemm rvp = rwr->r_lhs; 858c2aa98e2SPeter Wemm avp = pvp; 859c2aa98e2SPeter Wemm if (++loopcount > 100) 860c2aa98e2SPeter Wemm { 86106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 86206f25ae9SGregory Neil Shapiro rulename, ruleno); 863c2aa98e2SPeter Wemm if (tTd(21, 1)) 864c2aa98e2SPeter Wemm { 86506f25ae9SGregory Neil Shapiro dprintf("workspace: "); 866c2aa98e2SPeter Wemm printav(pvp); 867c2aa98e2SPeter Wemm } 868c2aa98e2SPeter Wemm break; 869c2aa98e2SPeter Wemm } 870c2aa98e2SPeter Wemm 871c2aa98e2SPeter Wemm while ((ap = *avp) != NULL || *rvp != NULL) 872c2aa98e2SPeter Wemm { 873c2aa98e2SPeter Wemm rp = *rvp; 874c2aa98e2SPeter Wemm if (tTd(21, 35)) 875c2aa98e2SPeter Wemm { 87606f25ae9SGregory Neil Shapiro dprintf("ADVANCE rp="); 877c2aa98e2SPeter Wemm xputs(rp); 87806f25ae9SGregory Neil Shapiro dprintf(", ap="); 879c2aa98e2SPeter Wemm xputs(ap); 88006f25ae9SGregory Neil Shapiro dprintf("\n"); 881c2aa98e2SPeter Wemm } 882c2aa98e2SPeter Wemm if (rp == NULL) 883c2aa98e2SPeter Wemm { 884c2aa98e2SPeter Wemm /* end-of-pattern before end-of-address */ 885c2aa98e2SPeter Wemm goto backup; 886c2aa98e2SPeter Wemm } 887c2aa98e2SPeter Wemm if (ap == NULL && (*rp & 0377) != MATCHZANY && 888c2aa98e2SPeter Wemm (*rp & 0377) != MATCHZERO) 889c2aa98e2SPeter Wemm { 890c2aa98e2SPeter Wemm /* end-of-input with patterns left */ 891c2aa98e2SPeter Wemm goto backup; 892c2aa98e2SPeter Wemm } 893c2aa98e2SPeter Wemm 894c2aa98e2SPeter Wemm switch (*rp & 0377) 895c2aa98e2SPeter Wemm { 896c2aa98e2SPeter Wemm case MATCHCLASS: 897c2aa98e2SPeter Wemm /* match any phrase in a class */ 89806f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 89906f25ae9SGregory Neil Shapiro mlp->match_first = avp; 900c2aa98e2SPeter Wemm extendclass: 901c2aa98e2SPeter Wemm ap = *avp; 902c2aa98e2SPeter Wemm if (ap == NULL) 903c2aa98e2SPeter Wemm goto backup; 90406f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 90506f25ae9SGregory Neil Shapiro cataddr(mlp->match_first, mlp->match_last, 90606f25ae9SGregory Neil Shapiro buf, sizeof buf, '\0'); 907c2aa98e2SPeter Wemm if (!wordinclass(buf, rp[1])) 908c2aa98e2SPeter Wemm { 909c2aa98e2SPeter Wemm if (tTd(21, 36)) 910c2aa98e2SPeter Wemm { 91106f25ae9SGregory Neil Shapiro dprintf("EXTEND rp="); 912c2aa98e2SPeter Wemm xputs(rp); 91306f25ae9SGregory Neil Shapiro dprintf(", ap="); 914c2aa98e2SPeter Wemm xputs(ap); 91506f25ae9SGregory Neil Shapiro dprintf("\n"); 916c2aa98e2SPeter Wemm } 917c2aa98e2SPeter Wemm goto extendclass; 918c2aa98e2SPeter Wemm } 919c2aa98e2SPeter Wemm if (tTd(21, 36)) 92006f25ae9SGregory Neil Shapiro dprintf("CLMATCH\n"); 921c2aa98e2SPeter Wemm mlp++; 922c2aa98e2SPeter Wemm break; 923c2aa98e2SPeter Wemm 924c2aa98e2SPeter Wemm case MATCHNCLASS: 925c2aa98e2SPeter Wemm /* match any token not in a class */ 926c2aa98e2SPeter Wemm if (wordinclass(ap, rp[1])) 927c2aa98e2SPeter Wemm goto backup; 928c2aa98e2SPeter Wemm 92906f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 930c2aa98e2SPeter Wemm 931c2aa98e2SPeter Wemm case MATCHONE: 932c2aa98e2SPeter Wemm case MATCHANY: 933c2aa98e2SPeter Wemm /* match exactly one token */ 93406f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 93506f25ae9SGregory Neil Shapiro mlp->match_first = avp; 93606f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 937c2aa98e2SPeter Wemm mlp++; 938c2aa98e2SPeter Wemm break; 939c2aa98e2SPeter Wemm 940c2aa98e2SPeter Wemm case MATCHZANY: 941c2aa98e2SPeter Wemm /* match zero or more tokens */ 94206f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 94306f25ae9SGregory Neil Shapiro mlp->match_first = avp; 94406f25ae9SGregory Neil Shapiro mlp->match_last = avp - 1; 945c2aa98e2SPeter Wemm mlp++; 946c2aa98e2SPeter Wemm break; 947c2aa98e2SPeter Wemm 948c2aa98e2SPeter Wemm case MATCHZERO: 949c2aa98e2SPeter Wemm /* match zero tokens */ 950c2aa98e2SPeter Wemm break; 951c2aa98e2SPeter Wemm 952c2aa98e2SPeter Wemm case MACRODEXPAND: 953c2aa98e2SPeter Wemm /* 954c2aa98e2SPeter Wemm ** Match against run-time macro. 955c2aa98e2SPeter Wemm ** This algorithm is broken for the 956c2aa98e2SPeter Wemm ** general case (no recursive macros, 957c2aa98e2SPeter Wemm ** improper tokenization) but should 958c2aa98e2SPeter Wemm ** work for the usual cases. 959c2aa98e2SPeter Wemm */ 960c2aa98e2SPeter Wemm 961c2aa98e2SPeter Wemm ap = macvalue(rp[1], e); 96206f25ae9SGregory Neil Shapiro mlp->match_first = avp; 963c2aa98e2SPeter Wemm if (tTd(21, 2)) 96406f25ae9SGregory Neil Shapiro dprintf("rewrite: LHS $&%s => \"%s\"\n", 965c2aa98e2SPeter Wemm macname(rp[1]), 966c2aa98e2SPeter Wemm ap == NULL ? "(NULL)" : ap); 967c2aa98e2SPeter Wemm 968c2aa98e2SPeter Wemm if (ap == NULL) 969c2aa98e2SPeter Wemm break; 970c2aa98e2SPeter Wemm while (*ap != '\0') 971c2aa98e2SPeter Wemm { 972c2aa98e2SPeter Wemm if (*avp == NULL || 973c2aa98e2SPeter Wemm strncasecmp(ap, *avp, strlen(*avp)) != 0) 974c2aa98e2SPeter Wemm { 975c2aa98e2SPeter Wemm /* no match */ 97606f25ae9SGregory Neil Shapiro avp = mlp->match_first; 977c2aa98e2SPeter Wemm goto backup; 978c2aa98e2SPeter Wemm } 979c2aa98e2SPeter Wemm ap += strlen(*avp++); 980c2aa98e2SPeter Wemm } 981c2aa98e2SPeter Wemm 982c2aa98e2SPeter Wemm /* match */ 983c2aa98e2SPeter Wemm break; 984c2aa98e2SPeter Wemm 985c2aa98e2SPeter Wemm default: 986c2aa98e2SPeter Wemm /* must have exact match */ 987c2aa98e2SPeter Wemm if (sm_strcasecmp(rp, ap)) 988c2aa98e2SPeter Wemm goto backup; 989c2aa98e2SPeter Wemm avp++; 990c2aa98e2SPeter Wemm break; 991c2aa98e2SPeter Wemm } 992c2aa98e2SPeter Wemm 993c2aa98e2SPeter Wemm /* successful match on this token */ 994c2aa98e2SPeter Wemm rvp++; 995c2aa98e2SPeter Wemm continue; 996c2aa98e2SPeter Wemm 997c2aa98e2SPeter Wemm backup: 998c2aa98e2SPeter Wemm /* match failed -- back up */ 999c2aa98e2SPeter Wemm while (--mlp >= mlist) 1000c2aa98e2SPeter Wemm { 100106f25ae9SGregory Neil Shapiro rvp = mlp->match_pattern; 1002c2aa98e2SPeter Wemm rp = *rvp; 100306f25ae9SGregory Neil Shapiro avp = mlp->match_last + 1; 1004c2aa98e2SPeter Wemm ap = *avp; 1005c2aa98e2SPeter Wemm 1006c2aa98e2SPeter Wemm if (tTd(21, 36)) 1007c2aa98e2SPeter Wemm { 100806f25ae9SGregory Neil Shapiro dprintf("BACKUP rp="); 1009c2aa98e2SPeter Wemm xputs(rp); 101006f25ae9SGregory Neil Shapiro dprintf(", ap="); 1011c2aa98e2SPeter Wemm xputs(ap); 101206f25ae9SGregory Neil Shapiro dprintf("\n"); 1013c2aa98e2SPeter Wemm } 1014c2aa98e2SPeter Wemm 1015c2aa98e2SPeter Wemm if (ap == NULL) 1016c2aa98e2SPeter Wemm { 1017c2aa98e2SPeter Wemm /* run off the end -- back up again */ 1018c2aa98e2SPeter Wemm continue; 1019c2aa98e2SPeter Wemm } 1020c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHANY || 1021c2aa98e2SPeter Wemm (*rp & 0377) == MATCHZANY) 1022c2aa98e2SPeter Wemm { 1023c2aa98e2SPeter Wemm /* extend binding and continue */ 102406f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1025c2aa98e2SPeter Wemm rvp++; 1026c2aa98e2SPeter Wemm mlp++; 1027c2aa98e2SPeter Wemm break; 1028c2aa98e2SPeter Wemm } 1029c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHCLASS) 1030c2aa98e2SPeter Wemm { 1031c2aa98e2SPeter Wemm /* extend binding and try again */ 103206f25ae9SGregory Neil Shapiro mlp->match_last = avp; 1033c2aa98e2SPeter Wemm goto extendclass; 1034c2aa98e2SPeter Wemm } 1035c2aa98e2SPeter Wemm } 1036c2aa98e2SPeter Wemm 1037c2aa98e2SPeter Wemm if (mlp < mlist) 1038c2aa98e2SPeter Wemm { 1039c2aa98e2SPeter Wemm /* total failure to match */ 1040c2aa98e2SPeter Wemm break; 1041c2aa98e2SPeter Wemm } 1042c2aa98e2SPeter Wemm } 1043c2aa98e2SPeter Wemm 1044c2aa98e2SPeter Wemm /* 1045c2aa98e2SPeter Wemm ** See if we successfully matched 1046c2aa98e2SPeter Wemm */ 1047c2aa98e2SPeter Wemm 1048c2aa98e2SPeter Wemm if (mlp < mlist || *rvp != NULL) 1049c2aa98e2SPeter Wemm { 1050c2aa98e2SPeter Wemm if (tTd(21, 10)) 105106f25ae9SGregory Neil Shapiro dprintf("----- rule fails\n"); 1052c2aa98e2SPeter Wemm rwr = rwr->r_next; 1053c2aa98e2SPeter Wemm ruleno++; 1054c2aa98e2SPeter Wemm loopcount = 0; 1055c2aa98e2SPeter Wemm continue; 1056c2aa98e2SPeter Wemm } 1057c2aa98e2SPeter Wemm 1058c2aa98e2SPeter Wemm rvp = rwr->r_rhs; 1059c2aa98e2SPeter Wemm if (tTd(21, 12)) 1060c2aa98e2SPeter Wemm { 106106f25ae9SGregory Neil Shapiro dprintf("-----rule matches:"); 1062c2aa98e2SPeter Wemm printav(rvp); 1063c2aa98e2SPeter Wemm } 1064c2aa98e2SPeter Wemm 1065c2aa98e2SPeter Wemm rp = *rvp; 106606f25ae9SGregory Neil Shapiro if (rp != NULL) 106706f25ae9SGregory Neil Shapiro { 1068c2aa98e2SPeter Wemm if ((*rp & 0377) == CANONUSER) 1069c2aa98e2SPeter Wemm { 1070c2aa98e2SPeter Wemm rvp++; 1071c2aa98e2SPeter Wemm rwr = rwr->r_next; 1072c2aa98e2SPeter Wemm ruleno++; 1073c2aa98e2SPeter Wemm loopcount = 0; 1074c2aa98e2SPeter Wemm } 1075c2aa98e2SPeter Wemm else if ((*rp & 0377) == CANONHOST) 1076c2aa98e2SPeter Wemm { 1077c2aa98e2SPeter Wemm rvp++; 1078c2aa98e2SPeter Wemm rwr = NULL; 1079c2aa98e2SPeter Wemm } 108006f25ae9SGregory Neil Shapiro } 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm /* substitute */ 1083c2aa98e2SPeter Wemm for (avp = npvp; *rvp != NULL; rvp++) 1084c2aa98e2SPeter Wemm { 1085c2aa98e2SPeter Wemm register struct match *m; 1086c2aa98e2SPeter Wemm register char **pp; 1087c2aa98e2SPeter Wemm 1088c2aa98e2SPeter Wemm rp = *rvp; 1089c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHREPL) 1090c2aa98e2SPeter Wemm { 1091c2aa98e2SPeter Wemm /* substitute from LHS */ 1092c2aa98e2SPeter Wemm m = &mlist[rp[1] - '1']; 1093c2aa98e2SPeter Wemm if (m < mlist || m >= mlp) 1094c2aa98e2SPeter Wemm { 109506f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 109606f25ae9SGregory Neil Shapiro rulename, rp[1]); 1097c2aa98e2SPeter Wemm return EX_CONFIG; 1098c2aa98e2SPeter Wemm } 1099c2aa98e2SPeter Wemm if (tTd(21, 15)) 1100c2aa98e2SPeter Wemm { 110106f25ae9SGregory Neil Shapiro dprintf("$%c:", rp[1]); 110206f25ae9SGregory Neil Shapiro pp = m->match_first; 110306f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1104c2aa98e2SPeter Wemm { 110506f25ae9SGregory Neil Shapiro dprintf(" %lx=\"", 110606f25ae9SGregory Neil Shapiro (u_long) *pp); 110706f25ae9SGregory Neil Shapiro (void) dflush(); 110806f25ae9SGregory Neil Shapiro dprintf("%s\"", *pp++); 1109c2aa98e2SPeter Wemm } 111006f25ae9SGregory Neil Shapiro dprintf("\n"); 1111c2aa98e2SPeter Wemm } 111206f25ae9SGregory Neil Shapiro pp = m->match_first; 111306f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1114c2aa98e2SPeter Wemm { 1115c2aa98e2SPeter Wemm if (avp >= &npvp[MAXATOM]) 1116c2aa98e2SPeter Wemm { 111706f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 1118c2aa98e2SPeter Wemm return EX_DATAERR; 1119c2aa98e2SPeter Wemm } 1120c2aa98e2SPeter Wemm *avp++ = *pp++; 1121c2aa98e2SPeter Wemm } 1122c2aa98e2SPeter Wemm } 1123c2aa98e2SPeter Wemm else 1124c2aa98e2SPeter Wemm { 1125c2aa98e2SPeter Wemm /* some sort of replacement */ 1126c2aa98e2SPeter Wemm if (avp >= &npvp[MAXATOM]) 1127c2aa98e2SPeter Wemm { 1128c2aa98e2SPeter Wemm toolong: 112906f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 1130c2aa98e2SPeter Wemm return EX_DATAERR; 1131c2aa98e2SPeter Wemm } 1132c2aa98e2SPeter Wemm if ((*rp & 0377) != MACRODEXPAND) 1133c2aa98e2SPeter Wemm { 1134c2aa98e2SPeter Wemm /* vanilla replacement */ 1135c2aa98e2SPeter Wemm *avp++ = rp; 1136c2aa98e2SPeter Wemm } 1137c2aa98e2SPeter Wemm else 1138c2aa98e2SPeter Wemm { 1139c2aa98e2SPeter Wemm /* $&x replacement */ 1140c2aa98e2SPeter Wemm char *mval = macvalue(rp[1], e); 1141c2aa98e2SPeter Wemm char **xpvp; 1142c2aa98e2SPeter Wemm int trsize = 0; 1143c2aa98e2SPeter Wemm static size_t pvpb1_size = 0; 1144c2aa98e2SPeter Wemm static char **pvpb1 = NULL; 1145c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1146c2aa98e2SPeter Wemm 1147c2aa98e2SPeter Wemm if (tTd(21, 2)) 114806f25ae9SGregory Neil Shapiro dprintf("rewrite: RHS $&%s => \"%s\"\n", 1149c2aa98e2SPeter Wemm macname(rp[1]), 1150c2aa98e2SPeter Wemm mval == NULL ? "(NULL)" : mval); 1151c2aa98e2SPeter Wemm if (mval == NULL || *mval == '\0') 1152c2aa98e2SPeter Wemm continue; 1153c2aa98e2SPeter Wemm 1154c2aa98e2SPeter Wemm /* save the remainder of the input */ 1155c2aa98e2SPeter Wemm for (xpvp = pvp; *xpvp != NULL; xpvp++) 1156c2aa98e2SPeter Wemm trsize += sizeof *xpvp; 115706f25ae9SGregory Neil Shapiro if ((size_t) trsize > pvpb1_size) 1158c2aa98e2SPeter Wemm { 1159c2aa98e2SPeter Wemm if (pvpb1 != NULL) 1160c2aa98e2SPeter Wemm free(pvpb1); 1161c2aa98e2SPeter Wemm pvpb1 = (char **)xalloc(trsize); 1162c2aa98e2SPeter Wemm pvpb1_size = trsize; 1163c2aa98e2SPeter Wemm } 1164c2aa98e2SPeter Wemm 116506f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, 116606f25ae9SGregory Neil Shapiro (char *) pvp, 116706f25ae9SGregory Neil Shapiro trsize); 1168c2aa98e2SPeter Wemm 1169c2aa98e2SPeter Wemm /* scan the new replacement */ 1170c2aa98e2SPeter Wemm xpvp = prescan(mval, '\0', pvpbuf, 117106f25ae9SGregory Neil Shapiro sizeof pvpbuf, NULL, 117206f25ae9SGregory Neil Shapiro NULL); 1173c2aa98e2SPeter Wemm if (xpvp == NULL) 1174c2aa98e2SPeter Wemm { 1175c2aa98e2SPeter Wemm /* prescan pre-printed error */ 1176c2aa98e2SPeter Wemm return EX_DATAERR; 1177c2aa98e2SPeter Wemm } 1178c2aa98e2SPeter Wemm 1179c2aa98e2SPeter Wemm /* insert it into the output stream */ 1180c2aa98e2SPeter Wemm while (*xpvp != NULL) 1181c2aa98e2SPeter Wemm { 1182c2aa98e2SPeter Wemm if (tTd(21, 19)) 118306f25ae9SGregory Neil Shapiro dprintf(" ... %s\n", 118406f25ae9SGregory Neil Shapiro *xpvp); 1185c2aa98e2SPeter Wemm *avp++ = newstr(*xpvp); 1186c2aa98e2SPeter Wemm if (avp >= &npvp[MAXATOM]) 1187c2aa98e2SPeter Wemm goto toolong; 1188c2aa98e2SPeter Wemm xpvp++; 1189c2aa98e2SPeter Wemm } 1190c2aa98e2SPeter Wemm if (tTd(21, 19)) 119106f25ae9SGregory Neil Shapiro dprintf(" ... DONE\n"); 1192c2aa98e2SPeter Wemm 1193c2aa98e2SPeter Wemm /* restore the old trailing input */ 119406f25ae9SGregory Neil Shapiro memmove((char *) pvp, 119506f25ae9SGregory Neil Shapiro (char *) pvpb1, 119606f25ae9SGregory Neil Shapiro trsize); 1197c2aa98e2SPeter Wemm } 1198c2aa98e2SPeter Wemm } 1199c2aa98e2SPeter Wemm } 1200c2aa98e2SPeter Wemm *avp++ = NULL; 1201c2aa98e2SPeter Wemm 1202c2aa98e2SPeter Wemm /* 1203c2aa98e2SPeter Wemm ** Check for any hostname/keyword lookups. 1204c2aa98e2SPeter Wemm */ 1205c2aa98e2SPeter Wemm 1206c2aa98e2SPeter Wemm for (rvp = npvp; *rvp != NULL; rvp++) 1207c2aa98e2SPeter Wemm { 1208c2aa98e2SPeter Wemm char **hbrvp; 1209c2aa98e2SPeter Wemm char **xpvp; 1210c2aa98e2SPeter Wemm int trsize; 1211c2aa98e2SPeter Wemm char *replac; 1212c2aa98e2SPeter Wemm int endtoken; 1213c2aa98e2SPeter Wemm STAB *map; 1214c2aa98e2SPeter Wemm char *mapname; 1215c2aa98e2SPeter Wemm char **key_rvp; 1216c2aa98e2SPeter Wemm char **arg_rvp; 1217c2aa98e2SPeter Wemm char **default_rvp; 121806f25ae9SGregory Neil Shapiro char cbuf[MAXNAME + 1]; 1219c2aa98e2SPeter Wemm char *pvpb1[MAXATOM + 1]; 1220c2aa98e2SPeter Wemm char *argvect[10]; 1221c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1222c2aa98e2SPeter Wemm char *nullpvp[1]; 1223c2aa98e2SPeter Wemm 1224c2aa98e2SPeter Wemm if ((**rvp & 0377) != HOSTBEGIN && 1225c2aa98e2SPeter Wemm (**rvp & 0377) != LOOKUPBEGIN) 1226c2aa98e2SPeter Wemm continue; 1227c2aa98e2SPeter Wemm 1228c2aa98e2SPeter Wemm /* 1229c2aa98e2SPeter Wemm ** Got a hostname/keyword lookup. 1230c2aa98e2SPeter Wemm ** 1231c2aa98e2SPeter Wemm ** This could be optimized fairly easily. 1232c2aa98e2SPeter Wemm */ 1233c2aa98e2SPeter Wemm 1234c2aa98e2SPeter Wemm hbrvp = rvp; 1235c2aa98e2SPeter Wemm if ((**rvp & 0377) == HOSTBEGIN) 1236c2aa98e2SPeter Wemm { 1237c2aa98e2SPeter Wemm endtoken = HOSTEND; 1238c2aa98e2SPeter Wemm mapname = "host"; 1239c2aa98e2SPeter Wemm } 1240c2aa98e2SPeter Wemm else 1241c2aa98e2SPeter Wemm { 1242c2aa98e2SPeter Wemm endtoken = LOOKUPEND; 1243c2aa98e2SPeter Wemm mapname = *++rvp; 1244c2aa98e2SPeter Wemm } 1245c2aa98e2SPeter Wemm map = stab(mapname, ST_MAP, ST_FIND); 1246c2aa98e2SPeter Wemm if (map == NULL) 124706f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: map %s not found", mapname); 1248c2aa98e2SPeter Wemm 1249c2aa98e2SPeter Wemm /* extract the match part */ 1250c2aa98e2SPeter Wemm key_rvp = ++rvp; 1251c2aa98e2SPeter Wemm default_rvp = NULL; 1252c2aa98e2SPeter Wemm arg_rvp = argvect; 1253c2aa98e2SPeter Wemm xpvp = NULL; 1254c2aa98e2SPeter Wemm replac = pvpbuf; 1255c2aa98e2SPeter Wemm while (*rvp != NULL && (**rvp & 0377) != endtoken) 1256c2aa98e2SPeter Wemm { 1257c2aa98e2SPeter Wemm int nodetype = **rvp & 0377; 1258c2aa98e2SPeter Wemm 1259c2aa98e2SPeter Wemm if (nodetype != CANONHOST && nodetype != CANONUSER) 1260c2aa98e2SPeter Wemm { 1261c2aa98e2SPeter Wemm rvp++; 1262c2aa98e2SPeter Wemm continue; 1263c2aa98e2SPeter Wemm } 1264c2aa98e2SPeter Wemm 1265c2aa98e2SPeter Wemm *rvp++ = NULL; 1266c2aa98e2SPeter Wemm 1267c2aa98e2SPeter Wemm if (xpvp != NULL) 1268c2aa98e2SPeter Wemm { 1269c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1270c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1271c2aa98e2SPeter Wemm '\0'); 1272c2aa98e2SPeter Wemm *++arg_rvp = replac; 1273c2aa98e2SPeter Wemm replac += strlen(replac) + 1; 1274c2aa98e2SPeter Wemm xpvp = NULL; 1275c2aa98e2SPeter Wemm } 1276c2aa98e2SPeter Wemm switch (nodetype) 1277c2aa98e2SPeter Wemm { 1278c2aa98e2SPeter Wemm case CANONHOST: 1279c2aa98e2SPeter Wemm xpvp = rvp; 1280c2aa98e2SPeter Wemm break; 1281c2aa98e2SPeter Wemm 1282c2aa98e2SPeter Wemm case CANONUSER: 1283c2aa98e2SPeter Wemm default_rvp = rvp; 1284c2aa98e2SPeter Wemm break; 1285c2aa98e2SPeter Wemm } 1286c2aa98e2SPeter Wemm } 1287c2aa98e2SPeter Wemm if (*rvp != NULL) 1288c2aa98e2SPeter Wemm *rvp++ = NULL; 1289c2aa98e2SPeter Wemm if (xpvp != NULL) 1290c2aa98e2SPeter Wemm { 1291c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1292c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1293c2aa98e2SPeter Wemm '\0'); 1294c2aa98e2SPeter Wemm *++arg_rvp = replac; 1295c2aa98e2SPeter Wemm } 1296c2aa98e2SPeter Wemm *++arg_rvp = NULL; 1297c2aa98e2SPeter Wemm 1298c2aa98e2SPeter Wemm /* save the remainder of the input string */ 1299c2aa98e2SPeter Wemm trsize = (int) (avp - rvp + 1) * sizeof *rvp; 130006f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, (char *) rvp, trsize); 1301c2aa98e2SPeter Wemm 1302c2aa98e2SPeter Wemm /* look it up */ 130306f25ae9SGregory Neil Shapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 130406f25ae9SGregory Neil Shapiro map == NULL ? '\0' : map->s_map.map_spacesub); 130506f25ae9SGregory Neil Shapiro argvect[0] = cbuf; 130606f25ae9SGregory Neil Shapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 1307c2aa98e2SPeter Wemm 1308c2aa98e2SPeter Wemm /* if no replacement, use default */ 1309c2aa98e2SPeter Wemm if (replac == NULL && default_rvp != NULL) 1310c2aa98e2SPeter Wemm { 1311c2aa98e2SPeter Wemm /* create the default */ 131206f25ae9SGregory Neil Shapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 131306f25ae9SGregory Neil Shapiro replac = cbuf; 1314c2aa98e2SPeter Wemm } 1315c2aa98e2SPeter Wemm 1316c2aa98e2SPeter Wemm if (replac == NULL) 1317c2aa98e2SPeter Wemm { 1318c2aa98e2SPeter Wemm xpvp = key_rvp; 1319c2aa98e2SPeter Wemm } 1320c2aa98e2SPeter Wemm else if (*replac == '\0') 1321c2aa98e2SPeter Wemm { 1322c2aa98e2SPeter Wemm /* null replacement */ 1323c2aa98e2SPeter Wemm nullpvp[0] = NULL; 1324c2aa98e2SPeter Wemm xpvp = nullpvp; 1325c2aa98e2SPeter Wemm } 1326c2aa98e2SPeter Wemm else 1327c2aa98e2SPeter Wemm { 1328c2aa98e2SPeter Wemm /* scan the new replacement */ 1329c2aa98e2SPeter Wemm xpvp = prescan(replac, '\0', pvpbuf, 1330c2aa98e2SPeter Wemm sizeof pvpbuf, NULL, NULL); 1331c2aa98e2SPeter Wemm if (xpvp == NULL) 1332c2aa98e2SPeter Wemm { 1333c2aa98e2SPeter Wemm /* prescan already printed error */ 1334c2aa98e2SPeter Wemm return EX_DATAERR; 1335c2aa98e2SPeter Wemm } 1336c2aa98e2SPeter Wemm } 1337c2aa98e2SPeter Wemm 1338c2aa98e2SPeter Wemm /* append it to the token list */ 1339c2aa98e2SPeter Wemm for (avp = hbrvp; *xpvp != NULL; xpvp++) 1340c2aa98e2SPeter Wemm { 1341c2aa98e2SPeter Wemm *avp++ = newstr(*xpvp); 1342c2aa98e2SPeter Wemm if (avp >= &npvp[MAXATOM]) 1343c2aa98e2SPeter Wemm goto toolong; 1344c2aa98e2SPeter Wemm } 1345c2aa98e2SPeter Wemm 1346c2aa98e2SPeter Wemm /* restore the old trailing information */ 1347c2aa98e2SPeter Wemm rvp = avp - 1; 1348c2aa98e2SPeter Wemm for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1349c2aa98e2SPeter Wemm if (avp >= &npvp[MAXATOM]) 1350c2aa98e2SPeter Wemm goto toolong; 1351c2aa98e2SPeter Wemm } 1352c2aa98e2SPeter Wemm 1353c2aa98e2SPeter Wemm /* 1354c2aa98e2SPeter Wemm ** Check for subroutine calls. 1355c2aa98e2SPeter Wemm */ 1356c2aa98e2SPeter Wemm 135706f25ae9SGregory Neil Shapiro status = callsubr(npvp, reclevel, e); 135806f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 135906f25ae9SGregory Neil Shapiro rstat = status; 1360c2aa98e2SPeter Wemm 1361c2aa98e2SPeter Wemm /* copy vector back into original space. */ 1362c2aa98e2SPeter Wemm for (avp = npvp; *avp++ != NULL;) 1363c2aa98e2SPeter Wemm continue; 136406f25ae9SGregory Neil Shapiro memmove((char *) pvp, (char *) npvp, 1365c2aa98e2SPeter Wemm (int) (avp - npvp) * sizeof *avp); 1366c2aa98e2SPeter Wemm 1367c2aa98e2SPeter Wemm if (tTd(21, 4)) 1368c2aa98e2SPeter Wemm { 136906f25ae9SGregory Neil Shapiro dprintf("rewritten as:"); 1370c2aa98e2SPeter Wemm printav(pvp); 1371c2aa98e2SPeter Wemm } 1372c2aa98e2SPeter Wemm } 1373c2aa98e2SPeter Wemm 137406f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 1375c2aa98e2SPeter Wemm { 137606f25ae9SGregory Neil Shapiro printf("%s%-16.16s returns:", prefix, rulename); 1377c2aa98e2SPeter Wemm printav(pvp); 1378c2aa98e2SPeter Wemm } 137906f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 138006f25ae9SGregory Neil Shapiro { 138106f25ae9SGregory Neil Shapiro dprintf("%s%-16.16s returns:", prefix, rulename); 138206f25ae9SGregory Neil Shapiro printav(pvp); 138306f25ae9SGregory Neil Shapiro } 1384c2aa98e2SPeter Wemm return rstat; 1385c2aa98e2SPeter Wemm } 1386c2aa98e2SPeter Wemm /* 1387c2aa98e2SPeter Wemm ** CALLSUBR -- call subroutines in rewrite vector 1388c2aa98e2SPeter Wemm ** 1389c2aa98e2SPeter Wemm ** Parameters: 1390c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 1391c2aa98e2SPeter Wemm ** reclevel -- the current recursion level. 1392c2aa98e2SPeter Wemm ** e -- the current envelope. 1393c2aa98e2SPeter Wemm ** 1394c2aa98e2SPeter Wemm ** Returns: 1395c2aa98e2SPeter Wemm ** The status from the subroutine call. 1396c2aa98e2SPeter Wemm ** 1397c2aa98e2SPeter Wemm ** Side Effects: 1398c2aa98e2SPeter Wemm ** pvp is modified. 1399c2aa98e2SPeter Wemm */ 1400c2aa98e2SPeter Wemm 140106f25ae9SGregory Neil Shapiro static int 1402c2aa98e2SPeter Wemm callsubr(pvp, reclevel, e) 1403c2aa98e2SPeter Wemm char **pvp; 1404c2aa98e2SPeter Wemm int reclevel; 1405c2aa98e2SPeter Wemm ENVELOPE *e; 1406c2aa98e2SPeter Wemm { 1407c2aa98e2SPeter Wemm char **avp; 1408c2aa98e2SPeter Wemm char **rvp; 1409c2aa98e2SPeter Wemm register int i; 1410c2aa98e2SPeter Wemm int subr; 141106f25ae9SGregory Neil Shapiro int status; 1412c2aa98e2SPeter Wemm int rstat = EX_OK; 1413c2aa98e2SPeter Wemm char *tpvp[MAXATOM + 1]; 1414c2aa98e2SPeter Wemm 1415c2aa98e2SPeter Wemm for (avp = pvp; *avp != NULL; avp++) 1416c2aa98e2SPeter Wemm { 1417c2aa98e2SPeter Wemm if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1418c2aa98e2SPeter Wemm { 1419c2aa98e2SPeter Wemm stripquotes(avp[1]); 1420c2aa98e2SPeter Wemm subr = strtorwset(avp[1], NULL, ST_FIND); 1421c2aa98e2SPeter Wemm if (subr < 0) 1422c2aa98e2SPeter Wemm { 1423c2aa98e2SPeter Wemm syserr("Unknown ruleset %s", avp[1]); 1424c2aa98e2SPeter Wemm return EX_CONFIG; 1425c2aa98e2SPeter Wemm } 1426c2aa98e2SPeter Wemm 1427c2aa98e2SPeter Wemm if (tTd(21, 3)) 142806f25ae9SGregory Neil Shapiro dprintf("-----callsubr %s (%d)\n", 142906f25ae9SGregory Neil Shapiro avp[1], subr); 1430c2aa98e2SPeter Wemm 1431c2aa98e2SPeter Wemm /* 1432c2aa98e2SPeter Wemm ** Take care of possible inner calls first. 1433c2aa98e2SPeter Wemm ** use a full size temporary buffer to avoid 1434c2aa98e2SPeter Wemm ** overflows in rewrite, but strip off the 1435c2aa98e2SPeter Wemm ** subroutine call. 1436c2aa98e2SPeter Wemm */ 1437c2aa98e2SPeter Wemm 1438c2aa98e2SPeter Wemm for (i = 2; avp[i] != NULL; i++) 1439c2aa98e2SPeter Wemm tpvp[i - 2] = avp[i]; 1440c2aa98e2SPeter Wemm tpvp[i - 2] = NULL; 1441c2aa98e2SPeter Wemm 144206f25ae9SGregory Neil Shapiro status = callsubr(tpvp, reclevel, e); 144306f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 144406f25ae9SGregory Neil Shapiro rstat = status; 1445c2aa98e2SPeter Wemm 1446c2aa98e2SPeter Wemm /* 1447c2aa98e2SPeter Wemm ** Now we need to call the ruleset specified for 1448c2aa98e2SPeter Wemm ** the subroutine. we can do this with the 1449c2aa98e2SPeter Wemm ** temporary buffer that we set up earlier, 1450c2aa98e2SPeter Wemm ** since it has all the data we want to rewrite. 1451c2aa98e2SPeter Wemm */ 1452c2aa98e2SPeter Wemm 145306f25ae9SGregory Neil Shapiro status = rewrite(tpvp, subr, reclevel, e); 145406f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 145506f25ae9SGregory Neil Shapiro rstat = status; 1456c2aa98e2SPeter Wemm 1457c2aa98e2SPeter Wemm /* 1458c2aa98e2SPeter Wemm ** Find length of tpvp and current offset into 1459c2aa98e2SPeter Wemm ** pvp, if the total is greater than MAXATOM, 1460c2aa98e2SPeter Wemm ** then it would overflow the buffer if we copied 1461c2aa98e2SPeter Wemm ** it back in to pvp, in which case we throw a 1462c2aa98e2SPeter Wemm ** fit. 1463c2aa98e2SPeter Wemm */ 1464c2aa98e2SPeter Wemm 1465c2aa98e2SPeter Wemm for (rvp = tpvp; *rvp != NULL; rvp++) 1466c2aa98e2SPeter Wemm continue; 1467c2aa98e2SPeter Wemm if (((rvp - tpvp) + (avp - pvp)) > MAXATOM) 1468c2aa98e2SPeter Wemm { 146906f25ae9SGregory Neil Shapiro syserr("554 5.3.0 callsubr: expansion too long"); 1470c2aa98e2SPeter Wemm return EX_DATAERR; 1471c2aa98e2SPeter Wemm } 1472c2aa98e2SPeter Wemm 1473c2aa98e2SPeter Wemm /* 1474c2aa98e2SPeter Wemm ** Now we can copy the rewritten code over 1475c2aa98e2SPeter Wemm ** the initial subroutine call in the buffer. 1476c2aa98e2SPeter Wemm */ 1477c2aa98e2SPeter Wemm 1478c2aa98e2SPeter Wemm for (i = 0; tpvp[i] != NULL; i++) 1479c2aa98e2SPeter Wemm avp[i] = tpvp[i]; 1480c2aa98e2SPeter Wemm avp[i] = NULL; 1481c2aa98e2SPeter Wemm 1482c2aa98e2SPeter Wemm /* 1483c2aa98e2SPeter Wemm ** If we got this far, we've processed the left 1484c2aa98e2SPeter Wemm ** most subroutine, and recursively called ourselves 1485c2aa98e2SPeter Wemm ** to handle any other subroutines. We're done. 1486c2aa98e2SPeter Wemm */ 1487c2aa98e2SPeter Wemm 1488c2aa98e2SPeter Wemm break; 1489c2aa98e2SPeter Wemm } 1490c2aa98e2SPeter Wemm } 1491c2aa98e2SPeter Wemm return rstat; 1492c2aa98e2SPeter Wemm } 1493c2aa98e2SPeter Wemm /* 1494c2aa98e2SPeter Wemm ** MAP_LOOKUP -- do lookup in map 1495c2aa98e2SPeter Wemm ** 1496c2aa98e2SPeter Wemm ** Parameters: 1497c2aa98e2SPeter Wemm ** map -- the map to use for the lookup. 1498c2aa98e2SPeter Wemm ** key -- the key to look up. 1499c2aa98e2SPeter Wemm ** argvect -- arguments to pass to the map lookup. 1500c2aa98e2SPeter Wemm ** pstat -- a pointer to an integer in which to store the 1501c2aa98e2SPeter Wemm ** status from the lookup. 1502c2aa98e2SPeter Wemm ** e -- the current envelope. 1503c2aa98e2SPeter Wemm ** 1504c2aa98e2SPeter Wemm ** Returns: 1505c2aa98e2SPeter Wemm ** The result of the lookup. 1506c2aa98e2SPeter Wemm ** NULL -- if there was no data for the given key. 1507c2aa98e2SPeter Wemm */ 1508c2aa98e2SPeter Wemm 150906f25ae9SGregory Neil Shapiro static char * 151006f25ae9SGregory Neil Shapiro map_lookup(smap, key, argvect, pstat, e) 151106f25ae9SGregory Neil Shapiro STAB *smap; 1512c2aa98e2SPeter Wemm char key[]; 1513c2aa98e2SPeter Wemm char **argvect; 1514c2aa98e2SPeter Wemm int *pstat; 1515c2aa98e2SPeter Wemm ENVELOPE *e; 1516c2aa98e2SPeter Wemm { 151706f25ae9SGregory Neil Shapiro auto int status = EX_OK; 151806f25ae9SGregory Neil Shapiro MAP *map; 1519c2aa98e2SPeter Wemm char *replac; 1520c2aa98e2SPeter Wemm 152106f25ae9SGregory Neil Shapiro if (smap == NULL) 152206f25ae9SGregory Neil Shapiro return NULL; 152306f25ae9SGregory Neil Shapiro 152406f25ae9SGregory Neil Shapiro map = &smap->s_map; 152506f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 152606f25ae9SGregory Neil Shapiro 152706f25ae9SGregory Neil Shapiro if (e->e_sendmode == SM_DEFER && 152806f25ae9SGregory Neil Shapiro bitset(MF_DEFER, map->map_mflags)) 1529c2aa98e2SPeter Wemm { 1530c2aa98e2SPeter Wemm /* don't do any map lookups */ 1531c2aa98e2SPeter Wemm if (tTd(60, 1)) 153206f25ae9SGregory Neil Shapiro dprintf("map_lookup(%s, %s) => DEFERRED\n", 153306f25ae9SGregory Neil Shapiro smap->s_name, key); 1534c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1535c2aa98e2SPeter Wemm return NULL; 1536c2aa98e2SPeter Wemm } 1537c2aa98e2SPeter Wemm 153806f25ae9SGregory Neil Shapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1539c2aa98e2SPeter Wemm stripquotes(key); 1540c2aa98e2SPeter Wemm 1541c2aa98e2SPeter Wemm if (tTd(60, 1)) 1542065a643dSPeter Wemm { 154306f25ae9SGregory Neil Shapiro dprintf("map_lookup(%s, %s", smap->s_name, key); 1544065a643dSPeter Wemm if (tTd(60, 5)) 1545065a643dSPeter Wemm { 1546065a643dSPeter Wemm int i; 1547065a643dSPeter Wemm 1548065a643dSPeter Wemm for (i = 0; argvect[i] != NULL; i++) 154906f25ae9SGregory Neil Shapiro dprintf(", %%%d=%s", i, argvect[i]); 1550065a643dSPeter Wemm } 155106f25ae9SGregory Neil Shapiro dprintf(") => "); 1552065a643dSPeter Wemm } 155306f25ae9SGregory Neil Shapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1554c2aa98e2SPeter Wemm if (tTd(60, 1)) 155506f25ae9SGregory Neil Shapiro dprintf("%s (%d)\n", 1556c2aa98e2SPeter Wemm replac != NULL ? replac : "NOT FOUND", 155706f25ae9SGregory Neil Shapiro status); 1558c2aa98e2SPeter Wemm 155906f25ae9SGregory Neil Shapiro /* should recover if status == EX_TEMPFAIL */ 156006f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1561c2aa98e2SPeter Wemm { 1562c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1563c2aa98e2SPeter Wemm if (tTd(60, 1)) 156406f25ae9SGregory Neil Shapiro dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 156506f25ae9SGregory Neil Shapiro smap->s_name, key, errno); 1566c2aa98e2SPeter Wemm if (e->e_message == NULL) 1567c2aa98e2SPeter Wemm { 1568c2aa98e2SPeter Wemm char mbuf[320]; 1569c2aa98e2SPeter Wemm 1570c2aa98e2SPeter Wemm snprintf(mbuf, sizeof mbuf, 1571c2aa98e2SPeter Wemm "%.80s map: lookup (%s): deferred", 157206f25ae9SGregory Neil Shapiro smap->s_name, 1573c2aa98e2SPeter Wemm shortenstring(key, MAXSHORTSTR)); 1574c2aa98e2SPeter Wemm e->e_message = newstr(mbuf); 1575c2aa98e2SPeter Wemm } 1576c2aa98e2SPeter Wemm } 157706f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1578c2aa98e2SPeter Wemm { 157906f25ae9SGregory Neil Shapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1580c2aa98e2SPeter Wemm static char *rwbuf = NULL; 1581c2aa98e2SPeter Wemm static size_t rwbuflen = 0; 1582c2aa98e2SPeter Wemm 1583c2aa98e2SPeter Wemm if (i > rwbuflen) 1584c2aa98e2SPeter Wemm { 1585c2aa98e2SPeter Wemm if (rwbuf != NULL) 1586c2aa98e2SPeter Wemm free(rwbuf); 1587c2aa98e2SPeter Wemm rwbuflen = i; 1588c2aa98e2SPeter Wemm rwbuf = (char *) xalloc(rwbuflen); 1589c2aa98e2SPeter Wemm } 159006f25ae9SGregory Neil Shapiro snprintf(rwbuf, rwbuflen, "%s%s", key, map->map_tapp); 1591c2aa98e2SPeter Wemm if (tTd(60, 4)) 159206f25ae9SGregory Neil Shapiro dprintf("map_lookup tempfail: returning \"%s\"\n", 1593c2aa98e2SPeter Wemm rwbuf); 1594c2aa98e2SPeter Wemm return rwbuf; 1595c2aa98e2SPeter Wemm } 1596c2aa98e2SPeter Wemm return replac; 1597c2aa98e2SPeter Wemm } 1598c2aa98e2SPeter Wemm /* 159906f25ae9SGregory Neil Shapiro ** INITERRMAILERS -- initialize error and discard mailers 160006f25ae9SGregory Neil Shapiro ** 160106f25ae9SGregory Neil Shapiro ** Parameters: 160206f25ae9SGregory Neil Shapiro ** none. 160306f25ae9SGregory Neil Shapiro ** 160406f25ae9SGregory Neil Shapiro ** Returns: 160506f25ae9SGregory Neil Shapiro ** none. 160606f25ae9SGregory Neil Shapiro ** 160706f25ae9SGregory Neil Shapiro ** Side Effects: 160806f25ae9SGregory Neil Shapiro ** initializes error and discard mailers. 160906f25ae9SGregory Neil Shapiro */ 161006f25ae9SGregory Neil Shapiro 161106f25ae9SGregory Neil Shapiro static MAILER discardmailer; 161206f25ae9SGregory Neil Shapiro static MAILER errormailer; 161306f25ae9SGregory Neil Shapiro static char *discardargv[] = { "DISCARD", NULL }; 161406f25ae9SGregory Neil Shapiro static char *errorargv[] = { "ERROR", NULL }; 161506f25ae9SGregory Neil Shapiro 161606f25ae9SGregory Neil Shapiro void 161706f25ae9SGregory Neil Shapiro initerrmailers() 161806f25ae9SGregory Neil Shapiro { 161906f25ae9SGregory Neil Shapiro if (discardmailer.m_name == NULL) 162006f25ae9SGregory Neil Shapiro { 162106f25ae9SGregory Neil Shapiro /* initialize the discard mailer */ 162206f25ae9SGregory Neil Shapiro discardmailer.m_name = "*discard*"; 162306f25ae9SGregory Neil Shapiro discardmailer.m_mailer = "DISCARD"; 162406f25ae9SGregory Neil Shapiro discardmailer.m_argv = discardargv; 162506f25ae9SGregory Neil Shapiro } 162606f25ae9SGregory Neil Shapiro if (errormailer.m_name == NULL) 162706f25ae9SGregory Neil Shapiro { 162806f25ae9SGregory Neil Shapiro /* initialize the bogus mailer */ 162906f25ae9SGregory Neil Shapiro errormailer.m_name = "*error*"; 163006f25ae9SGregory Neil Shapiro errormailer.m_mailer = "ERROR"; 163106f25ae9SGregory Neil Shapiro errormailer.m_argv = errorargv; 163206f25ae9SGregory Neil Shapiro } 163306f25ae9SGregory Neil Shapiro } 163406f25ae9SGregory Neil Shapiro /* 1635c2aa98e2SPeter Wemm ** BUILDADDR -- build address from token vector. 1636c2aa98e2SPeter Wemm ** 1637c2aa98e2SPeter Wemm ** Parameters: 1638c2aa98e2SPeter Wemm ** tv -- token vector. 1639c2aa98e2SPeter Wemm ** a -- pointer to address descriptor to fill. 1640c2aa98e2SPeter Wemm ** If NULL, one will be allocated. 1641c2aa98e2SPeter Wemm ** flags -- info regarding whether this is a sender or 1642c2aa98e2SPeter Wemm ** a recipient. 1643c2aa98e2SPeter Wemm ** e -- the current envelope. 1644c2aa98e2SPeter Wemm ** 1645c2aa98e2SPeter Wemm ** Returns: 1646c2aa98e2SPeter Wemm ** NULL if there was an error. 1647c2aa98e2SPeter Wemm ** 'a' otherwise. 1648c2aa98e2SPeter Wemm ** 1649c2aa98e2SPeter Wemm ** Side Effects: 1650c2aa98e2SPeter Wemm ** fills in 'a' 1651c2aa98e2SPeter Wemm */ 1652c2aa98e2SPeter Wemm 165306f25ae9SGregory Neil Shapiro static struct errcodes 1654c2aa98e2SPeter Wemm { 1655c2aa98e2SPeter Wemm char *ec_name; /* name of error code */ 1656c2aa98e2SPeter Wemm int ec_code; /* numeric code */ 1657c2aa98e2SPeter Wemm } ErrorCodes[] = 1658c2aa98e2SPeter Wemm { 1659c2aa98e2SPeter Wemm { "usage", EX_USAGE }, 1660c2aa98e2SPeter Wemm { "nouser", EX_NOUSER }, 1661c2aa98e2SPeter Wemm { "nohost", EX_NOHOST }, 1662c2aa98e2SPeter Wemm { "unavailable", EX_UNAVAILABLE }, 1663c2aa98e2SPeter Wemm { "software", EX_SOFTWARE }, 1664c2aa98e2SPeter Wemm { "tempfail", EX_TEMPFAIL }, 1665c2aa98e2SPeter Wemm { "protocol", EX_PROTOCOL }, 1666c2aa98e2SPeter Wemm #ifdef EX_CONFIG 1667c2aa98e2SPeter Wemm { "config", EX_CONFIG }, 166806f25ae9SGregory Neil Shapiro #endif /* EX_CONFIG */ 1669c2aa98e2SPeter Wemm { NULL, EX_UNAVAILABLE } 1670c2aa98e2SPeter Wemm }; 1671c2aa98e2SPeter Wemm 167206f25ae9SGregory Neil Shapiro 167306f25ae9SGregory Neil Shapiro static ADDRESS * 1674c2aa98e2SPeter Wemm buildaddr(tv, a, flags, e) 1675c2aa98e2SPeter Wemm register char **tv; 1676c2aa98e2SPeter Wemm register ADDRESS *a; 1677c2aa98e2SPeter Wemm int flags; 1678c2aa98e2SPeter Wemm register ENVELOPE *e; 1679c2aa98e2SPeter Wemm { 1680c2aa98e2SPeter Wemm struct mailer **mp; 1681c2aa98e2SPeter Wemm register struct mailer *m; 1682c2aa98e2SPeter Wemm register char *p; 1683c2aa98e2SPeter Wemm char *mname; 1684c2aa98e2SPeter Wemm char **hostp; 1685c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1686065a643dSPeter Wemm static char ubuf[MAXNAME + 2]; 1687c2aa98e2SPeter Wemm 1688c2aa98e2SPeter Wemm if (tTd(24, 5)) 1689c2aa98e2SPeter Wemm { 169006f25ae9SGregory Neil Shapiro dprintf("buildaddr, flags=%x, tv=", flags); 1691c2aa98e2SPeter Wemm printav(tv); 1692c2aa98e2SPeter Wemm } 1693c2aa98e2SPeter Wemm 1694c2aa98e2SPeter Wemm if (a == NULL) 1695c2aa98e2SPeter Wemm a = (ADDRESS *) xalloc(sizeof *a); 169606f25ae9SGregory Neil Shapiro memset((char *) a, '\0', sizeof *a); 169706f25ae9SGregory Neil Shapiro hbuf[0] = '\0'; 1698c2aa98e2SPeter Wemm 1699c2aa98e2SPeter Wemm /* set up default error return flags */ 1700c2aa98e2SPeter Wemm a->q_flags |= DefaultNotify; 1701c2aa98e2SPeter Wemm 1702c2aa98e2SPeter Wemm /* figure out what net/mailer to use */ 1703c2aa98e2SPeter Wemm if (*tv == NULL || (**tv & 0377) != CANONNET) 1704c2aa98e2SPeter Wemm { 170506f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1706c2aa98e2SPeter Wemm badaddr: 170706f25ae9SGregory Neil Shapiro if (ExitStat == EX_TEMPFAIL) 170806f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 170906f25ae9SGregory Neil Shapiro else 1710c2aa98e2SPeter Wemm { 171106f25ae9SGregory Neil Shapiro a->q_state = QS_BADADDR; 171206f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 1713c2aa98e2SPeter Wemm } 1714c2aa98e2SPeter Wemm return a; 1715c2aa98e2SPeter Wemm } 1716c2aa98e2SPeter Wemm mname = *++tv; 1717c2aa98e2SPeter Wemm 1718c2aa98e2SPeter Wemm /* extract host and user portions */ 1719c2aa98e2SPeter Wemm if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1720c2aa98e2SPeter Wemm hostp = ++tv; 1721c2aa98e2SPeter Wemm else 1722c2aa98e2SPeter Wemm hostp = NULL; 1723c2aa98e2SPeter Wemm while (*tv != NULL && (**tv & 0377) != CANONUSER) 1724c2aa98e2SPeter Wemm tv++; 1725c2aa98e2SPeter Wemm if (*tv == NULL) 1726c2aa98e2SPeter Wemm { 172706f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no user"); 1728c2aa98e2SPeter Wemm goto badaddr; 1729c2aa98e2SPeter Wemm } 1730c2aa98e2SPeter Wemm if (tv == hostp) 1731c2aa98e2SPeter Wemm hostp = NULL; 1732c2aa98e2SPeter Wemm else if (hostp != NULL) 1733c2aa98e2SPeter Wemm cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1734c2aa98e2SPeter Wemm cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1735c2aa98e2SPeter Wemm 1736c2aa98e2SPeter Wemm /* save away the host name */ 1737c2aa98e2SPeter Wemm if (strcasecmp(mname, "error") == 0) 1738c2aa98e2SPeter Wemm { 173906f25ae9SGregory Neil Shapiro /* Set up triplet for use by -bv */ 174006f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 174106f25ae9SGregory Neil Shapiro a->q_user = newstr(ubuf); 174206f25ae9SGregory Neil Shapiro 1743c2aa98e2SPeter Wemm if (hostp != NULL) 1744c2aa98e2SPeter Wemm { 1745c2aa98e2SPeter Wemm register struct errcodes *ep; 1746c2aa98e2SPeter Wemm 174706f25ae9SGregory Neil Shapiro a->q_host = newstr(hbuf); 1748c2aa98e2SPeter Wemm if (strchr(hbuf, '.') != NULL) 1749c2aa98e2SPeter Wemm { 1750c2aa98e2SPeter Wemm a->q_status = newstr(hbuf); 1751c2aa98e2SPeter Wemm setstat(dsntoexitstat(hbuf)); 1752c2aa98e2SPeter Wemm } 1753c2aa98e2SPeter Wemm else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1754c2aa98e2SPeter Wemm { 1755c2aa98e2SPeter Wemm setstat(atoi(hbuf)); 1756c2aa98e2SPeter Wemm } 1757c2aa98e2SPeter Wemm else 1758c2aa98e2SPeter Wemm { 1759c2aa98e2SPeter Wemm for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1760c2aa98e2SPeter Wemm if (strcasecmp(ep->ec_name, hbuf) == 0) 1761c2aa98e2SPeter Wemm break; 1762c2aa98e2SPeter Wemm setstat(ep->ec_code); 1763c2aa98e2SPeter Wemm } 1764c2aa98e2SPeter Wemm } 1765c2aa98e2SPeter Wemm else 176606f25ae9SGregory Neil Shapiro { 176706f25ae9SGregory Neil Shapiro a->q_host = NULL; 1768c2aa98e2SPeter Wemm setstat(EX_UNAVAILABLE); 1769c2aa98e2SPeter Wemm } 177006f25ae9SGregory Neil Shapiro stripquotes(ubuf); 177106f25ae9SGregory Neil Shapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 177206f25ae9SGregory Neil Shapiro { 177306f25ae9SGregory Neil Shapiro char fmt[16]; 177406f25ae9SGregory Neil Shapiro int off; 177506f25ae9SGregory Neil Shapiro 177606f25ae9SGregory Neil Shapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 177706f25ae9SGregory Neil Shapiro { 177806f25ae9SGregory Neil Shapiro ubuf[off + 4] = '\0'; 177906f25ae9SGregory Neil Shapiro off += 5; 1780c2aa98e2SPeter Wemm } 1781c2aa98e2SPeter Wemm else 1782c2aa98e2SPeter Wemm { 178306f25ae9SGregory Neil Shapiro off = 4; 178406f25ae9SGregory Neil Shapiro ubuf[3] = '\0'; 178506f25ae9SGregory Neil Shapiro } 178606f25ae9SGregory Neil Shapiro (void) snprintf(fmt, sizeof fmt, "%s %%s", ubuf); 178706f25ae9SGregory Neil Shapiro if (off > 4) 178806f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 178906f25ae9SGregory Neil Shapiro else if (isenhsc(hbuf, '\0') > 0) 179006f25ae9SGregory Neil Shapiro usrerrenh(hbuf, fmt, ubuf + off); 179106f25ae9SGregory Neil Shapiro else 179206f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 179306f25ae9SGregory Neil Shapiro /* XXX ubuf[off - 1] = ' '; */ 179406f25ae9SGregory Neil Shapiro } 179506f25ae9SGregory Neil Shapiro else 179606f25ae9SGregory Neil Shapiro { 179706f25ae9SGregory Neil Shapiro usrerr("553 5.3.0 %s", ubuf); 1798c2aa98e2SPeter Wemm } 1799c2aa98e2SPeter Wemm goto badaddr; 1800c2aa98e2SPeter Wemm } 1801c2aa98e2SPeter Wemm 1802c2aa98e2SPeter Wemm for (mp = Mailer; (m = *mp++) != NULL; ) 1803c2aa98e2SPeter Wemm { 1804c2aa98e2SPeter Wemm if (strcasecmp(m->m_name, mname) == 0) 1805c2aa98e2SPeter Wemm break; 1806c2aa98e2SPeter Wemm } 1807c2aa98e2SPeter Wemm if (m == NULL) 1808c2aa98e2SPeter Wemm { 180906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 1810c2aa98e2SPeter Wemm goto badaddr; 1811c2aa98e2SPeter Wemm } 1812c2aa98e2SPeter Wemm a->q_mailer = m; 1813c2aa98e2SPeter Wemm 1814c2aa98e2SPeter Wemm /* figure out what host (if any) */ 1815c2aa98e2SPeter Wemm if (hostp == NULL) 1816c2aa98e2SPeter Wemm { 1817c2aa98e2SPeter Wemm if (!bitnset(M_LOCALMAILER, m->m_flags)) 1818c2aa98e2SPeter Wemm { 181906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no host"); 1820c2aa98e2SPeter Wemm goto badaddr; 1821c2aa98e2SPeter Wemm } 1822c2aa98e2SPeter Wemm a->q_host = NULL; 1823c2aa98e2SPeter Wemm } 1824c2aa98e2SPeter Wemm else 1825c2aa98e2SPeter Wemm a->q_host = newstr(hbuf); 1826c2aa98e2SPeter Wemm 1827c2aa98e2SPeter Wemm /* figure out the user */ 1828c2aa98e2SPeter Wemm p = ubuf; 1829c2aa98e2SPeter Wemm if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 1830c2aa98e2SPeter Wemm { 1831c2aa98e2SPeter Wemm p++; 1832c2aa98e2SPeter Wemm tv++; 1833c2aa98e2SPeter Wemm a->q_flags |= QNOTREMOTE; 1834c2aa98e2SPeter Wemm } 1835c2aa98e2SPeter Wemm 1836c2aa98e2SPeter Wemm /* do special mapping for local mailer */ 1837c2aa98e2SPeter Wemm if (*p == '"') 1838c2aa98e2SPeter Wemm p++; 1839c2aa98e2SPeter Wemm if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1840c2aa98e2SPeter Wemm a->q_mailer = m = ProgMailer; 1841c2aa98e2SPeter Wemm else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1842c2aa98e2SPeter Wemm a->q_mailer = m = FileMailer; 1843c2aa98e2SPeter Wemm else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1844c2aa98e2SPeter Wemm { 1845c2aa98e2SPeter Wemm /* may be :include: */ 1846c2aa98e2SPeter Wemm stripquotes(ubuf); 1847c2aa98e2SPeter Wemm if (strncasecmp(ubuf, ":include:", 9) == 0) 1848c2aa98e2SPeter Wemm { 1849c2aa98e2SPeter Wemm /* if :include:, don't need further rewriting */ 1850c2aa98e2SPeter Wemm a->q_mailer = m = InclMailer; 1851c2aa98e2SPeter Wemm a->q_user = newstr(&ubuf[9]); 1852c2aa98e2SPeter Wemm return a; 1853c2aa98e2SPeter Wemm } 1854c2aa98e2SPeter Wemm } 1855c2aa98e2SPeter Wemm 1856c2aa98e2SPeter Wemm /* rewrite according recipient mailer rewriting rules */ 1857c2aa98e2SPeter Wemm define('h', a->q_host, e); 185806f25ae9SGregory Neil Shapiro 185906f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 186006f25ae9SGregory Neil Shapiro /* 186106f25ae9SGregory Neil Shapiro ** Note, change the 9 to a 10 before removing #if FFR check 186206f25ae9SGregory Neil Shapiro ** in a future version. 186306f25ae9SGregory Neil Shapiro */ 186406f25ae9SGregory Neil Shapiro 186506f25ae9SGregory Neil Shapiro if (ConfigLevel >= 9 || 186606f25ae9SGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 186706f25ae9SGregory Neil Shapiro #else /* _FFR_ADDR_TYPE */ 1868c2aa98e2SPeter Wemm if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 186906f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 1870c2aa98e2SPeter Wemm { 1871c2aa98e2SPeter Wemm /* sender addresses done later */ 1872c2aa98e2SPeter Wemm (void) rewrite(tv, 2, 0, e); 1873c2aa98e2SPeter Wemm if (m->m_re_rwset > 0) 1874c2aa98e2SPeter Wemm (void) rewrite(tv, m->m_re_rwset, 0, e); 1875c2aa98e2SPeter Wemm } 1876c2aa98e2SPeter Wemm (void) rewrite(tv, 4, 0, e); 1877c2aa98e2SPeter Wemm 1878c2aa98e2SPeter Wemm /* save the result for the command line/RCPT argument */ 1879c2aa98e2SPeter Wemm cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 188006f25ae9SGregory Neil Shapiro a->q_user = newstr(ubuf); 1881c2aa98e2SPeter Wemm 1882c2aa98e2SPeter Wemm /* 1883c2aa98e2SPeter Wemm ** Do mapping to lower case as requested by mailer 1884c2aa98e2SPeter Wemm */ 1885c2aa98e2SPeter Wemm 1886c2aa98e2SPeter Wemm if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1887c2aa98e2SPeter Wemm makelower(a->q_host); 1888c2aa98e2SPeter Wemm if (!bitnset(M_USR_UPPER, m->m_flags)) 1889c2aa98e2SPeter Wemm makelower(a->q_user); 1890c2aa98e2SPeter Wemm 1891c2aa98e2SPeter Wemm if (tTd(24, 6)) 1892c2aa98e2SPeter Wemm { 189306f25ae9SGregory Neil Shapiro dprintf("buildaddr => "); 1894c2aa98e2SPeter Wemm printaddr(a, FALSE); 1895c2aa98e2SPeter Wemm } 1896c2aa98e2SPeter Wemm return a; 1897c2aa98e2SPeter Wemm } 1898c2aa98e2SPeter Wemm /* 1899c2aa98e2SPeter Wemm ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1900c2aa98e2SPeter Wemm ** 1901c2aa98e2SPeter Wemm ** Parameters: 1902c2aa98e2SPeter Wemm ** pvp -- parameter vector to rebuild. 1903c2aa98e2SPeter Wemm ** evp -- last parameter to include. Can be NULL to 1904c2aa98e2SPeter Wemm ** use entire pvp. 1905c2aa98e2SPeter Wemm ** buf -- buffer to build the string into. 1906c2aa98e2SPeter Wemm ** sz -- size of buf. 1907c2aa98e2SPeter Wemm ** spacesub -- the space separator character; if null, 1908c2aa98e2SPeter Wemm ** use SpaceSub. 1909c2aa98e2SPeter Wemm ** 1910c2aa98e2SPeter Wemm ** Returns: 1911c2aa98e2SPeter Wemm ** none. 1912c2aa98e2SPeter Wemm ** 1913c2aa98e2SPeter Wemm ** Side Effects: 1914c2aa98e2SPeter Wemm ** Destroys buf. 1915c2aa98e2SPeter Wemm */ 1916c2aa98e2SPeter Wemm 1917c2aa98e2SPeter Wemm void 1918c2aa98e2SPeter Wemm cataddr(pvp, evp, buf, sz, spacesub) 1919c2aa98e2SPeter Wemm char **pvp; 1920c2aa98e2SPeter Wemm char **evp; 1921c2aa98e2SPeter Wemm char *buf; 1922c2aa98e2SPeter Wemm register int sz; 1923c2aa98e2SPeter Wemm int spacesub; 1924c2aa98e2SPeter Wemm { 1925c2aa98e2SPeter Wemm bool oatomtok = FALSE; 1926c2aa98e2SPeter Wemm bool natomtok = FALSE; 1927c2aa98e2SPeter Wemm register int i; 1928c2aa98e2SPeter Wemm register char *p; 1929c2aa98e2SPeter Wemm 193006f25ae9SGregory Neil Shapiro if (sz <= 0) 193106f25ae9SGregory Neil Shapiro return; 193206f25ae9SGregory Neil Shapiro 1933c2aa98e2SPeter Wemm if (spacesub == '\0') 1934c2aa98e2SPeter Wemm spacesub = SpaceSub; 1935c2aa98e2SPeter Wemm 1936c2aa98e2SPeter Wemm if (pvp == NULL) 1937c2aa98e2SPeter Wemm { 193806f25ae9SGregory Neil Shapiro *buf = '\0'; 1939c2aa98e2SPeter Wemm return; 1940c2aa98e2SPeter Wemm } 1941c2aa98e2SPeter Wemm p = buf; 1942c2aa98e2SPeter Wemm sz -= 2; 194306f25ae9SGregory Neil Shapiro while (*pvp != NULL && (i = strlen(*pvp)) < sz - 1) 1944c2aa98e2SPeter Wemm { 1945c2aa98e2SPeter Wemm natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 1946c2aa98e2SPeter Wemm if (oatomtok && natomtok) 194706f25ae9SGregory Neil Shapiro { 1948c2aa98e2SPeter Wemm *p++ = spacesub; 194906f25ae9SGregory Neil Shapiro --sz; 195006f25ae9SGregory Neil Shapiro } 195106f25ae9SGregory Neil Shapiro (void) strlcpy(p, *pvp, sz); 1952c2aa98e2SPeter Wemm oatomtok = natomtok; 1953c2aa98e2SPeter Wemm p += i; 195406f25ae9SGregory Neil Shapiro sz -= i; 1955c2aa98e2SPeter Wemm if (pvp++ == evp) 1956c2aa98e2SPeter Wemm break; 1957c2aa98e2SPeter Wemm } 1958c2aa98e2SPeter Wemm *p = '\0'; 1959c2aa98e2SPeter Wemm } 1960c2aa98e2SPeter Wemm /* 1961c2aa98e2SPeter Wemm ** SAMEADDR -- Determine if two addresses are the same 1962c2aa98e2SPeter Wemm ** 1963c2aa98e2SPeter Wemm ** This is not just a straight comparison -- if the mailer doesn't 1964c2aa98e2SPeter Wemm ** care about the host we just ignore it, etc. 1965c2aa98e2SPeter Wemm ** 1966c2aa98e2SPeter Wemm ** Parameters: 1967c2aa98e2SPeter Wemm ** a, b -- pointers to the internal forms to compare. 1968c2aa98e2SPeter Wemm ** 1969c2aa98e2SPeter Wemm ** Returns: 1970c2aa98e2SPeter Wemm ** TRUE -- they represent the same mailbox. 1971c2aa98e2SPeter Wemm ** FALSE -- they don't. 1972c2aa98e2SPeter Wemm ** 1973c2aa98e2SPeter Wemm ** Side Effects: 1974c2aa98e2SPeter Wemm ** none. 1975c2aa98e2SPeter Wemm */ 1976c2aa98e2SPeter Wemm 1977c2aa98e2SPeter Wemm bool 1978c2aa98e2SPeter Wemm sameaddr(a, b) 1979c2aa98e2SPeter Wemm register ADDRESS *a; 1980c2aa98e2SPeter Wemm register ADDRESS *b; 1981c2aa98e2SPeter Wemm { 1982c2aa98e2SPeter Wemm register ADDRESS *ca, *cb; 1983c2aa98e2SPeter Wemm 1984c2aa98e2SPeter Wemm /* if they don't have the same mailer, forget it */ 1985c2aa98e2SPeter Wemm if (a->q_mailer != b->q_mailer) 198606f25ae9SGregory Neil Shapiro return FALSE; 1987c2aa98e2SPeter Wemm 1988c2aa98e2SPeter Wemm /* if the user isn't the same, we can drop out */ 1989c2aa98e2SPeter Wemm if (strcmp(a->q_user, b->q_user) != 0) 199006f25ae9SGregory Neil Shapiro return FALSE; 1991c2aa98e2SPeter Wemm 1992c2aa98e2SPeter Wemm /* if we have good uids for both but they differ, these are different */ 1993c2aa98e2SPeter Wemm if (a->q_mailer == ProgMailer) 1994c2aa98e2SPeter Wemm { 1995c2aa98e2SPeter Wemm ca = getctladdr(a); 1996c2aa98e2SPeter Wemm cb = getctladdr(b); 1997c2aa98e2SPeter Wemm if (ca != NULL && cb != NULL && 1998c2aa98e2SPeter Wemm bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1999c2aa98e2SPeter Wemm ca->q_uid != cb->q_uid) 200006f25ae9SGregory Neil Shapiro return FALSE; 2001c2aa98e2SPeter Wemm } 2002c2aa98e2SPeter Wemm 2003c2aa98e2SPeter Wemm /* otherwise compare hosts (but be careful for NULL ptrs) */ 2004c2aa98e2SPeter Wemm if (a->q_host == b->q_host) 2005c2aa98e2SPeter Wemm { 2006c2aa98e2SPeter Wemm /* probably both null pointers */ 200706f25ae9SGregory Neil Shapiro return TRUE; 2008c2aa98e2SPeter Wemm } 2009c2aa98e2SPeter Wemm if (a->q_host == NULL || b->q_host == NULL) 2010c2aa98e2SPeter Wemm { 2011c2aa98e2SPeter Wemm /* only one is a null pointer */ 201206f25ae9SGregory Neil Shapiro return FALSE; 2013c2aa98e2SPeter Wemm } 2014c2aa98e2SPeter Wemm if (strcmp(a->q_host, b->q_host) != 0) 201506f25ae9SGregory Neil Shapiro return FALSE; 2016c2aa98e2SPeter Wemm 201706f25ae9SGregory Neil Shapiro return TRUE; 2018c2aa98e2SPeter Wemm } 2019c2aa98e2SPeter Wemm /* 2020c2aa98e2SPeter Wemm ** PRINTADDR -- print address (for debugging) 2021c2aa98e2SPeter Wemm ** 2022c2aa98e2SPeter Wemm ** Parameters: 2023c2aa98e2SPeter Wemm ** a -- the address to print 2024c2aa98e2SPeter Wemm ** follow -- follow the q_next chain. 2025c2aa98e2SPeter Wemm ** 2026c2aa98e2SPeter Wemm ** Returns: 2027c2aa98e2SPeter Wemm ** none. 2028c2aa98e2SPeter Wemm ** 2029c2aa98e2SPeter Wemm ** Side Effects: 2030c2aa98e2SPeter Wemm ** none. 2031c2aa98e2SPeter Wemm */ 2032c2aa98e2SPeter Wemm 2033c2aa98e2SPeter Wemm struct qflags 2034c2aa98e2SPeter Wemm { 2035c2aa98e2SPeter Wemm char *qf_name; 2036c2aa98e2SPeter Wemm u_long qf_bit; 2037c2aa98e2SPeter Wemm }; 2038c2aa98e2SPeter Wemm 203906f25ae9SGregory Neil Shapiro static struct qflags AddressFlags[] = 2040c2aa98e2SPeter Wemm { 2041c2aa98e2SPeter Wemm { "QGOODUID", QGOODUID }, 2042c2aa98e2SPeter Wemm { "QPRIMARY", QPRIMARY }, 2043c2aa98e2SPeter Wemm { "QNOTREMOTE", QNOTREMOTE }, 2044c2aa98e2SPeter Wemm { "QSELFREF", QSELFREF }, 2045c2aa98e2SPeter Wemm { "QBOGUSSHELL", QBOGUSSHELL }, 2046c2aa98e2SPeter Wemm { "QUNSAFEADDR", QUNSAFEADDR }, 2047c2aa98e2SPeter Wemm { "QPINGONSUCCESS", QPINGONSUCCESS }, 2048c2aa98e2SPeter Wemm { "QPINGONFAILURE", QPINGONFAILURE }, 2049c2aa98e2SPeter Wemm { "QPINGONDELAY", QPINGONDELAY }, 2050c2aa98e2SPeter Wemm { "QHASNOTIFY", QHASNOTIFY }, 2051c2aa98e2SPeter Wemm { "QRELAYED", QRELAYED }, 2052c2aa98e2SPeter Wemm { "QEXPANDED", QEXPANDED }, 2053c2aa98e2SPeter Wemm { "QDELIVERED", QDELIVERED }, 2054c2aa98e2SPeter Wemm { "QDELAYED", QDELAYED }, 2055c2aa98e2SPeter Wemm { "QTHISPASS", QTHISPASS }, 2056c2aa98e2SPeter Wemm { "QRCPTOK", QRCPTOK }, 2057c2aa98e2SPeter Wemm { NULL } 2058c2aa98e2SPeter Wemm }; 2059c2aa98e2SPeter Wemm 2060c2aa98e2SPeter Wemm void 2061c2aa98e2SPeter Wemm printaddr(a, follow) 2062c2aa98e2SPeter Wemm register ADDRESS *a; 2063c2aa98e2SPeter Wemm bool follow; 2064c2aa98e2SPeter Wemm { 2065c2aa98e2SPeter Wemm register MAILER *m; 2066c2aa98e2SPeter Wemm MAILER pseudomailer; 2067c2aa98e2SPeter Wemm register struct qflags *qfp; 2068c2aa98e2SPeter Wemm bool firstone; 2069c2aa98e2SPeter Wemm 2070c2aa98e2SPeter Wemm if (a == NULL) 2071c2aa98e2SPeter Wemm { 2072c2aa98e2SPeter Wemm printf("[NULL]\n"); 2073c2aa98e2SPeter Wemm return; 2074c2aa98e2SPeter Wemm } 2075c2aa98e2SPeter Wemm 2076c2aa98e2SPeter Wemm while (a != NULL) 2077c2aa98e2SPeter Wemm { 2078c2aa98e2SPeter Wemm printf("%lx=", (u_long) a); 2079c2aa98e2SPeter Wemm (void) fflush(stdout); 2080c2aa98e2SPeter Wemm 2081c2aa98e2SPeter Wemm /* find the mailer -- carefully */ 2082c2aa98e2SPeter Wemm m = a->q_mailer; 2083c2aa98e2SPeter Wemm if (m == NULL) 2084c2aa98e2SPeter Wemm { 2085c2aa98e2SPeter Wemm m = &pseudomailer; 2086c2aa98e2SPeter Wemm m->m_mno = -1; 2087c2aa98e2SPeter Wemm m->m_name = "NULL"; 2088c2aa98e2SPeter Wemm } 2089c2aa98e2SPeter Wemm 2090c2aa98e2SPeter Wemm printf("%s:\n\tmailer %d (%s), host `%s'\n", 2091c2aa98e2SPeter Wemm a->q_paddr == NULL ? "<null>" : a->q_paddr, 2092c2aa98e2SPeter Wemm m->m_mno, m->m_name, 2093c2aa98e2SPeter Wemm a->q_host == NULL ? "<null>" : a->q_host); 2094c2aa98e2SPeter Wemm printf("\tuser `%s', ruser `%s'\n", 2095c2aa98e2SPeter Wemm a->q_user, 2096c2aa98e2SPeter Wemm a->q_ruser == NULL ? "<null>" : a->q_ruser); 209706f25ae9SGregory Neil Shapiro printf("\tstate="); 209806f25ae9SGregory Neil Shapiro switch (a->q_state) 209906f25ae9SGregory Neil Shapiro { 210006f25ae9SGregory Neil Shapiro case QS_OK: 210106f25ae9SGregory Neil Shapiro printf("OK"); 210206f25ae9SGregory Neil Shapiro break; 210306f25ae9SGregory Neil Shapiro 210406f25ae9SGregory Neil Shapiro case QS_DONTSEND: 210506f25ae9SGregory Neil Shapiro printf("DONTSEND"); 210606f25ae9SGregory Neil Shapiro break; 210706f25ae9SGregory Neil Shapiro 210806f25ae9SGregory Neil Shapiro case QS_BADADDR: 210906f25ae9SGregory Neil Shapiro printf("BADADDR"); 211006f25ae9SGregory Neil Shapiro break; 211106f25ae9SGregory Neil Shapiro 211206f25ae9SGregory Neil Shapiro case QS_QUEUEUP: 211306f25ae9SGregory Neil Shapiro printf("QUEUEUP"); 211406f25ae9SGregory Neil Shapiro break; 211506f25ae9SGregory Neil Shapiro 211606f25ae9SGregory Neil Shapiro case QS_SENT: 211706f25ae9SGregory Neil Shapiro printf("SENT"); 211806f25ae9SGregory Neil Shapiro break; 211906f25ae9SGregory Neil Shapiro 212006f25ae9SGregory Neil Shapiro case QS_VERIFIED: 212106f25ae9SGregory Neil Shapiro printf("VERIFIED"); 212206f25ae9SGregory Neil Shapiro break; 212306f25ae9SGregory Neil Shapiro 212406f25ae9SGregory Neil Shapiro case QS_EXPANDED: 212506f25ae9SGregory Neil Shapiro printf("EXPANDED"); 212606f25ae9SGregory Neil Shapiro break; 212706f25ae9SGregory Neil Shapiro 212806f25ae9SGregory Neil Shapiro case QS_SENDER: 212906f25ae9SGregory Neil Shapiro printf("SENDER"); 213006f25ae9SGregory Neil Shapiro break; 213106f25ae9SGregory Neil Shapiro 213206f25ae9SGregory Neil Shapiro case QS_CLONED: 213306f25ae9SGregory Neil Shapiro printf("CLONED"); 213406f25ae9SGregory Neil Shapiro break; 213506f25ae9SGregory Neil Shapiro 213606f25ae9SGregory Neil Shapiro case QS_DISCARDED: 213706f25ae9SGregory Neil Shapiro printf("DISCARDED"); 213806f25ae9SGregory Neil Shapiro break; 213906f25ae9SGregory Neil Shapiro 214006f25ae9SGregory Neil Shapiro case QS_REPLACED: 214106f25ae9SGregory Neil Shapiro printf("REPLACED"); 214206f25ae9SGregory Neil Shapiro break; 214306f25ae9SGregory Neil Shapiro 214406f25ae9SGregory Neil Shapiro case QS_REMOVED: 214506f25ae9SGregory Neil Shapiro printf("REMOVED"); 214606f25ae9SGregory Neil Shapiro break; 214706f25ae9SGregory Neil Shapiro 214806f25ae9SGregory Neil Shapiro case QS_DUPLICATE: 214906f25ae9SGregory Neil Shapiro printf("DUPLICATE"); 215006f25ae9SGregory Neil Shapiro break; 215106f25ae9SGregory Neil Shapiro 215206f25ae9SGregory Neil Shapiro case QS_INCLUDED: 215306f25ae9SGregory Neil Shapiro printf("INCLUDED"); 215406f25ae9SGregory Neil Shapiro break; 215506f25ae9SGregory Neil Shapiro 215606f25ae9SGregory Neil Shapiro default: 215706f25ae9SGregory Neil Shapiro printf("%d", a->q_state); 215806f25ae9SGregory Neil Shapiro break; 215906f25ae9SGregory Neil Shapiro } 216006f25ae9SGregory Neil Shapiro printf(", next=%lx, alias %lx, uid %d, gid %d\n", 2161c2aa98e2SPeter Wemm (u_long) a->q_next, (u_long) a->q_alias, 2162c2aa98e2SPeter Wemm (int) a->q_uid, (int) a->q_gid); 2163c2aa98e2SPeter Wemm printf("\tflags=%lx<", a->q_flags); 2164c2aa98e2SPeter Wemm firstone = TRUE; 2165c2aa98e2SPeter Wemm for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2166c2aa98e2SPeter Wemm { 2167c2aa98e2SPeter Wemm if (!bitset(qfp->qf_bit, a->q_flags)) 2168c2aa98e2SPeter Wemm continue; 2169c2aa98e2SPeter Wemm if (!firstone) 2170c2aa98e2SPeter Wemm printf(","); 2171c2aa98e2SPeter Wemm firstone = FALSE; 2172c2aa98e2SPeter Wemm printf("%s", qfp->qf_name); 2173c2aa98e2SPeter Wemm } 2174c2aa98e2SPeter Wemm printf(">\n"); 2175c2aa98e2SPeter Wemm printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2176c2aa98e2SPeter Wemm a->q_owner == NULL ? "(none)" : a->q_owner, 2177c2aa98e2SPeter Wemm a->q_home == NULL ? "(none)" : a->q_home, 2178c2aa98e2SPeter Wemm a->q_fullname == NULL ? "(none)" : a->q_fullname); 2179c2aa98e2SPeter Wemm printf("\torcpt=\"%s\", statmta=%s, status=%s\n", 2180c2aa98e2SPeter Wemm a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2181c2aa98e2SPeter Wemm a->q_statmta == NULL ? "(none)" : a->q_statmta, 2182c2aa98e2SPeter Wemm a->q_status == NULL ? "(none)" : a->q_status); 2183c2aa98e2SPeter Wemm printf("\trstatus=\"%s\"\n", 2184c2aa98e2SPeter Wemm a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2185c2aa98e2SPeter Wemm printf("\tspecificity=%d, statdate=%s\n", 218606f25ae9SGregory Neil Shapiro a->q_specificity, 218706f25ae9SGregory Neil Shapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2188c2aa98e2SPeter Wemm 2189c2aa98e2SPeter Wemm if (!follow) 2190c2aa98e2SPeter Wemm return; 2191c2aa98e2SPeter Wemm a = a->q_next; 2192c2aa98e2SPeter Wemm } 2193c2aa98e2SPeter Wemm } 2194c2aa98e2SPeter Wemm /* 2195c2aa98e2SPeter Wemm ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 2196c2aa98e2SPeter Wemm ** 2197c2aa98e2SPeter Wemm ** Parameters: 2198c2aa98e2SPeter Wemm ** a -- pointer to the address 2199c2aa98e2SPeter Wemm ** 2200c2aa98e2SPeter Wemm ** Returns: 2201c2aa98e2SPeter Wemm ** TRUE -- if this address is "empty" (i.e., no one should 2202c2aa98e2SPeter Wemm ** ever generate replies to it. 2203c2aa98e2SPeter Wemm ** FALSE -- if it is a "regular" (read: replyable) address. 2204c2aa98e2SPeter Wemm */ 2205c2aa98e2SPeter Wemm 2206c2aa98e2SPeter Wemm bool 2207c2aa98e2SPeter Wemm emptyaddr(a) 2208c2aa98e2SPeter Wemm register ADDRESS *a; 2209c2aa98e2SPeter Wemm { 2210c2aa98e2SPeter Wemm return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2211c2aa98e2SPeter Wemm a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2212c2aa98e2SPeter Wemm } 2213c2aa98e2SPeter Wemm /* 2214c2aa98e2SPeter Wemm ** REMOTENAME -- return the name relative to the current mailer 2215c2aa98e2SPeter Wemm ** 2216c2aa98e2SPeter Wemm ** Parameters: 2217c2aa98e2SPeter Wemm ** name -- the name to translate. 2218c2aa98e2SPeter Wemm ** m -- the mailer that we want to do rewriting relative 2219c2aa98e2SPeter Wemm ** to. 2220c2aa98e2SPeter Wemm ** flags -- fine tune operations. 2221c2aa98e2SPeter Wemm ** pstat -- pointer to status word. 2222c2aa98e2SPeter Wemm ** e -- the current envelope. 2223c2aa98e2SPeter Wemm ** 2224c2aa98e2SPeter Wemm ** Returns: 2225c2aa98e2SPeter Wemm ** the text string representing this address relative to 2226c2aa98e2SPeter Wemm ** the receiving mailer. 2227c2aa98e2SPeter Wemm ** 2228c2aa98e2SPeter Wemm ** Side Effects: 2229c2aa98e2SPeter Wemm ** none. 2230c2aa98e2SPeter Wemm ** 2231c2aa98e2SPeter Wemm ** Warnings: 2232c2aa98e2SPeter Wemm ** The text string returned is tucked away locally; 2233c2aa98e2SPeter Wemm ** copy it if you intend to save it. 2234c2aa98e2SPeter Wemm */ 2235c2aa98e2SPeter Wemm 2236c2aa98e2SPeter Wemm char * 2237c2aa98e2SPeter Wemm remotename(name, m, flags, pstat, e) 2238c2aa98e2SPeter Wemm char *name; 2239c2aa98e2SPeter Wemm struct mailer *m; 2240c2aa98e2SPeter Wemm int flags; 2241c2aa98e2SPeter Wemm int *pstat; 2242c2aa98e2SPeter Wemm register ENVELOPE *e; 2243c2aa98e2SPeter Wemm { 2244c2aa98e2SPeter Wemm register char **pvp; 2245c2aa98e2SPeter Wemm char *fancy; 2246c2aa98e2SPeter Wemm char *oldg = macvalue('g', e); 2247c2aa98e2SPeter Wemm int rwset; 2248c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 2249c2aa98e2SPeter Wemm char lbuf[MAXNAME + 1]; 2250c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 225106f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 225206f25ae9SGregory Neil Shapiro char addrtype[4]; 225306f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 2254c2aa98e2SPeter Wemm 2255c2aa98e2SPeter Wemm if (tTd(12, 1)) 225606f25ae9SGregory Neil Shapiro dprintf("remotename(%s)\n", name); 2257c2aa98e2SPeter Wemm 2258c2aa98e2SPeter Wemm /* don't do anything if we are tagging it as special */ 2259c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 226006f25ae9SGregory Neil Shapiro { 2261c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2262c2aa98e2SPeter Wemm : m->m_se_rwset; 226306f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 226406f25ae9SGregory Neil Shapiro addrtype[2] = 's'; 226506f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 226606f25ae9SGregory Neil Shapiro } 2267c2aa98e2SPeter Wemm else 226806f25ae9SGregory Neil Shapiro { 2269c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2270c2aa98e2SPeter Wemm : m->m_re_rwset; 227106f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 227206f25ae9SGregory Neil Shapiro addrtype[2] = 'r'; 227306f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 227406f25ae9SGregory Neil Shapiro } 2275c2aa98e2SPeter Wemm if (rwset < 0) 227606f25ae9SGregory Neil Shapiro return name; 227706f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 227806f25ae9SGregory Neil Shapiro addrtype[1] = ' '; 227906f25ae9SGregory Neil Shapiro addrtype[3] = '\0'; 228006f25ae9SGregory Neil Shapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 228106f25ae9SGregory Neil Shapiro define(macid("{addr_type}", NULL), addrtype, e); 228206f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 2283c2aa98e2SPeter Wemm 2284c2aa98e2SPeter Wemm /* 2285c2aa98e2SPeter Wemm ** Do a heuristic crack of this name to extract any comment info. 2286c2aa98e2SPeter Wemm ** This will leave the name as a comment and a $g macro. 2287c2aa98e2SPeter Wemm */ 2288c2aa98e2SPeter Wemm 2289c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2290c2aa98e2SPeter Wemm fancy = "\201g"; 2291c2aa98e2SPeter Wemm else 2292c2aa98e2SPeter Wemm fancy = crackaddr(name); 2293c2aa98e2SPeter Wemm 2294c2aa98e2SPeter Wemm /* 2295c2aa98e2SPeter Wemm ** Turn the name into canonical form. 2296c2aa98e2SPeter Wemm ** Normally this will be RFC 822 style, i.e., "user@domain". 2297c2aa98e2SPeter Wemm ** If this only resolves to "user", and the "C" flag is 2298c2aa98e2SPeter Wemm ** specified in the sending mailer, then the sender's 2299c2aa98e2SPeter Wemm ** domain will be appended. 2300c2aa98e2SPeter Wemm */ 2301c2aa98e2SPeter Wemm 2302c2aa98e2SPeter Wemm pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2303c2aa98e2SPeter Wemm if (pvp == NULL) 230406f25ae9SGregory Neil Shapiro return name; 2305c2aa98e2SPeter Wemm if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2306c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2307c2aa98e2SPeter Wemm if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2308c2aa98e2SPeter Wemm { 2309c2aa98e2SPeter Wemm /* append from domain to this address */ 2310c2aa98e2SPeter Wemm register char **pxp = pvp; 231106f25ae9SGregory Neil Shapiro int l = MAXATOM; /* size of buffer for pvp */ 2312c2aa98e2SPeter Wemm 2313c2aa98e2SPeter Wemm /* see if there is an "@domain" in the current name */ 2314c2aa98e2SPeter Wemm while (*pxp != NULL && strcmp(*pxp, "@") != 0) 231506f25ae9SGregory Neil Shapiro { 2316c2aa98e2SPeter Wemm pxp++; 231706f25ae9SGregory Neil Shapiro --l; 231806f25ae9SGregory Neil Shapiro } 2319c2aa98e2SPeter Wemm if (*pxp == NULL) 2320c2aa98e2SPeter Wemm { 2321c2aa98e2SPeter Wemm /* no.... append the "@domain" from the sender */ 2322c2aa98e2SPeter Wemm register char **qxq = e->e_fromdomain; 2323c2aa98e2SPeter Wemm 2324c2aa98e2SPeter Wemm while ((*pxp++ = *qxq++) != NULL) 232506f25ae9SGregory Neil Shapiro { 232606f25ae9SGregory Neil Shapiro if (--l <= 0) 232706f25ae9SGregory Neil Shapiro { 232806f25ae9SGregory Neil Shapiro *--pxp = NULL; 232906f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 remotename: too many tokens"); 233006f25ae9SGregory Neil Shapiro *pstat = EX_UNAVAILABLE; 233106f25ae9SGregory Neil Shapiro break; 233206f25ae9SGregory Neil Shapiro } 233306f25ae9SGregory Neil Shapiro } 2334c2aa98e2SPeter Wemm if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 2335c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2336c2aa98e2SPeter Wemm } 2337c2aa98e2SPeter Wemm } 2338c2aa98e2SPeter Wemm 2339c2aa98e2SPeter Wemm /* 2340c2aa98e2SPeter Wemm ** Do more specific rewriting. 2341c2aa98e2SPeter Wemm ** Rewrite using ruleset 1 or 2 depending on whether this is 2342c2aa98e2SPeter Wemm ** a sender address or not. 2343c2aa98e2SPeter Wemm ** Then run it through any receiving-mailer-specific rulesets. 2344c2aa98e2SPeter Wemm */ 2345c2aa98e2SPeter Wemm 2346c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 2347c2aa98e2SPeter Wemm { 2348c2aa98e2SPeter Wemm if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 2349c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2350c2aa98e2SPeter Wemm } 2351c2aa98e2SPeter Wemm else 2352c2aa98e2SPeter Wemm { 2353c2aa98e2SPeter Wemm if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 2354c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2355c2aa98e2SPeter Wemm } 2356c2aa98e2SPeter Wemm if (rwset > 0) 2357c2aa98e2SPeter Wemm { 2358c2aa98e2SPeter Wemm if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 2359c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2360c2aa98e2SPeter Wemm } 2361c2aa98e2SPeter Wemm 2362c2aa98e2SPeter Wemm /* 2363c2aa98e2SPeter Wemm ** Do any final sanitation the address may require. 2364c2aa98e2SPeter Wemm ** This will normally be used to turn internal forms 2365c2aa98e2SPeter Wemm ** (e.g., user@host.LOCAL) into external form. This 2366c2aa98e2SPeter Wemm ** may be used as a default to the above rules. 2367c2aa98e2SPeter Wemm */ 2368c2aa98e2SPeter Wemm 2369c2aa98e2SPeter Wemm if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 2370c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2371c2aa98e2SPeter Wemm 2372c2aa98e2SPeter Wemm /* 2373c2aa98e2SPeter Wemm ** Now restore the comment information we had at the beginning. 2374c2aa98e2SPeter Wemm */ 2375c2aa98e2SPeter Wemm 2376c2aa98e2SPeter Wemm cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 2377c2aa98e2SPeter Wemm define('g', lbuf, e); 2378c2aa98e2SPeter Wemm 2379c2aa98e2SPeter Wemm /* need to make sure route-addrs have <angle brackets> */ 2380c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2381c2aa98e2SPeter Wemm expand("<\201g>", buf, sizeof buf, e); 2382c2aa98e2SPeter Wemm else 2383c2aa98e2SPeter Wemm expand(fancy, buf, sizeof buf, e); 2384c2aa98e2SPeter Wemm 2385c2aa98e2SPeter Wemm define('g', oldg, e); 2386c2aa98e2SPeter Wemm 2387c2aa98e2SPeter Wemm if (tTd(12, 1)) 238806f25ae9SGregory Neil Shapiro dprintf("remotename => `%s'\n", buf); 238906f25ae9SGregory Neil Shapiro return buf; 2390c2aa98e2SPeter Wemm } 2391c2aa98e2SPeter Wemm /* 2392c2aa98e2SPeter Wemm ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2393c2aa98e2SPeter Wemm ** 2394c2aa98e2SPeter Wemm ** Parameters: 2395c2aa98e2SPeter Wemm ** a -- the address to map (but just the user name part). 2396c2aa98e2SPeter Wemm ** sendq -- the sendq in which to install any replacement 2397c2aa98e2SPeter Wemm ** addresses. 2398c2aa98e2SPeter Wemm ** aliaslevel -- the alias nesting depth. 2399c2aa98e2SPeter Wemm ** e -- the envelope. 2400c2aa98e2SPeter Wemm ** 2401c2aa98e2SPeter Wemm ** Returns: 2402c2aa98e2SPeter Wemm ** none. 2403c2aa98e2SPeter Wemm */ 2404c2aa98e2SPeter Wemm 2405c2aa98e2SPeter Wemm #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2406c2aa98e2SPeter Wemm Q_PINGFLAGS|QHASNOTIFY|\ 2407c2aa98e2SPeter Wemm QRELAYED|QEXPANDED|QDELIVERED|QDELAYED) 2408c2aa98e2SPeter Wemm 2409c2aa98e2SPeter Wemm void 2410c2aa98e2SPeter Wemm maplocaluser(a, sendq, aliaslevel, e) 2411c2aa98e2SPeter Wemm register ADDRESS *a; 2412c2aa98e2SPeter Wemm ADDRESS **sendq; 2413c2aa98e2SPeter Wemm int aliaslevel; 2414c2aa98e2SPeter Wemm ENVELOPE *e; 2415c2aa98e2SPeter Wemm { 2416c2aa98e2SPeter Wemm register char **pvp; 2417c2aa98e2SPeter Wemm register ADDRESS *a1 = NULL; 2418c2aa98e2SPeter Wemm auto char *delimptr; 2419c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2420c2aa98e2SPeter Wemm 2421c2aa98e2SPeter Wemm if (tTd(29, 1)) 2422c2aa98e2SPeter Wemm { 242306f25ae9SGregory Neil Shapiro dprintf("maplocaluser: "); 2424c2aa98e2SPeter Wemm printaddr(a, FALSE); 2425c2aa98e2SPeter Wemm } 2426c2aa98e2SPeter Wemm pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 2427c2aa98e2SPeter Wemm if (pvp == NULL) 2428c2aa98e2SPeter Wemm { 2429c2aa98e2SPeter Wemm if (tTd(29, 9)) 243006f25ae9SGregory Neil Shapiro dprintf("maplocaluser: cannot prescan %s\n", 243106f25ae9SGregory Neil Shapiro a->q_user); 2432c2aa98e2SPeter Wemm return; 2433c2aa98e2SPeter Wemm } 2434c2aa98e2SPeter Wemm 2435c2aa98e2SPeter Wemm define('h', a->q_host, e); 2436c2aa98e2SPeter Wemm define('u', a->q_user, e); 2437c2aa98e2SPeter Wemm define('z', a->q_home, e); 2438c2aa98e2SPeter Wemm 243906f25ae9SGregory Neil Shapiro #if _FFR_ADDR_TYPE 244006f25ae9SGregory Neil Shapiro define(macid("{addr_type}", NULL), "e r", e); 244106f25ae9SGregory Neil Shapiro #endif /* _FFR_ADDR_TYPE */ 2442c2aa98e2SPeter Wemm if (rewrite(pvp, 5, 0, e) == EX_TEMPFAIL) 2443c2aa98e2SPeter Wemm { 2444c2aa98e2SPeter Wemm if (tTd(29, 9)) 244506f25ae9SGregory Neil Shapiro dprintf("maplocaluser: rewrite tempfail\n"); 244606f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 2447c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 2448c2aa98e2SPeter Wemm return; 2449c2aa98e2SPeter Wemm } 2450c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2451c2aa98e2SPeter Wemm { 2452c2aa98e2SPeter Wemm if (tTd(29, 9)) 245306f25ae9SGregory Neil Shapiro dprintf("maplocaluser: doesn't resolve\n"); 2454c2aa98e2SPeter Wemm return; 2455c2aa98e2SPeter Wemm } 2456c2aa98e2SPeter Wemm 2457c2aa98e2SPeter Wemm /* if non-null, mailer destination specified -- has it changed? */ 2458c2aa98e2SPeter Wemm a1 = buildaddr(pvp, NULL, 0, e); 2459c2aa98e2SPeter Wemm if (a1 == NULL || sameaddr(a, a1)) 2460c2aa98e2SPeter Wemm { 2461c2aa98e2SPeter Wemm if (tTd(29, 9)) 246206f25ae9SGregory Neil Shapiro dprintf("maplocaluser: address unchanged\n"); 2463c2aa98e2SPeter Wemm if (a1 != NULL) 2464c2aa98e2SPeter Wemm free(a1); 2465c2aa98e2SPeter Wemm return; 2466c2aa98e2SPeter Wemm } 2467c2aa98e2SPeter Wemm 2468c2aa98e2SPeter Wemm /* make new address take on flags and print attributes of old */ 2469c2aa98e2SPeter Wemm a1->q_flags &= ~Q_COPYFLAGS; 2470c2aa98e2SPeter Wemm a1->q_flags |= a->q_flags & Q_COPYFLAGS; 247106f25ae9SGregory Neil Shapiro a1->q_paddr = newstr(a->q_paddr); 247206f25ae9SGregory Neil Shapiro a1->q_orcpt = a->q_orcpt; 2473c2aa98e2SPeter Wemm 2474c2aa98e2SPeter Wemm /* mark old address as dead; insert new address */ 247506f25ae9SGregory Neil Shapiro a->q_state = QS_REPLACED; 2476c2aa98e2SPeter Wemm if (tTd(29, 5)) 2477c2aa98e2SPeter Wemm { 247806f25ae9SGregory Neil Shapiro dprintf("maplocaluser: QS_REPLACED "); 2479c2aa98e2SPeter Wemm printaddr(a, FALSE); 2480c2aa98e2SPeter Wemm } 2481c2aa98e2SPeter Wemm a1->q_alias = a; 248206f25ae9SGregory Neil Shapiro allocaddr(a1, RF_COPYALL, newstr(a->q_paddr)); 2483c2aa98e2SPeter Wemm (void) recipient(a1, sendq, aliaslevel, e); 2484c2aa98e2SPeter Wemm } 2485c2aa98e2SPeter Wemm /* 2486c2aa98e2SPeter Wemm ** DEQUOTE_INIT -- initialize dequote map 2487c2aa98e2SPeter Wemm ** 2488c2aa98e2SPeter Wemm ** This is a no-op. 2489c2aa98e2SPeter Wemm ** 2490c2aa98e2SPeter Wemm ** Parameters: 2491c2aa98e2SPeter Wemm ** map -- the internal map structure. 2492c2aa98e2SPeter Wemm ** args -- arguments. 2493c2aa98e2SPeter Wemm ** 2494c2aa98e2SPeter Wemm ** Returns: 2495c2aa98e2SPeter Wemm ** TRUE. 2496c2aa98e2SPeter Wemm */ 2497c2aa98e2SPeter Wemm 2498c2aa98e2SPeter Wemm bool 2499c2aa98e2SPeter Wemm dequote_init(map, args) 2500c2aa98e2SPeter Wemm MAP *map; 2501c2aa98e2SPeter Wemm char *args; 2502c2aa98e2SPeter Wemm { 2503c2aa98e2SPeter Wemm register char *p = args; 2504c2aa98e2SPeter Wemm 250506f25ae9SGregory Neil Shapiro /* there is no check whether there is really an argument */ 2506c2aa98e2SPeter Wemm map->map_mflags |= MF_KEEPQUOTES; 2507c2aa98e2SPeter Wemm for (;;) 2508c2aa98e2SPeter Wemm { 2509c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 2510c2aa98e2SPeter Wemm p++; 2511c2aa98e2SPeter Wemm if (*p != '-') 2512c2aa98e2SPeter Wemm break; 2513c2aa98e2SPeter Wemm switch (*++p) 2514c2aa98e2SPeter Wemm { 2515c2aa98e2SPeter Wemm case 'a': 2516c2aa98e2SPeter Wemm map->map_app = ++p; 2517c2aa98e2SPeter Wemm break; 2518c2aa98e2SPeter Wemm 251906f25ae9SGregory Neil Shapiro case 'D': 252006f25ae9SGregory Neil Shapiro map->map_mflags |= MF_DEFER; 252106f25ae9SGregory Neil Shapiro break; 252206f25ae9SGregory Neil Shapiro 252306f25ae9SGregory Neil Shapiro case 'S': 2524c2aa98e2SPeter Wemm case 's': 252506f25ae9SGregory Neil Shapiro map->map_spacesub = *++p; 2526c2aa98e2SPeter Wemm break; 2527c2aa98e2SPeter Wemm } 2528c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2529c2aa98e2SPeter Wemm p++; 2530c2aa98e2SPeter Wemm if (*p != '\0') 2531c2aa98e2SPeter Wemm *p = '\0'; 2532c2aa98e2SPeter Wemm } 2533c2aa98e2SPeter Wemm if (map->map_app != NULL) 2534c2aa98e2SPeter Wemm map->map_app = newstr(map->map_app); 2535c2aa98e2SPeter Wemm 2536c2aa98e2SPeter Wemm return TRUE; 2537c2aa98e2SPeter Wemm } 2538c2aa98e2SPeter Wemm /* 2539c2aa98e2SPeter Wemm ** DEQUOTE_MAP -- unquote an address 2540c2aa98e2SPeter Wemm ** 2541c2aa98e2SPeter Wemm ** Parameters: 2542c2aa98e2SPeter Wemm ** map -- the internal map structure (ignored). 2543c2aa98e2SPeter Wemm ** name -- the name to dequote. 2544c2aa98e2SPeter Wemm ** av -- arguments (ignored). 2545c2aa98e2SPeter Wemm ** statp -- pointer to status out-parameter. 2546c2aa98e2SPeter Wemm ** 2547c2aa98e2SPeter Wemm ** Returns: 2548c2aa98e2SPeter Wemm ** NULL -- if there were no quotes, or if the resulting 2549c2aa98e2SPeter Wemm ** unquoted buffer would not be acceptable to prescan. 2550c2aa98e2SPeter Wemm ** else -- The dequoted buffer. 2551c2aa98e2SPeter Wemm */ 2552c2aa98e2SPeter Wemm 2553c2aa98e2SPeter Wemm /* ARGSUSED2 */ 2554c2aa98e2SPeter Wemm char * 2555c2aa98e2SPeter Wemm dequote_map(map, name, av, statp) 2556c2aa98e2SPeter Wemm MAP *map; 2557c2aa98e2SPeter Wemm char *name; 2558c2aa98e2SPeter Wemm char **av; 2559c2aa98e2SPeter Wemm int *statp; 2560c2aa98e2SPeter Wemm { 2561c2aa98e2SPeter Wemm register char *p; 2562c2aa98e2SPeter Wemm register char *q; 2563c2aa98e2SPeter Wemm register char c; 2564c2aa98e2SPeter Wemm int anglecnt = 0; 2565c2aa98e2SPeter Wemm int cmntcnt = 0; 2566c2aa98e2SPeter Wemm int quotecnt = 0; 2567c2aa98e2SPeter Wemm int spacecnt = 0; 2568c2aa98e2SPeter Wemm bool quotemode = FALSE; 2569c2aa98e2SPeter Wemm bool bslashmode = FALSE; 257006f25ae9SGregory Neil Shapiro char spacesub = map->map_spacesub; 2571c2aa98e2SPeter Wemm 2572c2aa98e2SPeter Wemm for (p = q = name; (c = *p++) != '\0'; ) 2573c2aa98e2SPeter Wemm { 2574c2aa98e2SPeter Wemm if (bslashmode) 2575c2aa98e2SPeter Wemm { 2576c2aa98e2SPeter Wemm bslashmode = FALSE; 2577c2aa98e2SPeter Wemm *q++ = c; 2578c2aa98e2SPeter Wemm continue; 2579c2aa98e2SPeter Wemm } 2580c2aa98e2SPeter Wemm 2581c2aa98e2SPeter Wemm if (c == ' ' && spacesub != '\0') 2582c2aa98e2SPeter Wemm c = spacesub; 2583c2aa98e2SPeter Wemm 2584c2aa98e2SPeter Wemm switch (c) 2585c2aa98e2SPeter Wemm { 2586c2aa98e2SPeter Wemm case '\\': 2587c2aa98e2SPeter Wemm bslashmode = TRUE; 2588c2aa98e2SPeter Wemm break; 2589c2aa98e2SPeter Wemm 2590c2aa98e2SPeter Wemm case '(': 2591c2aa98e2SPeter Wemm cmntcnt++; 2592c2aa98e2SPeter Wemm break; 2593c2aa98e2SPeter Wemm 2594c2aa98e2SPeter Wemm case ')': 2595c2aa98e2SPeter Wemm if (cmntcnt-- <= 0) 2596c2aa98e2SPeter Wemm return NULL; 2597c2aa98e2SPeter Wemm break; 2598c2aa98e2SPeter Wemm 2599c2aa98e2SPeter Wemm case ' ': 260006f25ae9SGregory Neil Shapiro case '\t': 2601c2aa98e2SPeter Wemm spacecnt++; 2602c2aa98e2SPeter Wemm break; 2603c2aa98e2SPeter Wemm } 2604c2aa98e2SPeter Wemm 2605c2aa98e2SPeter Wemm if (cmntcnt > 0) 2606c2aa98e2SPeter Wemm { 2607c2aa98e2SPeter Wemm *q++ = c; 2608c2aa98e2SPeter Wemm continue; 2609c2aa98e2SPeter Wemm } 2610c2aa98e2SPeter Wemm 2611c2aa98e2SPeter Wemm switch (c) 2612c2aa98e2SPeter Wemm { 2613c2aa98e2SPeter Wemm case '"': 2614c2aa98e2SPeter Wemm quotemode = !quotemode; 2615c2aa98e2SPeter Wemm quotecnt++; 2616c2aa98e2SPeter Wemm continue; 2617c2aa98e2SPeter Wemm 2618c2aa98e2SPeter Wemm case '<': 2619c2aa98e2SPeter Wemm anglecnt++; 2620c2aa98e2SPeter Wemm break; 2621c2aa98e2SPeter Wemm 2622c2aa98e2SPeter Wemm case '>': 2623c2aa98e2SPeter Wemm if (anglecnt-- <= 0) 2624c2aa98e2SPeter Wemm return NULL; 2625c2aa98e2SPeter Wemm break; 2626c2aa98e2SPeter Wemm } 2627c2aa98e2SPeter Wemm *q++ = c; 2628c2aa98e2SPeter Wemm } 2629c2aa98e2SPeter Wemm 2630c2aa98e2SPeter Wemm if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2631c2aa98e2SPeter Wemm quotemode || quotecnt <= 0 || spacecnt != 0) 2632c2aa98e2SPeter Wemm return NULL; 2633c2aa98e2SPeter Wemm *q++ = '\0'; 2634c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 2635c2aa98e2SPeter Wemm } 2636c2aa98e2SPeter Wemm /* 2637c2aa98e2SPeter Wemm ** RSCHECK -- check string(s) for validity using rewriting sets 2638c2aa98e2SPeter Wemm ** 2639c2aa98e2SPeter Wemm ** Parameters: 2640c2aa98e2SPeter Wemm ** rwset -- the rewriting set to use. 2641c2aa98e2SPeter Wemm ** p1 -- the first string to check. 2642c2aa98e2SPeter Wemm ** p2 -- the second string to check -- may be null. 2643c2aa98e2SPeter Wemm ** e -- the current envelope. 264406f25ae9SGregory Neil Shapiro ** rmcomm -- remove comments? 264506f25ae9SGregory Neil Shapiro ** cnt -- count rejections (statistics)? 264606f25ae9SGregory Neil Shapiro ** logl -- logging level 2647c2aa98e2SPeter Wemm ** 2648c2aa98e2SPeter Wemm ** Returns: 2649c2aa98e2SPeter Wemm ** EX_OK -- if the rwset doesn't resolve to $#error 2650c2aa98e2SPeter Wemm ** else -- the failure status (message printed) 2651c2aa98e2SPeter Wemm */ 2652c2aa98e2SPeter Wemm 2653c2aa98e2SPeter Wemm int 265406f25ae9SGregory Neil Shapiro rscheck(rwset, p1, p2, e, rmcomm, cnt, logl) 2655c2aa98e2SPeter Wemm char *rwset; 2656c2aa98e2SPeter Wemm char *p1; 2657c2aa98e2SPeter Wemm char *p2; 2658c2aa98e2SPeter Wemm ENVELOPE *e; 265906f25ae9SGregory Neil Shapiro bool rmcomm, cnt; 266006f25ae9SGregory Neil Shapiro int logl; 2661c2aa98e2SPeter Wemm { 2662c2aa98e2SPeter Wemm char *buf; 2663c2aa98e2SPeter Wemm int bufsize; 2664c2aa98e2SPeter Wemm int saveexitstat; 2665c2aa98e2SPeter Wemm int rstat = EX_OK; 2666c2aa98e2SPeter Wemm char **pvp; 2667c2aa98e2SPeter Wemm int rsno; 2668c2aa98e2SPeter Wemm bool discard = FALSE; 2669c2aa98e2SPeter Wemm auto ADDRESS a1; 2670c2aa98e2SPeter Wemm bool saveQuickAbort = QuickAbort; 2671c2aa98e2SPeter Wemm bool saveSuprErrs = SuprErrs; 2672c2aa98e2SPeter Wemm char buf0[MAXLINE]; 2673c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2674c2aa98e2SPeter Wemm extern char MsgBuf[]; 2675c2aa98e2SPeter Wemm 2676c2aa98e2SPeter Wemm if (tTd(48, 2)) 267706f25ae9SGregory Neil Shapiro dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2678c2aa98e2SPeter Wemm p2 == NULL ? "(NULL)" : p2); 2679c2aa98e2SPeter Wemm 2680c2aa98e2SPeter Wemm rsno = strtorwset(rwset, NULL, ST_FIND); 2681c2aa98e2SPeter Wemm if (rsno < 0) 2682c2aa98e2SPeter Wemm return EX_OK; 2683c2aa98e2SPeter Wemm 2684c2aa98e2SPeter Wemm if (p2 != NULL) 2685c2aa98e2SPeter Wemm { 2686c2aa98e2SPeter Wemm bufsize = strlen(p1) + strlen(p2) + 2; 2687c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 2688c2aa98e2SPeter Wemm buf = xalloc(bufsize); 2689c2aa98e2SPeter Wemm else 2690c2aa98e2SPeter Wemm { 2691c2aa98e2SPeter Wemm buf = buf0; 2692c2aa98e2SPeter Wemm bufsize = sizeof buf0; 2693c2aa98e2SPeter Wemm } 2694c2aa98e2SPeter Wemm (void) snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2695c2aa98e2SPeter Wemm } 2696c2aa98e2SPeter Wemm else 2697c2aa98e2SPeter Wemm { 2698c2aa98e2SPeter Wemm bufsize = strlen(p1) + 1; 2699c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 2700c2aa98e2SPeter Wemm buf = xalloc(bufsize); 2701c2aa98e2SPeter Wemm else 2702c2aa98e2SPeter Wemm { 2703c2aa98e2SPeter Wemm buf = buf0; 2704c2aa98e2SPeter Wemm bufsize = sizeof buf0; 2705c2aa98e2SPeter Wemm } 2706c2aa98e2SPeter Wemm (void) snprintf(buf, bufsize, "%s", p1); 2707c2aa98e2SPeter Wemm } 2708c2aa98e2SPeter Wemm SuprErrs = TRUE; 2709c2aa98e2SPeter Wemm QuickAbort = FALSE; 271006f25ae9SGregory Neil Shapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 271106f25ae9SGregory Neil Shapiro rmcomm ? NULL : TokTypeNoC); 2712c2aa98e2SPeter Wemm SuprErrs = saveSuprErrs; 2713c2aa98e2SPeter Wemm if (pvp == NULL) 2714c2aa98e2SPeter Wemm { 2715c2aa98e2SPeter Wemm if (tTd(48, 2)) 271606f25ae9SGregory Neil Shapiro dprintf("rscheck: cannot prescan input\n"); 2717c2aa98e2SPeter Wemm /* 2718c2aa98e2SPeter Wemm syserr("rscheck: cannot prescan input: \"%s\"", 2719c2aa98e2SPeter Wemm shortenstring(buf, MAXSHORTSTR)); 2720c2aa98e2SPeter Wemm rstat = EX_DATAERR; 2721c2aa98e2SPeter Wemm */ 2722c2aa98e2SPeter Wemm goto finis; 2723c2aa98e2SPeter Wemm } 2724c2aa98e2SPeter Wemm (void) rewrite(pvp, rsno, 0, e); 2725c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 2726c2aa98e2SPeter Wemm pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 2727c2aa98e2SPeter Wemm strcmp(pvp[1], "discard") != 0)) 2728c2aa98e2SPeter Wemm { 2729c2aa98e2SPeter Wemm goto finis; 2730c2aa98e2SPeter Wemm } 2731c2aa98e2SPeter Wemm 2732c2aa98e2SPeter Wemm if (strcmp(pvp[1], "discard") == 0) 2733c2aa98e2SPeter Wemm { 2734c2aa98e2SPeter Wemm if (tTd(48, 2)) 273506f25ae9SGregory Neil Shapiro dprintf("rscheck: discard mailer selected\n"); 2736c2aa98e2SPeter Wemm e->e_flags |= EF_DISCARD; 2737c2aa98e2SPeter Wemm discard = TRUE; 2738c2aa98e2SPeter Wemm } 2739c2aa98e2SPeter Wemm else 2740c2aa98e2SPeter Wemm { 2741c2aa98e2SPeter Wemm int savelogusrerrs = LogUsrErrs; 2742c2aa98e2SPeter Wemm static bool logged = FALSE; 2743c2aa98e2SPeter Wemm 2744c2aa98e2SPeter Wemm /* got an error -- process it */ 2745c2aa98e2SPeter Wemm saveexitstat = ExitStat; 2746c2aa98e2SPeter Wemm LogUsrErrs = FALSE; 2747c2aa98e2SPeter Wemm (void) buildaddr(pvp, &a1, 0, e); 2748c2aa98e2SPeter Wemm LogUsrErrs = savelogusrerrs; 2749c2aa98e2SPeter Wemm rstat = ExitStat; 2750c2aa98e2SPeter Wemm ExitStat = saveexitstat; 2751c2aa98e2SPeter Wemm if (!logged) 2752c2aa98e2SPeter Wemm { 275306f25ae9SGregory Neil Shapiro if (cnt) 2754c2aa98e2SPeter Wemm markstats(e, &a1, TRUE); 2755c2aa98e2SPeter Wemm logged = TRUE; 2756c2aa98e2SPeter Wemm } 2757c2aa98e2SPeter Wemm } 2758c2aa98e2SPeter Wemm 275906f25ae9SGregory Neil Shapiro if (LogLevel >= logl) 2760c2aa98e2SPeter Wemm { 2761c2aa98e2SPeter Wemm char *relay; 2762c2aa98e2SPeter Wemm char *p; 2763c2aa98e2SPeter Wemm char lbuf[MAXLINE]; 2764c2aa98e2SPeter Wemm 2765c2aa98e2SPeter Wemm p = lbuf; 2766c2aa98e2SPeter Wemm if (p2 != NULL) 2767c2aa98e2SPeter Wemm { 2768c2aa98e2SPeter Wemm snprintf(p, SPACELEFT(lbuf, p), 2769c2aa98e2SPeter Wemm ", arg2=%s", 2770c2aa98e2SPeter Wemm p2); 2771c2aa98e2SPeter Wemm p += strlen(p); 2772c2aa98e2SPeter Wemm } 2773c2aa98e2SPeter Wemm if ((relay = macvalue('_', e)) != NULL) 2774c2aa98e2SPeter Wemm { 2775c2aa98e2SPeter Wemm snprintf(p, SPACELEFT(lbuf, p), 2776c2aa98e2SPeter Wemm ", relay=%s", relay); 2777c2aa98e2SPeter Wemm p += strlen(p); 2778c2aa98e2SPeter Wemm } 2779c2aa98e2SPeter Wemm *p = '\0'; 2780c2aa98e2SPeter Wemm if (discard) 2781c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 2782c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, discard", 2783c2aa98e2SPeter Wemm rwset, p1, lbuf); 2784c2aa98e2SPeter Wemm else 2785c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id, 2786c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, reject=%s", 2787c2aa98e2SPeter Wemm rwset, p1, lbuf, MsgBuf); 2788c2aa98e2SPeter Wemm } 2789c2aa98e2SPeter Wemm 2790c2aa98e2SPeter Wemm finis: 2791c2aa98e2SPeter Wemm /* clean up */ 2792c2aa98e2SPeter Wemm QuickAbort = saveQuickAbort; 2793c2aa98e2SPeter Wemm setstat(rstat); 2794c2aa98e2SPeter Wemm if (buf != buf0) 2795c2aa98e2SPeter Wemm free(buf); 2796c2aa98e2SPeter Wemm 2797c2aa98e2SPeter Wemm if (rstat != EX_OK && QuickAbort) 2798c2aa98e2SPeter Wemm longjmp(TopFrame, 2); 2799c2aa98e2SPeter Wemm return rstat; 2800c2aa98e2SPeter Wemm } 2801