📄 parseaddr.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)parseaddr.c 8.31 (Berkeley) 4/15/94";#endif /* not lint */# include "sendmail.h"/*** PARSEADDR -- Parse an address**** Parses an address and breaks it up into three parts: a** net to transmit the message on, the host to transmit it** to, and a user on that host. These are loaded into an** ADDRESS header with the values squirreled away if necessary.** The "user" part may not be a real user; the process may** just reoccur on that machine. For example, on a machine** with an arpanet connection, the address** csvax.bill@berkeley** will break up to a "user" of 'csvax.bill' and a host** of 'berkeley' -- to be transmitted over the arpanet.**** Parameters:** addr -- the address to parse.** a -- a pointer to the address descriptor buffer.** If NULL, a header will be created.** flags -- describe detail for parsing. See RF_ definitions** in sendmail.h.** delim -- the character to terminate the address, passed** to prescan.** delimptr -- if non-NULL, set to the location of the** delim character that was found.** e -- the envelope that will contain this address.**** Returns:** A pointer to the address descriptor header (`a' if** `a' is non-NULL).** NULL on error.**** Side Effects:** none*//* following delimiters are inherent to the internal algorithms */# define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ADDRESS *parseaddr(addr, a, flags, delim, delimptr, e) char *addr; register ADDRESS *a; int flags; int delim; char **delimptr; register ENVELOPE *e;{ register char **pvp; auto char *delimptrbuf; bool queueup; char pvpbuf[PSBUFSIZE]; extern ADDRESS *buildaddr(); extern bool invalidaddr(); /* ** Initialize and prescan address. */ e->e_to = addr; if (tTd(20, 1)) printf("\n--parseaddr(%s)\n", addr); if (delimptr == NULL) delimptr = &delimptrbuf; pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr); if (pvp == NULL) { if (tTd(20, 1)) printf("parseaddr-->NULL\n"); return (NULL); } if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) { if (tTd(20, 1)) printf("parseaddr-->bad address\n"); return NULL; } /* ** Save addr if we are going to have to. ** ** We have to do this early because there is a chance that ** the map lookups in the rewriting rules could clobber ** static memory somewhere. */ if (bitset(RF_COPYPADDR, flags) && addr != NULL) { char savec = **delimptr; if (savec != '\0') **delimptr = '\0'; e->e_to = addr = newstr(addr); if (savec != '\0') **delimptr = savec; } /* ** Apply rewriting rules. ** Ruleset 0 does basic parsing. It must resolve. */ queueup = FALSE; if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) queueup = TRUE; if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) queueup = TRUE; /* ** Build canonical address from pvp. */ a = buildaddr(pvp, a, flags, e); /* ** Make local copies of the host & user and then ** transport them out. */ allocaddr(a, flags, addr); if (bitset(QBADADDR, a->q_flags)) return a; /* ** If there was a parsing failure, mark it for queueing. */ if (queueup) { char *msg = "Transient parse error -- message queued for future delivery"; if (tTd(20, 1)) printf("parseaddr: queuing message\n"); message(msg); if (e->e_message == NULL) e->e_message = newstr(msg); a->q_flags |= QQUEUEUP; } /* ** Compute return value. */ if (tTd(20, 1)) { printf("parseaddr-->"); printaddr(a, FALSE); } return (a);}/*** INVALIDADDR -- check for address containing meta-characters**** Parameters:** addr -- the address to check.**** Returns:** TRUE -- if the address has any "wierd" characters** FALSE -- otherwise.*/boolinvalidaddr(addr, delimptr) register char *addr; char *delimptr;{ char savedelim; if (delimptr != NULL) { savedelim = *delimptr; if (savedelim != '\0') *delimptr = '\0'; }#if 0 /* for testing.... */ if (strcmp(addr, "INvalidADDR") == 0) { usrerr("553 INvalid ADDRess"); goto addrfailure; }#endif for (; *addr != '\0'; addr++) { if ((*addr & 0340) == 0200) break; } if (*addr == '\0') { if (savedelim != '\0' && delimptr != NULL) *delimptr = savedelim; return FALSE; } setstat(EX_USAGE); usrerr("553 Address contained invalid control characters"); addrfailure: if (savedelim != '\0' && delimptr != NULL) *delimptr = savedelim; return TRUE;}/*** ALLOCADDR -- do local allocations of address on demand.**** Also lowercases the host name if requested.**** Parameters:** a -- the address to reallocate.** flags -- the copy flag (see RF_ definitions in sendmail.h** for a description).** paddr -- the printname of the address.**** Returns:** none.**** Side Effects:** Copies portions of a into local buffers as requested.*/allocaddr(a, flags, paddr) register ADDRESS *a; int flags; char *paddr;{ if (tTd(24, 4)) printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr); a->q_paddr = paddr; if (a->q_user == NULL) a->q_user = ""; if (a->q_host == NULL) a->q_host = ""; if (bitset(RF_COPYPARSE, flags)) { a->q_host = newstr(a->q_host); if (a->q_user != a->q_paddr) a->q_user = newstr(a->q_user); } if (a->q_paddr == NULL) a->q_paddr = a->q_user;}/*** PRESCAN -- Prescan name and make it canonical**** Scans a name and turns it into a set of tokens. This process** deletes blanks and comments (in parentheses).**** This routine knows about quoted strings and angle brackets.**** There are certain subtleties to this routine. The one that** comes to mind now is that backslashes on the ends of names** are silently stripped off; this is intentional. The problem** is that some versions of sndmsg (like at LBL) set the kill** character to something other than @ when reading addresses;** so people type "csvax.eric\@berkeley" -- which screws up the** berknet mailer.**** Parameters:** addr -- the name to chomp.** delim -- the delimiter for the address, normally** '\0' or ','; \0 is accepted in any case.** If '\t' then we are reading the .cf file.** pvpbuf -- place to put the saved text -- note that** the pointers are static.** pvpbsize -- size of pvpbuf.** delimptr -- if non-NULL, set to the location of the** terminating delimiter.**** Returns:** A pointer to a vector of tokens.** NULL on error.*//* states and character types */# define OPR 0 /* operator */# define ATM 1 /* atom */# define QST 2 /* in quoted string */# define SPC 3 /* chewing up spaces */# define ONE 4 /* pick up one character */# define NSTATES 5 /* number of states */# define TYPE 017 /* mask to select state type *//* meta bits for table */# define M 020 /* meta character; don't pass through */# define B 040 /* cause a break */# define MB M|B /* meta-break */static short StateTab[NSTATES][NSTATES] ={ /* oldst chtype> OPR ATM QST SPC ONE */ /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, /*QST*/ QST, QST, OPR, QST, QST, /*SPC*/ OPR, ATM, QST, SPC|M, ONE, /*ONE*/ OPR, OPR, OPR, OPR, OPR,};/* token type table -- it gets modified with $o characters */static TokTypeTab[256] ={ ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,};#define toktype(c) ((int) TokTypeTab[(c) & 0xff])# define NOCHAR -1 /* signal nothing in lookahead token */char **prescan(addr, delim, pvpbuf, pvpbsize, delimptr) char *addr; char delim; char pvpbuf[]; char **delimptr;{ register char *p; register char *q; register int c; char **avp; bool bslashmode; int cmntcnt; int anglecnt; char *tok; int state; int newstate; char *saveto = CurEnv->e_to; static char *av[MAXATOM+1]; static char firsttime = TRUE; extern int errno; if (firsttime) { /* initialize the token type table */ char obuf[50]; firsttime = FALSE; expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv); strcat(obuf, DELIMCHARS); for (p = obuf; *p != '\0'; p++) { if (TokTypeTab[*p & 0xff] == ATM) TokTypeTab[*p & 0xff] = OPR; } } /* make sure error messages don't have garbage on them */ errno = 0; q = pvpbuf; bslashmode = FALSE; cmntcnt = 0; anglecnt = 0; avp = av; state = ATM; c = NOCHAR; p = addr; CurEnv->e_to = p; if (tTd(22, 11)) { printf("prescan: "); xputs(p); (void) putchar('\n'); } do { /* read a token */ tok = q; for (;;) { /* store away any old lookahead character */ if (c != NOCHAR && !bslashmode) { /* see if there is room */ if (q >= &pvpbuf[pvpbsize - 5]) { usrerr("553 Address too long"); returnnull: if (delimptr != NULL) *delimptr = p; CurEnv->e_to = saveto; return (NULL); } /* squirrel it away */ *q++ = c; } /* read a new input character */ c = *p++; if (c == '\0') { /* diagnose and patch up bad syntax */ if (state == QST) { usrerr("653 Unbalanced '\"'"); c = '"'; } else if (cmntcnt > 0) { usrerr("653 Unbalanced '('"); c = ')'; } else if (anglecnt > 0) { c = '>'; usrerr("653 Unbalanced '<'"); } else break; p--; } else if (c == delim && anglecnt <= 0 && cmntcnt <= 0 && state != QST) break; if (tTd(22, 101)) printf("c=%c, s=%d; ", c, state); /* chew up special characters */ *q = '\0'; if (bslashmode) { bslashmode = FALSE; /* kludge \! for naive users */ if (cmntcnt > 0) { c = NOCHAR; continue; } else if (c != '!' || state == QST) { *q++ = '\\'; continue; } } if (c == '\\') { bslashmode = TRUE; } else if (state == QST) { /* do nothing, just avoid next clauses */ } else if (c == '(') { cmntcnt++; c = NOCHAR; } else if (c == ')') { if (cmntcnt <= 0) { usrerr("653 Unbalanced ')'"); c = NOCHAR; } else cmntcnt--; } else if (cmntcnt > 0) c = NOCHAR; else if (c == '<') anglecnt++; else if (c == '>') { if (anglecnt <= 0) { usrerr("653 Unbalanced '>'"); c = NOCHAR; } else anglecnt--; } else if (delim == ' ' && isascii(c) && isspace(c)) c = ' '; if (c == NOCHAR) continue; /* see if this is end of input */ if (c == delim && anglecnt <= 0 && state != QST) break; newstate = StateTab[state][toktype(c)]; if (tTd(22, 101)) printf("ns=%02o\n", newstate); state = newstate & TYPE; if (bitset(M, newstate)) c = NOCHAR; if (bitset(B, newstate)) break; } /* new token */ if (tok != q) { *q++ = '\0'; if (tTd(22, 36)) { printf("tok="); xputs(tok); (void) putchar('\n'); } if (avp >= &av[MAXATOM]) { syserr("553 prescan: too many tokens"); goto returnnull; } if (q - tok > MAXNAME) { syserr("553 prescan: token too long"); goto returnnull; } *avp++ = tok; } } while (c != '\0' && (c != delim || anglecnt > 0)); *avp = NULL; p--; if (delimptr != NULL) *delimptr = p; if (tTd(22, 12)) { printf("prescan==>"); printav(av); } CurEnv->e_to = saveto; if (av[0] == NULL) { if (tTd(22, 1)) printf("prescan: null leading token\n"); return (NULL); } return (av);}/*** REWRITE -- apply rewrite rules to token vector.**** This routine is an ordered production system. Each rewrite** rule has a LHS (called the pattern) and a RHS (called the** rewrite); 'rwr' points the the current rewrite rule.**** For each rewrite rule, 'avp' points the address vector we** are trying to match against, and 'pvp' points to the pattern.** If pvp points to a special match value (MATCHZANY, MATCHANY,** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp** matched is saved away in the match vector (pointed to by 'mvp').**** When a match between avp & pvp does not match, we try to** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS** we must also back out the match in mvp. If we reach a** MATCHANY or MATCHZANY we just extend the match and start** over again.**** When we finally match, we rewrite the address vector** and try over again.**** Parameters:** pvp -- pointer to token vector.** ruleset -- the ruleset to use for rewriting.** reclevel -- recursion level (to catch loops).** e -- the current envelope.**** Returns:** A status code. If EX_TEMPFAIL, higher level code should** attempt recovery.**** Side Effects:** pvp is modified.*/struct match{ char **first; /* first token matched */ char **last; /* last token matched */ char **pattern; /* pointer to pattern */};# define MAXMATCH 9 /* max params per rewrite */# ifndef MAXRULERECURSION# define MAXRULERECURSION 50 /* max recursion depth */# endifintrewrite(pvp, ruleset, reclevel, e) char **pvp; int ruleset; int reclevel; register ENVELOPE *e;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -