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