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
expand(s,buf,bufsize,e)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
define(n,v,e)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 *
macvalue(n,e)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 *
macname(n)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
macid(p,ep)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
wordinclass(str,cl)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