1 # include "sendmail.h"
2 
3 SCCSID(@(#)macro.c	3.17		09/12/82);
4 
5 /*
6 **  EXPAND -- macro expand a string using $x escapes.
7 **
8 **	Parameters:
9 **		s -- the string to expand.
10 **		buf -- the place to put the expansion.
11 **		buflim -- the buffer limit, i.e., the address
12 **			of the last usable position in buf.
13 **		e -- envelope in which to work.
14 **
15 **	Returns:
16 **		End of interpolated output.
17 **
18 **	Side Effects:
19 **		none.
20 */
21 
22 expand(s, buf, buflim, e)
23 	register char *s;
24 	register char *buf;
25 	char *buflim;
26 	register ENVELOPE *e;
27 {
28 	extern char *expand2();
29 
30 	(void) expand2(s, buf, buflim, e);
31 }
32 
33 
34 char *
35 expand2(s, buf, buflim, e)
36 	register char *s;
37 	register char *buf;
38 	char *buflim;
39 	register ENVELOPE *e;
40 {
41 	register char *q;
42 	char xbuf[BUFSIZ];
43 	register char *xp = xbuf;
44 	bool skipping;		/* set if conditionally skipping output */
45 	bool gotone = FALSE;	/* set if any expansion done */
46 	extern char *macvalue();
47 
48 # ifdef DEBUG
49 	if (tTd(35, 4))
50 	{
51 		printf("expand(");
52 		xputs(s);
53 		printf(")\n");
54 	}
55 # endif DEBUG
56 
57 	skipping = FALSE;
58 	if (s == NULL)
59 		s = "";
60 	for (; *s != '\0'; s++)
61 	{
62 		char c;
63 
64 		/*
65 		**  Check for non-ordinary (special?) character.
66 		**	'q' will be the interpolated quantity.
67 		*/
68 
69 		q = NULL;
70 		c = *s;
71 		switch (c)
72 		{
73 		  case CONDIF:		/* see if var set */
74 			c = *++s;
75 			skipping = macvalue(c, e) == NULL;
76 			continue;
77 
78 		  case CONDELSE:	/* change state of skipping */
79 			skipping = !skipping;
80 			continue;
81 
82 		  case CONDFI:		/* stop skipping */
83 			skipping = FALSE;
84 			continue;
85 
86 		  case '$':		/* macro interpolation */
87 			c = *++s;
88 			q = macvalue(c & 0177, e);
89 			if (q == NULL && c != '$')
90 				continue;
91 			gotone = TRUE;
92 			break;
93 		}
94 
95 		/*
96 		**  Interpolate q or output one character
97 		*/
98 
99 		if (skipping)
100 			continue;
101 		while (xp < &xbuf[sizeof xbuf])
102 		{
103 			if (q == NULL)
104 			{
105 				*xp++ = c;
106 				break;
107 			}
108 			if (*q == NULL)
109 				break;
110 			*xp++ = *q++;
111 		}
112 	}
113 	*xp = '\0';
114 
115 # ifdef DEBUG
116 	if (tTd(35, 4))
117 	{
118 		printf("expand ==> ");
119 		xputs(xbuf);
120 		printf("\n");
121 	}
122 # endif DEBUG
123 
124 	/* recurse as appropriate */
125 	if (gotone)
126 		return (expand2(xbuf, buf, buflim, e));
127 
128 	/* copy results out */
129 	for (q = buf, xp = xbuf; xp != '\0' && q < buflim-1; )
130 		*q++ = *xp++;
131 	*q = '\0';
132 
133 	return (q);
134 }
135 /*
136 **  DEFINE -- define a macro.
137 **
138 **	this would be better done using a #define macro.
139 **
140 **	Parameters:
141 **		n -- the macro name.
142 **		v -- the macro value.
143 **
144 **	Returns:
145 **		none.
146 **
147 **	Side Effects:
148 **		CurEnv->e_macro[n] is defined.
149 **
150 **	Notes:
151 **		There is one macro for each ASCII character,
152 **		although they are not all used.  The currently
153 **		defined macros are:
154 **
155 **		$a   date in ARPANET format (preferring the Date: line
156 **		     of the message)
157 **		$b   the current date (as opposed to the date as found
158 **		     the message) in ARPANET format
159 **		$c   hop count
160 **		$d   (current) date in UNIX (ctime) format
161 **		$f   raw from address
162 **		$g   translated from address
163 **		$h   to host
164 **		$i   queue id
165 **		$j   official SMTP hostname, used in messages+
166 **		$l   UNIX-style from line+
167 **		$n   name of sendmail ("MAILER-DAEMON" on local
168 **		     net typically)+
169 **		$o   delimiters ("operators") for address tokens+
170 **		$p   my process id in decimal
171 **		$q   the string that becomes an address -- this is
172 **		     normally used to combine $g & $x.
173 **		$r   protocol used to talk to sender
174 **		$s   sender's host name
175 **		$t   the current time in seconds since 1/1/1970
176 **		$u   to user
177 **		$v   version number of sendmail
178 **		$x   signature (full name) of from person
179 **		$y   the tty id of our terminal
180 **		$z   home directory of to person
181 **
182 **		Macros marked with + must be defined in the
183 **		configuration file and are used internally, but
184 **		are not set.
185 **
186 **		There are also some macros that can be used
187 **		arbitrarily to make the configuration file
188 **		cleaner.  In general all upper-case letters
189 **		are available.
190 */
191 
192 define(n, v)
193 	char n;
194 	char *v;
195 {
196 # ifdef DEBUG
197 	if (tTd(35, 3))
198 	{
199 		printf("define(%c as ", n);
200 		xputs(v);
201 		printf(")\n");
202 	}
203 # endif DEBUG
204 	CurEnv->e_macro[n & 0177] = v;
205 }
206 /*
207 **  MACVALUE -- return uninterpreted value of a macro.
208 **
209 **	Parameters:
210 **		n -- the name of the macro.
211 **
212 **	Returns:
213 **		The value of n.
214 **
215 **	Side Effects:
216 **		none.
217 */
218 
219 char *
220 macvalue(n, e)
221 	char n;
222 	register ENVELOPE *e;
223 {
224 	n &= 0177;
225 	while (e != NULL)
226 	{
227 		register char *p = e->e_macro[n];
228 
229 		if (p != NULL)
230 			return (p);
231 		e = e->e_parent;
232 	}
233 	return (NULL);
234 }
235