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