summaryrefslogtreecommitdiff
path: root/src/macro.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/macro.c')
-rw-r--r--src/macro.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/src/macro.c b/src/macro.c
new file mode 100644
index 0000000..0f31d11
--- /dev/null
+++ b/src/macro.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 1983, 1995-1997 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 lint
+static char sccsid[] = "@(#)macro.c 8.18 (Berkeley) 2/1/97";
+#endif /* not lint */
+
+# include "sendmail.h"
+
+char *MacroName[256]; /* macro id to name table */
+int NextMacroId = 0240; /* codes for long named macros */
+
+
+/*
+** EXPAND -- macro expand a string using $x escapes.
+**
+** Parameters:
+** s -- the string to expand.
+** buf -- the place to put the expansion.
+** bufsize -- the size of the buffer.
+** e -- envelope in which to work.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** none.
+*/
+
+void
+expand(s, buf, bufsize, e)
+ register char *s;
+ register char *buf;
+ size_t bufsize;
+ register ENVELOPE *e;
+{
+ register char *xp;
+ register char *q;
+ bool skipping; /* set if conditionally skipping output */
+ bool recurse = FALSE; /* set if recursion required */
+ int i;
+ int skiplev; /* skipping nesting level */
+ int iflev; /* if nesting level */
+ char xbuf[BUFSIZ];
+ static int explevel = 0;
+
+ if (tTd(35, 24))
+ {
+ printf("expand(");
+ xputs(s);
+ printf(")\n");
+ }
+
+ skipping = FALSE;
+ skiplev = 0;
+ iflev = 0;
+ if (s == NULL)
+ s = "";
+ for (xp = xbuf; *s != '\0'; s++)
+ {
+ int c;
+
+ /*
+ ** Check for non-ordinary (special?) character.
+ ** 'q' will be the interpolated quantity.
+ */
+
+ q = NULL;
+ c = *s;
+ switch (c & 0377)
+ {
+ case CONDIF: /* see if var set */
+ iflev++;
+ c = *++s;
+ if (skipping)
+ skiplev++;
+ else
+ skipping = macvalue(c, e) == NULL;
+ continue;
+
+ case CONDELSE: /* change state of skipping */
+ if (iflev == 0)
+ break;
+ if (skiplev == 0)
+ skipping = !skipping;
+ continue;
+
+ case CONDFI: /* stop skipping */
+ if (iflev == 0)
+ break;
+ iflev--;
+ if (skiplev == 0)
+ skipping = FALSE;
+ if (skipping)
+ skiplev--;
+ continue;
+
+ case MACROEXPAND: /* macro interpolation */
+ c = *++s & 0377;
+ if (c != '\0')
+ q = macvalue(c, e);
+ else
+ {
+ s--;
+ q = NULL;
+ }
+ if (q == NULL)
+ continue;
+ break;
+ }
+
+ /*
+ ** Interpolate q or output one character
+ */
+
+ if (skipping || xp >= &xbuf[sizeof xbuf - 1])
+ continue;
+ if (q == NULL)
+ *xp++ = c;
+ else
+ {
+ /* copy to end of q or max space remaining in buf */
+ while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
+ {
+ /* check for any sendmail metacharacters */
+ if ((c & 0340) == 0200)
+ recurse = TRUE;
+ *xp++ = c;
+ }
+ }
+ }
+ *xp = '\0';
+
+ if (tTd(35, 24))
+ {
+ printf("expand ==> ");
+ xputs(xbuf);
+ printf("\n");
+ }
+
+ /* recurse as appropriate */
+ if (recurse)
+ {
+ if (explevel < MaxMacroRecursion)
+ {
+ explevel++;
+ expand(xbuf, buf, bufsize, e);
+ explevel--;
+ return;
+ }
+ syserr("expand: recursion too deep (%d max)",
+ MaxMacroRecursion);
+ }
+
+ /* copy results out */
+ i = xp - xbuf;
+ if (i >= bufsize)
+ i = bufsize - 1;
+ bcopy(xbuf, buf, i);
+ buf[i] = '\0';
+}
+ /*
+** DEFINE -- define a macro.
+**
+** this would be better done using a #define macro.
+**
+** Parameters:
+** n -- the macro name.
+** v -- the macro value.
+** e -- the envelope to store the definition in.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** e->e_macro[n] is defined.
+**
+** Notes:
+** There is one macro for each ASCII character,
+** although they are not all used. The currently
+** defined macros are:
+**
+** $a date in ARPANET format (preferring the Date: line
+** of the message)
+** $b the current date (as opposed to the date as found
+** the message) in ARPANET format
+** $c hop count
+** $d (current) date in UNIX (ctime) format
+** $e the SMTP entry message+
+** $f raw from address
+** $g translated from address
+** $h to host
+** $i queue id
+** $j official SMTP hostname, used in messages+
+** $k UUCP node name
+** $l UNIX-style from line+
+** $m The domain part of our full name.
+** $n name of sendmail ("MAILER-DAEMON" on local
+** net typically)+
+** $o delimiters ("operators") for address tokens+
+** $p my process id in decimal
+** $q the string that becomes an address -- this is
+** normally used to combine $g & $x.
+** $r protocol used to talk to sender
+** $s sender's host name
+** $t the current time in seconds since 1/1/1970
+** $u to user
+** $v version number of sendmail
+** $w our host name (if it can be determined)
+** $x signature (full name) of from person
+** $y the tty id of our terminal
+** $z home directory of to person
+** $_ RFC1413 authenticated sender address
+**
+** Macros marked with + must be defined in the
+** configuration file and are used internally, but
+** are not set.
+**
+** There are also some macros that can be used
+** arbitrarily to make the configuration file
+** cleaner. In general all upper-case letters
+** are available.
+*/
+
+void
+define(n, v, e)
+ int n;
+ char *v;
+ register ENVELOPE *e;
+{
+ if (tTd(35, 9))
+ {
+ printf("%sdefine(%s as ",
+ (e->e_macro[n & 0377] == NULL) ? "" : "re", macname(n));
+ xputs(v);
+ printf(")\n");
+ }
+ e->e_macro[n & 0377] = v;
+}
+ /*
+** MACVALUE -- return uninterpreted value of a macro.
+**
+** Parameters:
+** n -- the name of the macro.
+**
+** Returns:
+** The value of n.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+macvalue(n, e)
+ int n;
+ register ENVELOPE *e;
+{
+ n &= 0377;
+ while (e != NULL)
+ {
+ register char *p = e->e_macro[n];
+
+ if (p != NULL)
+ return (p);
+ e = e->e_parent;
+ }
+ return (NULL);
+}
+ /*
+** MACNAME -- return the name of a macro given its internal id
+**
+** Parameter:
+** n -- the id of the macro
+**
+** Returns:
+** The name of n.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+macname(n)
+ int n;
+{
+ static char mbuf[2];
+
+ n &= 0377;
+ if (bitset(0200, n))
+ {
+ char *p = MacroName[n];
+
+ if (p != NULL)
+ return p;
+ return "***UNDEFINED MACRO***";
+ }
+ mbuf[0] = n;
+ mbuf[1] = '\0';
+ return mbuf;
+}
+ /*
+** MACID -- return id of macro identified by its name
+**
+** Parameters:
+** p -- pointer to name string -- either a single
+** character or {name}.
+** ep -- filled in with the pointer to the byte
+** after the name.
+**
+** Returns:
+** The internal id code for this macro. This will
+** fit into a single byte.
+**
+** Side Effects:
+** If this is a new macro name, a new id is allocated.
+*/
+
+int
+macid(p, ep)
+ register char *p;
+ char **ep;
+{
+ int mid;
+ register char *bp;
+ char mbuf[21];
+
+ if (tTd(35, 14))
+ {
+ printf("macid(");
+ xputs(p);
+ printf(") => ");
+ }
+
+ if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
+ {
+ syserr("Name required for macro/class");
+ if (ep != NULL)
+ *ep = p;
+ if (tTd(35, 14))
+ printf("NULL\n");
+ return '\0';
+ }
+ if (*p != '{')
+ {
+ /* the macro is its own code */
+ if (ep != NULL)
+ *ep = p + 1;
+ if (tTd(35, 14))
+ printf("%c\n", *p);
+ return *p;
+ }
+ bp = mbuf;
+ while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf])
+ {
+ if (isascii(*p) && (isalnum(*p) || *p == '_'))
+ *bp++ = *p;
+ else
+ syserr("Invalid macro/class character %c", *p);
+ }
+ *bp = '\0';
+ mid = -1;
+ if (*p == '\0')
+ {
+ syserr("Unbalanced { on %s", mbuf); /* missing } */
+ }
+ else if (*p != '}')
+ {
+ syserr("Macro/class name ({%s}) too long (%d chars max)",
+ mbuf, sizeof mbuf - 1);
+ }
+ else if (mbuf[1] == '\0')
+ {
+ /* ${x} == $x */
+ mid = mbuf[0];
+ p++;
+ }
+ else
+ {
+ register STAB *s;
+
+ s = stab(mbuf, ST_MACRO, ST_ENTER);
+ if (s->s_macro != 0)
+ mid = s->s_macro;
+ else
+ {
+ if (NextMacroId > 0377)
+ {
+ syserr("Macro/class {%s}: too many long names", mbuf);
+ s->s_macro = -1;
+ }
+ else
+ {
+ MacroName[NextMacroId] = s->s_name;
+ s->s_macro = mid = NextMacroId++;
+ }
+ }
+ p++;
+ }
+ if (ep != NULL)
+ *ep = p;
+ if (tTd(35, 14))
+ printf("0x%x\n", mid);
+ return mid;
+}
+ /*
+** WORDINCLASS -- tell if a word is in a specific class
+**
+** Parameters:
+** str -- the name of the word to look up.
+** cl -- the class name.
+**
+** Returns:
+** TRUE if str can be found in cl.
+** FALSE otherwise.
+*/
+
+bool
+wordinclass(str, cl)
+ char *str;
+ int cl;
+{
+ register STAB *s;
+
+ s = stab(str, ST_CLASS, ST_FIND);
+ return s != NULL && bitnset(cl & 0xff, s->s_class);
+}