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