1 # include <pwd.h>
2 # include "sendmail.h"
3 
4 static char SccsId[] = "@(#)recipient.c	3.6	08/22/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 		}
108 	}
109 
110 	/*
111 	**  Look up this person in the recipient list.  If they
112 	**  are there already, return, otherwise continue.
113 	**  If the list is empty, just add it.
114 	*/
115 
116 	if (m->m_sendq == NULL)
117 	{
118 		m->m_sendq = a;
119 	}
120 	else
121 	{
122 		ADDRESS *pq;
123 
124 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
125 		{
126 			if (!ForceMail && sameaddr(q, a, FALSE))
127 			{
128 # ifdef DEBUG
129 				if (Debug)
130 					printf("(%s in sendq)\n", a->q_paddr);
131 # endif DEBUG
132 				if (Verbose && !bitset(QDONTSEND, a->q_flags))
133 					message(Arpa_Info, "duplicate supressed");
134 				return;
135 			}
136 		}
137 
138 		/* add address on list */
139 		q = pq;
140 		q->q_next = a;
141 	}
142 	a->q_next = NULL;
143 
144 	/*
145 	**  Alias the name and handle :include: specs.
146 	*/
147 
148 	if (a->q_mailer == MN_LOCAL)
149 	{
150 		if (strncmp(a->q_user, ":include:", 9) == 0)
151 		{
152 			a->q_flags |= QDONTSEND;
153 			if (Verbose)
154 				message(Arpa_Info, "including file %s", &a->q_user[9]);
155 			include(&a->q_user[9], " sending");
156 		}
157 		else
158 			alias(a);
159 	}
160 
161 	/*
162 	**  If the user is local and still being sent, verify that
163 	**  the address is good.  If it is, try to forward.
164 	**  If the address is already good, we have a forwarding
165 	**  loop.  This can be broken by just sending directly to
166 	**  the user (which is probably correct anyway).
167 	*/
168 
169 	if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL)
170 	{
171 		char buf[MAXNAME];
172 		register char *p;
173 
174 		strcpy(buf, a->q_user);
175 		stripquotes(buf, TRUE);
176 
177 		/* see if this is to a file */
178 		if ((p = rindex(buf, '/')) != NULL)
179 		{
180 			/* check if writable or creatable */
181 			if ((access(buf, 0) >= 0) ?
182 			    (access(buf, 2) < 0) :
183 			    (*p = '\0', access(buf, 3) < 0))
184 			{
185 				a->q_flags |= QBADADDR;
186 				giveresponse(EX_CANTCREAT, TRUE, m);
187 			}
188 		}
189 		else
190 		{
191 			register struct passwd *pw;
192 			extern struct passwd *getpwnam();
193 			pw = getpwnam(buf);
194 			if (pw == NULL)
195 			{
196 				a->q_flags |= QBADADDR;
197 				giveresponse(EX_NOUSER, TRUE, m);
198 			}
199 			else
200 			{
201 				a->q_home = newstr(pw->pw_dir);
202 				if (strcmp(buf, a->q_user) == 0)
203 					forward(a);
204 			}
205 		}
206 	}
207 }
208 /*
209 **  INCLUDE -- handle :include: specification.
210 **
211 **	Parameters:
212 **		fname -- filename to include.
213 **		msg -- message to print in verbose mode.
214 **
215 **	Returns:
216 **		none.
217 **
218 **	Side Effects:
219 **		reads the :include: file and sends to everyone
220 **		listed in that file.
221 */
222 
223 include(fname, msg)
224 	char *fname;
225 	char *msg;
226 {
227 	char buf[MAXLINE];
228 	register FILE *fp;
229 	char *oldto = To;
230 
231 	fp = fopen(fname, "r");
232 	if (fp == NULL)
233 	{
234 		usrerr("Cannot open %s", fname);
235 		return;
236 	}
237 
238 	/* read the file -- each line is a comma-separated list. */
239 	while (fgets(buf, sizeof buf, fp) != NULL)
240 	{
241 		register char *p = index(buf, '\n');
242 
243 		if (p != NULL)
244 			*p = '\0';
245 		if (buf[0] == '\0')
246 			continue;
247 		To = oldto;
248 		if (Verbose)
249 			message(Arpa_Info, "%s to %s", msg, buf);
250 		AliasLevel++;
251 		sendto(buf, 1);
252 		AliasLevel--;
253 	}
254 
255 	fclose(fp);
256 }
257