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