1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms are permitted 7 * provided that the above copyright notice and this paragraph are 8 * duplicated in all such forms and that any documentation, 9 * advertising materials, and other materials related to such 10 * distribution and use acknowledge that the software was developed 11 * by the University of California, Berkeley. The name of the 12 * University may not be used to endorse or promote products derived 13 * from this software without specific prior written permission. 14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18 19 #ifndef lint 20 static char sccsid[] = "@(#)macro.c 5.5 (Berkeley) 06/30/88"; 21 #endif /* not lint */ 22 23 # include "sendmail.h" 24 25 /* 26 ** EXPAND -- macro expand a string using $x escapes. 27 ** 28 ** Parameters: 29 ** s -- the string to expand. 30 ** buf -- the place to put the expansion. 31 ** buflim -- the buffer limit, i.e., the address 32 ** of the last usable position in buf. 33 ** e -- envelope in which to work. 34 ** 35 ** Returns: 36 ** none. 37 ** 38 ** Side Effects: 39 ** none. 40 */ 41 42 expand(s, buf, buflim, e) 43 register char *s; 44 register char *buf; 45 char *buflim; 46 register ENVELOPE *e; 47 { 48 register char *xp; 49 register char *q; 50 bool skipping; /* set if conditionally skipping output */ 51 bool recurse = FALSE; /* set if recursion required */ 52 int i; 53 char xbuf[BUFSIZ]; 54 extern char *macvalue(); 55 56 # ifdef DEBUG 57 if (tTd(35, 24)) 58 { 59 printf("expand("); 60 xputs(s); 61 printf(")\n"); 62 } 63 # endif DEBUG 64 65 skipping = FALSE; 66 if (s == NULL) 67 s = ""; 68 for (xp = xbuf; *s != '\0'; s++) 69 { 70 char 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) 80 { 81 case CONDIF: /* see if var set */ 82 c = *++s; 83 skipping = macvalue(c, e) == NULL; 84 continue; 85 86 case CONDELSE: /* change state of skipping */ 87 skipping = !skipping; 88 continue; 89 90 case CONDFI: /* stop skipping */ 91 skipping = FALSE; 92 continue; 93 94 case '\001': /* macro interpolation */ 95 c = *++s; 96 q = macvalue(c & 0177, e); 97 if (q == NULL) 98 continue; 99 break; 100 } 101 102 /* 103 ** Interpolate q or output one character 104 */ 105 106 if (skipping || xp >= &xbuf[sizeof xbuf]) 107 continue; 108 if (q == NULL) 109 *xp++ = c; 110 else 111 { 112 /* copy to end of q or max space remaining in buf */ 113 while ((c = *q++) != '\0' && xp < &xbuf[sizeof xbuf - 1]) 114 { 115 if (iscntrl(c) && !isspace(c)) 116 recurse = TRUE; 117 *xp++ = c; 118 } 119 } 120 } 121 *xp = '\0'; 122 123 # ifdef DEBUG 124 if (tTd(35, 24)) 125 { 126 printf("expand ==> "); 127 xputs(xbuf); 128 printf("\n"); 129 } 130 # endif DEBUG 131 132 /* recurse as appropriate */ 133 if (recurse) 134 { 135 expand(xbuf, buf, buflim, e); 136 return; 137 } 138 139 /* copy results out */ 140 i = buflim - buf - 1; 141 if (i > xp - xbuf) 142 i = xp - xbuf; 143 bcopy(xbuf, buf, i); 144 buf[i] = '\0'; 145 } 146 /* 147 ** DEFINE -- define a macro. 148 ** 149 ** this would be better done using a #define macro. 150 ** 151 ** Parameters: 152 ** n -- the macro name. 153 ** v -- the macro value. 154 ** e -- the envelope to store the definition in. 155 ** 156 ** Returns: 157 ** none. 158 ** 159 ** Side Effects: 160 ** e->e_macro[n] is defined. 161 ** 162 ** Notes: 163 ** There is one macro for each ASCII character, 164 ** although they are not all used. The currently 165 ** defined macros are: 166 ** 167 ** $a date in ARPANET format (preferring the Date: line 168 ** of the message) 169 ** $b the current date (as opposed to the date as found 170 ** the message) in ARPANET format 171 ** $c hop count 172 ** $d (current) date in UNIX (ctime) format 173 ** $e the SMTP entry message+ 174 ** $f raw from address 175 ** $g translated from address 176 ** $h to host 177 ** $i queue id 178 ** $j official SMTP hostname, used in messages+ 179 ** $l UNIX-style from line+ 180 ** $n name of sendmail ("MAILER-DAEMON" on local 181 ** net typically)+ 182 ** $o delimiters ("operators") for address tokens+ 183 ** $p my process id in decimal 184 ** $q the string that becomes an address -- this is 185 ** normally used to combine $g & $x. 186 ** $r protocol used to talk to sender 187 ** $s sender's host name 188 ** $t the current time in seconds since 1/1/1970 189 ** $u to user 190 ** $v version number of sendmail 191 ** $w our host name (if it can be determined) 192 ** $x signature (full name) of from person 193 ** $y the tty id of our terminal 194 ** $z home directory of to person 195 ** 196 ** Macros marked with + must be defined in the 197 ** configuration file and are used internally, but 198 ** are not set. 199 ** 200 ** There are also some macros that can be used 201 ** arbitrarily to make the configuration file 202 ** cleaner. In general all upper-case letters 203 ** are available. 204 */ 205 206 define(n, v, e) 207 char n; 208 char *v; 209 register ENVELOPE *e; 210 { 211 # ifdef DEBUG 212 if (tTd(35, 9)) 213 { 214 printf("define(%c as ", n); 215 xputs(v); 216 printf(")\n"); 217 } 218 # endif DEBUG 219 e->e_macro[n & 0177] = v; 220 } 221 /* 222 ** MACVALUE -- return uninterpreted value of a macro. 223 ** 224 ** Parameters: 225 ** n -- the name of the macro. 226 ** 227 ** Returns: 228 ** The value of n. 229 ** 230 ** Side Effects: 231 ** none. 232 */ 233 234 char * 235 macvalue(n, e) 236 char n; 237 register ENVELOPE *e; 238 { 239 n &= 0177; 240 while (e != NULL) 241 { 242 register char *p = e->e_macro[n]; 243 244 if (p != NULL) 245 return (p); 246 e = e->e_parent; 247 } 248 return (NULL); 249 } 250