1294Seric # include <stdio.h>
2294Seric # include <pwd.h>
3294Seric # include <signal.h>
42898Seric # include <ctype.h>
53310Seric # include "sendmail.h"
6294Seric # ifdef LOG
72774Seric # include <syslog.h>
8294Seric # endif LOG
9294Seric 
10*4078Seric static char SccsId[] = "@(#)deliver.c	3.16	08/09/81";
11405Seric 
12294Seric /*
13294Seric **  DELIVER -- Deliver a message to a particular address.
14294Seric **
15294Seric **	Parameters:
16294Seric **		to -- the address to deliver the message to.
17294Seric **		editfcn -- if non-NULL, we want to call this function
18294Seric **			to output the letter (instead of just out-
19294Seric **			putting it raw).
20294Seric **
21294Seric **	Returns:
22294Seric **		zero -- successfully delivered.
23294Seric **		else -- some failure, see ExitStat for more info.
24294Seric **
25294Seric **	Side Effects:
26294Seric **		The standard input is passed off to someone.
27294Seric */
28294Seric 
29294Seric deliver(to, editfcn)
302968Seric 	ADDRESS *to;
31294Seric 	int (*editfcn)();
32294Seric {
33294Seric 	char *host;
34294Seric 	char *user;
35294Seric 	extern struct passwd *getpwnam();
36294Seric 	char **pvp;
373233Seric 	register char **mvp;
383233Seric 	register char *p;
393233Seric 	register struct mailer *m;
40294Seric 	register int i;
41294Seric 	extern int errno;
422898Seric 	extern putmessage();
431828Seric 	extern char *index();
442968Seric 	extern bool checkcompat();
453233Seric 	char *pv[MAXPV+1];
463233Seric 	extern char *newstr();
473233Seric 	char tobuf[MAXLINE];
483233Seric 	char buf[MAXNAME];
493233Seric 	extern char *expand();
503233Seric 	bool firstone;
51294Seric 
523233Seric 	if (bitset(QDONTSEND, to->q_flags))
533233Seric 		return (0);
54294Seric 
55294Seric # ifdef DEBUG
56294Seric 	if (Debug)
573233Seric 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
583233Seric 			to->q_mailer, to->q_host, to->q_user);
59294Seric # endif DEBUG
60294Seric 
61294Seric 	/*
623233Seric 	**  Do initial argv setup.
633233Seric 	**	Insert the mailer name.  Notice that $x expansion is
643233Seric 	**	NOT done on the mailer name.  Then, if the mailer has
653233Seric 	**	a picky -f flag, we insert it as appropriate.  This
663233Seric 	**	code does not check for 'pv' overflow; this places a
673233Seric 	**	manifest lower limit of 4 for MAXPV.
682968Seric 	*/
692968Seric 
703233Seric 	m = Mailer[to->q_mailer];
713233Seric 	host = to->q_host;
723233Seric 	define('g', m->m_from);		/* translated from address */
733233Seric 	define('h', host);		/* to host */
743233Seric 	Errors = 0;
753233Seric 	errno = 0;
763233Seric 	pvp = pv;
773233Seric 	*pvp++ = m->m_argv[0];
782968Seric 
793233Seric 	/* insert -f or -r flag as appropriate */
803233Seric 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
813233Seric 	{
823233Seric 		if (bitset(M_FOPT, m->m_flags))
833233Seric 			*pvp++ = "-f";
843233Seric 		else
853233Seric 			*pvp++ = "-r";
863233Seric 		expand("$g", buf, &buf[sizeof buf - 1]);
873233Seric 		*pvp++ = newstr(buf);
883233Seric 	}
89294Seric 
90294Seric 	/*
913233Seric 	**  Append the other fixed parts of the argv.  These run
923233Seric 	**  up to the first entry containing "$u".  There can only
933233Seric 	**  be one of these, and there are only a few more slots
943233Seric 	**  in the pv after it.
95294Seric 	*/
96294Seric 
973233Seric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
98294Seric 	{
993233Seric 		while ((p = index(p, '$')) != NULL)
1003233Seric 			if (*++p == 'u')
1013233Seric 				break;
1023233Seric 		if (p != NULL)
1033233Seric 			break;
1043233Seric 
1053233Seric 		/* this entry is safe -- go ahead and process it */
1063233Seric 		expand(*mvp, buf, &buf[sizeof buf - 1]);
1073233Seric 		*pvp++ = newstr(buf);
1083233Seric 		if (pvp >= &pv[MAXPV - 3])
1093233Seric 		{
1103233Seric 			syserr("Too many parameters to %s before $u", pv[0]);
1113233Seric 			return (-1);
1123233Seric 		}
113294Seric 	}
1143233Seric 	if (*mvp == NULL)
1153233Seric 		syserr("No $u in mailer argv for %s", pv[0]);
116294Seric 
117294Seric 	/*
1183233Seric 	**  At this point *mvp points to the argument with $u.  We
1193233Seric 	**  run through our address list and append all the addresses
1203233Seric 	**  we can.  If we run out of space, do not fret!  We can
1213233Seric 	**  always send another copy later.
122294Seric 	*/
123294Seric 
1243233Seric 	tobuf[0] = '\0';
1253233Seric 	firstone = TRUE;
1263233Seric 	To = tobuf;
1273233Seric 	for (; to != NULL; to = to->q_next)
128294Seric 	{
1293233Seric 		/* avoid sending multiple recipients to dumb mailers */
1303233Seric 		if (!firstone && !bitset(M_MUSER, m->m_flags))
1313233Seric 			break;
1323233Seric 
1333233Seric 		/* if already sent or not for this host, don't send */
1343233Seric 		if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0)
1353233Seric 			continue;
1363233Seric 		user = to->q_user;
1373233Seric 		To = to->q_paddr;
1383233Seric 		to->q_flags |= QDONTSEND;
1393233Seric 		firstone = FALSE;
1403233Seric 
1413233Seric # ifdef DEBUG
1423233Seric 		if (Debug)
1433233Seric 			printf("   send to `%s'\n", user);
1443233Seric # endif DEBUG
1453233Seric 
1463233Seric 		/*
1473233Seric 		**  Check to see that these people are allowed to
1483233Seric 		**  talk to each other.
1493233Seric 		*/
1503233Seric 
1513233Seric 		if (!checkcompat(to))
152294Seric 		{
1533233Seric 			giveresponse(EX_UNAVAILABLE, TRUE, m);
1543233Seric 			continue;
155294Seric 		}
1563233Seric 
1573233Seric 		/*
1583233Seric 		**  Remove quote bits from user/host.
1593233Seric 		*/
1603233Seric 
1613233Seric 		for (p = user; (*p++ &= 0177) != '\0'; )
1623233Seric 			continue;
1633233Seric 		if (host != NULL)
1643233Seric 			for (p = host; (*p++ &= 0177) != '\0'; )
1653233Seric 				continue;
1663233Seric 
1673233Seric 		/*
1683233Seric 		**  Strip quote bits from names if the mailer wants it.
1693233Seric 		*/
1703233Seric 
1713233Seric 		if (bitset(M_STRIPQ, m->m_flags))
172294Seric 		{
1733233Seric 			stripquotes(user);
1743233Seric 			stripquotes(host);
1753233Seric 		}
1763233Seric 
1773233Seric 		/*
1783233Seric 		**  See if this user name is "special".
1793233Seric 		**	If the user name has a slash in it, assume that this
1803233Seric 		**	is a file -- send it off without further ado.
1813233Seric 		**	Note that this means that editfcn's will not
1823233Seric 		**	be applied to the message.  Also note that
1833233Seric 		**	this type of addresses is not processed along
1843233Seric 		**	with the others, so we fudge on the To person.
1853233Seric 		*/
1863233Seric 
187*4078Seric 		if (m == Mailer[M_LOCAL])
1883233Seric 		{
189294Seric 			if (index(user, '/') != NULL)
190294Seric 			{
191294Seric 				i = mailfile(user);
192294Seric 				giveresponse(i, TRUE, m);
1933233Seric 				continue;
194294Seric 			}
195294Seric 		}
1963233Seric 
1973233Seric 		/*
1983233Seric 		**  See if the user exists.
1993233Seric 		**	Strictly, this is only needed to print a pretty
2003233Seric 		**	error message.
2013233Seric 		**
2023233Seric 		**	>>>>>>>>>> This clause assumes that the local mailer
2033233Seric 		**	>> NOTE >> cannot do any further aliasing; that
2043310Seric 		**	>>>>>>>>>> function is subsumed by sendmail.
2053233Seric 		*/
2063233Seric 
207*4078Seric 		if (bitset(QBADADDR, to->q_flags))
2083233Seric 		{
209*4078Seric 			giveresponse(EX_NOUSER, TRUE, m);
210*4078Seric 			continue;
2113233Seric 		}
2123233Seric 
2133233Seric 		/* create list of users for error messages */
2143233Seric 		if (tobuf[0] != '\0')
2153233Seric 			strcat(tobuf, ",");
2163233Seric 		strcat(tobuf, to->q_paddr);
2173233Seric 		define('u', user);		/* to user */
218*4078Seric 		define('z', to->q_home);	/* user's home */
2193233Seric 
2203233Seric 		/* expand out this user */
2213233Seric 		expand(user, buf, &buf[sizeof buf - 1]);
2223233Seric 		*pvp++ = newstr(buf);
2233233Seric 		if (pvp >= &pv[MAXPV - 2])
2243233Seric 		{
2253233Seric 			/* allow some space for trailing parms */
2263233Seric 			break;
2273233Seric 		}
228294Seric 	}
229294Seric 
2304067Seric 	/* see if any addresses still exist */
2314067Seric 	if (tobuf[0] == '\0')
2324067Seric 		return (0);
2334067Seric 
2343233Seric 	/* print out messages as full list */
2353233Seric 	To = tobuf;
2363233Seric 
237294Seric 	/*
2383233Seric 	**  Fill out any parameters after the $u parameter.
239294Seric 	*/
240294Seric 
2413233Seric 	while (*++mvp != NULL)
242294Seric 	{
2433233Seric 		expand(*mvp, buf, &buf[sizeof buf - 1]);
2443233Seric 		*pvp++ = newstr(buf);
2453233Seric 		if (pvp >= &pv[MAXPV])
2463233Seric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
247294Seric 	}
2483233Seric 	*pvp++ = NULL;
249294Seric 
250294Seric 	/*
251294Seric 	**  Call the mailer.
2522898Seric 	**	The argument vector gets built, pipes
253294Seric 	**	are created as necessary, and we fork & exec as
2542898Seric 	**	appropriate.
255*4078Seric 	**
256*4078Seric 	**	Notice the tacky hack to handle private mailers.
257294Seric 	*/
258294Seric 
2593233Seric 	if (editfcn == NULL)
2603233Seric 		editfcn = putmessage;
261*4078Seric 	if (m == Mailer[M_PRIVATE])
262*4078Seric 	{
263*4078Seric 		expand("$z/.mailer", buf, &buf[sizeof buf - 1]);
264*4078Seric 		m->m_mailer = buf;
265*4078Seric 	}
2663233Seric 	i = sendoff(m, pv, editfcn);
2673233Seric 
2683233Seric 	return (i);
2693233Seric }
2703233Seric /*
2713233Seric **  SENDOFF -- send off call to mailer & collect response.
2723233Seric **
2733233Seric **	Parameters:
2743233Seric **		m -- mailer descriptor.
2753233Seric **		pvp -- parameter vector to send to it.
2763233Seric **		editfcn -- function to pipe it through.
2773233Seric **
2783233Seric **	Returns:
2793233Seric **		exit status of mailer.
2803233Seric **
2813233Seric **	Side Effects:
2823233Seric **		none.
2833233Seric */
2843233Seric 
2854052Seric #define NFORKTRIES	5
2864052Seric 
2873233Seric sendoff(m, pvp, editfcn)
2883233Seric 	struct mailer *m;
2893233Seric 	char **pvp;
2903233Seric 	int (*editfcn)();
2913233Seric {
2923233Seric 	auto int st;
2933233Seric 	register int i;
2943233Seric 	int pid;
2953233Seric 	int pvect[2];
2963233Seric 	FILE *mfile;
2973233Seric 	extern putmessage();
2983233Seric 	extern pipesig();
2993233Seric 	extern FILE *fdopen();
3003233Seric 
3013233Seric # ifdef DEBUG
3023233Seric 	if (Debug)
303294Seric 	{
3043233Seric 		printf("Sendoff:\n");
3053233Seric 		printav(pvp);
306294Seric 	}
3073233Seric # endif DEBUG
3083233Seric 
3092898Seric 	/* create a pipe to shove the mail through */
3102898Seric 	if (pipe(pvect) < 0)
311294Seric 	{
312294Seric 		syserr("pipe");
313294Seric 		return (-1);
314294Seric 	}
3154052Seric 	for (i = NFORKTRIES; i-- > 0; )
3164052Seric 	{
3171504Smark # ifdef VFORK
3184052Seric 		pid = vfork();
3191504Smark # else
3204052Seric 		pid = fork();
3211504Smark # endif
3224052Seric 		if (pid >= 0)
3234052Seric 			break;
3244052Seric 		sleep(NFORKTRIES - i);
3254052Seric 	}
326294Seric 	if (pid < 0)
327294Seric 	{
328294Seric 		syserr("Cannot fork");
3292898Seric 		close(pvect[0]);
3302898Seric 		close(pvect[1]);
331294Seric 		return (-1);
332294Seric 	}
333294Seric 	else if (pid == 0)
334294Seric 	{
335294Seric 		/* child -- set up input & exec mailer */
3361621Seric 		/* make diagnostic output be standard output */
3371621Seric 		close(2);
3381621Seric 		dup(1);
339294Seric 		signal(SIGINT, SIG_IGN);
3402898Seric 		close(0);
3412898Seric 		if (dup(pvect[0]) < 0)
342294Seric 		{
3432898Seric 			syserr("Cannot dup to zero!");
3442898Seric 			_exit(EX_OSERR);
345294Seric 		}
3462898Seric 		close(pvect[0]);
3472898Seric 		close(pvect[1]);
3482968Seric 		if (!bitset(M_RESTR, m->m_flags))
349294Seric 			setuid(getuid());
3502774Seric # ifndef VFORK
3512774Seric 		/*
3522774Seric 		**  We have to be careful with vfork - we can't mung up the
3532774Seric 		**  memory but we don't want the mailer to inherit any extra
3542774Seric 		**  open files.  Chances are the mailer won't
3552774Seric 		**  care about an extra file, but then again you never know.
3562774Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
3572774Seric 		**  declared static so we can't.  But if we fclose(pwf), which
3582774Seric 		**  is what endpwent does, it closes it in the parent too and
3592774Seric 		**  the next getpwnam will be slower.  If you have a weird
3602774Seric 		**  mailer that chokes on the extra file you should do the
3612774Seric 		**  endpwent().
3622774Seric 		**
3632774Seric 		**  Similar comments apply to log.  However, openlog is
3642774Seric 		**  clever enough to set the FIOCLEX mode on the file,
3652774Seric 		**  so it will be closed automatically on the exec.
3662774Seric 		*/
3672774Seric 
3682774Seric 		endpwent();
369294Seric # ifdef LOG
3702089Seric 		closelog();
371294Seric # endif LOG
3722774Seric # endif VFORK
373294Seric 		execv(m->m_mailer, pvp);
374294Seric 		/* syserr fails because log is closed */
375294Seric 		/* syserr("Cannot exec %s", m->m_mailer); */
3762343Seric 		printf("Cannot exec %s\n", m->m_mailer);
3772343Seric 		fflush(stdout);
3781619Seric 		_exit(EX_UNAVAILABLE);
379294Seric 	}
380294Seric 
3812898Seric 	/* write out message to mailer */
3822898Seric 	close(pvect[0]);
3832898Seric 	signal(SIGPIPE, pipesig);
3842898Seric 	mfile = fdopen(pvect[1], "w");
3852898Seric 	if (editfcn == NULL)
3862898Seric 		editfcn = putmessage;
3872898Seric 	(*editfcn)(mfile, m);
3882898Seric 	fclose(mfile);
389294Seric 
390294Seric 	/*
391294Seric 	**  Wait for child to die and report status.
392294Seric 	**	We should never get fatal errors (e.g., segmentation
393294Seric 	**	violation), so we report those specially.  For other
394294Seric 	**	errors, we choose a status message (into statmsg),
395294Seric 	**	and if it represents an error, we print it.
396294Seric 	*/
397294Seric 
398294Seric 	while ((i = wait(&st)) > 0 && i != pid)
399294Seric 		continue;
400294Seric 	if (i < 0)
401294Seric 	{
402294Seric 		syserr("wait");
403294Seric 		return (-1);
404294Seric 	}
405294Seric 	if ((st & 0377) != 0)
406294Seric 	{
407294Seric 		syserr("%s: stat %o", pvp[0], st);
4081597Seric 		ExitStat = EX_UNAVAILABLE;
409294Seric 		return (-1);
410294Seric 	}
411294Seric 	i = (st >> 8) & 0377;
4122343Seric 	giveresponse(i, TRUE, m);
413294Seric 	return (i);
414294Seric }
415294Seric /*
416294Seric **  GIVERESPONSE -- Interpret an error response from a mailer
417294Seric **
418294Seric **	Parameters:
419294Seric **		stat -- the status code from the mailer (high byte
420294Seric **			only; core dumps must have been taken care of
421294Seric **			already).
422294Seric **		force -- if set, force an error message output, even
423294Seric **			if the mailer seems to like to print its own
424294Seric **			messages.
425294Seric **		m -- the mailer descriptor for this mailer.
426294Seric **
427294Seric **	Returns:
4282968Seric **		stat.
429294Seric **
430294Seric **	Side Effects:
4311518Seric **		Errors may be incremented.
432294Seric **		ExitStat may be set.
433294Seric **
434294Seric **	Called By:
435294Seric **		deliver
436294Seric */
437294Seric 
438294Seric giveresponse(stat, force, m)
439294Seric 	int stat;
440294Seric 	int force;
441294Seric 	register struct mailer *m;
442294Seric {
443294Seric 	register char *statmsg;
444294Seric 	extern char *SysExMsg[];
445294Seric 	register int i;
446294Seric 	extern int N_SysEx;
4471624Seric 	extern long MsgSize;
4481624Seric 	char buf[30];
4493044Seric 	extern char *sprintf();
450294Seric 
451294Seric 	i = stat - EX__BASE;
452294Seric 	if (i < 0 || i > N_SysEx)
453294Seric 		statmsg = NULL;
454294Seric 	else
455294Seric 		statmsg = SysExMsg[i];
456294Seric 	if (stat == 0)
4574065Seric 	{
458294Seric 		statmsg = "ok";
4594065Seric 		if (Verbose)
4604065Seric 			message("050", "ok");
4614065Seric 	}
462294Seric 	else
463294Seric 	{
4641518Seric 		Errors++;
465294Seric 		if (statmsg == NULL && m->m_badstat != 0)
466294Seric 		{
467294Seric 			stat = m->m_badstat;
468294Seric 			i = stat - EX__BASE;
469294Seric # ifdef DEBUG
470294Seric 			if (i < 0 || i >= N_SysEx)
471294Seric 				syserr("Bad m_badstat %d", stat);
472294Seric 			else
473294Seric # endif DEBUG
474294Seric 			statmsg = SysExMsg[i];
475294Seric 		}
476294Seric 		if (statmsg == NULL)
477294Seric 			usrerr("unknown mailer response %d", stat);
4784065Seric 		else if (force || !bitset(M_QUIET, m->m_flags) || Verbose)
479294Seric 			usrerr("%s", statmsg);
480294Seric 	}
481294Seric 
482294Seric 	/*
483294Seric 	**  Final cleanup.
484294Seric 	**	Log a record of the transaction.  Compute the new
485294Seric 	**	ExitStat -- if we already had an error, stick with
486294Seric 	**	that.
487294Seric 	*/
488294Seric 
4891624Seric 	if (statmsg == NULL)
4901624Seric 	{
4911624Seric 		sprintf(buf, "error %d", stat);
4921624Seric 		statmsg = buf;
4931624Seric 	}
4941624Seric 
495294Seric # ifdef LOG
4962774Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
497294Seric # endif LOG
4981389Seric 	setstat(stat);
499294Seric 	return (stat);
500294Seric }
501294Seric /*
5022898Seric **  PUTMESSAGE -- output a message to the final mailer.
503294Seric **
5042898Seric **	This routine takes care of recreating the header from the
5052898Seric **	in-core copy, etc.
506294Seric **
507294Seric **	Parameters:
5082898Seric **		fp -- file to output onto.
5092898Seric **		m -- a mailer descriptor.
510294Seric **
511294Seric **	Returns:
5122898Seric **		none.
513294Seric **
514294Seric **	Side Effects:
5152898Seric **		The message is written onto fp.
516294Seric */
517294Seric 
5182898Seric putmessage(fp, m)
5192898Seric 	FILE *fp;
5202898Seric 	struct mailer *m;
521294Seric {
5222898Seric 	char buf[BUFSIZ];
5232898Seric 	register int i;
5242898Seric 	HDR *h;
5251828Seric 	register char *p;
5262898Seric 	extern char *arpadate();
5272898Seric 	bool anyheader = FALSE;
5283186Seric 	extern char *expand();
5293044Seric 	extern char *capitalize();
530294Seric 
5313186Seric 	/* output "From" line unless supressed */
5323186Seric 	if (!bitset(M_NHDR, m->m_flags))
5333186Seric 		fprintf(fp, "%s\n", FromLine);
5343186Seric 
5353385Seric 	/* output all header lines */
5362898Seric 	for (h = Header; h != NULL; h = h->h_link)
5371828Seric 	{
5383389Seric 		if (bitset(H_DELETE, h->h_flags))
5393385Seric 			continue;
5403389Seric 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags))
5413389Seric 			continue;
5423385Seric 		if (bitset(H_DEFAULT, h->h_flags))
5433385Seric 		{
5443385Seric 			expand(h->h_value, buf, &buf[sizeof buf]);
5453385Seric 			p = buf;
5463385Seric 		}
5472898Seric 		else
5483385Seric 			p = h->h_value;
5493389Seric 		if (*p == '\0')
5503389Seric 			continue;
5513385Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), p);
5522898Seric 		h->h_flags |= H_USED;
5532898Seric 		anyheader = TRUE;
5542898Seric 	}
5552898Seric 
5562898Seric 	if (anyheader)
5572898Seric 		fprintf(fp, "\n");
5582898Seric 
5592898Seric 	/* output the body of the message */
5604062Seric 	rewind(stdin);
5614062Seric 	while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, stdin)) > 0)
5622898Seric 		fwrite(buf, 1, i, fp);
5632898Seric 
564294Seric 	if (ferror(fp))
565294Seric 	{
5662898Seric 		syserr("putmessage: write error");
567294Seric 		setstat(EX_IOERR);
568294Seric 	}
569294Seric }
570294Seric /*
571294Seric **  PIPESIG -- Handle broken pipe signals
572294Seric **
573294Seric **	This just logs an error.
574294Seric **
575294Seric **	Parameters:
576294Seric **		none
577294Seric **
578294Seric **	Returns:
579294Seric **		none
580294Seric **
581294Seric **	Side Effects:
582294Seric **		logs an error message.
583294Seric */
584294Seric 
585294Seric pipesig()
586294Seric {
587294Seric 	syserr("Broken pipe");
5881621Seric 	signal(SIGPIPE, SIG_IGN);
589294Seric }
590294Seric /*
591294Seric **  SENDTO -- Designate a send list.
592294Seric **
593294Seric **	The parameter is a comma-separated list of people to send to.
594294Seric **	This routine arranges to send to all of them.
595294Seric **
596294Seric **	Parameters:
597294Seric **		list -- the send list.
598294Seric **		copyf -- the copy flag; passed to parse.
599294Seric **
600294Seric **	Returns:
601294Seric **		none
602294Seric **
603294Seric **	Side Effects:
604294Seric **		none.
605294Seric */
606294Seric 
607294Seric sendto(list, copyf)
608294Seric 	char *list;
609294Seric 	int copyf;
610294Seric {
611294Seric 	register char *p;
612294Seric 	register char *q;
613294Seric 	register char c;
6142968Seric 	ADDRESS *a;
6152968Seric 	extern ADDRESS *parse();
616294Seric 	bool more;
617294Seric 
618294Seric 	/* more keeps track of what the previous delimiter was */
619294Seric 	more = TRUE;
620294Seric 	for (p = list; more; )
621294Seric 	{
622294Seric 		/* find the end of this address */
623294Seric 		q = p;
624294Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
625294Seric 			continue;
626294Seric 		more = c != '\0';
627294Seric 		*--p = '\0';
628294Seric 		if (more)
629294Seric 			p++;
630294Seric 
631294Seric 		/* parse the address */
6322968Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
633294Seric 			continue;
634294Seric 
635294Seric 		/* arrange to send to this person */
6363186Seric 		recipient(a);
637294Seric 	}
638294Seric 	To = NULL;
639294Seric }
640294Seric /*
641294Seric **  RECIPIENT -- Designate a message recipient
642294Seric **
643294Seric **	Saves the named person for future mailing.
644294Seric **
645294Seric **	Parameters:
646294Seric **		a -- the (preparsed) address header for the recipient.
647294Seric **
648294Seric **	Returns:
649294Seric **		none.
650294Seric **
651294Seric **	Side Effects:
652294Seric **		none.
653294Seric */
654294Seric 
6553186Seric recipient(a)
6562968Seric 	register ADDRESS *a;
657294Seric {
6582968Seric 	register ADDRESS *q;
659294Seric 	register struct mailer *m;
660294Seric 	extern bool forward();
661294Seric 	extern int errno;
662294Seric 	extern bool sameaddr();
663294Seric 
664294Seric 	To = a->q_paddr;
6653047Seric 	m = Mailer[a->q_mailer];
666294Seric 	errno = 0;
667294Seric # ifdef DEBUG
668294Seric 	if (Debug)
669294Seric 		printf("recipient(%s)\n", To);
670294Seric # endif DEBUG
671294Seric 
672294Seric 	/*
6733186Seric 	**  Do sickly crude mapping for program mailing, etc.
6743186Seric 	*/
6753186Seric 
676*4078Seric 	if (a->q_mailer == M_LOCAL)
6773186Seric 	{
678*4078Seric 		if (a->q_user[0] == '|')
679*4078Seric 		{
680*4078Seric 			a->q_mailer = M_PROG;
681*4078Seric 			m = Mailer[M_PROG];
682*4078Seric 			a->q_user++;
683*4078Seric 		}
684*4078Seric 		else
685*4078Seric 		{
686*4078Seric 			register struct passwd *pw;
687*4078Seric 
688*4078Seric 			pw = getpwnam(a->q_user);
689*4078Seric 			if (pw == NULL)
690*4078Seric 				a->q_flags |= QBADADDR;
691*4078Seric 			else
692*4078Seric 			{
693*4078Seric 				char xbuf[60];
694*4078Seric 
695*4078Seric 				a->q_home = newstr(pw->pw_dir);
696*4078Seric 				define('z', a->q_home);
697*4078Seric 				expand("$z/.mailer", xbuf, &xbuf[sizeof xbuf - 1]);
698*4078Seric 				if (access(xbuf, 1) == 0)
699*4078Seric 				{
700*4078Seric 					a->q_mailer = M_PRIVATE;
701*4078Seric 					m = Mailer[M_PROG];
702*4078Seric 				}
703*4078Seric 			}
704*4078Seric 		}
7053186Seric 	}
7063186Seric 
7073186Seric 	/*
708294Seric 	**  Look up this person in the recipient list.  If they
709294Seric 	**  are there already, return, otherwise continue.
7103186Seric 	**  If the list is empty, just add it.
711294Seric 	*/
712294Seric 
7133186Seric 	if (m->m_sendq == NULL)
714294Seric 	{
7153186Seric 		m->m_sendq = a;
7163186Seric 	}
7173186Seric 	else
7183186Seric 	{
7193186Seric 		ADDRESS *pq;
7203186Seric 
7213186Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
7223186Seric 		{
7233186Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
724294Seric 			{
725294Seric # ifdef DEBUG
726294Seric 				if (Debug)
7273186Seric 					printf("(%s in sendq)\n", a->q_paddr);
728294Seric # endif DEBUG
7294067Seric 				if (Verbose && !bitset(QDONTSEND, a->q_flags))
7304065Seric 					message("050", "duplicate supressed");
731294Seric 				return;
732294Seric 			}
7333186Seric 		}
7343186Seric 
7353186Seric 		/* add address on list */
7363186Seric 		q = pq;
7373233Seric 		q->q_next = a;
738294Seric 	}
7393186Seric 	a->q_next = NULL;
740294Seric 
741294Seric 	/*
742294Seric 	**  See if the user wants hir mail forwarded.
743294Seric 	**	`Forward' must do the forwarding recursively.
744294Seric 	*/
745294Seric 
746*4078Seric 	if (m == Mailer[M_LOCAL] && !NoAlias && forward(a))
7474067Seric 		a->q_flags |= QDONTSEND;
748294Seric 
749294Seric 	return;
750294Seric }
751294Seric /*
752294Seric **  MAILFILE -- Send a message to a file.
753294Seric **
754294Seric **	Parameters:
755294Seric **		filename -- the name of the file to send to.
756294Seric **
757294Seric **	Returns:
758294Seric **		The exit code associated with the operation.
759294Seric **
760294Seric **	Side Effects:
761294Seric **		none.
762294Seric **
763294Seric **	Called By:
764294Seric **		deliver
765294Seric */
766294Seric 
767294Seric mailfile(filename)
768294Seric 	char *filename;
769294Seric {
770294Seric 	register FILE *f;
771294Seric 
772294Seric 	f = fopen(filename, "a");
773294Seric 	if (f == NULL)
774294Seric 		return (EX_CANTCREAT);
7754067Seric 
7763186Seric 	putmessage(f, Mailer[1]);
777294Seric 	fputs("\n", f);
778294Seric 	fclose(f);
779294Seric 	return (EX_OK);
780294Seric }
781