xref: /original-bsd/usr.sbin/sendmail/src/macro.c (revision a79d9c15)
1 /*
2  * Copyright (c) 1983, 1995 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.12 (Berkeley) 06/17/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 	{
317 		printf("macid(");
318 		xputs(p);
319 		printf(") => ");
320 	}
321 
322 	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
323 	{
324 		syserr("Name required for macro/class");
325 		if (ep != NULL)
326 			*ep = p;
327 		if (tTd(35, 14))
328 			printf("NULL\n");
329 		return '\0';
330 	}
331 	if (*p != '{')
332 	{
333 		/* the macro is its own code */
334 		if (ep != NULL)
335 			*ep = p + 1;
336 		if (tTd(35, 14))
337 			printf("%c\n", *p);
338 		return *p;
339 	}
340 	bp = mbuf;
341 	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf])
342 	{
343 		if (isascii(*p) && (isalnum(*p) || *p == '_'))
344 			*bp++ = *p;
345 		else
346 			syserr("Invalid macro/class character %c", *p);
347 	}
348 	*bp = '\0';
349 	mid = -1;
350 	if (*p == '\0')
351 	{
352 		syserr("Unbalanced { on %s", mbuf);	/* missing } */
353 	}
354 	else if (*p != '}')
355 	{
356 		syserr("Macro/class name ({%s}) too long (%d chars max)",
357 			mbuf, sizeof mbuf - 1);
358 	}
359 	else if (mbuf[1] == '\0')
360 	{
361 		/* ${x} == $x */
362 		mid = mbuf[0];
363 		p++;
364 	}
365 	else
366 	{
367 		register STAB *s;
368 
369 		s = stab(mbuf, ST_MACRO, ST_ENTER);
370 		if (s->s_macro != 0)
371 			mid = s->s_macro;
372 		else
373 		{
374 			if (NextMacroId > 0377)
375 			{
376 				syserr("Macro/class {%s}: too many long names", mbuf);
377 				s->s_macro = -1;
378 			}
379 			else
380 			{
381 				MacroName[NextMacroId] = s->s_name;
382 				s->s_macro = mid = NextMacroId++;
383 			}
384 		}
385 		p++;
386 	}
387 	if (ep != NULL)
388 		*ep = p;
389 	if (tTd(35, 14))
390 		printf("0x%x\n", mid);
391 	return mid;
392 }
393 /*
394 **  WORDINCLASS -- tell if a word is in a specific class
395 **
396 **	Parameters:
397 **		str -- the name of the word to look up.
398 **		cl -- the class name.
399 **
400 **	Returns:
401 **		TRUE if str can be found in cl.
402 **		FALSE otherwise.
403 */
404 
405 bool
406 wordinclass(str, cl)
407 	char *str;
408 	int cl;
409 {
410 	register STAB *s;
411 
412 	s = stab(str, ST_CLASS, ST_FIND);
413 	return s != NULL && bitnset(cl & 0xff, s->s_class);
414 }
415