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.25 (Berkeley) 5/19/98"; 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 /* 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 /* 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 /* 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 /* 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[21]; 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]) 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 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 } 438