source: trunk/third/sendmail/sendmail/macro.c @ 19204

Revision 19204, 11.6 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *      The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: macro.c,v 1.1.1.1 2003-04-08 15:06:11 zacheiss Exp $")
17
18#if MAXMACROID != (BITMAPBITS - 1)
19        ERROR Read the comment in conf.h
20#endif /* MAXMACROID != (BITMAPBITS - 1) */
21
22static char     *MacroName[MAXMACROID + 1];     /* macro id to name table */
23int             NextMacroId = 0240;     /* codes for long named macros */
24
25/*
26**  INITMACROS -- initialize the macro system
27**
28**      This just involves defining some macros that are actually
29**      used internally as metasymbols to be themselves.
30**
31**      Parameters:
32**              none.
33**
34**      Returns:
35**              none.
36**
37**      Side Effects:
38**              initializes several macros to be themselves.
39*/
40
41struct metamac  MetaMacros[] =
42{
43        /* LHS pattern matching characters */
44        { '*', MATCHZANY },     { '+', MATCHANY },      { '-', MATCHONE },
45        { '=', MATCHCLASS },    { '~', MATCHNCLASS },
46
47        /* these are RHS metasymbols */
48        { '#', CANONNET },      { '@', CANONHOST },     { ':', CANONUSER },
49        { '>', CALLSUBR },
50
51        /* the conditional operations */
52        { '?', CONDIF },        { '|', CONDELSE },      { '.', CONDFI },
53
54        /* the hostname lookup characters */
55        { '[', HOSTBEGIN },     { ']', HOSTEND },
56        { '(', LOOKUPBEGIN },   { ')', LOOKUPEND },
57
58        /* miscellaneous control characters */
59        { '&', MACRODEXPAND },
60
61        { '\0', '\0' }
62};
63
64#define MACBINDING(name, mid) \
65                stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
66                MacroName[mid] = name;
67
68void
69initmacros(e)
70        register ENVELOPE *e;
71{
72        register struct metamac *m;
73        register int c;
74        char buf[5];
75
76        for (m = MetaMacros; m->metaname != '\0'; m++)
77        {
78                buf[0] = m->metaval;
79                buf[1] = '\0';
80                macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
81        }
82        buf[0] = MATCHREPL;
83        buf[2] = '\0';
84        for (c = '0'; c <= '9'; c++)
85        {
86                buf[1] = c;
87                macdefine(&e->e_macro, A_TEMP, c, buf);
88        }
89
90        /* set defaults for some macros sendmail will use later */
91        macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
92
93        /* set up external names for some internal macros */
94        MACBINDING("opMode", MID_OPMODE);
95        /*XXX should probably add equivalents for all short macros here XXX*/
96}
97/*
98**  EXPAND -- macro expand a string using $x escapes.
99**
100**      Parameters:
101**              s -- the string to expand.
102**              buf -- the place to put the expansion.
103**              bufsize -- the size of the buffer.
104**              e -- envelope in which to work.
105**
106**      Returns:
107**              none.
108**
109**      Side Effects:
110**              none.
111*/
112
113void
114expand(s, buf, bufsize, e)
115        register char *s;
116        register char *buf;
117        size_t bufsize;
118        register ENVELOPE *e;
119{
120        register char *xp;
121        register char *q;
122        bool skipping;          /* set if conditionally skipping output */
123        bool recurse;           /* set if recursion required */
124        size_t i;
125        int skiplev;            /* skipping nesting level */
126        int iflev;              /* if nesting level */
127        char xbuf[MACBUFSIZE];
128        static int explevel = 0;
129
130        if (tTd(35, 24))
131        {
132                sm_dprintf("expand(");
133                xputs(s);
134                sm_dprintf(")\n");
135        }
136
137        recurse = false;
138        skipping = false;
139        skiplev = 0;
140        iflev = 0;
141        if (s == NULL)
142                s = "";
143        for (xp = xbuf; *s != '\0'; s++)
144        {
145                int c;
146
147                /*
148                **  Check for non-ordinary (special?) character.
149                **      'q' will be the interpolated quantity.
150                */
151
152                q = NULL;
153                c = *s;
154                switch (c & 0377)
155                {
156                  case CONDIF:          /* see if var set */
157                        iflev++;
158                        c = *++s;
159                        if (skipping)
160                                skiplev++;
161                        else
162                        {
163                                char *mv;
164
165                                mv = macvalue(c, e);
166                                skipping = (mv == NULL || *mv == '\0');
167                        }
168                        continue;
169
170                  case CONDELSE:        /* change state of skipping */
171                        if (iflev == 0)
172                                break;  /* XXX: error */
173                        if (skiplev == 0)
174                                skipping = !skipping;
175                        continue;
176
177                  case CONDFI:          /* stop skipping */
178                        if (iflev == 0)
179                                break;  /* XXX: error */
180                        iflev--;
181                        if (skiplev == 0)
182                                skipping = false;
183                        if (skipping)
184                                skiplev--;
185                        continue;
186
187                  case MACROEXPAND:     /* macro interpolation */
188                        c = bitidx(*++s);
189                        if (c != '\0')
190                                q = macvalue(c, e);
191                        else
192                        {
193                                s--;
194                                q = NULL;
195                        }
196                        if (q == NULL)
197                                continue;
198                        break;
199                }
200
201                /*
202                **  Interpolate q or output one character
203                */
204
205                if (skipping || xp >= &xbuf[sizeof xbuf - 1])
206                        continue;
207                if (q == NULL)
208                        *xp++ = c;
209                else
210                {
211                        /* copy to end of q or max space remaining in buf */
212                        while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
213                        {
214                                /* check for any sendmail metacharacters */
215                                if ((c & 0340) == 0200)
216                                        recurse = true;
217                                *xp++ = c;
218                        }
219                }
220        }
221        *xp = '\0';
222
223        if (tTd(35, 24))
224        {
225                sm_dprintf("expand ==> ");
226                xputs(xbuf);
227                sm_dprintf("\n");
228        }
229
230        /* recurse as appropriate */
231        if (recurse)
232        {
233                if (explevel < MaxMacroRecursion)
234                {
235                        explevel++;
236                        expand(xbuf, buf, bufsize, e);
237                        explevel--;
238                        return;
239                }
240                syserr("expand: recursion too deep (%d max)",
241                        MaxMacroRecursion);
242        }
243
244        /* copy results out */
245        i = xp - xbuf;
246        if (i >= bufsize)
247                i = bufsize - 1;
248        memmove(buf, xbuf, i);
249        buf[i] = '\0';
250}
251
252/*
253**  MACDEFINE -- bind a macro name to a value
254**
255**      Set a macro to a value, with fancy storage management.
256**      macdefine will make a copy of the value, if required,
257**      and will ensure that the storage for the previous value
258**      is not leaked.
259**
260**      Parameters:
261**              mac -- Macro table.
262**              vclass -- storage class of 'value', ignored if value==NULL.
263**                      A_HEAP  means that the value was allocated by
264**                              malloc, and that macdefine owns the storage.
265**                      A_TEMP  means that value points to temporary storage,
266**                              and thus macdefine needs to make a copy.
267**                      A_PERM  means that value points to storage that
268**                              will remain allocated and unchanged for
269**                              at least the lifetime of mac.  Use A_PERM if:
270**                              -- value == NULL,
271**                              -- value points to a string literal,
272**                              -- value was allocated from mac->mac_rpool
273**                                 or (in the case of an envelope macro)
274**                                 from e->e_rpool,
275**                              -- in the case of an envelope macro,
276**                                 value is a string member of the envelope
277**                                 such as e->e_sender.
278**              id -- Macro id.  This is a single character macro name
279**                      such as 'g', or a value returned by macid().
280**              value -- Macro value: either NULL, or a string.
281*/
282
283void
284#if SM_HEAP_CHECK
285macdefine_tagged(mac, vclass, id, value, file, line, grp)
286#else /* SM_HEAP_CHECK */
287macdefine(mac, vclass, id, value)
288#endif /* SM_HEAP_CHECK */
289        MACROS_T *mac;
290        ARGCLASS_T vclass;
291        int id;
292        char *value;
293#if SM_HEAP_CHECK
294        char *file;
295        int line;
296        int grp;
297#endif /* SM_HEAP_CHECK */
298{
299        char *newvalue;
300
301        if (id < 0 || id > MAXMACROID)
302                return;
303
304        if (tTd(35, 9))
305        {
306                sm_dprintf("%sdefine(%s as ",
307                        mac->mac_table[id] == NULL ? "" : "re", macname(id));
308                xputs(value);
309                sm_dprintf(")\n");
310        }
311
312        if (mac->mac_rpool == NULL)
313        {
314                char *freeit = NULL;
315
316                if (mac->mac_table[id] != NULL &&
317                    bitnset(id, mac->mac_allocated))
318                        freeit = mac->mac_table[id];
319
320                if (value == NULL || vclass == A_HEAP)
321                {
322                        sm_heap_checkptr_tagged(value, file, line);
323                        newvalue = value;
324                        clrbitn(id, mac->mac_allocated);
325                }
326                else
327                {
328                        newvalue = sm_strdup_tagged_x(value, file, line, 0);
329                        setbitn(id, mac->mac_allocated);
330                }
331                mac->mac_table[id] = newvalue;
332                if (freeit != NULL)
333                        sm_free(freeit);
334        }
335        else
336        {
337                if (value == NULL || vclass == A_PERM)
338                        newvalue = value;
339                else
340                        newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
341                mac->mac_table[id] = newvalue;
342                if (vclass == A_HEAP)
343                        sm_free(value);
344        }
345
346#if _FFR_RESET_MACRO_GLOBALS
347        switch (id)
348        {
349          case 'j':
350                PSTRSET(MyHostName, value);
351                break;
352        }
353#endif /* _FFR_RESET_MACRO_GLOBALS */
354}
355
356/*
357**  MACSET -- set a named macro to a value (low level)
358**
359**      No fancy storage management; the caller takes full responsibility.
360**      Often used with macget; see also macdefine.
361**
362**      Parameters:
363**              mac -- Macro table.
364**              i -- Macro name, specified as an integer offset.
365**              value -- Macro value: either NULL, or a string.
366*/
367
368void
369macset(mac, i, value)
370        MACROS_T *mac;
371        int i;
372        char *value;
373{
374        if (i < 0 || i > MAXMACROID)
375                return;
376
377        if (tTd(35, 9))
378        {
379                sm_dprintf("macset(%s as ", macname(i));
380                xputs(value);
381                sm_dprintf(")\n");
382        }
383        mac->mac_table[i] = value;
384}
385
386/*
387**  MACVALUE -- return uninterpreted value of a macro.
388**
389**      Does fancy path searching.
390**      The low level counterpart is macget.
391**
392**      Parameters:
393**              n -- the name of the macro.
394**              e -- envelope in which to start looking for the macro.
395**
396**      Returns:
397**              The value of n.
398**
399**      Side Effects:
400**              none.
401*/
402
403char *
404macvalue(n, e)
405        int n;
406        register ENVELOPE *e;
407{
408        n = bitidx(n);
409        if (e != NULL && e->e_mci != NULL)
410        {
411                register char *p = e->e_mci->mci_macro.mac_table[n];
412
413                if (p != NULL)
414                        return p;
415        }
416        while (e != NULL)
417        {
418                register char *p = e->e_macro.mac_table[n];
419
420                if (p != NULL)
421                        return p;
422                if (e == e->e_parent)
423                        break;
424                e = e->e_parent;
425        }
426        return GlobalMacros.mac_table[n];
427}
428/*
429**  MACNAME -- return the name of a macro given its internal id
430**
431**      Parameter:
432**              n -- the id of the macro
433**
434**      Returns:
435**              The name of n.
436**
437**      Side Effects:
438**              none.
439*/
440
441char *
442macname(n)
443        int n;
444{
445        static char mbuf[2];
446
447        n = bitidx(n);
448        if (bitset(0200, n))
449        {
450                char *p = MacroName[n];
451
452                if (p != NULL)
453                        return p;
454                return "***UNDEFINED MACRO***";
455        }
456        mbuf[0] = n;
457        mbuf[1] = '\0';
458        return mbuf;
459}
460/*
461**  MACID_PARSE -- return id of macro identified by its name
462**
463**      Parameters:
464**              p -- pointer to name string -- either a single
465**                      character or {name}.
466**              ep -- filled in with the pointer to the byte
467**                      after the name.
468**
469**      Returns:
470**              0 -- An error was detected.
471**              1..255 -- The internal id code for this macro.
472**
473**      Side Effects:
474**              If this is a new macro name, a new id is allocated.
475**              On error, syserr is called.
476*/
477
478int
479macid_parse(p, ep)
480        register char *p;
481        char **ep;
482{
483        int mid;
484        register char *bp;
485        char mbuf[MAXMACNAMELEN + 1];
486
487        if (tTd(35, 14))
488        {
489                sm_dprintf("macid(");
490                xputs(p);
491                sm_dprintf(") => ");
492        }
493
494        if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
495        {
496                syserr("Name required for macro/class");
497                if (ep != NULL)
498                        *ep = p;
499                if (tTd(35, 14))
500                        sm_dprintf("NULL\n");
501                return 0;
502        }
503        if (*p != '{')
504        {
505                /* the macro is its own code */
506                if (ep != NULL)
507                        *ep = p + 1;
508                if (tTd(35, 14))
509                        sm_dprintf("%c\n", bitidx(*p));
510                return bitidx(*p);
511        }
512        bp = mbuf;
513        while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1])
514        {
515                if (isascii(*p) && (isalnum(*p) || *p == '_'))
516                        *bp++ = *p;
517                else
518                        syserr("Invalid macro/class character %c", *p);
519        }
520        *bp = '\0';
521        mid = -1;
522        if (*p == '\0')
523        {
524                syserr("Unbalanced { on %s", mbuf);     /* missing } */
525        }
526        else if (*p != '}')
527        {
528                syserr("Macro/class name ({%s}) too long (%d chars max)",
529                        mbuf, (int) (sizeof mbuf - 1));
530        }
531        else if (mbuf[1] == '\0')
532        {
533                /* ${x} == $x */
534                mid = bitidx(mbuf[0]);
535                p++;
536        }
537        else
538        {
539                register STAB *s;
540
541                s = stab(mbuf, ST_MACRO, ST_ENTER);
542                if (s->s_macro != 0)
543                        mid = s->s_macro;
544                else
545                {
546                        if (NextMacroId > MAXMACROID)
547                        {
548                                syserr("Macro/class {%s}: too many long names",
549                                        mbuf);
550                                s->s_macro = -1;
551                        }
552                        else
553                        {
554                                MacroName[NextMacroId] = s->s_name;
555                                s->s_macro = mid = NextMacroId++;
556                        }
557                }
558                p++;
559        }
560        if (ep != NULL)
561                *ep = p;
562        if (mid < 0 || mid > MAXMACROID)
563        {
564                syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
565                if (tTd(35, 14))
566                        sm_dprintf("NULL\n");
567                return 0;
568        }
569        if (tTd(35, 14))
570                sm_dprintf("0x%x\n", mid);
571        return mid;
572}
573/*
574**  WORDINCLASS -- tell if a word is in a specific class
575**
576**      Parameters:
577**              str -- the name of the word to look up.
578**              cl -- the class name.
579**
580**      Returns:
581**              true if str can be found in cl.
582**              false otherwise.
583*/
584
585bool
586wordinclass(str, cl)
587        char *str;
588        int cl;
589{
590        register STAB *s;
591
592        s = stab(str, ST_CLASS, ST_FIND);
593        return s != NULL && bitnset(bitidx(cl), s->s_class);
594}
Note: See TracBrowser for help on using the repository browser.