14174Seric # include <stdio.h>
24174Seric # include <pwd.h>
34174Seric # include <signal.h>
44174Seric # include <ctype.h>
54174Seric # include <errno.h>
64174Seric # include "sendmail.h"
74174Seric # ifdef LOG
84174Seric # include <syslog.h>
94174Seric # endif LOG
104174Seric 
11*4178Seric static char SccsId[] = "@(#)recipient.c	3.3	08/20/81";
124174Seric 
134174Seric /*
144174Seric **  SENDTO -- Designate a send list.
154174Seric **
164174Seric **	The parameter is a comma-separated list of people to send to.
174174Seric **	This routine arranges to send to all of them.
184174Seric **
194174Seric **	Parameters:
204174Seric **		list -- the send list.
214174Seric **		copyf -- the copy flag; passed to parse.
224174Seric **
234174Seric **	Returns:
244174Seric **		none
254174Seric **
264174Seric **	Side Effects:
274174Seric **		none.
284174Seric */
294174Seric 
304174Seric # define MAXRCRSN	10
314174Seric 
324174Seric sendto(list, copyf)
334174Seric 	char *list;
344174Seric 	int copyf;
354174Seric {
364174Seric 	register char *p;
374174Seric 	register char *q;
384174Seric 	register char c;
394174Seric 	ADDRESS *a;
404174Seric 	bool more;
414174Seric 
424174Seric 	/* more keeps track of what the previous delimiter was */
434174Seric 	more = TRUE;
444174Seric 	for (p = list; more; )
454174Seric 	{
464174Seric 		/* find the end of this address */
474174Seric 		while (*p == ' ' || *p == '\t')
484174Seric 			p++;
494174Seric 		q = p;
504174Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
514174Seric 			continue;
524174Seric 		more = c != '\0';
534174Seric 		*--p = '\0';
544174Seric 		if (more)
554174Seric 			p++;
564174Seric 
574174Seric 		/* parse the address */
584174Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
594174Seric 			continue;
604174Seric 
614174Seric 		/* arrange to send to this person */
624174Seric 		recipient(a);
634174Seric 	}
644174Seric 	To = NULL;
654174Seric }
664174Seric /*
674174Seric **  RECIPIENT -- Designate a message recipient
684174Seric **
694174Seric **	Saves the named person for future mailing.
704174Seric **
714174Seric **	Parameters:
724174Seric **		a -- the (preparsed) address header for the recipient.
734174Seric **
744174Seric **	Returns:
754174Seric **		none.
764174Seric **
774174Seric **	Side Effects:
784174Seric **		none.
794174Seric */
804174Seric 
814174Seric recipient(a)
824174Seric 	register ADDRESS *a;
834174Seric {
844174Seric 	register ADDRESS *q;
854174Seric 	register struct mailer *m;
864174Seric 	char buf[MAXNAME];
874174Seric 
884174Seric 	To = a->q_paddr;
894174Seric 	m = Mailer[a->q_mailer];
904174Seric 	errno = 0;
914174Seric # ifdef DEBUG
924174Seric 	if (Debug)
934174Seric 		printf("recipient(%s)\n", To);
944174Seric # endif DEBUG
954174Seric 
964174Seric 	/* break aliasing loops */
974174Seric 	if (AliasLevel > MAXRCRSN)
984174Seric 	{
994174Seric 		usrerr("aliasing/forwarding loop broken");
1004174Seric 		return;
1014174Seric 	}
1024174Seric 
1034174Seric 	/*
1044174Seric 	**  Do sickly crude mapping for program mailing, etc.
1054174Seric 	*/
1064174Seric 
1074174Seric 	if (a->q_mailer == M_LOCAL)
1084174Seric 	{
1094174Seric 		if (a->q_user[0] == '|')
1104174Seric 		{
1114174Seric 			a->q_mailer = M_PROG;
1124174Seric 			m = Mailer[M_PROG];
1134174Seric 			a->q_user++;
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 
1554174Seric 	if (a->q_mailer == M_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 
1764174Seric 	if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == M_LOCAL)
1774174Seric 	{
1784174Seric 		char buf[MAXNAME];
1794174Seric 
1804174Seric 		strcpy(buf, a->q_user);
1814174Seric 		stripquotes(buf, TRUE);
1824174Seric 
1834174Seric 		/* see if this is to a file */
1844174Seric 		if (index(buf, '/') != NULL)
1854174Seric 		{
1864174Seric 			if (access(buf, 2) < 0)
1874174Seric 			{
1884174Seric 				a->q_flags |= QBADADDR;
1894174Seric 				giveresponse(EX_CANTCREAT, TRUE, m);
1904174Seric 			}
1914174Seric 		}
1924174Seric 		else
1934174Seric 		{
1944174Seric 			register struct passwd *pw;
1954174Seric 			extern struct passwd *getpwnam();
1964174Seric 			pw = getpwnam(buf);
1974174Seric 			if (pw == NULL)
1984174Seric 			{
1994174Seric 				a->q_flags |= QBADADDR;
2004174Seric 				giveresponse(EX_NOUSER, TRUE, m);
2014174Seric 			}
2024174Seric 			else
2034174Seric 			{
2044174Seric 				a->q_home = newstr(pw->pw_dir);
2054174Seric 				if (strcmp(buf, a->q_user) == 0)
2064174Seric 					forward(a);
2074174Seric 			}
2084174Seric 		}
2094174Seric 	}
2104174Seric }
2114174Seric /*
2124174Seric **  INCLUDE -- handle :include: specification.
2134174Seric **
2144174Seric **	Parameters:
2154174Seric **		fname -- filename to include.
2164176Seric **		msg -- message to print in verbose mode.
2174174Seric **
2184174Seric **	Returns:
2194174Seric **		none.
2204174Seric **
2214174Seric **	Side Effects:
2224174Seric **		reads the :include: file and sends to everyone
2234174Seric **		listed in that file.
2244174Seric */
2254174Seric 
2264176Seric include(fname, msg)
2274174Seric 	char *fname;
2284176Seric 	char *msg;
2294174Seric {
2304174Seric 	char buf[MAXLINE];
2314174Seric 	register FILE *fp;
232*4178Seric 	char *oldto = To;
2334174Seric 
2344174Seric 	fp = fopen(fname, "r");
2354174Seric 	if (fp == NULL)
2364174Seric 	{
2374174Seric 		usrerr("Cannot open %s", fname);
2384174Seric 		return;
2394174Seric 	}
2404174Seric 
2414174Seric 	/* read the file -- each line is a comma-separated list. */
2424174Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
2434174Seric 	{
2444174Seric 		register char *p = index(buf, '\n');
2454174Seric 
2464174Seric 		if (p != NULL)
2474174Seric 			*p = '\0';
2484174Seric 		if (buf[0] == '\0')
2494174Seric 			continue;
250*4178Seric 		To = oldto;
2514174Seric 		if (Verbose)
2524176Seric 			message(Arpa_Info, "%s to %s", msg, buf);
2534176Seric 		AliasLevel++;
2544174Seric 		sendto(buf, 1);
2554176Seric 		AliasLevel--;
2564174Seric 	}
2574174Seric 
2584174Seric 	fclose(fp);
2594174Seric }
260