14174Seric # include <pwd.h>
24174Seric # include "sendmail.h"
34174Seric 
4*4217Seric static char SccsId[] = "@(#)recipient.c	3.8	08/23/81";
54174Seric 
64174Seric /*
74174Seric **  SENDTO -- Designate a send list.
84174Seric **
94174Seric **	The parameter is a comma-separated list of people to send to.
104174Seric **	This routine arranges to send to all of them.
114174Seric **
124174Seric **	Parameters:
134174Seric **		list -- the send list.
144174Seric **		copyf -- the copy flag; passed to parse.
154174Seric **
164174Seric **	Returns:
174174Seric **		none
184174Seric **
194174Seric **	Side Effects:
204174Seric **		none.
214174Seric */
224174Seric 
234174Seric # define MAXRCRSN	10
244174Seric 
254174Seric sendto(list, copyf)
264174Seric 	char *list;
274174Seric 	int copyf;
284174Seric {
294174Seric 	register char *p;
304174Seric 	register char *q;
314174Seric 	register char c;
324174Seric 	ADDRESS *a;
334174Seric 	bool more;
344174Seric 
354174Seric 	/* more keeps track of what the previous delimiter was */
364174Seric 	more = TRUE;
374174Seric 	for (p = list; more; )
384174Seric 	{
394174Seric 		/* find the end of this address */
404174Seric 		while (*p == ' ' || *p == '\t')
414174Seric 			p++;
424174Seric 		q = p;
434174Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
444174Seric 			continue;
454174Seric 		more = c != '\0';
464174Seric 		*--p = '\0';
474174Seric 		if (more)
484174Seric 			p++;
494174Seric 
504174Seric 		/* parse the address */
514174Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
524174Seric 			continue;
534174Seric 
544174Seric 		/* arrange to send to this person */
554174Seric 		recipient(a);
564174Seric 	}
574174Seric 	To = NULL;
584174Seric }
594174Seric /*
604174Seric **  RECIPIENT -- Designate a message recipient
614174Seric **
624174Seric **	Saves the named person for future mailing.
634174Seric **
644174Seric **	Parameters:
654174Seric **		a -- the (preparsed) address header for the recipient.
664174Seric **
674174Seric **	Returns:
684174Seric **		none.
694174Seric **
704174Seric **	Side Effects:
714174Seric **		none.
724174Seric */
734174Seric 
744174Seric recipient(a)
754174Seric 	register ADDRESS *a;
764174Seric {
774174Seric 	register ADDRESS *q;
784174Seric 	register struct mailer *m;
794174Seric 	char buf[MAXNAME];
804174Seric 
814174Seric 	To = a->q_paddr;
824174Seric 	m = Mailer[a->q_mailer];
834174Seric 	errno = 0;
844174Seric # ifdef DEBUG
854174Seric 	if (Debug)
864174Seric 		printf("recipient(%s)\n", To);
874174Seric # endif DEBUG
884174Seric 
894174Seric 	/* break aliasing loops */
904174Seric 	if (AliasLevel > MAXRCRSN)
914174Seric 	{
924174Seric 		usrerr("aliasing/forwarding loop broken");
934174Seric 		return;
944174Seric 	}
954174Seric 
964174Seric 	/*
974174Seric 	**  Do sickly crude mapping for program mailing, etc.
984174Seric 	*/
994174Seric 
1004197Seric 	if (a->q_mailer == MN_LOCAL)
1014174Seric 	{
1024174Seric 		if (a->q_user[0] == '|')
1034174Seric 		{
1044197Seric 			a->q_mailer = MN_PROG;
1054197Seric 			m = Mailer[MN_PROG];
1064174Seric 			a->q_user++;
107*4217Seric # ifdef PARANOID
108*4217Seric 			if (AliasLevel <= 0)
109*4217Seric 			{
110*4217Seric 				usrerr("Cannot mail directly to programs");
111*4217Seric 				a->q_flags |= QDONTSEND;
112*4217Seric 			}
113*4217Seric # endif PARANOID
1144174Seric 		}
1154174Seric 	}
1164174Seric 
1174174Seric 	/*
1184174Seric 	**  Look up this person in the recipient list.  If they
1194174Seric 	**  are there already, return, otherwise continue.
1204174Seric 	**  If the list is empty, just add it.
1214174Seric 	*/
1224174Seric 
1234174Seric 	if (m->m_sendq == NULL)
1244174Seric 	{
1254174Seric 		m->m_sendq = a;
1264174Seric 	}
1274174Seric 	else
1284174Seric 	{
1294174Seric 		ADDRESS *pq;
1304174Seric 
1314174Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
1324174Seric 		{
1334174Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
1344174Seric 			{
1354174Seric # ifdef DEBUG
1364174Seric 				if (Debug)
1374174Seric 					printf("(%s in sendq)\n", a->q_paddr);
1384174Seric # endif DEBUG
1394174Seric 				if (Verbose && !bitset(QDONTSEND, a->q_flags))
1404174Seric 					message(Arpa_Info, "duplicate supressed");
1414174Seric 				return;
1424174Seric 			}
1434174Seric 		}
1444174Seric 
1454174Seric 		/* add address on list */
1464174Seric 		q = pq;
1474174Seric 		q->q_next = a;
1484174Seric 	}
1494174Seric 	a->q_next = NULL;
1504174Seric 
1514174Seric 	/*
1524174Seric 	**  Alias the name and handle :include: specs.
1534174Seric 	*/
1544174Seric 
1554197Seric 	if (a->q_mailer == MN_LOCAL)
1564174Seric 	{
1574174Seric 		if (strncmp(a->q_user, ":include:", 9) == 0)
1584174Seric 		{
1594174Seric 			a->q_flags |= QDONTSEND;
1604176Seric 			if (Verbose)
1614176Seric 				message(Arpa_Info, "including file %s", &a->q_user[9]);
1624176Seric 			include(&a->q_user[9], " sending");
1634174Seric 		}
1644174Seric 		else
1654174Seric 			alias(a);
1664174Seric 	}
1674174Seric 
1684174Seric 	/*
1694174Seric 	**  If the user is local and still being sent, verify that
1704174Seric 	**  the address is good.  If it is, try to forward.
1714174Seric 	**  If the address is already good, we have a forwarding
1724174Seric 	**  loop.  This can be broken by just sending directly to
1734174Seric 	**  the user (which is probably correct anyway).
1744174Seric 	*/
1754174Seric 
1764197Seric 	if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == MN_LOCAL)
1774174Seric 	{
1784174Seric 		char buf[MAXNAME];
1794201Seric 		register char *p;
1804174Seric 
1814174Seric 		strcpy(buf, a->q_user);
1824174Seric 		stripquotes(buf, TRUE);
1834174Seric 
1844174Seric 		/* see if this is to a file */
1854201Seric 		if ((p = rindex(buf, '/')) != NULL)
1864174Seric 		{
1874201Seric 			/* check if writable or creatable */
1884201Seric 			if ((access(buf, 0) >= 0) ?
1894201Seric 			    (access(buf, 2) < 0) :
1904201Seric 			    (*p = '\0', access(buf, 3) < 0))
1914174Seric 			{
1924174Seric 				a->q_flags |= QBADADDR;
1934174Seric 				giveresponse(EX_CANTCREAT, TRUE, m);
1944174Seric 			}
1954174Seric 		}
1964174Seric 		else
1974174Seric 		{
1984174Seric 			register struct passwd *pw;
1994174Seric 			extern struct passwd *getpwnam();
2004174Seric 			pw = getpwnam(buf);
2014174Seric 			if (pw == NULL)
2024174Seric 			{
2034174Seric 				a->q_flags |= QBADADDR;
2044174Seric 				giveresponse(EX_NOUSER, TRUE, m);
2054174Seric 			}
2064174Seric 			else
2074174Seric 			{
2084174Seric 				a->q_home = newstr(pw->pw_dir);
2094213Seric 				a->q_uid = pw->pw_uid;
2104174Seric 				if (strcmp(buf, a->q_user) == 0)
2114174Seric 					forward(a);
2124174Seric 			}
2134174Seric 		}
2144174Seric 	}
2154174Seric }
2164174Seric /*
2174174Seric **  INCLUDE -- handle :include: specification.
2184174Seric **
2194174Seric **	Parameters:
2204174Seric **		fname -- filename to include.
2214176Seric **		msg -- message to print in verbose mode.
2224174Seric **
2234174Seric **	Returns:
2244174Seric **		none.
2254174Seric **
2264174Seric **	Side Effects:
2274174Seric **		reads the :include: file and sends to everyone
2284174Seric **		listed in that file.
2294174Seric */
2304174Seric 
2314176Seric include(fname, msg)
2324174Seric 	char *fname;
2334176Seric 	char *msg;
2344174Seric {
2354174Seric 	char buf[MAXLINE];
2364174Seric 	register FILE *fp;
2374178Seric 	char *oldto = To;
2384174Seric 
2394174Seric 	fp = fopen(fname, "r");
2404174Seric 	if (fp == NULL)
2414174Seric 	{
2424174Seric 		usrerr("Cannot open %s", fname);
2434174Seric 		return;
2444174Seric 	}
2454174Seric 
2464174Seric 	/* read the file -- each line is a comma-separated list. */
2474174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
2484174Seric 	{
2494174Seric 		register char *p = index(buf, '\n');
2504174Seric 
2514174Seric 		if (p != NULL)
2524174Seric 			*p = '\0';
2534174Seric 		if (buf[0] == '\0')
2544174Seric 			continue;
2554178Seric 		To = oldto;
2564174Seric 		if (Verbose)
2574176Seric 			message(Arpa_Info, "%s to %s", msg, buf);
2584176Seric 		AliasLevel++;
2594174Seric 		sendto(buf, 1);
2604176Seric 		AliasLevel--;
2614174Seric 	}
2624174Seric 
2634174Seric 	fclose(fp);
2644174Seric }
265