1 # include <stdio.h>
2 # include <ctype.h>
3 # include <pwd.h>
4 # include "postbox.h"
5 
6 static char SccsId[] = "@(#)alias.c	3.1	03/07/81";
7 
8 /*
9 **  ALIAS -- Compute aliases.
10 **
11 **	Scans the file ALIASFILE for a set of aliases.
12 **	If found, it arranges to deliver to them by inserting the
13 **	new names onto the SendQ queue.  Uses libdbm database if -DDBM.
14 **
15 **	Parameters:
16 **		none
17 **
18 **	Returns:
19 **		none
20 **
21 **	Side Effects:
22 **		Aliases found on SendQ are removed and put onto
23 **		AliasQ; replacements are added to SendQ.  This is
24 **		done until no such replacement occurs.
25 **
26 **	Defined Constants:
27 **		MAXRCRSN -- the maximum recursion depth.
28 **
29 **	Called By:
30 **		main
31 **
32 **	Files:
33 **		ALIASFILE -- the mail aliases.  The format is
34 **			a series of lines of the form:
35 **				alias:name1,name2,name3,...
36 **			where 'alias' expands to all of
37 **			'name[i]'.  Continuations begin with
38 **			space or tab.
39 **		ALIASFILE.pag, ALIASFILE.dir: libdbm version
40 **			of alias file.  Keys are aliases, datums
41 **			(data?) are name1,name2, ...
42 **
43 **	Notes:
44 **		If NoAlias (the "-n" flag) is set, no aliasing is
45 **			done.
46 **
47 **	Deficiencies:
48 **		It should complain about names that are aliased to
49 **			nothing.
50 **		It is unsophisticated about line overflows.
51 */
52 
53 
54 # define MAXRCRSN	10
55 
56 #ifdef DBM
57 typedef struct
58 {
59 	char	*dptr;
60 	int dsize;
61 } datum;
62 datum lhs, rhs;
63 extern datum fetch();
64 #endif DBM
65 
66 alias()
67 {
68 	register ADDRESS *q;
69 	ADDRESS *q2;
70 	FILE *af;
71 	char line[MAXLINE+1];
72 	register char *p;
73 	extern int errno;
74 	bool didalias;
75 	bool gotmatch;
76 	auto ADDRESS al;
77 	extern bool sameaddr();
78 	extern ADDRESS *parse();
79 
80 	if (NoAlias)
81 		return;
82 # ifdef DEBUG
83 	if (Debug)
84 		printf("--- alias ---\n");
85 # endif
86 
87 	/* open alias file if not already open */
88 #ifndef DBM
89 # ifdef DEBUG
90 	if (Debug && (af = fopen("mailaliases", "r")) != NULL)
91 		printf(" [using local alias file]\n");
92 	else
93 # endif
94 	if ((af = fopen(ALIASFILE, "r")) == NULL)
95 	{
96 # ifdef DEBUG
97 		if (Debug)
98 			printf("Can't open %s\n", ALIASFILE);
99 # endif
100 		errno = 0;
101 		return;
102 	}
103 #else DBM
104 	dbminit(ALIASFILE);
105 #endif DBM
106 
107 #ifndef DBM
108 	/*
109 	**  Scan alias file.
110 	**	If we find any user that any line matches any user, we
111 	**	will send to the line rather than to the user.
112 	**
113 	**	We pass through the file several times.  Didalias tells
114 	**	us if we took some alias on this pass through the file;
115 	**	when it goes false at the top of the loop we don't have
116 	**	to scan any more.  Gotmatch tells the same thing, but
117 	**	on a line-by-line basis; it is used for processing
118 	**	continuation lines.
119 	*/
120 
121 	do
122 	{
123 		didalias = FALSE;
124 		gotmatch = FALSE;
125 		rewind(af);
126 		while (fgets(line, sizeof line, af) != NULL)
127 		{
128 			/* comments begin with `#' */
129 			if (line[0] == '#')
130 				continue;
131 
132 			/* check for continuation lines */
133 			if (isspace(line[0]))
134 			{
135 				if (gotmatch)
136 				{
137 					sendto(line, 1);
138 				}
139 				continue;
140 			}
141 			gotmatch = FALSE;
142 
143 			/*
144 			**  Check to see if this pseudonym exists in SendQ.
145 			**	Turn the alias into canonical form.
146 			**	Then scan SendQ until you do (or do not)
147 			**	find that address.
148 			*/
149 
150 			/*  Get a canonical form for the alias. */
151 			for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
152 				continue;
153 			if (*p == '\0' || *p == '\n')
154 			{
155 			 syntaxerr:
156 				syserr("Bad alias line `%s'", line);
157 				continue;
158 			}
159 			*p++ = '\0';
160 			if (parse(line, &al, -1) == NULL)
161 			{
162 				*--p = ':';
163 				goto syntaxerr;
164 			}
165 
166 			/* if already in AliasQ don't realias */
167 			for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
168 			{
169 				if (sameaddr(&al, q, TRUE))
170 					break;
171 			}
172 			if (q != NULL)
173 				continue;
174 
175 			/*  Scan SendQ for that canonical form. */
176 			for (q = &SendQ; (q = nxtinq(q)) != NULL; )
177 			{
178 				if (sameaddr(&al, q, TRUE))
179 					break;
180 			}
181 			if (q != NULL)
182 			{
183 				/*
184 				**  Match on Alias.
185 				**	Deliver to the target list.
186 				**	Remove the alias from the send queue
187 				**	  and put it on the Alias queue.
188 				*/
189 
190 # ifdef DEBUG
191 				if (Debug)
192 					printf("%s (%s, %s) aliased to %s (%s,%s,%s)\n",
193 					    q->q_paddr, q->q_host, q->q_user,
194 					    p, al.q_paddr, al.q_host, al.q_user);
195 # endif
196 				tkoffq(q, &SendQ);
197 				didalias++;
198 				gotmatch++;
199 				sendto(p, 1);
200 				putonq(q, &AliasQ);
201 			}
202 		}
203 	} while (didalias);
204 	fclose(af);
205 #else DBM
206 	/*
207 	**  Scan SendQ
208 	**	We only have to do this once, since anything we alias
209 	**	to is being put at the end of the queue we are
210 	**	scanning.
211 	**	If the alias on SendQ is also (already) on AliasQ, we
212 	**	have an alias such as:
213 	**		eric:eric,i:eric
214 	**	In this case we have already done this alias once, and
215 	**	we don't want to do it again (for obvious reasons!).
216 	*/
217 
218 	for (q2 = nxtinq(&SendQ); q2 != NULL; )
219 	{
220 		/* if already in AliasQ, don't realias */
221 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
222 		{
223 			if (sameaddr(q, q2, TRUE))
224 				break;
225 		}
226 		if (q != NULL)
227 		{
228 			q2 = nxtinq(q2);
229 			continue;
230 		}
231 
232 		/* save ptr to next address */
233 		q = q2;
234 		q2 = nxtinq(q);
235 
236 		/* only alias local users */
237 		if (q->q_mailer != &Mailer[0])
238 			continue;
239 
240 		/* create a key for fetch */
241 		lhs.dptr = q->q_user;
242 		lhs.dsize = strlen(q->q_user) + 1;
243 		rhs = fetch(lhs);
244 
245 		/* find this alias? */
246 		p = rhs.dptr;
247 		if (p == NULL)
248 			continue;
249 
250 		/*
251 		**  Match on Alias.
252 		**	Deliver to the target list.
253 		**	Remove the alias from the send queue
254 		**	  and put it on the Alias queue.
255 		*/
256 
257 # ifdef DEBUG
258 		if (Debug)
259 			printf("%s (%s, %s) aliased to %s\n",
260 			    q->q_paddr, q->q_host, q->q_user, p);
261 # endif
262 		tkoffq(q, &SendQ);
263 		sendto(p, 1);
264 		putonq(q, &AliasQ);
265 
266 		/* if our last entry had an alias, process them */
267 		if (q2 == NULL)
268 			q2 = nxtinq(&SendQ);
269 	}
270 #endif DBM
271 }
272 /*
273 **  FORWARD -- Try to forward mail
274 **
275 **	This is similar but not identical to aliasing.
276 **
277 **	Currently it is undefined, until the protocol for userinfo
278 **	databases is finalized.
279 **
280 **	Parameters:
281 **		user -- the name of the user who's mail we
282 **			would like to forward to.
283 **
284 **	Returns:
285 **		TRUE -- we have forwarded it somewhere.
286 **		FALSE -- not forwarded; go ahead & deliver.
287 **
288 **	Side Effects:
289 **		New names are added to SendQ.
290 **
291 **	Called By:
292 **		recipient
293 */
294 
295 bool
296 forward(user)
297 	ADDRESS *user;
298 {
299 	return (FALSE);
300 }
301