1292Seric # include <stdio.h>
2292Seric # include <ctype.h>
3292Seric # include <pwd.h>
43309Seric # include "sendmail.h"
5292Seric 
6*4078Seric static char SccsId[] = "@(#)alias.c	3.7	08/09/81";
7402Seric 
8292Seric /*
9292Seric **  ALIAS -- Compute aliases.
10292Seric **
111503Smark **	Scans the file ALIASFILE for a set of aliases.
123185Seric **	If found, it arranges to deliver to them.  Uses libdbm
133185Seric **	database if -DDBM.
14292Seric **
15292Seric **	Parameters:
16292Seric **		none
17292Seric **
18292Seric **	Returns:
19292Seric **		none
20292Seric **
21292Seric **	Side Effects:
223185Seric **		Aliases found are expanded.
23292Seric **
24292Seric **	Defined Constants:
25292Seric **		MAXRCRSN -- the maximum recursion depth.
26292Seric **
27292Seric **	Files:
28569Seric **		ALIASFILE -- the mail aliases.  The format is
29569Seric **			a series of lines of the form:
30569Seric **				alias:name1,name2,name3,...
31569Seric **			where 'alias' expands to all of
32569Seric **			'name[i]'.  Continuations begin with
33569Seric **			space or tab.
341503Smark **		ALIASFILE.pag, ALIASFILE.dir: libdbm version
351503Smark **			of alias file.  Keys are aliases, datums
361503Smark **			(data?) are name1,name2, ...
37292Seric **
38292Seric **	Notes:
39292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
40292Seric **			done.
41292Seric **
42292Seric **	Deficiencies:
43292Seric **		It should complain about names that are aliased to
44292Seric **			nothing.
45292Seric **		It is unsophisticated about line overflows.
46292Seric */
47292Seric 
48292Seric 
49292Seric # define MAXRCRSN	10
50292Seric 
511503Smark #ifdef DBM
522966Seric typedef struct
532966Seric {
542966Seric 	char	*dptr;
552966Seric 	int dsize;
562966Seric } datum;
571503Smark datum lhs, rhs;
581515Seric extern datum fetch();
591503Smark #endif DBM
60292Seric 
61292Seric alias()
62292Seric {
632966Seric 	register ADDRESS *q;
642966Seric 	ADDRESS *q2;
65292Seric 	FILE *af;
66292Seric 	char line[MAXLINE+1];
67292Seric 	register char *p;
68292Seric 	extern int errno;
69292Seric 	bool didalias;
70292Seric 	bool gotmatch;
712966Seric 	auto ADDRESS al;
72292Seric 	extern bool sameaddr();
732966Seric 	extern ADDRESS *parse();
743185Seric 	int mno;
75292Seric 
76292Seric 	if (NoAlias)
77292Seric 		return;
78292Seric # ifdef DEBUG
79292Seric 	if (Debug)
80292Seric 		printf("--- alias ---\n");
81292Seric # endif
82292Seric 
83292Seric 	/* open alias file if not already open */
841503Smark #ifndef DBM
85292Seric # ifdef DEBUG
86292Seric 	if (Debug && (af = fopen("mailaliases", "r")) != NULL)
87292Seric 		printf(" [using local alias file]\n");
88292Seric 	else
89292Seric # endif
90292Seric 	if ((af = fopen(ALIASFILE, "r")) == NULL)
91292Seric 	{
92292Seric # ifdef DEBUG
93292Seric 		if (Debug)
94292Seric 			printf("Can't open %s\n", ALIASFILE);
95292Seric # endif
96292Seric 		errno = 0;
97292Seric 		return;
98292Seric 	}
991503Smark #else DBM
1001503Smark 	dbminit(ALIASFILE);
1011503Smark #endif DBM
102292Seric 
1031503Smark #ifndef DBM
104292Seric 	/*
105292Seric 	**  Scan alias file.
106292Seric 	**	If we find any user that any line matches any user, we
107292Seric 	**	will send to the line rather than to the user.
108292Seric 	**
109292Seric 	**	We pass through the file several times.  Didalias tells
110292Seric 	**	us if we took some alias on this pass through the file;
111292Seric 	**	when it goes false at the top of the loop we don't have
112292Seric 	**	to scan any more.  Gotmatch tells the same thing, but
113292Seric 	**	on a line-by-line basis; it is used for processing
114292Seric 	**	continuation lines.
115292Seric 	*/
116292Seric 
1171503Smark 	do
118292Seric 	{
119292Seric 		didalias = FALSE;
120292Seric 		gotmatch = FALSE;
121292Seric 		rewind(af);
122292Seric 		while (fgets(line, sizeof line, af) != NULL)
123292Seric 		{
124292Seric 			/* comments begin with `#' */
125292Seric 			if (line[0] == '#')
126292Seric 				continue;
127292Seric 
128292Seric 			/* check for continuation lines */
129292Seric 			if (isspace(line[0]))
130292Seric 			{
131292Seric 				if (gotmatch)
132292Seric 				{
133292Seric 					sendto(line, 1);
134292Seric 				}
135292Seric 				continue;
136292Seric 			}
137292Seric 			gotmatch = FALSE;
138292Seric 
139292Seric 			/*
1403185Seric 			**  Check to see if this pseudonym exists.
141292Seric 			**	Turn the alias into canonical form.
1423185Seric 			**	Then scan the send queue until you
1433185Seric 			**	do (or do not) find that address.
144292Seric 			*/
145292Seric 
146292Seric 			/*  Get a canonical form for the alias. */
147292Seric 			for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
148292Seric 				continue;
149292Seric 			if (*p == '\0' || *p == '\n')
150292Seric 			{
151292Seric 			 syntaxerr:
152292Seric 				syserr("Bad alias line `%s'", line);
153292Seric 				continue;
154292Seric 			}
155292Seric 			*p++ = '\0';
156292Seric 			if (parse(line, &al, -1) == NULL)
157292Seric 			{
158292Seric 				*--p = ':';
159292Seric 				goto syntaxerr;
160292Seric 			}
161292Seric 
1623185Seric 			/* if already queued up, don't realias */
1633185Seric 			for (q = Mailer[al.q_mailer]->m_sendq; q != NULL; q = q->q_next)
1641874Seric 			{
1651874Seric 				if (sameaddr(&al, q, TRUE))
1661874Seric 					break;
1671874Seric 			}
1683185Seric 			if (q == NULL || bitset(QDONTSEND, q->q_flags))
1691874Seric 				continue;
1701874Seric 
1713185Seric 			/*
1723185Seric 			**  Match on Alias.
1733185Seric 			**	Deliver to the target list.
1743185Seric 			**	Remove the alias from the send queue
1753185Seric 			**	  and put it on the Alias queue.
1763185Seric 			*/
177292Seric 
178292Seric # ifdef DEBUG
1793185Seric 			if (Debug)
1803185Seric 				printf("%s (%s, %s) aliased to %s (%s,%s,%s)\n",
1813185Seric 				    q->q_paddr, q->q_host, q->q_user,
1823185Seric 				    p, al.q_paddr, al.q_host, al.q_user);
183292Seric # endif
1844065Seric 			if (Verbose)
1854065Seric 				message("050", "aliased to %s", p);
1863185Seric 			q->q_flags |= QDONTSEND;
1873185Seric 			didalias++;
1883185Seric 			gotmatch++;
1893185Seric 			sendto(p, 1);
190292Seric 		}
1911503Smark 	} while (didalias);
192292Seric 	fclose(af);
1931515Seric #else DBM
1941515Seric 	/*
1953185Seric 	**  Scan send queues
1961515Seric 	**	We only have to do this once, since anything we alias
1971874Seric 	**	to is being put at the end of the queue we are
1981515Seric 	**	scanning.
1991515Seric 	*/
2001515Seric 
2013185Seric 	for (mno = 0; Mailer[mno] != NULL; mno++)
2021515Seric 	{
2033185Seric 		for (q = Mailer[mno]->m_sendq; q != NULL; q = q->q_next)
2041874Seric 		{
2054065Seric 			To = q->q_paddr;
2064065Seric 
2073185Seric 			/* don't realias already aliased names */
2083185Seric 			if (bitset(QDONTSEND, q->q_flags))
2093185Seric 				continue;
2101874Seric 
2113185Seric 			/* only alias local users */
212*4078Seric 			if (q->q_mailer != M_LOCAL)
2133185Seric 				continue;
2141622Seric 
2153185Seric 			/* create a key for fetch */
2163185Seric 			lhs.dptr = q->q_user;
2173185Seric 			lhs.dsize = strlen(q->q_user) + 1;
2183185Seric 			rhs = fetch(lhs);
2191515Seric 
2203185Seric 			/* find this alias? */
2213185Seric 			p = rhs.dptr;
2223185Seric 			if (p == NULL)
2233185Seric 				continue;
2241515Seric 
2253185Seric 			/*
2263185Seric 			**  Match on Alias.
2273185Seric 			**	Deliver to the target list.
2283185Seric 			**	Remove the alias from the send queue
2293185Seric 			**	  and put it on the Alias queue.
2303185Seric 			*/
2311515Seric 
2321515Seric # ifdef DEBUG
2333185Seric 			if (Debug)
2343185Seric 				printf("%s (%s, %s) aliased to %s\n",
2353185Seric 				    q->q_paddr, q->q_host, q->q_user, p);
2361515Seric # endif
2374065Seric 			if (Verbose)
2384065Seric 				message("050", "aliased to %s", p);
2393185Seric 			q->q_flags |= QDONTSEND;
2403185Seric 			sendto(p, 1);
2413185Seric 		}
2421515Seric 	}
2431515Seric #endif DBM
244292Seric }
245292Seric /*
246292Seric **  FORWARD -- Try to forward mail
247292Seric **
248292Seric **	This is similar but not identical to aliasing.
249292Seric **
250292Seric **	Currently it is undefined, until the protocol for userinfo
251292Seric **	databases is finalized.
252292Seric **
253292Seric **	Parameters:
254292Seric **		user -- the name of the user who's mail we
255292Seric **			would like to forward to.
256292Seric **
257292Seric **	Returns:
258292Seric **		TRUE -- we have forwarded it somewhere.
259292Seric **		FALSE -- not forwarded; go ahead & deliver.
260292Seric **
261292Seric **	Side Effects:
2623185Seric **		New names are added to send queues.
263292Seric */
264292Seric 
265292Seric bool
266292Seric forward(user)
2672966Seric 	ADDRESS *user;
268292Seric {
269*4078Seric 	char buf[60];
2704069Seric 	register FILE *fp;
2714069Seric 	register char *p;
2724069Seric 	extern char *index();
2734069Seric 
274*4078Seric 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
2754069Seric 		return (FALSE);
2764069Seric 
2774069Seric 	/* good address -- look for .forward file in home */
278*4078Seric 	expand("$z/.forward", buf, &buf[sizeof buf - 1]);
2794069Seric 	fp = fopen(buf, "r");
2804069Seric 	if (fp == NULL)
2814069Seric 		return (FALSE);
2824069Seric 
2834069Seric 	/* we do have an address to forward to -- do it */
2844069Seric 	fgets(buf, sizeof buf, fp);
2854069Seric 	if ((p = index(buf, '\n')) != NULL)
2864069Seric 		*p = '\0';
2874069Seric 	fclose(fp);
2884069Seric 	if (buf[0] == '\0')
2894069Seric 		return (FALSE);
2904069Seric 	if (Verbose)
2914069Seric 		message("050", "forwarded to %s", buf);
2924069Seric 	sendto(buf, 1);
2934069Seric 	return (TRUE);
294292Seric }
295