1294Seric # include <stdio.h>
2294Seric # include <pwd.h>
3294Seric # include <signal.h>
42898Seric # include <ctype.h>
54123Seric # include <errno.h>
63310Seric # include "sendmail.h"
7294Seric # ifdef LOG
82774Seric # include <syslog.h>
9294Seric # endif LOG
10294Seric 
11*4166Seric static char SccsId[] = "@(#)deliver.c	3.23	08/18/81";
12405Seric 
13294Seric /*
14294Seric **  DELIVER -- Deliver a message to a particular address.
15294Seric **
16294Seric **	Parameters:
17294Seric **		to -- the address to deliver the message to.
18294Seric **		editfcn -- if non-NULL, we want to call this function
19294Seric **			to output the letter (instead of just out-
20294Seric **			putting it raw).
21294Seric **
22294Seric **	Returns:
23294Seric **		zero -- successfully delivered.
24294Seric **		else -- some failure, see ExitStat for more info.
25294Seric **
26294Seric **	Side Effects:
27294Seric **		The standard input is passed off to someone.
28294Seric */
29294Seric 
30294Seric deliver(to, editfcn)
312968Seric 	ADDRESS *to;
32294Seric 	int (*editfcn)();
33294Seric {
34294Seric 	char *host;
35294Seric 	char *user;
36294Seric 	char **pvp;
373233Seric 	register char **mvp;
383233Seric 	register char *p;
393233Seric 	register struct mailer *m;
40294Seric 	register int i;
412898Seric 	extern putmessage();
422968Seric 	extern bool checkcompat();
433233Seric 	char *pv[MAXPV+1];
443233Seric 	char tobuf[MAXLINE];
453233Seric 	char buf[MAXNAME];
463233Seric 	bool firstone;
47294Seric 
483233Seric 	if (bitset(QDONTSEND, to->q_flags))
493233Seric 		return (0);
50294Seric 
51294Seric # ifdef DEBUG
52294Seric 	if (Debug)
533233Seric 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
543233Seric 			to->q_mailer, to->q_host, to->q_user);
55294Seric # endif DEBUG
56294Seric 
57294Seric 	/*
583233Seric 	**  Do initial argv setup.
593233Seric 	**	Insert the mailer name.  Notice that $x expansion is
603233Seric 	**	NOT done on the mailer name.  Then, if the mailer has
613233Seric 	**	a picky -f flag, we insert it as appropriate.  This
623233Seric 	**	code does not check for 'pv' overflow; this places a
633233Seric 	**	manifest lower limit of 4 for MAXPV.
642968Seric 	*/
652968Seric 
663233Seric 	m = Mailer[to->q_mailer];
673233Seric 	host = to->q_host;
683233Seric 	define('g', m->m_from);		/* translated from address */
693233Seric 	define('h', host);		/* to host */
703233Seric 	Errors = 0;
713233Seric 	errno = 0;
723233Seric 	pvp = pv;
733233Seric 	*pvp++ = m->m_argv[0];
742968Seric 
753233Seric 	/* insert -f or -r flag as appropriate */
763233Seric 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
773233Seric 	{
783233Seric 		if (bitset(M_FOPT, m->m_flags))
793233Seric 			*pvp++ = "-f";
803233Seric 		else
813233Seric 			*pvp++ = "-r";
824082Seric 		(void) expand("$g", buf, &buf[sizeof buf - 1]);
833233Seric 		*pvp++ = newstr(buf);
843233Seric 	}
85294Seric 
86294Seric 	/*
873233Seric 	**  Append the other fixed parts of the argv.  These run
883233Seric 	**  up to the first entry containing "$u".  There can only
893233Seric 	**  be one of these, and there are only a few more slots
903233Seric 	**  in the pv after it.
91294Seric 	*/
92294Seric 
933233Seric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
94294Seric 	{
953233Seric 		while ((p = index(p, '$')) != NULL)
963233Seric 			if (*++p == 'u')
973233Seric 				break;
983233Seric 		if (p != NULL)
993233Seric 			break;
1003233Seric 
1013233Seric 		/* this entry is safe -- go ahead and process it */
1024082Seric 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
1033233Seric 		*pvp++ = newstr(buf);
1043233Seric 		if (pvp >= &pv[MAXPV - 3])
1053233Seric 		{
1063233Seric 			syserr("Too many parameters to %s before $u", pv[0]);
1073233Seric 			return (-1);
1083233Seric 		}
109294Seric 	}
1103233Seric 	if (*mvp == NULL)
1113233Seric 		syserr("No $u in mailer argv for %s", pv[0]);
112294Seric 
113294Seric 	/*
1143233Seric 	**  At this point *mvp points to the argument with $u.  We
1153233Seric 	**  run through our address list and append all the addresses
1163233Seric 	**  we can.  If we run out of space, do not fret!  We can
1173233Seric 	**  always send another copy later.
118294Seric 	*/
119294Seric 
1203233Seric 	tobuf[0] = '\0';
1213233Seric 	firstone = TRUE;
1223233Seric 	To = tobuf;
1233233Seric 	for (; to != NULL; to = to->q_next)
124294Seric 	{
1253233Seric 		/* avoid sending multiple recipients to dumb mailers */
1263233Seric 		if (!firstone && !bitset(M_MUSER, m->m_flags))
1273233Seric 			break;
1283233Seric 
1293233Seric 		/* if already sent or not for this host, don't send */
1303233Seric 		if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0)
1313233Seric 			continue;
1323233Seric 		user = to->q_user;
1333233Seric 		To = to->q_paddr;
1343233Seric 		to->q_flags |= QDONTSEND;
1353233Seric 		firstone = FALSE;
1363233Seric 
1373233Seric # ifdef DEBUG
1383233Seric 		if (Debug)
1393233Seric 			printf("   send to `%s'\n", user);
1403233Seric # endif DEBUG
1413233Seric 
1423233Seric 		/*
1433233Seric 		**  Check to see that these people are allowed to
1443233Seric 		**  talk to each other.
1453233Seric 		*/
1463233Seric 
1473233Seric 		if (!checkcompat(to))
148294Seric 		{
1493233Seric 			giveresponse(EX_UNAVAILABLE, TRUE, m);
1503233Seric 			continue;
151294Seric 		}
1523233Seric 
1533233Seric 		/*
1544099Seric 		**  Strip quote bits from names if the mailer is dumb
1554099Seric 		**	about them.
1563233Seric 		*/
1573233Seric 
1583233Seric 		if (bitset(M_STRIPQ, m->m_flags))
159294Seric 		{
1604099Seric 			stripquotes(user, TRUE);
1614099Seric 			stripquotes(host, TRUE);
1623233Seric 		}
1634099Seric 		else
1644099Seric 		{
1654099Seric 			stripquotes(user, FALSE);
1664099Seric 			stripquotes(host, FALSE);
1674099Seric 		}
1683233Seric 
1693233Seric 		/*
1704161Seric 		**  If an error message has already been given, don't
1714161Seric 		**	bother to send to this address.
1724161Seric 		**
1734161Seric 		**	>>>>>>>>>> This clause assumes that the local mailer
1744161Seric 		**	>> NOTE >> cannot do any further aliasing; that
1754161Seric 		**	>>>>>>>>>> function is subsumed by sendmail.
1764161Seric 		*/
1774161Seric 
1784161Seric 		if (bitset(QBADADDR, to->q_flags))
1794161Seric 			continue;
1804161Seric 
1814161Seric 		/*
1823233Seric 		**  See if this user name is "special".
1833233Seric 		**	If the user name has a slash in it, assume that this
1843233Seric 		**	is a file -- send it off without further ado.
1853233Seric 		**	Note that this means that editfcn's will not
1863233Seric 		**	be applied to the message.  Also note that
1873233Seric 		**	this type of addresses is not processed along
1883233Seric 		**	with the others, so we fudge on the To person.
1893233Seric 		*/
1903233Seric 
1914078Seric 		if (m == Mailer[M_LOCAL])
1923233Seric 		{
193294Seric 			if (index(user, '/') != NULL)
194294Seric 			{
195294Seric 				i = mailfile(user);
196294Seric 				giveresponse(i, TRUE, m);
1973233Seric 				continue;
198294Seric 			}
199294Seric 		}
2003233Seric 
2013233Seric 		/* create list of users for error messages */
2023233Seric 		if (tobuf[0] != '\0')
2034082Seric 			(void) strcat(tobuf, ",");
2044082Seric 		(void) strcat(tobuf, to->q_paddr);
2053233Seric 		define('u', user);		/* to user */
2064078Seric 		define('z', to->q_home);	/* user's home */
2073233Seric 
2083233Seric 		/* expand out this user */
2094082Seric 		(void) expand(user, buf, &buf[sizeof buf - 1]);
2103233Seric 		*pvp++ = newstr(buf);
2113233Seric 		if (pvp >= &pv[MAXPV - 2])
2123233Seric 		{
2133233Seric 			/* allow some space for trailing parms */
2143233Seric 			break;
2153233Seric 		}
216294Seric 	}
217294Seric 
2184067Seric 	/* see if any addresses still exist */
2194067Seric 	if (tobuf[0] == '\0')
2204067Seric 		return (0);
2214067Seric 
2223233Seric 	/* print out messages as full list */
2233233Seric 	To = tobuf;
2243233Seric 
225294Seric 	/*
2263233Seric 	**  Fill out any parameters after the $u parameter.
227294Seric 	*/
228294Seric 
2293233Seric 	while (*++mvp != NULL)
230294Seric 	{
2314082Seric 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
2323233Seric 		*pvp++ = newstr(buf);
2333233Seric 		if (pvp >= &pv[MAXPV])
2343233Seric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
235294Seric 	}
2363233Seric 	*pvp++ = NULL;
237294Seric 
238294Seric 	/*
239294Seric 	**  Call the mailer.
2402898Seric 	**	The argument vector gets built, pipes
241294Seric 	**	are created as necessary, and we fork & exec as
2422898Seric 	**	appropriate.
2434078Seric 	**
2444078Seric 	**	Notice the tacky hack to handle private mailers.
245294Seric 	*/
246294Seric 
2473233Seric 	if (editfcn == NULL)
2483233Seric 		editfcn = putmessage;
2493233Seric 	i = sendoff(m, pv, editfcn);
2503233Seric 
2513233Seric 	return (i);
2523233Seric }
2533233Seric /*
2543233Seric **  SENDOFF -- send off call to mailer & collect response.
2553233Seric **
2563233Seric **	Parameters:
2573233Seric **		m -- mailer descriptor.
2583233Seric **		pvp -- parameter vector to send to it.
2593233Seric **		editfcn -- function to pipe it through.
2603233Seric **
2613233Seric **	Returns:
2623233Seric **		exit status of mailer.
2633233Seric **
2643233Seric **	Side Effects:
2653233Seric **		none.
2663233Seric */
2673233Seric 
2684052Seric #define NFORKTRIES	5
2694052Seric 
2703233Seric sendoff(m, pvp, editfcn)
2713233Seric 	struct mailer *m;
2723233Seric 	char **pvp;
2733233Seric 	int (*editfcn)();
2743233Seric {
2753233Seric 	auto int st;
2763233Seric 	register int i;
2773233Seric 	int pid;
2783233Seric 	int pvect[2];
2793233Seric 	FILE *mfile;
2803233Seric 	extern putmessage();
2813233Seric 	extern FILE *fdopen();
2823233Seric 
2833233Seric # ifdef DEBUG
2843233Seric 	if (Debug)
285294Seric 	{
2863233Seric 		printf("Sendoff:\n");
2873233Seric 		printav(pvp);
288294Seric 	}
2893233Seric # endif DEBUG
2903233Seric 
2912898Seric 	/* create a pipe to shove the mail through */
2922898Seric 	if (pipe(pvect) < 0)
293294Seric 	{
294294Seric 		syserr("pipe");
295294Seric 		return (-1);
296294Seric 	}
2974052Seric 	for (i = NFORKTRIES; i-- > 0; )
2984052Seric 	{
2991504Smark # ifdef VFORK
3004052Seric 		pid = vfork();
3011504Smark # else
3024052Seric 		pid = fork();
3031504Smark # endif
3044052Seric 		if (pid >= 0)
3054052Seric 			break;
3064082Seric 		sleep((unsigned) NFORKTRIES - i);
3074052Seric 	}
308294Seric 	if (pid < 0)
309294Seric 	{
310294Seric 		syserr("Cannot fork");
3114082Seric 		(void) close(pvect[0]);
3124082Seric 		(void) close(pvect[1]);
313294Seric 		return (-1);
314294Seric 	}
315294Seric 	else if (pid == 0)
316294Seric 	{
317294Seric 		/* child -- set up input & exec mailer */
3181621Seric 		/* make diagnostic output be standard output */
3194082Seric 		(void) close(2);
3204082Seric 		(void) dup(1);
3214082Seric 		(void) signal(SIGINT, SIG_IGN);
3224082Seric 		(void) close(0);
3232898Seric 		if (dup(pvect[0]) < 0)
324294Seric 		{
3252898Seric 			syserr("Cannot dup to zero!");
3262898Seric 			_exit(EX_OSERR);
327294Seric 		}
3284082Seric 		(void) close(pvect[0]);
3294082Seric 		(void) close(pvect[1]);
3302968Seric 		if (!bitset(M_RESTR, m->m_flags))
3314082Seric 			(void) setuid(getuid());
3322774Seric # ifndef VFORK
3332774Seric 		/*
3342774Seric 		**  We have to be careful with vfork - we can't mung up the
3352774Seric 		**  memory but we don't want the mailer to inherit any extra
3362774Seric 		**  open files.  Chances are the mailer won't
3372774Seric 		**  care about an extra file, but then again you never know.
3382774Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
3392774Seric 		**  declared static so we can't.  But if we fclose(pwf), which
3402774Seric 		**  is what endpwent does, it closes it in the parent too and
3412774Seric 		**  the next getpwnam will be slower.  If you have a weird
3422774Seric 		**  mailer that chokes on the extra file you should do the
3432774Seric 		**  endpwent().
3442774Seric 		**
3452774Seric 		**  Similar comments apply to log.  However, openlog is
3462774Seric 		**  clever enough to set the FIOCLEX mode on the file,
3472774Seric 		**  so it will be closed automatically on the exec.
3482774Seric 		*/
3492774Seric 
3502774Seric 		endpwent();
351294Seric # ifdef LOG
3522089Seric 		closelog();
353294Seric # endif LOG
3542774Seric # endif VFORK
355294Seric 		execv(m->m_mailer, pvp);
356294Seric 		/* syserr fails because log is closed */
357294Seric 		/* syserr("Cannot exec %s", m->m_mailer); */
3582343Seric 		printf("Cannot exec %s\n", m->m_mailer);
3594082Seric 		(void) fflush(stdout);
3601619Seric 		_exit(EX_UNAVAILABLE);
361294Seric 	}
362294Seric 
3632898Seric 	/* write out message to mailer */
3644082Seric 	(void) close(pvect[0]);
3654123Seric 	(void) signal(SIGPIPE, SIG_IGN);
3662898Seric 	mfile = fdopen(pvect[1], "w");
3672898Seric 	if (editfcn == NULL)
3682898Seric 		editfcn = putmessage;
3692898Seric 	(*editfcn)(mfile, m);
3704082Seric 	(void) fclose(mfile);
371294Seric 
372294Seric 	/*
373294Seric 	**  Wait for child to die and report status.
374294Seric 	**	We should never get fatal errors (e.g., segmentation
375294Seric 	**	violation), so we report those specially.  For other
376294Seric 	**	errors, we choose a status message (into statmsg),
377294Seric 	**	and if it represents an error, we print it.
378294Seric 	*/
379294Seric 
380294Seric 	while ((i = wait(&st)) > 0 && i != pid)
381294Seric 		continue;
382294Seric 	if (i < 0)
383294Seric 	{
384294Seric 		syserr("wait");
385294Seric 		return (-1);
386294Seric 	}
387294Seric 	if ((st & 0377) != 0)
388294Seric 	{
389294Seric 		syserr("%s: stat %o", pvp[0], st);
3901597Seric 		ExitStat = EX_UNAVAILABLE;
391294Seric 		return (-1);
392294Seric 	}
393294Seric 	i = (st >> 8) & 0377;
3942343Seric 	giveresponse(i, TRUE, m);
395294Seric 	return (i);
396294Seric }
397294Seric /*
398294Seric **  GIVERESPONSE -- Interpret an error response from a mailer
399294Seric **
400294Seric **	Parameters:
401294Seric **		stat -- the status code from the mailer (high byte
402294Seric **			only; core dumps must have been taken care of
403294Seric **			already).
404294Seric **		force -- if set, force an error message output, even
405294Seric **			if the mailer seems to like to print its own
406294Seric **			messages.
407294Seric **		m -- the mailer descriptor for this mailer.
408294Seric **
409294Seric **	Returns:
4104082Seric **		none.
411294Seric **
412294Seric **	Side Effects:
4131518Seric **		Errors may be incremented.
414294Seric **		ExitStat may be set.
415294Seric **
416294Seric **	Called By:
417294Seric **		deliver
418294Seric */
419294Seric 
420294Seric giveresponse(stat, force, m)
421294Seric 	int stat;
422294Seric 	int force;
423294Seric 	register struct mailer *m;
424294Seric {
425294Seric 	register char *statmsg;
426294Seric 	extern char *SysExMsg[];
427294Seric 	register int i;
428294Seric 	extern int N_SysEx;
4291624Seric 	extern long MsgSize;
4301624Seric 	char buf[30];
431294Seric 
432294Seric 	i = stat - EX__BASE;
433294Seric 	if (i < 0 || i > N_SysEx)
434294Seric 		statmsg = NULL;
435294Seric 	else
436294Seric 		statmsg = SysExMsg[i];
437294Seric 	if (stat == 0)
4384065Seric 	{
4394161Seric 		if (bitset(M_FINAL, m->m_flags))
4404161Seric 			statmsg = "delivered";
4414161Seric 		else
4424161Seric 			statmsg = "queued";
4434065Seric 		if (Verbose)
444*4166Seric 			message(Arpa_Info, statmsg);
4454065Seric 	}
446294Seric 	else
447294Seric 	{
4481518Seric 		Errors++;
449294Seric 		if (statmsg == NULL && m->m_badstat != 0)
450294Seric 		{
451294Seric 			stat = m->m_badstat;
452294Seric 			i = stat - EX__BASE;
453294Seric # ifdef DEBUG
454294Seric 			if (i < 0 || i >= N_SysEx)
455294Seric 				syserr("Bad m_badstat %d", stat);
456294Seric 			else
457294Seric # endif DEBUG
458294Seric 			statmsg = SysExMsg[i];
459294Seric 		}
460294Seric 		if (statmsg == NULL)
461294Seric 			usrerr("unknown mailer response %d", stat);
4624065Seric 		else if (force || !bitset(M_QUIET, m->m_flags) || Verbose)
463294Seric 			usrerr("%s", statmsg);
464294Seric 	}
465294Seric 
466294Seric 	/*
467294Seric 	**  Final cleanup.
468294Seric 	**	Log a record of the transaction.  Compute the new
469294Seric 	**	ExitStat -- if we already had an error, stick with
470294Seric 	**	that.
471294Seric 	*/
472294Seric 
4731624Seric 	if (statmsg == NULL)
4741624Seric 	{
4754082Seric 		(void) sprintf(buf, "error %d", stat);
4761624Seric 		statmsg = buf;
4771624Seric 	}
4781624Seric 
479294Seric # ifdef LOG
4802774Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
481294Seric # endif LOG
4821389Seric 	setstat(stat);
483294Seric }
484294Seric /*
4852898Seric **  PUTMESSAGE -- output a message to the final mailer.
486294Seric **
4872898Seric **	This routine takes care of recreating the header from the
4882898Seric **	in-core copy, etc.
489294Seric **
490294Seric **	Parameters:
4912898Seric **		fp -- file to output onto.
4922898Seric **		m -- a mailer descriptor.
493294Seric **
494294Seric **	Returns:
4952898Seric **		none.
496294Seric **
497294Seric **	Side Effects:
4982898Seric **		The message is written onto fp.
499294Seric */
500294Seric 
5012898Seric putmessage(fp, m)
5022898Seric 	FILE *fp;
5032898Seric 	struct mailer *m;
504294Seric {
5052898Seric 	char buf[BUFSIZ];
5062898Seric 	register int i;
5072898Seric 	HDR *h;
5081828Seric 	register char *p;
5092898Seric 	extern char *arpadate();
5102898Seric 	bool anyheader = FALSE;
5113044Seric 	extern char *capitalize();
512294Seric 
5133186Seric 	/* output "From" line unless supressed */
5143186Seric 	if (!bitset(M_NHDR, m->m_flags))
5153186Seric 		fprintf(fp, "%s\n", FromLine);
5163186Seric 
5173385Seric 	/* output all header lines */
5182898Seric 	for (h = Header; h != NULL; h = h->h_link)
5191828Seric 	{
5203389Seric 		if (bitset(H_DELETE, h->h_flags))
5213385Seric 			continue;
5223389Seric 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags))
5233389Seric 			continue;
5243385Seric 		if (bitset(H_DEFAULT, h->h_flags))
5253385Seric 		{
5264082Seric 			(void) expand(h->h_value, buf, &buf[sizeof buf]);
5273385Seric 			p = buf;
5283385Seric 		}
5292898Seric 		else
5303385Seric 			p = h->h_value;
5313389Seric 		if (*p == '\0')
5323389Seric 			continue;
5333385Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), p);
5342898Seric 		h->h_flags |= H_USED;
5352898Seric 		anyheader = TRUE;
5362898Seric 	}
5372898Seric 
5382898Seric 	if (anyheader)
5392898Seric 		fprintf(fp, "\n");
5402898Seric 
5412898Seric 	/* output the body of the message */
5424062Seric 	rewind(stdin);
5434062Seric 	while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, stdin)) > 0)
5444082Seric 		(void) fwrite(buf, 1, i, fp);
5452898Seric 
5464123Seric 	if (ferror(fp) && errno != EPIPE)
547294Seric 	{
5482898Seric 		syserr("putmessage: write error");
549294Seric 		setstat(EX_IOERR);
550294Seric 	}
5514123Seric 	errno = 0;
552294Seric }
553294Seric /*
554294Seric **  SENDTO -- Designate a send list.
555294Seric **
556294Seric **	The parameter is a comma-separated list of people to send to.
557294Seric **	This routine arranges to send to all of them.
558294Seric **
559294Seric **	Parameters:
560294Seric **		list -- the send list.
561294Seric **		copyf -- the copy flag; passed to parse.
562294Seric **
563294Seric **	Returns:
564294Seric **		none
565294Seric **
566294Seric **	Side Effects:
567294Seric **		none.
568294Seric */
569294Seric 
5704099Seric # define MAXRCRSN	10
5714099Seric 
572294Seric sendto(list, copyf)
573294Seric 	char *list;
574294Seric 	int copyf;
575294Seric {
576294Seric 	register char *p;
577294Seric 	register char *q;
578294Seric 	register char c;
5792968Seric 	ADDRESS *a;
580294Seric 	bool more;
581294Seric 
582294Seric 	/* more keeps track of what the previous delimiter was */
583294Seric 	more = TRUE;
584294Seric 	for (p = list; more; )
585294Seric 	{
586294Seric 		/* find the end of this address */
5874159Seric 		while (*p == ' ' || *p == '\t')
5884159Seric 			p++;
589294Seric 		q = p;
590294Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
591294Seric 			continue;
592294Seric 		more = c != '\0';
593294Seric 		*--p = '\0';
594294Seric 		if (more)
595294Seric 			p++;
596294Seric 
597294Seric 		/* parse the address */
5982968Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
599294Seric 			continue;
600294Seric 
601294Seric 		/* arrange to send to this person */
6023186Seric 		recipient(a);
603294Seric 	}
604294Seric 	To = NULL;
605294Seric }
606294Seric /*
607294Seric **  RECIPIENT -- Designate a message recipient
608294Seric **
609294Seric **	Saves the named person for future mailing.
610294Seric **
611294Seric **	Parameters:
612294Seric **		a -- the (preparsed) address header for the recipient.
613294Seric **
614294Seric **	Returns:
615294Seric **		none.
616294Seric **
617294Seric **	Side Effects:
618294Seric **		none.
619294Seric */
620294Seric 
6213186Seric recipient(a)
6222968Seric 	register ADDRESS *a;
623294Seric {
6242968Seric 	register ADDRESS *q;
625294Seric 	register struct mailer *m;
6264099Seric 	char buf[MAXNAME];
627294Seric 
628294Seric 	To = a->q_paddr;
6293047Seric 	m = Mailer[a->q_mailer];
630294Seric 	errno = 0;
631294Seric # ifdef DEBUG
632294Seric 	if (Debug)
633294Seric 		printf("recipient(%s)\n", To);
634294Seric # endif DEBUG
635294Seric 
6364099Seric 	/* break aliasing loops */
6374099Seric 	if (AliasLevel > MAXRCRSN)
6384099Seric 	{
6394099Seric 		usrerr("aliasing/forwarding loop broken");
6404099Seric 		return;
6414099Seric 	}
6424099Seric 
643294Seric 	/*
6443186Seric 	**  Do sickly crude mapping for program mailing, etc.
6453186Seric 	*/
6463186Seric 
6474078Seric 	if (a->q_mailer == M_LOCAL)
6483186Seric 	{
6494078Seric 		if (a->q_user[0] == '|')
6504078Seric 		{
6514078Seric 			a->q_mailer = M_PROG;
6524078Seric 			m = Mailer[M_PROG];
6534078Seric 			a->q_user++;
6544078Seric 		}
6553186Seric 	}
6563186Seric 
6573186Seric 	/*
658294Seric 	**  Look up this person in the recipient list.  If they
659294Seric 	**  are there already, return, otherwise continue.
6603186Seric 	**  If the list is empty, just add it.
661294Seric 	*/
662294Seric 
6633186Seric 	if (m->m_sendq == NULL)
664294Seric 	{
6653186Seric 		m->m_sendq = a;
6663186Seric 	}
6673186Seric 	else
6683186Seric 	{
6693186Seric 		ADDRESS *pq;
6703186Seric 
6713186Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
6723186Seric 		{
6733186Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
674294Seric 			{
675294Seric # ifdef DEBUG
676294Seric 				if (Debug)
6773186Seric 					printf("(%s in sendq)\n", a->q_paddr);
678294Seric # endif DEBUG
6794067Seric 				if (Verbose && !bitset(QDONTSEND, a->q_flags))
680*4166Seric 					message(Arpa_Info, "duplicate supressed");
681294Seric 				return;
682294Seric 			}
6833186Seric 		}
6843186Seric 
6853186Seric 		/* add address on list */
6863186Seric 		q = pq;
6873233Seric 		q->q_next = a;
688294Seric 	}
6893186Seric 	a->q_next = NULL;
690294Seric 
691294Seric 	/*
6924159Seric 	**  Alias the name and handle :include: specs.
693294Seric 	*/
694294Seric 
6954099Seric 	if (a->q_mailer == M_LOCAL)
6964159Seric 	{
6974159Seric 		if (strncmp(a->q_user, ":include:", 9) == 0)
6984159Seric 		{
6994159Seric 			a->q_flags |= QDONTSEND;
7004159Seric 			include(&a->q_user[9]);
7014159Seric 		}
7024159Seric 		else
7034159Seric 			alias(a);
7044159Seric 	}
705294Seric 
7064099Seric 	/*
7074099Seric 	**  If the user is local and still being sent, verify that
7084099Seric 	**  the address is good.  If it is, try to forward.
7094099Seric 	**  If the address is already good, we have a forwarding
7104099Seric 	**  loop.  This can be broken by just sending directly to
7114099Seric 	**  the user (which is probably correct anyway).
7124099Seric 	*/
7134099Seric 
7144161Seric 	if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == M_LOCAL)
7154099Seric 	{
7164099Seric 		char buf[MAXNAME];
7174099Seric 
7184099Seric 		strcpy(buf, a->q_user);
7194099Seric 		stripquotes(buf, TRUE);
7204161Seric 
7214161Seric 		/* see if this is to a file */
7224161Seric 		if (index(buf, '/') != NULL)
7234161Seric 		{
7244161Seric 			if (access(buf, 2) < 0)
7254161Seric 			{
7264161Seric 				a->q_flags |= QBADADDR;
7274161Seric 				giveresponse(EX_CANTCREAT, TRUE, m);
7284161Seric 			}
7294161Seric 		}
7304099Seric 		else
7314105Seric 		{
7324161Seric 			register struct passwd *pw;
7334161Seric 			extern struct passwd *getpwnam();
7344161Seric 			pw = getpwnam(buf);
7354161Seric 			if (pw == NULL)
7364161Seric 			{
7374161Seric 				a->q_flags |= QBADADDR;
7384161Seric 				giveresponse(EX_NOUSER, TRUE, m);
7394161Seric 			}
7404161Seric 			else
7414161Seric 			{
7424161Seric 				a->q_home = newstr(pw->pw_dir);
7434161Seric 				if (strcmp(buf, a->q_user) == 0)
7444161Seric 					forward(a);
7454161Seric 			}
7464105Seric 		}
7474099Seric 	}
7484159Seric }
7494159Seric /*
7504159Seric **  INCLUDE -- handle :include: specification.
7514159Seric **
7524159Seric **	Parameters:
7534159Seric **		fname -- filename to include.
7544159Seric **
7554159Seric **	Returns:
7564159Seric **		none.
7574159Seric **
7584159Seric **	Side Effects:
7594159Seric **		reads the :include: file and sends to everyone
7604159Seric **		listed in that file.
7614159Seric */
7624099Seric 
7634159Seric include(fname)
7644159Seric 	char *fname;
7654159Seric {
7664159Seric 	char buf[MAXLINE];
7674159Seric 	register FILE *fp;
7684159Seric 
7694159Seric 	if (Verbose)
770*4166Seric 		message(Arpa_Info, "Including file %s", fname);
7714159Seric 	fp = fopen(fname, "r");
7724159Seric 	if (fp == NULL)
7734159Seric 	{
7744159Seric 		usrerr("Cannot open %s", fname);
7754159Seric 		return;
7764159Seric 	}
7774159Seric 
7784159Seric 	/* read the file -- each line is a comma-separated list. */
7794159Seric 	while (fgets(buf, sizeof buf, fp) != NULL)
7804159Seric 	{
7814159Seric 		register char *p = index(buf, '\n');
7824159Seric 
7834159Seric 		if (p != NULL)
7844159Seric 			*p = '\0';
7854159Seric 		if (buf[0] == '\0')
7864159Seric 			continue;
7874159Seric 		To = fname;
7884159Seric 		if (Verbose)
789*4166Seric 			message(Arpa_Info, " >> %s", buf);
7904159Seric 		sendto(buf, 1);
7914159Seric 	}
7924159Seric 
7934159Seric 	fclose(fp);
794294Seric }
795294Seric /*
796294Seric **  MAILFILE -- Send a message to a file.
797294Seric **
798294Seric **	Parameters:
799294Seric **		filename -- the name of the file to send to.
800294Seric **
801294Seric **	Returns:
802294Seric **		The exit code associated with the operation.
803294Seric **
804294Seric **	Side Effects:
805294Seric **		none.
806294Seric **
807294Seric **	Called By:
808294Seric **		deliver
809294Seric */
810294Seric 
811294Seric mailfile(filename)
812294Seric 	char *filename;
813294Seric {
814294Seric 	register FILE *f;
815294Seric 
816294Seric 	f = fopen(filename, "a");
817294Seric 	if (f == NULL)
818294Seric 		return (EX_CANTCREAT);
8194067Seric 
8203186Seric 	putmessage(f, Mailer[1]);
821294Seric 	fputs("\n", f);
8224082Seric 	(void) fclose(f);
823294Seric 	return (EX_OK);
824294Seric }
825