Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
eb0bafab KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
832e8a27 | 10 | static char sccsid[] = "@(#)macro.c 8.10 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
9dbc8d99 | 13 | # include "sendmail.h" |
b5fd168f | 14 | # include "conf.h" |
980d20dd | 15 | |
1be6e8d1 EA |
16 | char *MacroName[256]; /* macro id to name table */ |
17 | int NextMacroId = 0240; /* codes for long named macros */ | |
18 | ||
19 | ||
980d20dd EA |
20 | /* |
21 | ** EXPAND -- macro expand a string using $x escapes. | |
22 | ** | |
23 | ** Parameters: | |
24 | ** s -- the string to expand. | |
25 | ** buf -- the place to put the expansion. | |
832e8a27 | 26 | ** bufsize -- the size of the buffer. |
dd1fe05b | 27 | ** e -- envelope in which to work. |
980d20dd EA |
28 | ** |
29 | ** Returns: | |
7338e3d4 | 30 | ** none. |
980d20dd EA |
31 | ** |
32 | ** Side Effects: | |
33 | ** none. | |
34 | */ | |
35 | ||
5a972da1 | 36 | void |
832e8a27 | 37 | expand(s, buf, bufsize, e) |
dd1fe05b EA |
38 | register char *s; |
39 | register char *buf; | |
832e8a27 | 40 | size_t bufsize; |
dd1fe05b | 41 | register ENVELOPE *e; |
980d20dd | 42 | { |
68d6c559 | 43 | register char *xp; |
9dbc8d99 | 44 | register char *q; |
74c5fe7c | 45 | bool skipping; /* set if conditionally skipping output */ |
68d6c559 EA |
46 | bool recurse = FALSE; /* set if recursion required */ |
47 | int i; | |
1627a785 | 48 | int iflev; /* if nesting level */ |
7338e3d4 | 49 | char xbuf[BUFSIZ]; |
980d20dd | 50 | |
2e3062fe | 51 | if (tTd(35, 24)) |
9dbc8d99 EA |
52 | { |
53 | printf("expand("); | |
54 | xputs(s); | |
55 | printf(")\n"); | |
56 | } | |
980d20dd | 57 | |
2f0c5bd8 | 58 | skipping = FALSE; |
1627a785 | 59 | iflev = 0; |
aa4ef64d EA |
60 | if (s == NULL) |
61 | s = ""; | |
68d6c559 | 62 | for (xp = xbuf; *s != '\0'; s++) |
980d20dd | 63 | { |
2610adfd | 64 | int c; |
74c5fe7c EA |
65 | |
66 | /* | |
9dbc8d99 | 67 | ** Check for non-ordinary (special?) character. |
74c5fe7c EA |
68 | ** 'q' will be the interpolated quantity. |
69 | */ | |
70 | ||
980d20dd | 71 | q = NULL; |
9dbc8d99 | 72 | c = *s; |
2bee003d | 73 | switch (c & 0377) |
2f0c5bd8 | 74 | { |
9dbc8d99 | 75 | case CONDIF: /* see if var set */ |
aa102c71 EA |
76 | c = *++s; |
77 | if (skipping) | |
78 | iflev++; | |
79 | else | |
1627a785 | 80 | skipping = macvalue(c, e) == NULL; |
aa102c71 | 81 | continue; |
2f0c5bd8 | 82 | |
9dbc8d99 | 83 | case CONDELSE: /* change state of skipping */ |
aa102c71 | 84 | if (iflev == 0) |
1627a785 | 85 | skipping = !skipping; |
9dbc8d99 | 86 | continue; |
2f0c5bd8 | 87 | |
9dbc8d99 | 88 | case CONDFI: /* stop skipping */ |
aa102c71 | 89 | if (iflev == 0) |
1627a785 | 90 | skipping = FALSE; |
aa102c71 EA |
91 | if (skipping) |
92 | iflev--; | |
93 | continue; | |
2f0c5bd8 | 94 | |
2bee003d | 95 | case MACROEXPAND: /* macro interpolation */ |
1be6e8d1 | 96 | c = *++s & 0377; |
f7082d56 EA |
97 | if (c != '\0') |
98 | q = macvalue(c, e); | |
99 | else | |
100 | { | |
101 | s--; | |
102 | q = NULL; | |
103 | } | |
7338e3d4 | 104 | if (q == NULL) |
2f0c5bd8 | 105 | continue; |
9dbc8d99 | 106 | break; |
2f0c5bd8 | 107 | } |
980d20dd EA |
108 | |
109 | /* | |
110 | ** Interpolate q or output one character | |
111 | */ | |
112 | ||
68d6c559 | 113 | if (skipping || xp >= &xbuf[sizeof xbuf]) |
2f0c5bd8 | 114 | continue; |
68d6c559 EA |
115 | if (q == NULL) |
116 | *xp++ = c; | |
117 | else | |
9dbc8d99 | 118 | { |
68d6c559 EA |
119 | /* copy to end of q or max space remaining in buf */ |
120 | while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1]) | |
9dbc8d99 | 121 | { |
2bee003d EA |
122 | /* check for any sendmail metacharacters */ |
123 | if ((c & 0340) == 0200) | |
68d6c559 | 124 | recurse = TRUE; |
9dbc8d99 | 125 | *xp++ = c; |
9dbc8d99 | 126 | } |
9dbc8d99 | 127 | } |
980d20dd | 128 | } |
9dbc8d99 | 129 | *xp = '\0'; |
980d20dd | 130 | |
2e3062fe | 131 | if (tTd(35, 24)) |
9dbc8d99 | 132 | { |
aa4ef64d | 133 | printf("expand ==> "); |
9dbc8d99 | 134 | xputs(xbuf); |
aa4ef64d | 135 | printf("\n"); |
9dbc8d99 | 136 | } |
980d20dd | 137 | |
9dbc8d99 | 138 | /* recurse as appropriate */ |
68d6c559 | 139 | if (recurse) |
7338e3d4 | 140 | { |
832e8a27 | 141 | expand(xbuf, buf, bufsize, e); |
7338e3d4 EA |
142 | return; |
143 | } | |
9dbc8d99 EA |
144 | |
145 | /* copy results out */ | |
832e8a27 EA |
146 | i = xp - xbuf; |
147 | if (i >= bufsize) | |
148 | i = bufsize - 1; | |
68d6c559 EA |
149 | bcopy(xbuf, buf, i); |
150 | buf[i] = '\0'; | |
980d20dd EA |
151 | } |
152 | \f/* | |
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. | |
7338e3d4 | 160 | ** e -- the envelope to store the definition in. |
980d20dd EA |
161 | ** |
162 | ** Returns: | |
163 | ** none. | |
164 | ** | |
165 | ** Side Effects: | |
7338e3d4 | 166 | ** e->e_macro[n] is defined. |
490bdc0f EA |
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 | ** | |
0626766c EA |
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 | |
490bdc0f | 177 | ** $c hop count |
0626766c | 178 | ** $d (current) date in UNIX (ctime) format |
378e8da7 | 179 | ** $e the SMTP entry message+ |
490bdc0f EA |
180 | ** $f raw from address |
181 | ** $g translated from address | |
182 | ** $h to host | |
3d54489c EA |
183 | ** $i queue id |
184 | ** $j official SMTP hostname, used in messages+ | |
422bed79 | 185 | ** $k UUCP node name |
490bdc0f | 186 | ** $l UNIX-style from line+ |
c15ec973 | 187 | ** $m The domain part of our full name. |
490bdc0f EA |
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 | |
028b97f3 EA |
192 | ** $q the string that becomes an address -- this is |
193 | ** normally used to combine $g & $x. | |
d87a0dbb EA |
194 | ** $r protocol used to talk to sender |
195 | ** $s sender's host name | |
490bdc0f EA |
196 | ** $t the current time in seconds since 1/1/1970 |
197 | ** $u to user | |
198 | ** $v version number of sendmail | |
68c04bed | 199 | ** $w our host name (if it can be determined) |
490bdc0f | 200 | ** $x signature (full name) of from person |
0626766c | 201 | ** $y the tty id of our terminal |
490bdc0f | 202 | ** $z home directory of to person |
3f03d7a7 | 203 | ** $_ RFC1413 authenticated sender address |
490bdc0f EA |
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. | |
980d20dd EA |
213 | */ |
214 | ||
5a972da1 | 215 | void |
7338e3d4 | 216 | define(n, v, e) |
2610adfd | 217 | int n; |
980d20dd | 218 | char *v; |
7338e3d4 | 219 | register ENVELOPE *e; |
980d20dd | 220 | { |
2e3062fe | 221 | if (tTd(35, 9)) |
9dbc8d99 | 222 | { |
1be6e8d1 | 223 | printf("define(%s as ", macname(n)); |
9dbc8d99 EA |
224 | xputs(v); |
225 | printf(")\n"); | |
226 | } | |
1be6e8d1 | 227 | e->e_macro[n & 0377] = v; |
980d20dd | 228 | } |
86d9dc4e EA |
229 | \f/* |
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 * | |
857afefe | 243 | macvalue(n, e) |
2610adfd | 244 | int n; |
857afefe | 245 | register ENVELOPE *e; |
86d9dc4e | 246 | { |
1be6e8d1 | 247 | n &= 0377; |
857afefe EA |
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); | |
86d9dc4e | 257 | } |
1be6e8d1 EA |
258 | \f/* |
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 | \f/* | |
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 | ||
4fd905c3 | 319 | if (*p == '\0' || (p[0] == '{' && p[1] == '}')) |
1be6e8d1 EA |
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]) | |
4fd905c3 EA |
339 | { |
340 | if (isascii(*p) && (isalnum(*p) || *p == '_')) | |
341 | *bp++ = *p; | |
342 | else | |
343 | syserr("Invalid macro/class character %c", *p); | |
344 | } | |
1be6e8d1 EA |
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 | } | |
c85d44ca EA |
390 | \f/* |
391 | ** WORDINCLASS -- tell if a word is in a specific class | |
392 | ** | |
393 | ** Parameters: | |
f88b683d | 394 | ** str -- the name of the word to look up. |
c85d44ca EA |
395 | ** cl -- the class name. |
396 | ** | |
397 | ** Returns: | |
f88b683d | 398 | ** TRUE if str can be found in cl. |
c85d44ca EA |
399 | ** FALSE otherwise. |
400 | */ | |
401 | ||
402 | bool | |
f88b683d EA |
403 | wordinclass(str, cl) |
404 | char *str; | |
28ec685f | 405 | int cl; |
c85d44ca EA |
406 | { |
407 | register STAB *s; | |
408 | ||
f88b683d | 409 | s = stab(str, ST_CLASS, ST_FIND); |
28ec685f | 410 | return s != NULL && bitnset(cl & 0xff, s->s_class); |
c85d44ca | 411 | } |