1292Seric # include <stdio.h>
2292Seric # include <ctype.h>
3292Seric # include <pwd.h>
4*2966Seric # include "postbox.h"
5292Seric 
6*2966Seric static char SccsId[] = "@(#)alias.c	3.1	03/07/81";
7402Seric 
8292Seric /*
9292Seric **  ALIAS -- Compute aliases.
10292Seric **
111503Smark **	Scans the file ALIASFILE for a set of aliases.
12292Seric **	If found, it arranges to deliver to them by inserting the
131503Smark **	new names onto the SendQ queue.  Uses libdbm database if -DDBM.
14292Seric **
15292Seric **	Parameters:
16292Seric **		none
17292Seric **
18292Seric **	Returns:
19292Seric **		none
20292Seric **
21292Seric **	Side Effects:
22292Seric **		Aliases found on SendQ are removed and put onto
23292Seric **		AliasQ; replacements are added to SendQ.  This is
24292Seric **		done until no such replacement occurs.
25292Seric **
26292Seric **	Defined Constants:
27292Seric **		MAXRCRSN -- the maximum recursion depth.
28292Seric **
29292Seric **	Called By:
30292Seric **		main
31292Seric **
32292Seric **	Files:
33569Seric **		ALIASFILE -- the mail aliases.  The format is
34569Seric **			a series of lines of the form:
35569Seric **				alias:name1,name2,name3,...
36569Seric **			where 'alias' expands to all of
37569Seric **			'name[i]'.  Continuations begin with
38569Seric **			space or tab.
391503Smark **		ALIASFILE.pag, ALIASFILE.dir: libdbm version
401503Smark **			of alias file.  Keys are aliases, datums
411503Smark **			(data?) are name1,name2, ...
42292Seric **
43292Seric **	Notes:
44292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
45292Seric **			done.
46292Seric **
47292Seric **	Deficiencies:
48292Seric **		It should complain about names that are aliased to
49292Seric **			nothing.
50292Seric **		It is unsophisticated about line overflows.
51292Seric */
52292Seric 
53292Seric 
54292Seric # define MAXRCRSN	10
55292Seric 
561503Smark #ifdef DBM
57*2966Seric typedef struct
58*2966Seric {
59*2966Seric 	char	*dptr;
60*2966Seric 	int dsize;
61*2966Seric } datum;
621503Smark datum lhs, rhs;
631515Seric extern datum fetch();
641503Smark #endif DBM
65292Seric 
66292Seric alias()
67292Seric {
68*2966Seric 	register ADDRESS *q;
69*2966Seric 	ADDRESS *q2;
70292Seric 	FILE *af;
71292Seric 	char line[MAXLINE+1];
72292Seric 	register char *p;
73292Seric 	extern int errno;
74292Seric 	bool didalias;
75292Seric 	bool gotmatch;
76*2966Seric 	auto ADDRESS al;
77292Seric 	extern bool sameaddr();
78*2966Seric 	extern ADDRESS *parse();
79292Seric 
80292Seric 	if (NoAlias)
81292Seric 		return;
82292Seric # ifdef DEBUG
83292Seric 	if (Debug)
84292Seric 		printf("--- alias ---\n");
85292Seric # endif
86292Seric 
87292Seric 	/* open alias file if not already open */
881503Smark #ifndef DBM
89292Seric # ifdef DEBUG
90292Seric 	if (Debug && (af = fopen("mailaliases", "r")) != NULL)
91292Seric 		printf(" [using local alias file]\n");
92292Seric 	else
93292Seric # endif
94292Seric 	if ((af = fopen(ALIASFILE, "r")) == NULL)
95292Seric 	{
96292Seric # ifdef DEBUG
97292Seric 		if (Debug)
98292Seric 			printf("Can't open %s\n", ALIASFILE);
99292Seric # endif
100292Seric 		errno = 0;
101292Seric 		return;
102292Seric 	}
1031503Smark #else DBM
1041503Smark 	dbminit(ALIASFILE);
1051503Smark #endif DBM
106292Seric 
1071503Smark #ifndef DBM
108292Seric 	/*
109292Seric 	**  Scan alias file.
110292Seric 	**	If we find any user that any line matches any user, we
111292Seric 	**	will send to the line rather than to the user.
112292Seric 	**
113292Seric 	**	We pass through the file several times.  Didalias tells
114292Seric 	**	us if we took some alias on this pass through the file;
115292Seric 	**	when it goes false at the top of the loop we don't have
116292Seric 	**	to scan any more.  Gotmatch tells the same thing, but
117292Seric 	**	on a line-by-line basis; it is used for processing
118292Seric 	**	continuation lines.
119292Seric 	*/
120292Seric 
1211503Smark 	do
122292Seric 	{
123292Seric 		didalias = FALSE;
124292Seric 		gotmatch = FALSE;
125292Seric 		rewind(af);
126292Seric 		while (fgets(line, sizeof line, af) != NULL)
127292Seric 		{
128292Seric 			/* comments begin with `#' */
129292Seric 			if (line[0] == '#')
130292Seric 				continue;
131292Seric 
132292Seric 			/* check for continuation lines */
133292Seric 			if (isspace(line[0]))
134292Seric 			{
135292Seric 				if (gotmatch)
136292Seric 				{
137292Seric 					sendto(line, 1);
138292Seric 				}
139292Seric 				continue;
140292Seric 			}
141292Seric 			gotmatch = FALSE;
142292Seric 
143292Seric 			/*
144292Seric 			**  Check to see if this pseudonym exists in SendQ.
145292Seric 			**	Turn the alias into canonical form.
146292Seric 			**	Then scan SendQ until you do (or do not)
147292Seric 			**	find that address.
148292Seric 			*/
149292Seric 
150292Seric 			/*  Get a canonical form for the alias. */
151292Seric 			for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
152292Seric 				continue;
153292Seric 			if (*p == '\0' || *p == '\n')
154292Seric 			{
155292Seric 			 syntaxerr:
156292Seric 				syserr("Bad alias line `%s'", line);
157292Seric 				continue;
158292Seric 			}
159292Seric 			*p++ = '\0';
160292Seric 			if (parse(line, &al, -1) == NULL)
161292Seric 			{
162292Seric 				*--p = ':';
163292Seric 				goto syntaxerr;
164292Seric 			}
165292Seric 
1661874Seric 			/* if already in AliasQ don't realias */
1671874Seric 			for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
1681874Seric 			{
1691874Seric 				if (sameaddr(&al, q, TRUE))
1701874Seric 					break;
1711874Seric 			}
1721874Seric 			if (q != NULL)
1731874Seric 				continue;
1741874Seric 
175292Seric 			/*  Scan SendQ for that canonical form. */
176292Seric 			for (q = &SendQ; (q = nxtinq(q)) != NULL; )
177292Seric 			{
178292Seric 				if (sameaddr(&al, q, TRUE))
179292Seric 					break;
180292Seric 			}
181292Seric 			if (q != NULL)
182292Seric 			{
183292Seric 				/*
184292Seric 				**  Match on Alias.
185292Seric 				**	Deliver to the target list.
186292Seric 				**	Remove the alias from the send queue
187292Seric 				**	  and put it on the Alias queue.
188292Seric 				*/
189292Seric 
190292Seric # ifdef DEBUG
191292Seric 				if (Debug)
192292Seric 					printf("%s (%s, %s) aliased to %s (%s,%s,%s)\n",
193292Seric 					    q->q_paddr, q->q_host, q->q_user,
194292Seric 					    p, al.q_paddr, al.q_host, al.q_user);
195292Seric # endif
196292Seric 				tkoffq(q, &SendQ);
197292Seric 				didalias++;
198292Seric 				gotmatch++;
199292Seric 				sendto(p, 1);
2001874Seric 				putonq(q, &AliasQ);
201292Seric 			}
202292Seric 		}
2031503Smark 	} while (didalias);
204292Seric 	fclose(af);
2051515Seric #else DBM
2061515Seric 	/*
2071515Seric 	**  Scan SendQ
2081515Seric 	**	We only have to do this once, since anything we alias
2091874Seric 	**	to is being put at the end of the queue we are
2101515Seric 	**	scanning.
2111874Seric 	**	If the alias on SendQ is also (already) on AliasQ, we
2121874Seric 	**	have an alias such as:
2131874Seric 	**		eric:eric,i:eric
2141874Seric 	**	In this case we have already done this alias once, and
2151874Seric 	**	we don't want to do it again (for obvious reasons!).
2161515Seric 	*/
2171515Seric 
2181874Seric 	for (q2 = nxtinq(&SendQ); q2 != NULL; )
2191515Seric 	{
2201874Seric 		/* if already in AliasQ, don't realias */
2211874Seric 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
2221874Seric 		{
2231874Seric 			if (sameaddr(q, q2, TRUE))
2241874Seric 				break;
2251874Seric 		}
2261874Seric 		if (q != NULL)
2271874Seric 		{
2281874Seric 			q2 = nxtinq(q2);
2291874Seric 			continue;
2301874Seric 		}
2311874Seric 
2321622Seric 		/* save ptr to next address */
2331874Seric 		q = q2;
2341622Seric 		q2 = nxtinq(q);
2351622Seric 
2361515Seric 		/* only alias local users */
2371515Seric 		if (q->q_mailer != &Mailer[0])
2381515Seric 			continue;
2391515Seric 
2401515Seric 		/* create a key for fetch */
2411515Seric 		lhs.dptr = q->q_user;
2421515Seric 		lhs.dsize = strlen(q->q_user) + 1;
2431515Seric 		rhs = fetch(lhs);
2441515Seric 
2451515Seric 		/* find this alias? */
2461515Seric 		p = rhs.dptr;
2471515Seric 		if (p == NULL)
2481515Seric 			continue;
2491515Seric 
2501515Seric 		/*
2511515Seric 		**  Match on Alias.
2521515Seric 		**	Deliver to the target list.
2531515Seric 		**	Remove the alias from the send queue
2541515Seric 		**	  and put it on the Alias queue.
2551515Seric 		*/
2561515Seric 
2571515Seric # ifdef DEBUG
2581515Seric 		if (Debug)
2591515Seric 			printf("%s (%s, %s) aliased to %s\n",
2601515Seric 			    q->q_paddr, q->q_host, q->q_user, p);
2611515Seric # endif
2621515Seric 		tkoffq(q, &SendQ);
2631874Seric 		sendto(p, 1);
2641515Seric 		putonq(q, &AliasQ);
2651633Seric 
2661633Seric 		/* if our last entry had an alias, process them */
2671633Seric 		if (q2 == NULL)
2681633Seric 			q2 = nxtinq(&SendQ);
2691515Seric 	}
2701515Seric #endif DBM
271292Seric }
272292Seric /*
273292Seric **  FORWARD -- Try to forward mail
274292Seric **
275292Seric **	This is similar but not identical to aliasing.
276292Seric **
277292Seric **	Currently it is undefined, until the protocol for userinfo
278292Seric **	databases is finalized.
279292Seric **
280292Seric **	Parameters:
281292Seric **		user -- the name of the user who's mail we
282292Seric **			would like to forward to.
283292Seric **
284292Seric **	Returns:
285292Seric **		TRUE -- we have forwarded it somewhere.
286292Seric **		FALSE -- not forwarded; go ahead & deliver.
287292Seric **
288292Seric **	Side Effects:
289292Seric **		New names are added to SendQ.
290292Seric **
291292Seric **	Called By:
292292Seric **		recipient
293292Seric */
294292Seric 
295292Seric bool
296292Seric forward(user)
297*2966Seric 	ADDRESS *user;
298292Seric {
299292Seric 	return (FALSE);
300292Seric }
301