source: trunk/third/sendmail/src/macro.c @ 12554

Revision 12554, 8.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)macro.c     8.26 (Berkeley) 11/8/1998";
15#endif /* not lint */
16
17# include "sendmail.h"
18
19char    *MacroName[256];        /* macro id to name table */
20int     NextMacroId = 0240;     /* codes for long named macros */
21
22
23/*
24**  EXPAND -- macro expand a string using $x escapes.
25**
26**      Parameters:
27**              s -- the string to expand.
28**              buf -- the place to put the expansion.
29**              bufsize -- the size of the buffer.
30**              e -- envelope in which to work.
31**
32**      Returns:
33**              none.
34**
35**      Side Effects:
36**              none.
37*/
38
39void
40expand(s, buf, bufsize, e)
41        register char *s;
42        register char *buf;
43        size_t bufsize;
44        register ENVELOPE *e;
45{
46        register char *xp;
47        register char *q;
48        bool skipping;          /* set if conditionally skipping output */
49        bool recurse = FALSE;   /* set if recursion required */
50        int i;
51        int skiplev;            /* skipping nesting level */
52        int iflev;              /* if nesting level */
53        char xbuf[MACBUFSIZE];
54        static int explevel = 0;
55
56        if (tTd(35, 24))
57        {
58                printf("expand(");
59                xputs(s);
60                printf(")\n");
61        }
62
63        skipping = FALSE;
64        skiplev = 0;
65        iflev = 0;
66        if (s == NULL)
67                s = "";
68        for (xp = xbuf; *s != '\0'; s++)
69        {
70                int c;
71
72                /*
73                **  Check for non-ordinary (special?) character.
74                **      'q' will be the interpolated quantity.
75                */
76
77                q = NULL;
78                c = *s;
79                switch (c & 0377)
80                {
81                  case CONDIF:          /* see if var set */
82                        iflev++;
83                        c = *++s;
84                        if (skipping)
85                                skiplev++;
86                        else
87                                skipping = macvalue(c, e) == NULL;
88                        continue;
89
90                  case CONDELSE:        /* change state of skipping */
91                        if (iflev == 0)
92                                break;
93                        if (skiplev == 0)
94                                skipping = !skipping;
95                        continue;
96
97                  case CONDFI:          /* stop skipping */
98                        if (iflev == 0)
99                                break;
100                        iflev--;
101                        if (skiplev == 0)
102                                skipping = FALSE;
103                        if (skipping)
104                                skiplev--;
105                        continue;
106
107                  case MACROEXPAND:     /* macro interpolation */
108                        c = *++s & 0377;
109                        if (c != '\0')
110                                q = macvalue(c, e);
111                        else
112                        {
113                                s--;
114                                q = NULL;
115                        }
116                        if (q == NULL)
117                                continue;
118                        break;
119                }
120
121                /*
122                **  Interpolate q or output one character
123                */
124
125                if (skipping || xp >= &xbuf[sizeof xbuf - 1])
126                        continue;
127                if (q == NULL)
128                        *xp++ = c;
129                else
130                {
131                        /* copy to end of q or max space remaining in buf */
132                        while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1])
133                        {
134                                /* check for any sendmail metacharacters */
135                                if ((c & 0340) == 0200)
136                                        recurse = TRUE;
137                                *xp++ = c;
138                        }
139                }
140        }
141        *xp = '\0';
142
143        if (tTd(35, 24))
144        {
145                printf("expand ==> ");
146                xputs(xbuf);
147                printf("\n");
148        }
149
150        /* recurse as appropriate */
151        if (recurse)
152        {
153                if (explevel < MaxMacroRecursion)
154                {
155                        explevel++;
156                        expand(xbuf, buf, bufsize, e);
157                        explevel--;
158                        return;
159                }
160                syserr("expand: recursion too deep (%d max)",
161                        MaxMacroRecursion);
162        }
163
164        /* copy results out */
165        i = xp - xbuf;
166        if (i >= bufsize)
167                i = bufsize - 1;
168        bcopy(xbuf, buf, i);
169        buf[i] = '\0';
170}
171/*
172**  DEFINE -- define a macro.
173**
174**      this would be better done using a #define macro.
175**
176**      Parameters:
177**              n -- the macro name.
178**              v -- the macro value.
179**              e -- the envelope to store the definition in.
180**
181**      Returns:
182**              none.
183**
184**      Side Effects:
185**              e->e_macro[n] is defined.
186**
187**      Notes:
188**              There is one macro for each ASCII character,
189**              although they are not all used.  The currently
190**              defined macros are:
191**
192**              $a   date in ARPANET format (preferring the Date: line
193**                   of the message)
194**              $b   the current date (as opposed to the date as found
195**                   the message) in ARPANET format
196**              $c   hop count
197**              $d   (current) date in UNIX (ctime) format
198**              $e   the SMTP entry message+
199**              $f   raw from address
200**              $g   translated from address
201**              $h   to host
202**              $i   queue id
203**              $j   official SMTP hostname, used in messages+
204**              $k   UUCP node name
205**              $l   UNIX-style from line+
206**              $m   The domain part of our full name.
207**              $n   name of sendmail ("MAILER-DAEMON" on local
208**                   net typically)+
209**              $o   delimiters ("operators") for address tokens+
210**                   (set via OperatorChars option in V6 or later
211**                    sendmail.cf files)
212**              $p   my process id in decimal
213**              $q   the string that becomes an address -- this is
214**                   normally used to combine $g & $x.
215**              $r   protocol used to talk to sender
216**              $s   sender's host name
217**              $t   the current time in seconds since 1/1/1970
218**              $u   to user
219**              $v   version number of sendmail
220**              $w   our host name (if it can be determined)
221**              $x   signature (full name) of from person
222**              $y   the tty id of our terminal
223**              $z   home directory of to person
224**              $_   RFC1413 authenticated sender address
225**
226**              Macros marked with + must be defined in the
227**              configuration file and are used internally, but
228**              are not set.
229**
230**              There are also some macros that can be used
231**              arbitrarily to make the configuration file
232**              cleaner.  In general all upper-case letters
233**              are available.
234*/
235
236void
237define(n, v, e)
238        int n;
239        char *v;
240        register ENVELOPE *e;
241{
242        if (tTd(35, 9))
243        {
244                printf("%sdefine(%s as ",
245                    (e->e_macro[n & 0377] == NULL) ? "" : "re", macname(n));
246                xputs(v);
247                printf(")\n");
248        }
249        e->e_macro[n & 0377] = v;
250}
251/*
252**  MACVALUE -- return uninterpreted value of a macro.
253**
254**      Parameters:
255**              n -- the name of the macro.
256**
257**      Returns:
258**              The value of n.
259**
260**      Side Effects:
261**              none.
262*/
263
264char *
265macvalue(n, e)
266        int n;
267        register ENVELOPE *e;
268{
269        n &= 0377;
270        while (e != NULL)
271        {
272                register char *p = e->e_macro[n];
273
274                if (p != NULL)
275                        return (p);
276                e = e->e_parent;
277        }
278        return (NULL);
279}
280/*
281**  MACNAME -- return the name of a macro given its internal id
282**
283**      Parameter:
284**              n -- the id of the macro
285**
286**      Returns:
287**              The name of n.
288**
289**      Side Effects:
290**              none.
291*/
292
293char *
294macname(n)
295        int n;
296{
297        static char mbuf[2];
298
299        n &= 0377;
300        if (bitset(0200, n))
301        {
302                char *p = MacroName[n];
303
304                if (p != NULL)
305                        return p;
306                return "***UNDEFINED MACRO***";
307        }
308        mbuf[0] = n;
309        mbuf[1] = '\0';
310        return mbuf;
311}
312/*
313**  MACID -- return id of macro identified by its name
314**
315**      Parameters:
316**              p -- pointer to name string -- either a single
317**                      character or {name}.
318**              ep -- filled in with the pointer to the byte
319**                      after the name.
320**
321**      Returns:
322**              The internal id code for this macro.  This will
323**              fit into a single byte.
324**
325**      Side Effects:
326**              If this is a new macro name, a new id is allocated.
327*/
328
329int
330macid(p, ep)
331        register char *p;
332        char **ep;
333{
334        int mid;
335        register char *bp;
336        char mbuf[MAXMACNAMELEN + 1];
337
338        if (tTd(35, 14))
339        {
340                printf("macid(");
341                xputs(p);
342                printf(") => ");
343        }
344
345        if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
346        {
347                syserr("Name required for macro/class");
348                if (ep != NULL)
349                        *ep = p;
350                if (tTd(35, 14))
351                        printf("NULL\n");
352                return '\0';
353        }
354        if (*p != '{')
355        {
356                /* the macro is its own code */
357                if (ep != NULL)
358                        *ep = p + 1;
359                if (tTd(35, 14))
360                        printf("%c\n", *p);
361                return *p;
362        }
363        bp = mbuf;
364        while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof mbuf - 1])
365        {
366                if (isascii(*p) && (isalnum(*p) || *p == '_'))
367                        *bp++ = *p;
368                else
369                        syserr("Invalid macro/class character %c", *p);
370        }
371        *bp = '\0';
372        mid = -1;
373        if (*p == '\0')
374        {
375                syserr("Unbalanced { on %s", mbuf);     /* missing } */
376        }
377        else if (*p != '}')
378        {
379                syserr("Macro/class name ({%s}) too long (%d chars max)",
380                        mbuf, sizeof mbuf - 1);
381        }
382        else if (mbuf[1] == '\0')
383        {
384                /* ${x} == $x */
385                mid = mbuf[0];
386                p++;
387        }
388        else
389        {
390                register STAB *s;
391
392                s = stab(mbuf, ST_MACRO, ST_ENTER);
393                if (s->s_macro != 0)
394                        mid = s->s_macro;
395                else
396                {
397                        if (NextMacroId > 0377)
398                        {
399                                syserr("Macro/class {%s}: too many long names", mbuf);
400                                s->s_macro = -1;
401                        }
402                        else
403                        {
404                                MacroName[NextMacroId] = s->s_name;
405                                s->s_macro = mid = NextMacroId++;
406                        }
407                }
408                p++;
409        }
410        if (ep != NULL)
411                *ep = p;
412        if (tTd(35, 14))
413                printf("0x%x\n", mid);
414        return mid;
415}
416/*
417**  WORDINCLASS -- tell if a word is in a specific class
418**
419**      Parameters:
420**              str -- the name of the word to look up.
421**              cl -- the class name.
422**
423**      Returns:
424**              TRUE if str can be found in cl.
425**              FALSE otherwise.
426*/
427
428bool
429wordinclass(str, cl)
430        char *str;
431        int cl;
432{
433        register STAB *s;
434
435        s = stab(str, ST_CLASS, ST_FIND);
436        return s != NULL && bitnset(cl & 0xff, s->s_class);
437}
Note: See TracBrowser for help on using the repository browser.