change call to expand() to be more rational (and consistent!)
[unix-history] / usr / src / usr.sbin / sendmail / src / macro.c
CommitLineData
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 10static 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
16char *MacroName[256]; /* macro id to name table */
17int 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 36void
832e8a27 37expand(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 215void
7338e3d4 216define(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
242char *
857afefe 243macvalue(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
271char *
272macname(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
307int
308macid(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
402bool
f88b683d
EA
403wordinclass(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}