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