1 # include <stdio.h>
2 # include <ctype.h>
3 # include <pwd.h>
4 # include "sendmail.h"
5 
6 static char SccsId[] = "@(#)alias.c	3.11	08/10/81";
7 
8 /*
9 **  ALIAS -- Compute aliases.
10 **
11 **	Scans the file /usr/lib/aliases for a set of aliases.
12 **	If found, it arranges to deliver to them.  Uses libdbm
13 **	database if -DDBM.
14 **
15 **	Parameters:
16 **		a -- address to alias.
17 **
18 **	Returns:
19 **		none
20 **
21 **	Side Effects:
22 **		Aliases found are expanded.
23 **
24 **	Files:
25 **		/usr/lib/aliases -- the mail aliases.  The format is
26 **			a series of lines of the form:
27 **				alias:name1,name2,name3,...
28 **			where 'alias' expands to all of
29 **			'name[i]'.  Continuations begin with
30 **			space or tab.
31 **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
32 **			of alias file.  Keys are aliases, datums
33 **			(data?) are name1,name2, ...
34 **
35 **	Notes:
36 **		If NoAlias (the "-n" flag) is set, no aliasing is
37 **			done.
38 **
39 **	Deficiencies:
40 **		It should complain about names that are aliased to
41 **			nothing.
42 **		It is unsophisticated about line overflows.
43 */
44 
45 
46 #ifdef DBM
47 typedef struct
48 {
49 	char	*dptr;
50 	int dsize;
51 } datum;
52 datum lhs, rhs;
53 extern datum fetch();
54 #endif DBM
55 
56 alias(a)
57 	register ADDRESS *a;
58 {
59 	register char *p;
60 # ifndef DBM
61 	register STAB *s;
62 # endif DBM
63 
64 	if (NoAlias)
65 		return;
66 # ifdef DEBUG
67 	if (Debug)
68 		printf("alias(%s)\n", a->q_paddr);
69 # endif
70 
71 	/* don't realias already aliased names */
72 	if (bitset(QDONTSEND, a->q_flags))
73 		return;
74 
75 	To = a->q_paddr;
76 
77 # ifdef DBM
78 	/* create a key for fetch */
79 	lhs.dptr = a->q_user;
80 	lhs.dsize = strlen(a->q_user) + 1;
81 	rhs = fetch(lhs);
82 
83 	/* find this alias? */
84 	p = rhs.dptr;
85 	if (p == NULL)
86 		return;
87 # else DBM
88 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
89 	if (s == NULL)
90 		return;
91 	p = s->s_alias;
92 # endif DBM
93 
94 	/*
95 	**  Match on Alias.
96 	**	Deliver to the target list.
97 	*/
98 
99 # ifdef DEBUG
100 	if (Debug)
101 		printf("%s (%s, %s) aliased to %s\n",
102 		    a->q_paddr, a->q_host, a->q_user, p);
103 # endif
104 	if (Verbose)
105 		message("050", "aliased to %s", p);
106 	a->q_flags |= QDONTSEND;
107 	AliasLevel++;
108 	sendto(p, 1);
109 	AliasLevel--;
110 }
111 /*
112 **  INITALIASES -- initialize for aliasing
113 **
114 **	Very different depending on whether we are running DBM or not.
115 **
116 **	Parameters:
117 **		aliasfile -- location of aliases.
118 **
119 **	Returns:
120 **		none.
121 **
122 **	Side Effects:
123 **		initializes aliases:
124 **		if DBM:  opens the database.
125 **		if ~DBM: reads the aliases into the symbol table.
126 */
127 
128 initaliases(aliasfile)
129 	char *aliasfile;
130 {
131 # ifdef DBM
132 	dbminit(aliasfile);
133 # else DBM
134 	char line[BUFSIZ];
135 	register char *p;
136 	char *p2;
137 	char *rhs;
138 	bool skipping;
139 	ADDRESS al, bl;
140 	extern char *prescan();
141 	bool contin;
142 
143 	if ((af = fopen(aliasfile, "r")) == NULL)
144 	{
145 # ifdef DEBUG
146 		if (Debug)
147 			printf("Can't open %s\n", AliasFile);
148 # endif
149 		errno = 0;
150 		NoAlias++;
151 		return;
152 	}
153 	/* read and interpret lines */
154 	lineno = 0;
155 	skipping = FALSE;
156 	while (fgets(line, sizeof (line), af) != NULL)
157 	{
158 		lineno++;
159 		switch (line[0])
160 		{
161 		  case '#':
162 		  case '\n':
163 		  case '\0':
164 			skipping = FALSE;
165 			continue;
166 
167 		  case ' ':
168 		  case '\t':
169 			if (!skipping)
170 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
171 			skipping = TRUE;
172 			continue;
173 		}
174 		skipping = FALSE;
175 
176 		/* process the LHS */
177 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
178 			continue;
179 		if (*p == '\0' || *p == '\n')
180 		{
181 		 syntaxerr:
182 			syserr("aliases: %d: missing colon", lineno);
183 			continue;
184 		}
185 		*p++ = '\0';
186 		if (parse(line, &al, 1) == NULL)
187 		{
188 			*--p = ':';
189 			goto syntaxerr;
190 		}
191 		rhs = p;
192 		contin = FALSE;
193 		for (;;)
194 		{
195 			register char c;
196 
197 			/* do parsing & compression of addresses */
198 			c = *p;
199 			while (c != '\0')
200 			{
201 				p2 = p;
202 				while (*p != '\n' && *p != ',' && *p != '\0')
203 					p++;
204 				c = *p;
205 				*p++ = '\0';
206 				if (*p2 == '\0')
207 				{
208 					p[-1] = c;
209 					continue;
210 				}
211 				parse(p2, &bl, -1);
212 				contin = (c == ',');
213 				p[-1] = c;
214 				while (isspace(*p))
215 					p++;
216 			}
217 
218 			/* see if there should be a continuation line */
219 			if (!contin)
220 				break;
221 
222 			/* read continuation line */
223 			p--;
224 			if (fgets(p, sizeof line - (p - line), af) == NULL)
225 				break;
226 			lineno++;
227 
228 			if (!isspace(*p))
229 				syserr("aliases: %d: continuation line missing", lineno);
230 		}
231 		if (al.q_mailer != M_LOCAL)
232 		{
233 			syserr("aliases: %d: cannot alias non-local names", lineno);
234 			continue;
235 		}
236 		s = stab(al.q_user, ST_ALIAS, rhs);
237 	}
238 	(void) fclose(af);
239 # endif DBM
240 }
241 /*
242 **  FORWARD -- Try to forward mail
243 **
244 **	This is similar but not identical to aliasing.
245 **
246 **	Parameters:
247 **		user -- the name of the user who's mail we
248 **			would like to forward to.
249 **
250 **	Returns:
251 **		none.
252 **
253 **	Side Effects:
254 **		New names are added to send queues.
255 **		Sets the QDONTSEND bit in addresses that are forwarded.
256 */
257 
258 forward(user)
259 	ADDRESS *user;
260 {
261 	char buf[60];
262 	register FILE *fp;
263 	register char *p;
264 
265 # ifdef DEBUG
266 	if (Debug)
267 		printf("forward(%s)\n", user->q_paddr);
268 # endif DEBUG
269 
270 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
271 		return;
272 
273 	/* good address -- look for .forward file in home */
274 	define('z', user->q_home);
275 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
276 	fp = fopen(buf, "r");
277 	if (fp == NULL)
278 		return;
279 
280 	/* we do have an address to forward to -- do it */
281 	user->q_flags |= QDONTSEND;
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;
288 	if (Verbose)
289 		message("050", "forwarded to %s", buf);
290 	AliasLevel++;
291 	sendto(buf, 1);
292 	AliasLevel--;
293 	return;
294 }
295