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