]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/macro.c
This commit was generated by cvs2svn to compensate for changes in r51728,
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / macro.c
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
14 static char sccsid[] = "@(#)macro.c     8.26 (Berkeley) 11/8/1998";
15 #endif /* not lint */
16
17 # include "sendmail.h"
18
19 char    *MacroName[256];        /* macro id to name table */
20 int     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
39 void
40 expand(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 \f/*
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
236 void
237 define(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 \f/*
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
264 char *
265 macvalue(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 \f/*
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
293 char *
294 macname(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 \f/*
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
329 int
330 macid(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 \f/*
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
428 bool
429 wordinclass(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 }