1 # include <pwd.h>
2 # include "sendmail.h"
3 
4 static char SccsId[] = "@(#)recipient.c	3.8	08/23/81";
5 
6 /*
7 **  SENDTO -- Designate a send list.
8 **
9 **	The parameter is a comma-separated list of people to send to.
10 **	This routine arranges to send to all of them.
11 **
12 **	Parameters:
13 **		list -- the send list.
14 **		copyf -- the copy flag; passed to parse.
15 **
16 **	Returns:
17 **		none
18 **
19 **	Side Effects:
20 **		none.
21 */
22 
23 # define MAXRCRSN	10
24 
25 sendto(list, copyf)
26 	char *list;
27 	int copyf;
28 {
29 	register char *p;
30 	register char *q;
31 	register char c;
32 	ADDRESS *a;
33 	bool more;
34 
35 	/* more keeps track of what the previous delimiter was */
36 	more = TRUE;
37 	for (p = list; more; )
38 	{
39 		/* find the end of this address */
40 		while (*p == ' ' || *p == '\t')
41 			p++;
42 		q = p;
43 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
44 			continue;
45 		more = c != '\0';
46 		*--p = '\0';
47 		if (more)
48 			p++;
49 
50 		/* parse the address */
51 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
52 			continue;
53 
54 		/* arrange to send to this person */
55 		recipient(a);
56 	}
57 	To = NULL;
58 }
59 /*
60 **  RECIPIENT -- Designate a message recipient
61 **
62 **	Saves the named person for future mailing.
63 **
64 **	Parameters:
65 **		a -- the (preparsed) address header for the recipient.
66 **
67 **	Returns:
68 **		none.
69 **
70 **	Side Effects:
71 **		none.
72 */
73 
74 recipient(a)
75 	register ADDRESS *a;
76 {
77 	register ADDRESS *q;
78 	register struct mailer *m;
79 	char buf[MAXNAME];
80 
81 	To = a->q_paddr;
82 	m = Mailer[a->q_mailer];
83 	errno = 0;
84 # ifdef DEBUG
85 	if (Debug)
86 		printf("recipient(%s)\n", To);
87 # endif DEBUG
88 
89 	/* break aliasing loops */
90 	if (AliasLevel > MAXRCRSN)
91 	{
92 		usrerr("aliasing/forwarding loop broken");
93 		return;
94 	}
95 
96 	/*
97 	**  Do sickly crude mapping for program mailing, etc.
98 	*/
99 
100 	if (a->q_mailer == MN_LOCAL)
101 	{
102 		if (a->q_user[0] == '|')
103 		{
104 			a->q_mailer = MN_PROG;
105 			m = Mailer[MN_PROG];
106 			a->q_user++;
107 # ifdef PARANOID
108 			if (AliasLevel <= 0)
109 			{
110 				usrerr("Cannot mail directly to programs");
111 				a->q_flags |= QDONTSEND;
112 			}
113 # endif PARANOID
114 		}
115 	}
116 
117 	/*
118 	**  Look up this person in the recipient list.  If they
119 	**  are there already, return, otherwise continue.
120 	**  If the list is empty, just add it.
121 	*/
122 
123 	if (m->m_sendq == NULL)
124 	{
125 		m->m_sendq = a;
126 	}
127 	else
128 	{
129 		ADDRESS *pq;
130 
131 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
132 		{
133 			if (!ForceMail && sameaddr(q, a, FALSE))
134 			{
135 # ifdef DEBUG
136 				if (Debug)
137 					printf("(%s in sendq)\n", a->q_paddr);
138 # endif DEBUG
139 				if (Verbose && !bitset(QDONTSEND, a->q_flags))
140 					message(Arpa_Info, "duplicate supressed");
141 				return;
142 			}
143 		}
144 
145 		/* add address on list */
146 		q = pq;
147 		q->q_next = a;
148 	}
149 	a->q_next = NULL;
150 
151 	/*
152 	**  Alias the name and handle :include: specs.
153 	*/
154 
155 	if (a->q_mailer == MN_LOCAL)
156 	{
157 		if (strncmp(a->q_user, ":include:", 9) == 0)
158 		{
159 			a->q_flags |= QDONTSEND;
160 			if (Verbose)
161 				message(Arpa_Info, "including file %s", &a->q_user[9]);
162 			include(&a->q_user[9], " sending");
163 		}
164 		else
165 			alias(a);
166 	}
167 
168 	/*
169 	**  If the user is local and still being sent, verify that
170 	**  the address is good.  If it is, try to forward.
171 	**  If the address is already good, we have a forwarding
172 	**  loop.  This can be broken by just sending directly to
173 	**  the user (which is probably correct anyway).
174 	*/
175 
176 	if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL)
177 	{
178 		char buf[MAXNAME];
179 		register char *p;
180 
181 		strcpy(buf, a->q_user);
182 		stripquotes(buf, TRUE);
183 
184 		/* see if this is to a file */
185 		if ((p = rindex(buf, '/')) != NULL)
186 		{
187 			/* check if writable or creatable */
188 			if ((access(buf, 0) >= 0) ?
189 			    (access(buf, 2) < 0) :
190 			    (*p = '\0', access(buf, 3) < 0))
191 			{
192 				a->q_flags |= QBADADDR;
193 				giveresponse(EX_CANTCREAT, TRUE, m);
194 			}
195 		}
196 		else
197 		{
198 			register struct passwd *pw;
199 			extern struct passwd *getpwnam();
200 			pw = getpwnam(buf);
201 			if (pw == NULL)
202 			{
203 				a->q_flags |= QBADADDR;
204 				giveresponse(EX_NOUSER, TRUE, m);
205 			}
206 			else
207 			{
208 				a->q_home = newstr(pw->pw_dir);
209 				a->q_uid = pw->pw_uid;
210 				if (strcmp(buf, a->q_user) == 0)
211 					forward(a);
212 			}
213 		}
214 	}
215 }
216 /*
217 **  INCLUDE -- handle :include: specification.
218 **
219 **	Parameters:
220 **		fname -- filename to include.
221 **		msg -- message to print in verbose mode.
222 **
223 **	Returns:
224 **		none.
225 **
226 **	Side Effects:
227 **		reads the :include: file and sends to everyone
228 **		listed in that file.
229 */
230 
231 include(fname, msg)
232 	char *fname;
233 	char *msg;
234 {
235 	char buf[MAXLINE];
236 	register FILE *fp;
237 	char *oldto = To;
238 
239 	fp = fopen(fname, "r");
240 	if (fp == NULL)
241 	{
242 		usrerr("Cannot open %s", fname);
243 		return;
244 	}
245 
246 	/* read the file -- each line is a comma-separated list. */
247 	while (fgets(buf, sizeof buf, fp) != NULL)
248 	{
249 		register char *p = index(buf, '\n');
250 
251 		if (p != NULL)
252 			*p = '\0';
253 		if (buf[0] == '\0')
254 			continue;
255 		To = oldto;
256 		if (Verbose)
257 			message(Arpa_Info, "%s to %s", msg, buf);
258 		AliasLevel++;
259 		sendto(buf, 1);
260 		AliasLevel--;
261 	}
262 
263 	fclose(fp);
264 }
265