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