xref: /original-bsd/usr.sbin/sendmail/src/macro.c (revision deff14a8)
1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)macro.c	8.5 (Berkeley) 10/15/94";
11 #endif /* not lint */
12 
13 # include "sendmail.h"
14 
15 char	*MacroName[256];	/* macro id to name table */
16 int	NextMacroId = 0240;	/* codes for long named macros */
17 
18 
19 /*
20 **  EXPAND -- macro expand a string using $x escapes.
21 **
22 **	Parameters:
23 **		s -- the string to expand.
24 **		buf -- the place to put the expansion.
25 **		buflim -- the buffer limit, i.e., the address
26 **			of the last usable position in buf.
27 **		e -- envelope in which to work.
28 **
29 **	Returns:
30 **		none.
31 **
32 **	Side Effects:
33 **		none.
34 */
35 
36 void
37 expand(s, buf, buflim, e)
38 	register char *s;
39 	register char *buf;
40 	char *buflim;
41 	register ENVELOPE *e;
42 {
43 	register char *xp;
44 	register char *q;
45 	bool skipping;		/* set if conditionally skipping output */
46 	bool recurse = FALSE;	/* set if recursion required */
47 	int i;
48 	int iflev;		/* if nesting level */
49 	char xbuf[BUFSIZ];
50 
51 	if (tTd(35, 24))
52 	{
53 		printf("expand(");
54 		xputs(s);
55 		printf(")\n");
56 	}
57 
58 	skipping = FALSE;
59 	iflev = 0;
60 	if (s == NULL)
61 		s = "";
62 	for (xp = xbuf; *s != '\0'; s++)
63 	{
64 		int c;
65 
66 		/*
67 		**  Check for non-ordinary (special?) character.
68 		**	'q' will be the interpolated quantity.
69 		*/
70 
71 		q = NULL;
72 		c = *s;
73 		switch (c & 0377)
74 		{
75 		  case CONDIF:		/* see if var set */
76 			c = *++s;
77 			if (skipping)
78 				iflev++;
79 			else
80 				skipping = macvalue(c, e) == NULL;
81 			continue;
82 
83 		  case CONDELSE:	/* change state of skipping */
84 			if (iflev == 0)
85 				skipping = !skipping;
86 			continue;
87 
88 		  case CONDFI:		/* stop skipping */
89 			if (iflev == 0)
90 				skipping = FALSE;
91 			if (skipping)
92 				iflev--;
93 			continue;
94 
95 		  case MACROEXPAND:	/* macro interpolation */
96 			c = *++s & 0377;
97 			if (c != '\0')
98 				q = macvalue(c, e);
99 			else
100 			{
101 				s--;
102 				q = NULL;
103 			}
104 			if (q == NULL)
105 				continue;
106 			break;
107 		}
108 
109 		/*
110 		**  Interpolate q or output one character
111 		*/
112 
113 		if (skipping || xp >= &xbuf[sizeof xbuf])
114 			continue;
115 		if (q == NULL)
116 			*xp++ = c;
117 		else
118 		{
119 			/* copy to end of q or max space remaining in buf */
120 			while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
121 			{
122 				/* check for any sendmail metacharacters */
123 				if ((c & 0340) == 0200)
124 					recurse = TRUE;
125 				*xp++ = c;
126 			}
127 		}
128 	}
129 	*xp = '\0';
130 
131 	if (tTd(35, 24))
132 	{
133 		printf("expand ==> ");
134 		xputs(xbuf);
135 		printf("\n");
136 	}
137 
138 	/* recurse as appropriate */
139 	if (recurse)
140 	{
141 		expand(xbuf, buf, buflim, e);
142 		return;
143 	}
144 
145 	/* copy results out */
146 	i = buflim - buf - 1;
147 	if (i > xp - xbuf)
148 		i = xp - xbuf;
149 	bcopy(xbuf, buf, i);
150 	buf[i] = '\0';
151 }
152 /*
153 **  DEFINE -- define a macro.
154 **
155 **	this would be better done using a #define macro.
156 **
157 **	Parameters:
158 **		n -- the macro name.
159 **		v -- the macro value.
160 **		e -- the envelope to store the definition in.
161 **
162 **	Returns:
163 **		none.
164 **
165 **	Side Effects:
166 **		e->e_macro[n] is defined.
167 **
168 **	Notes:
169 **		There is one macro for each ASCII character,
170 **		although they are not all used.  The currently
171 **		defined macros are:
172 **
173 **		$a   date in ARPANET format (preferring the Date: line
174 **		     of the message)
175 **		$b   the current date (as opposed to the date as found
176 **		     the message) in ARPANET format
177 **		$c   hop count
178 **		$d   (current) date in UNIX (ctime) format
179 **		$e   the SMTP entry message+
180 **		$f   raw from address
181 **		$g   translated from address
182 **		$h   to host
183 **		$i   queue id
184 **		$j   official SMTP hostname, used in messages+
185 **		$k   UUCP node name
186 **		$l   UNIX-style from line+
187 **		$m   The domain part of our full name.
188 **		$n   name of sendmail ("MAILER-DAEMON" on local
189 **		     net typically)+
190 **		$o   delimiters ("operators") for address tokens+
191 **		$p   my process id in decimal
192 **		$q   the string that becomes an address -- this is
193 **		     normally used to combine $g & $x.
194 **		$r   protocol used to talk to sender
195 **		$s   sender's host name
196 **		$t   the current time in seconds since 1/1/1970
197 **		$u   to user
198 **		$v   version number of sendmail
199 **		$w   our host name (if it can be determined)
200 **		$x   signature (full name) of from person
201 **		$y   the tty id of our terminal
202 **		$z   home directory of to person
203 **		$_   RFC1413 authenticated sender address
204 **
205 **		Macros marked with + must be defined in the
206 **		configuration file and are used internally, but
207 **		are not set.
208 **
209 **		There are also some macros that can be used
210 **		arbitrarily to make the configuration file
211 **		cleaner.  In general all upper-case letters
212 **		are available.
213 */
214 
215 void
216 define(n, v, e)
217 	int n;
218 	char *v;
219 	register ENVELOPE *e;
220 {
221 	if (tTd(35, 9))
222 	{
223 		printf("define(%s as ", macname(n));
224 		xputs(v);
225 		printf(")\n");
226 	}
227 	e->e_macro[n & 0377] = v;
228 }
229 /*
230 **  MACVALUE -- return uninterpreted value of a macro.
231 **
232 **	Parameters:
233 **		n -- the name of the macro.
234 **
235 **	Returns:
236 **		The value of n.
237 **
238 **	Side Effects:
239 **		none.
240 */
241 
242 char *
243 macvalue(n, e)
244 	int n;
245 	register ENVELOPE *e;
246 {
247 	n &= 0377;
248 	while (e != NULL)
249 	{
250 		register char *p = e->e_macro[n];
251 
252 		if (p != NULL)
253 			return (p);
254 		e = e->e_parent;
255 	}
256 	return (NULL);
257 }
258 /*
259 **  MACNAME -- return the name of a macro given its internal id
260 **
261 **	Parameter:
262 **		n -- the id of the macro
263 **
264 **	Returns:
265 **		The name of n.
266 **
267 **	Side Effects:
268 **		none.
269 */
270 
271 char *
272 macname(n)
273 	int n;
274 {
275 	static char mbuf[2];
276 
277 	n &= 0377;
278 	if (bitset(0200, n))
279 	{
280 		char *p = MacroName[n];
281 
282 		if (p != NULL)
283 			return p;
284 		return "***UNDEFINED MACRO***";
285 	}
286 	mbuf[0] = n;
287 	mbuf[1] = '\0';
288 	return mbuf;
289 }
290 /*
291 **  MACID -- return id of macro identified by its name
292 **
293 **	Parameters:
294 **		p -- pointer to name string -- either a single
295 **			character or {name}.
296 **		ep -- filled in with the pointer to the byte
297 **			after the name.
298 **
299 **	Returns:
300 **		The internal id code for this macro.  This will
301 **		fit into a single byte.
302 **
303 **	Side Effects:
304 **		If this is a new macro name, a new id is allocated.
305 */
306 
307 int
308 macid(p, ep)
309 	register char *p;
310 	char **ep;
311 {
312 	int mid;
313 	register char *bp;
314 	char mbuf[21];
315 
316 	if (tTd(35, 14))
317 		printf("macid(%s) => ", p);
318 
319 	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
320 	{
321 		syserr("Name required for macro/class");
322 		if (ep != NULL)
323 			*ep = p;
324 		if (tTd(35, 14))
325 			printf("NULL\n");
326 		return '\0';
327 	}
328 	if (*p != '{')
329 	{
330 		/* the macro is its own code */
331 		if (ep != NULL)
332 			*ep = p + 1;
333 		if (tTd(35, 14))
334 			printf("%c\n", *p);
335 		return *p;
336 	}
337 	bp = mbuf;
338 	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf])
339 	{
340 		if (isascii(*p) && (isalnum(*p) || *p == '_'))
341 			*bp++ = *p;
342 		else
343 			syserr("Invalid macro/class character %c", *p);
344 	}
345 	*bp = '\0';
346 	mid = -1;
347 	if (*p == '\0')
348 	{
349 		syserr("Unbalanced { on %s", mbuf);	/* missing } */
350 	}
351 	else if (*p != '}')
352 	{
353 		syserr("Macro/class name ({%s}) too long (%d chars max)",
354 			mbuf, sizeof mbuf - 1);
355 	}
356 	else if (mbuf[1] == '\0')
357 	{
358 		/* ${x} == $x */
359 		mid = mbuf[0];
360 		p++;
361 	}
362 	else
363 	{
364 		register STAB *s;
365 
366 		s = stab(mbuf, ST_MACRO, ST_ENTER);
367 		if (s->s_macro != 0)
368 			mid = s->s_macro;
369 		else
370 		{
371 			if (NextMacroId > 0377)
372 			{
373 				syserr("Macro/class {%s}: too many long names", mbuf);
374 				s->s_macro = -1;
375 			}
376 			else
377 			{
378 				MacroName[NextMacroId] = s->s_name;
379 				s->s_macro = mid = NextMacroId++;
380 			}
381 		}
382 		p++;
383 	}
384 	if (ep != NULL)
385 		*ep = p;
386 	if (tTd(35, 14))
387 		printf("0x%x\n", mid);
388 	return mid;
389 }
390