1292Seric # include <stdio.h>
2292Seric # include <ctype.h>
3292Seric # include <pwd.h>
43309Seric # include "sendmail.h"
5292Seric 
6*4098Seric static char SccsId[] = "@(#)alias.c	3.10	08/10/81";
7402Seric 
8292Seric /*
9292Seric **  ALIAS -- Compute aliases.
10292Seric **
11*4098Seric **	Scans the file /usr/lib/aliases for a set of aliases.
123185Seric **	If found, it arranges to deliver to them.  Uses libdbm
133185Seric **	database if -DDBM.
14292Seric **
15292Seric **	Parameters:
164097Seric **		a -- address to alias.
17292Seric **
18292Seric **	Returns:
19292Seric **		none
20292Seric **
21292Seric **	Side Effects:
223185Seric **		Aliases found are expanded.
23292Seric **
24292Seric **	Files:
25*4098Seric **		/usr/lib/aliases -- the mail aliases.  The format is
26569Seric **			a series of lines of the form:
27569Seric **				alias:name1,name2,name3,...
28569Seric **			where 'alias' expands to all of
29569Seric **			'name[i]'.  Continuations begin with
30569Seric **			space or tab.
31*4098Seric **		/usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
321503Smark **			of alias file.  Keys are aliases, datums
331503Smark **			(data?) are name1,name2, ...
34292Seric **
35292Seric **	Notes:
36292Seric **		If NoAlias (the "-n" flag) is set, no aliasing is
37292Seric **			done.
38292Seric **
39292Seric **	Deficiencies:
40292Seric **		It should complain about names that are aliased to
41292Seric **			nothing.
42292Seric **		It is unsophisticated about line overflows.
43292Seric */
44292Seric 
45292Seric 
461503Smark #ifdef DBM
472966Seric typedef struct
482966Seric {
492966Seric 	char	*dptr;
502966Seric 	int dsize;
512966Seric } datum;
521503Smark datum lhs, rhs;
531515Seric extern datum fetch();
541503Smark #endif DBM
55292Seric 
564097Seric alias(a)
574097Seric 	register ADDRESS *a;
58292Seric {
594081Seric 	register char *p;
604081Seric # ifndef DBM
61*4098Seric 	register STAB *s;
624081Seric # endif DBM
63292Seric 
64292Seric 	if (NoAlias)
65292Seric 		return;
66292Seric # ifdef DEBUG
67292Seric 	if (Debug)
68*4098Seric 		printf("alias(%s)\n", a->q_paddr);
69292Seric # endif
70292Seric 
71*4098Seric 	/* don't realias already aliased names */
72*4098Seric 	if (bitset(QDONTSEND, a->q_flags))
73*4098Seric 		return;
74*4098Seric 
75*4098Seric 	To = a->q_paddr;
76*4098Seric 
774097Seric # ifdef DBM
78*4098Seric 	/* create a key for fetch */
79*4098Seric 	lhs.dptr = a->q_user;
80*4098Seric 	lhs.dsize = strlen(a->q_user) + 1;
81*4098Seric 	rhs = fetch(lhs);
82*4098Seric 
83*4098Seric 	/* find this alias? */
84*4098Seric 	p = rhs.dptr;
85*4098Seric 	if (p == NULL)
86*4098Seric 		return;
87*4098Seric # else DBM
88*4098Seric 	s = stab(a->q_user, ST_ALIAS, ST_FIND);
89*4098Seric 	if (s == NULL)
90*4098Seric 		return;
91*4098Seric 	p = s->s_alias;
924097Seric # endif DBM
93292Seric 
94292Seric 	/*
95*4098Seric 	**  Match on Alias.
96*4098Seric 	**	Deliver to the target list.
971515Seric 	*/
981515Seric 
99*4098Seric # ifdef DEBUG
100*4098Seric 	if (Debug)
101*4098Seric 		printf("%s (%s, %s) aliased to %s\n",
102*4098Seric 		    a->q_paddr, a->q_host, a->q_user, p);
103*4098Seric # endif
104*4098Seric 	if (Verbose)
105*4098Seric 		message("050", "aliased to %s", p);
106*4098Seric 	a->q_flags |= QDONTSEND;
107*4098Seric 	AliasLevel++;
108*4098Seric 	sendto(p, 1);
109*4098Seric 	AliasLevel--;
110*4098Seric }
111*4098Seric /*
112*4098Seric **  INITALIASES -- initialize for aliasing
113*4098Seric **
114*4098Seric **	Very different depending on whether we are running DBM or not.
115*4098Seric **
116*4098Seric **	Parameters:
117*4098Seric **		aliasfile -- location of aliases.
118*4098Seric **
119*4098Seric **	Returns:
120*4098Seric **		none.
121*4098Seric **
122*4098Seric **	Side Effects:
123*4098Seric **		initializes aliases:
124*4098Seric **		if DBM:  opens the database.
125*4098Seric **		if ~DBM: reads the aliases into the symbol table.
126*4098Seric */
127*4098Seric 
128*4098Seric initaliases(aliasfile)
129*4098Seric 	char *aliasfile;
130*4098Seric {
131*4098Seric # ifdef DBM
132*4098Seric 	dbminit(aliasfile);
133*4098Seric # else DBM
134*4098Seric 	char line[BUFSIZ];
135*4098Seric 	register char *p;
136*4098Seric 	char *p2;
137*4098Seric 	char *rhs;
138*4098Seric 	bool skipping;
139*4098Seric 	ADDRESS al, bl;
140*4098Seric 	extern char *prescan();
141*4098Seric 	bool contin;
142*4098Seric 
143*4098Seric 	if ((af = fopen(aliasfile, "r")) == NULL)
1441515Seric 	{
145*4098Seric # ifdef DEBUG
146*4098Seric 		if (Debug)
147*4098Seric 			printf("Can't open %s\n", AliasFile);
148*4098Seric # endif
149*4098Seric 		errno = 0;
150*4098Seric 		NoAlias++;
151*4098Seric 		return;
152*4098Seric 	}
153*4098Seric 	/* read and interpret lines */
154*4098Seric 	lineno = 0;
155*4098Seric 	skipping = FALSE;
156*4098Seric 	while (fgets(line, sizeof (line), af) != NULL)
157*4098Seric 	{
158*4098Seric 		lineno++;
159*4098Seric 		switch (line[0])
160*4098Seric 		{
161*4098Seric 		  case '#':
162*4098Seric 		  case '\n':
163*4098Seric 		  case '\0':
164*4098Seric 			skipping = FALSE;
165*4098Seric 			continue;
1664065Seric 
167*4098Seric 		  case ' ':
168*4098Seric 		  case '\t':
169*4098Seric 			if (!skipping)
170*4098Seric 				syserr("aliases: %d: Non-continuation line starts with space", lineno);
171*4098Seric 			skipping = TRUE;
1724097Seric 			continue;
173*4098Seric 		}
174*4098Seric 		skipping = FALSE;
1751874Seric 
176*4098Seric 		/* process the LHS */
177*4098Seric 		for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
1784097Seric 			continue;
179*4098Seric 		if (*p == '\0' || *p == '\n')
180*4098Seric 		{
181*4098Seric 		 syntaxerr:
182*4098Seric 			syserr("aliases: %d: missing colon", lineno);
1834097Seric 			continue;
184*4098Seric 		}
185*4098Seric 		*p++ = '\0';
186*4098Seric 		if (parse(line, &al, 1) == NULL)
187*4098Seric 		{
188*4098Seric 			*--p = ':';
189*4098Seric 			goto syntaxerr;
190*4098Seric 		}
191*4098Seric 		rhs = p;
192*4098Seric 		contin = FALSE;
193*4098Seric 		for (;;)
194*4098Seric 		{
195*4098Seric 			register char c;
1961515Seric 
197*4098Seric 			/* do parsing & compression of addresses */
198*4098Seric 			c = *p;
199*4098Seric 			while (c != '\0')
200*4098Seric 			{
201*4098Seric 				p2 = p;
202*4098Seric 				while (*p != '\n' && *p != ',' && *p != '\0')
203*4098Seric 					p++;
204*4098Seric 				c = *p;
205*4098Seric 				*p++ = '\0';
206*4098Seric 				if (*p2 == '\0')
207*4098Seric 				{
208*4098Seric 					p[-1] = c;
209*4098Seric 					continue;
210*4098Seric 				}
211*4098Seric 				parse(p2, &bl, -1);
212*4098Seric 				contin = (c == ',');
213*4098Seric 				p[-1] = c;
214*4098Seric 				while (isspace(*p))
215*4098Seric 					p++;
216*4098Seric 			}
2171515Seric 
218*4098Seric 			/* see if there should be a continuation line */
219*4098Seric 			if (!contin)
220*4098Seric 				break;
221*4098Seric 
222*4098Seric 			/* read continuation line */
223*4098Seric 			p--;
224*4098Seric 			if (fgets(p, sizeof line - (p - line), af) == NULL)
225*4098Seric 				break;
226*4098Seric 			lineno++;
227*4098Seric 
228*4098Seric 			if (!isspace(*p))
229*4098Seric 				syserr("aliases: %d: continuation line missing", lineno);
230*4098Seric 		}
231*4098Seric 		if (al.q_mailer != M_LOCAL)
232*4098Seric 		{
233*4098Seric 			syserr("aliases: %d: cannot alias non-local names", lineno);
234*4098Seric 			continue;
235*4098Seric 		}
236*4098Seric 		s = stab(al.q_user, ST_ALIAS, rhs);
2371515Seric 	}
238*4098Seric 	(void) fclose(af);
239*4098Seric # endif DBM
240292Seric }
241292Seric /*
242292Seric **  FORWARD -- Try to forward mail
243292Seric **
244292Seric **	This is similar but not identical to aliasing.
245292Seric **
246292Seric **	Parameters:
247292Seric **		user -- the name of the user who's mail we
248292Seric **			would like to forward to.
249292Seric **
250292Seric **	Returns:
251*4098Seric **		none.
252292Seric **
253292Seric **	Side Effects:
2543185Seric **		New names are added to send queues.
255*4098Seric **		Sets the QDONTSEND bit in addresses that are forwarded.
256292Seric */
257292Seric 
258292Seric forward(user)
2592966Seric 	ADDRESS *user;
260292Seric {
2614078Seric 	char buf[60];
2624069Seric 	register FILE *fp;
2634069Seric 	register char *p;
2644069Seric 
265*4098Seric # ifdef DEBUG
266*4098Seric 	if (Debug)
267*4098Seric 		printf("forward(%s)\n", user->q_paddr);
268*4098Seric # endif DEBUG
269*4098Seric 
2704078Seric 	if (user->q_mailer != M_LOCAL || bitset(QBADADDR, user->q_flags))
271*4098Seric 		return;
2724069Seric 
2734069Seric 	/* good address -- look for .forward file in home */
2744081Seric 	(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
2754069Seric 	fp = fopen(buf, "r");
2764069Seric 	if (fp == NULL)
277*4098Seric 		return;
2784069Seric 
2794069Seric 	/* we do have an address to forward to -- do it */
280*4098Seric 	user->q_flags |= QDONTSEND;
2814081Seric 	(void) fgets(buf, sizeof buf, fp);
2824069Seric 	if ((p = index(buf, '\n')) != NULL)
2834069Seric 		*p = '\0';
2844081Seric 	(void) fclose(fp);
2854069Seric 	if (buf[0] == '\0')
286*4098Seric 		return;
2874069Seric 	if (Verbose)
2884069Seric 		message("050", "forwarded to %s", buf);
289*4098Seric 	AliasLevel++;
2904069Seric 	sendto(buf, 1);
291*4098Seric 	AliasLevel--;
292*4098Seric 	return;
293292Seric }
294