macro.c revision 64562
138032Speter/* 264562Sgshapiro * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1438032Speter#ifndef lint 1564562Sgshapirostatic char id[] = "@(#)$Id: macro.c,v 8.40.16.1 2000/05/25 18:56:15 gshapiro Exp $"; 1664562Sgshapiro#endif /* ! lint */ 1738032Speter 1864562Sgshapiro#include <sendmail.h> 1938032Speter 2038032Speterchar *MacroName[256]; /* macro id to name table */ 2138032Speterint NextMacroId = 0240; /* codes for long named macros */ 2238032Speter 2338032Speter 2438032Speter/* 2538032Speter** EXPAND -- macro expand a string using $x escapes. 2638032Speter** 2738032Speter** Parameters: 2838032Speter** s -- the string to expand. 2938032Speter** buf -- the place to put the expansion. 3038032Speter** bufsize -- the size of the buffer. 3138032Speter** e -- envelope in which to work. 3238032Speter** 3338032Speter** Returns: 3438032Speter** none. 3538032Speter** 3638032Speter** Side Effects: 3738032Speter** none. 3838032Speter*/ 3938032Speter 4038032Spetervoid 4138032Speterexpand(s, buf, bufsize, e) 4238032Speter register char *s; 4338032Speter register char *buf; 4438032Speter size_t bufsize; 4538032Speter register ENVELOPE *e; 4638032Speter{ 4738032Speter register char *xp; 4838032Speter register char *q; 4938032Speter bool skipping; /* set if conditionally skipping output */ 5038032Speter bool recurse = FALSE; /* set if recursion required */ 5138032Speter int i; 5238032Speter int skiplev; /* skipping nesting level */ 5338032Speter int iflev; /* if nesting level */ 5438032Speter char xbuf[MACBUFSIZE]; 5538032Speter static int explevel = 0; 5638032Speter 5738032Speter if (tTd(35, 24)) 5838032Speter { 5964562Sgshapiro dprintf("expand("); 6038032Speter xputs(s); 6164562Sgshapiro dprintf(")\n"); 6238032Speter } 6338032Speter 6438032Speter skipping = FALSE; 6538032Speter skiplev = 0; 6638032Speter iflev = 0; 6738032Speter if (s == NULL) 6838032Speter s = ""; 6938032Speter for (xp = xbuf; *s != '\0'; s++) 7038032Speter { 7138032Speter int c; 7238032Speter 7338032Speter /* 7438032Speter ** Check for non-ordinary (special?) character. 7538032Speter ** 'q' will be the interpolated quantity. 7638032Speter */ 7738032Speter 7838032Speter q = NULL; 7938032Speter c = *s; 8038032Speter switch (c & 0377) 8138032Speter { 8238032Speter case CONDIF: /* see if var set */ 8338032Speter iflev++; 8438032Speter c = *++s; 8538032Speter if (skipping) 8638032Speter skiplev++; 8738032Speter else 8864562Sgshapiro { 8964562Sgshapiro char *mv; 9064562Sgshapiro 9164562Sgshapiro mv = macvalue(c, e); 9264562Sgshapiro skipping = (mv == NULL || *mv == '\0'); 9364562Sgshapiro } 9438032Speter continue; 9538032Speter 9638032Speter case CONDELSE: /* change state of skipping */ 9738032Speter if (iflev == 0) 9838032Speter break; 9938032Speter if (skiplev == 0) 10038032Speter skipping = !skipping; 10138032Speter continue; 10238032Speter 10338032Speter case CONDFI: /* stop skipping */ 10438032Speter if (iflev == 0) 10538032Speter break; 10638032Speter iflev--; 10738032Speter if (skiplev == 0) 10838032Speter skipping = FALSE; 10938032Speter if (skipping) 11038032Speter skiplev--; 11138032Speter continue; 11238032Speter 11338032Speter case MACROEXPAND: /* macro interpolation */ 11438032Speter c = *++s & 0377; 11538032Speter if (c != '\0') 11638032Speter q = macvalue(c, e); 11738032Speter else 11838032Speter { 11938032Speter s--; 12038032Speter q = NULL; 12138032Speter } 12238032Speter if (q == NULL) 12338032Speter continue; 12438032Speter break; 12538032Speter } 12638032Speter 12738032Speter /* 12838032Speter ** Interpolate q or output one character 12938032Speter */ 13038032Speter 13138032Speter if (skipping || xp >= &xbuf[sizeof xbuf - 1]) 13238032Speter continue; 13338032Speter if (q == NULL) 13438032Speter *xp++ = c; 13538032Speter else 13638032Speter { 13738032Speter /* copy to end of q or max space remaining in buf */ 13838032Speter while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1]) 13938032Speter { 14038032Speter /* check for any sendmail metacharacters */ 14138032Speter if ((c & 0340) == 0200) 14238032Speter recurse = TRUE; 14338032Speter *xp++ = c; 14438032Speter } 14538032Speter } 14638032Speter } 14738032Speter *xp = '\0'; 14838032Speter 14938032Speter if (tTd(35, 24)) 15038032Speter { 15164562Sgshapiro dprintf("expand ==> "); 15238032Speter xputs(xbuf); 15364562Sgshapiro dprintf("\n"); 15438032Speter } 15538032Speter 15638032Speter /* recurse as appropriate */ 15738032Speter if (recurse) 15838032Speter { 15938032Speter if (explevel < MaxMacroRecursion) 16038032Speter { 16138032Speter explevel++; 16238032Speter expand(xbuf, buf, bufsize, e); 16338032Speter explevel--; 16438032Speter return; 16538032Speter } 16638032Speter syserr("expand: recursion too deep (%d max)", 16738032Speter MaxMacroRecursion); 16838032Speter } 16938032Speter 17038032Speter /* copy results out */ 17138032Speter i = xp - xbuf; 17264562Sgshapiro if ((size_t)i >= bufsize) 17338032Speter i = bufsize - 1; 17464562Sgshapiro memmove(buf, xbuf, i); 17538032Speter buf[i] = '\0'; 17638032Speter} 17738032Speter/* 17838032Speter** DEFINE -- define a macro. 17938032Speter** 18038032Speter** this would be better done using a #define macro. 18138032Speter** 18238032Speter** Parameters: 18338032Speter** n -- the macro name. 18438032Speter** v -- the macro value. 18538032Speter** e -- the envelope to store the definition in. 18638032Speter** 18738032Speter** Returns: 18838032Speter** none. 18938032Speter** 19038032Speter** Side Effects: 19138032Speter** e->e_macro[n] is defined. 19238032Speter** 19338032Speter** Notes: 19438032Speter** There is one macro for each ASCII character, 19538032Speter** although they are not all used. The currently 19638032Speter** defined macros are: 19738032Speter** 19838032Speter** $a date in ARPANET format (preferring the Date: line 19938032Speter** of the message) 20038032Speter** $b the current date (as opposed to the date as found 20138032Speter** the message) in ARPANET format 20238032Speter** $c hop count 20338032Speter** $d (current) date in UNIX (ctime) format 20438032Speter** $e the SMTP entry message+ 20538032Speter** $f raw from address 20638032Speter** $g translated from address 20738032Speter** $h to host 20838032Speter** $i queue id 20938032Speter** $j official SMTP hostname, used in messages+ 21038032Speter** $k UUCP node name 21138032Speter** $l UNIX-style from line+ 21238032Speter** $m The domain part of our full name. 21338032Speter** $n name of sendmail ("MAILER-DAEMON" on local 21438032Speter** net typically)+ 21538032Speter** $o delimiters ("operators") for address tokens+ 21638032Speter** (set via OperatorChars option in V6 or later 21738032Speter** sendmail.cf files) 21838032Speter** $p my process id in decimal 21938032Speter** $q the string that becomes an address -- this is 22038032Speter** normally used to combine $g & $x. 22138032Speter** $r protocol used to talk to sender 22238032Speter** $s sender's host name 22338032Speter** $t the current time in seconds since 1/1/1970 22438032Speter** $u to user 22538032Speter** $v version number of sendmail 22638032Speter** $w our host name (if it can be determined) 22738032Speter** $x signature (full name) of from person 22838032Speter** $y the tty id of our terminal 22938032Speter** $z home directory of to person 23038032Speter** $_ RFC1413 authenticated sender address 23138032Speter** 23238032Speter** Macros marked with + must be defined in the 23338032Speter** configuration file and are used internally, but 23438032Speter** are not set. 23538032Speter** 23638032Speter** There are also some macros that can be used 23738032Speter** arbitrarily to make the configuration file 23838032Speter** cleaner. In general all upper-case letters 23938032Speter** are available. 24038032Speter*/ 24138032Speter 24238032Spetervoid 24338032Speterdefine(n, v, e) 24438032Speter int n; 24538032Speter char *v; 24638032Speter register ENVELOPE *e; 24738032Speter{ 24864562Sgshapiro int m; 24964562Sgshapiro 25064562Sgshapiro m = n & 0377; 25138032Speter if (tTd(35, 9)) 25238032Speter { 25364562Sgshapiro dprintf("%sdefine(%s as ", 25464562Sgshapiro (e->e_macro[m] == NULL) ? "" 25564562Sgshapiro : "re", macname(n)); 25638032Speter xputs(v); 25764562Sgshapiro dprintf(")\n"); 25838032Speter } 25964562Sgshapiro e->e_macro[m] = v; 26064562Sgshapiro 26164562Sgshapiro#if _FFR_RESET_MACRO_GLOBALS 26264562Sgshapiro switch (m) 26364562Sgshapiro { 26464562Sgshapiro case 'j': 26564562Sgshapiro MyHostName = v; 26664562Sgshapiro break; 26764562Sgshapiro } 26864562Sgshapiro#endif /* _FFR_RESET_MACRO_GLOBALS */ 26938032Speter} 27038032Speter/* 27138032Speter** MACVALUE -- return uninterpreted value of a macro. 27238032Speter** 27338032Speter** Parameters: 27438032Speter** n -- the name of the macro. 27538032Speter** 27638032Speter** Returns: 27738032Speter** The value of n. 27838032Speter** 27938032Speter** Side Effects: 28038032Speter** none. 28138032Speter*/ 28238032Speter 28338032Speterchar * 28438032Spetermacvalue(n, e) 28538032Speter int n; 28638032Speter register ENVELOPE *e; 28738032Speter{ 28838032Speter n &= 0377; 28938032Speter while (e != NULL) 29038032Speter { 29138032Speter register char *p = e->e_macro[n]; 29238032Speter 29338032Speter if (p != NULL) 29464562Sgshapiro return p; 29538032Speter e = e->e_parent; 29638032Speter } 29764562Sgshapiro return NULL; 29838032Speter} 29938032Speter/* 30038032Speter** MACNAME -- return the name of a macro given its internal id 30138032Speter** 30238032Speter** Parameter: 30338032Speter** n -- the id of the macro 30438032Speter** 30538032Speter** Returns: 30638032Speter** The name of n. 30738032Speter** 30838032Speter** Side Effects: 30938032Speter** none. 31038032Speter*/ 31138032Speter 31238032Speterchar * 31338032Spetermacname(n) 31438032Speter int n; 31538032Speter{ 31638032Speter static char mbuf[2]; 31738032Speter 31838032Speter n &= 0377; 31938032Speter if (bitset(0200, n)) 32038032Speter { 32138032Speter char *p = MacroName[n]; 32238032Speter 32338032Speter if (p != NULL) 32438032Speter return p; 32538032Speter return "***UNDEFINED MACRO***"; 32638032Speter } 32738032Speter mbuf[0] = n; 32838032Speter mbuf[1] = '\0'; 32938032Speter return mbuf; 33038032Speter} 33138032Speter/* 33238032Speter** MACID -- return id of macro identified by its name 33338032Speter** 33438032Speter** Parameters: 33538032Speter** p -- pointer to name string -- either a single 33638032Speter** character or {name}. 33738032Speter** ep -- filled in with the pointer to the byte 33838032Speter** after the name. 33938032Speter** 34038032Speter** Returns: 34138032Speter** The internal id code for this macro. This will 34238032Speter** fit into a single byte. 34338032Speter** 34438032Speter** Side Effects: 34538032Speter** If this is a new macro name, a new id is allocated. 34638032Speter*/ 34738032Speter 34838032Speterint 34938032Spetermacid(p, ep) 35038032Speter register char *p; 35138032Speter char **ep; 35238032Speter{ 35338032Speter int mid; 35438032Speter register char *bp; 35542575Speter char mbuf[MAXMACNAMELEN + 1]; 35638032Speter 35738032Speter if (tTd(35, 14)) 35838032Speter { 35964562Sgshapiro dprintf("macid("); 36038032Speter xputs(p); 36164562Sgshapiro dprintf(") => "); 36238032Speter } 36338032Speter 36438032Speter if (*p == '\0' || (p[0] == '{' && p[1] == '}')) 36538032Speter { 36638032Speter syserr("Name required for macro/class"); 36738032Speter if (ep != NULL) 36838032Speter *ep = p; 36938032Speter if (tTd(35, 14)) 37064562Sgshapiro dprintf("NULL\n"); 37138032Speter return '\0'; 37238032Speter } 37338032Speter if (*p != '{') 37438032Speter { 37538032Speter /* the macro is its own code */ 37638032Speter if (ep != NULL) 37738032Speter *ep = p + 1; 37838032Speter if (tTd(35, 14)) 37964562Sgshapiro dprintf("%c\n", *p); 38038032Speter return *p; 38138032Speter } 38238032Speter bp = mbuf; 38342575Speter while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1]) 38438032Speter { 38538032Speter if (isascii(*p) && (isalnum(*p) || *p == '_')) 38638032Speter *bp++ = *p; 38738032Speter else 38838032Speter syserr("Invalid macro/class character %c", *p); 38938032Speter } 39038032Speter *bp = '\0'; 39138032Speter mid = -1; 39238032Speter if (*p == '\0') 39338032Speter { 39438032Speter syserr("Unbalanced { on %s", mbuf); /* missing } */ 39538032Speter } 39638032Speter else if (*p != '}') 39738032Speter { 39838032Speter syserr("Macro/class name ({%s}) too long (%d chars max)", 39938032Speter mbuf, sizeof mbuf - 1); 40038032Speter } 40138032Speter else if (mbuf[1] == '\0') 40238032Speter { 40338032Speter /* ${x} == $x */ 40438032Speter mid = mbuf[0]; 40538032Speter p++; 40638032Speter } 40738032Speter else 40838032Speter { 40938032Speter register STAB *s; 41038032Speter 41138032Speter s = stab(mbuf, ST_MACRO, ST_ENTER); 41238032Speter if (s->s_macro != 0) 41338032Speter mid = s->s_macro; 41438032Speter else 41538032Speter { 41664562Sgshapiro if (NextMacroId > MAXMACROID) 41738032Speter { 41838032Speter syserr("Macro/class {%s}: too many long names", mbuf); 41938032Speter s->s_macro = -1; 42038032Speter } 42138032Speter else 42238032Speter { 42338032Speter MacroName[NextMacroId] = s->s_name; 42438032Speter s->s_macro = mid = NextMacroId++; 42538032Speter } 42638032Speter } 42738032Speter p++; 42838032Speter } 42938032Speter if (ep != NULL) 43038032Speter *ep = p; 43138032Speter if (tTd(35, 14)) 43264562Sgshapiro dprintf("0x%x\n", mid); 43338032Speter return mid; 43438032Speter} 43538032Speter/* 43638032Speter** WORDINCLASS -- tell if a word is in a specific class 43738032Speter** 43838032Speter** Parameters: 43938032Speter** str -- the name of the word to look up. 44038032Speter** cl -- the class name. 44138032Speter** 44238032Speter** Returns: 44338032Speter** TRUE if str can be found in cl. 44438032Speter** FALSE otherwise. 44538032Speter*/ 44638032Speter 44738032Speterbool 44838032Speterwordinclass(str, cl) 44938032Speter char *str; 45038032Speter int cl; 45138032Speter{ 45238032Speter register STAB *s; 45338032Speter 45438032Speter s = stab(str, ST_CLASS, ST_FIND); 45538032Speter return s != NULL && bitnset(cl & 0xff, s->s_class); 45638032Speter} 457