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*3389Seric static char SccsId[] = "@(#)deliver.c	3.10	03/28/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 
1873233Seric 		if (m == Mailer[0])
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 
2073233Seric 		if (m == Mailer[0])
2083233Seric 		{
2093233Seric 			if (getpwnam(user) == NULL)
2103233Seric 			{
2113233Seric 				giveresponse(EX_NOUSER, TRUE, m);
2123233Seric 				continue;
2133233Seric 			}
2143233Seric 		}
2153233Seric 
2163233Seric 		/* create list of users for error messages */
2173233Seric 		if (tobuf[0] != '\0')
2183233Seric 			strcat(tobuf, ",");
2193233Seric 		strcat(tobuf, to->q_paddr);
2203233Seric 		define('u', user);		/* to user */
2213233Seric 
2223233Seric 		/* expand out this user */
2233233Seric 		expand(user, buf, &buf[sizeof buf - 1]);
2243233Seric 		*pvp++ = newstr(buf);
2253233Seric 		if (pvp >= &pv[MAXPV - 2])
2263233Seric 		{
2273233Seric 			/* allow some space for trailing parms */
2283233Seric 			break;
2293233Seric 		}
230294Seric 	}
231294Seric 
2323233Seric 	/* print out messages as full list */
2333233Seric 	To = tobuf;
2343233Seric 
235294Seric 	/*
2363233Seric 	**  Fill out any parameters after the $u parameter.
237294Seric 	*/
238294Seric 
2393233Seric 	while (*++mvp != NULL)
240294Seric 	{
2413233Seric 		expand(*mvp, buf, &buf[sizeof buf - 1]);
2423233Seric 		*pvp++ = newstr(buf);
2433233Seric 		if (pvp >= &pv[MAXPV])
2443233Seric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
245294Seric 	}
2463233Seric 	*pvp++ = NULL;
247294Seric 
248294Seric 	/*
249294Seric 	**  Call the mailer.
2502898Seric 	**	The argument vector gets built, pipes
251294Seric 	**	are created as necessary, and we fork & exec as
2522898Seric 	**	appropriate.
253294Seric 	*/
254294Seric 
2553233Seric 	if (editfcn == NULL)
2563233Seric 		editfcn = putmessage;
2573233Seric 	i = sendoff(m, pv, editfcn);
2583233Seric 
2593233Seric 	return (i);
2603233Seric }
2613233Seric /*
2623233Seric **  SENDOFF -- send off call to mailer & collect response.
2633233Seric **
2643233Seric **	Parameters:
2653233Seric **		m -- mailer descriptor.
2663233Seric **		pvp -- parameter vector to send to it.
2673233Seric **		editfcn -- function to pipe it through.
2683233Seric **
2693233Seric **	Returns:
2703233Seric **		exit status of mailer.
2713233Seric **
2723233Seric **	Side Effects:
2733233Seric **		none.
2743233Seric */
2753233Seric 
2763233Seric sendoff(m, pvp, editfcn)
2773233Seric 	struct mailer *m;
2783233Seric 	char **pvp;
2793233Seric 	int (*editfcn)();
2803233Seric {
2813233Seric 	auto int st;
2823233Seric 	register int i;
2833233Seric 	int pid;
2843233Seric 	int pvect[2];
2853233Seric 	FILE *mfile;
2863233Seric 	extern putmessage();
2873233Seric 	extern pipesig();
2883233Seric 	extern FILE *fdopen();
2893233Seric 
2903233Seric # ifdef DEBUG
2913233Seric 	if (Debug)
292294Seric 	{
2933233Seric 		printf("Sendoff:\n");
2943233Seric 		printav(pvp);
295294Seric 	}
2963233Seric # endif DEBUG
2973233Seric 
298294Seric 	rewind(stdin);
299294Seric 
3002898Seric 	/* create a pipe to shove the mail through */
3012898Seric 	if (pipe(pvect) < 0)
302294Seric 	{
303294Seric 		syserr("pipe");
304294Seric 		return (-1);
305294Seric 	}
3061504Smark # ifdef VFORK
3071504Smark 	pid = vfork();
3081504Smark # else
309294Seric 	pid = fork();
3101504Smark # endif
311294Seric 	if (pid < 0)
312294Seric 	{
313294Seric 		syserr("Cannot fork");
3142898Seric 		close(pvect[0]);
3152898Seric 		close(pvect[1]);
316294Seric 		return (-1);
317294Seric 	}
318294Seric 	else if (pid == 0)
319294Seric 	{
320294Seric 		/* child -- set up input & exec mailer */
3211621Seric 		/* make diagnostic output be standard output */
3221621Seric 		close(2);
3231621Seric 		dup(1);
324294Seric 		signal(SIGINT, SIG_IGN);
3252898Seric 		close(0);
3262898Seric 		if (dup(pvect[0]) < 0)
327294Seric 		{
3282898Seric 			syserr("Cannot dup to zero!");
3292898Seric 			_exit(EX_OSERR);
330294Seric 		}
3312898Seric 		close(pvect[0]);
3322898Seric 		close(pvect[1]);
3332968Seric 		if (!bitset(M_RESTR, m->m_flags))
334294Seric 			setuid(getuid());
3352774Seric # ifndef VFORK
3362774Seric 		/*
3372774Seric 		**  We have to be careful with vfork - we can't mung up the
3382774Seric 		**  memory but we don't want the mailer to inherit any extra
3392774Seric 		**  open files.  Chances are the mailer won't
3402774Seric 		**  care about an extra file, but then again you never know.
3412774Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
3422774Seric 		**  declared static so we can't.  But if we fclose(pwf), which
3432774Seric 		**  is what endpwent does, it closes it in the parent too and
3442774Seric 		**  the next getpwnam will be slower.  If you have a weird
3452774Seric 		**  mailer that chokes on the extra file you should do the
3462774Seric 		**  endpwent().
3472774Seric 		**
3482774Seric 		**  Similar comments apply to log.  However, openlog is
3492774Seric 		**  clever enough to set the FIOCLEX mode on the file,
3502774Seric 		**  so it will be closed automatically on the exec.
3512774Seric 		*/
3522774Seric 
3532774Seric 		endpwent();
354294Seric # ifdef LOG
3552089Seric 		closelog();
356294Seric # endif LOG
3572774Seric # endif VFORK
358294Seric 		execv(m->m_mailer, pvp);
359294Seric 		/* syserr fails because log is closed */
360294Seric 		/* syserr("Cannot exec %s", m->m_mailer); */
3612343Seric 		printf("Cannot exec %s\n", m->m_mailer);
3622343Seric 		fflush(stdout);
3631619Seric 		_exit(EX_UNAVAILABLE);
364294Seric 	}
365294Seric 
3662898Seric 	/* write out message to mailer */
3672898Seric 	close(pvect[0]);
3682898Seric 	signal(SIGPIPE, pipesig);
3692898Seric 	mfile = fdopen(pvect[1], "w");
3702898Seric 	if (editfcn == NULL)
3712898Seric 		editfcn = putmessage;
3722898Seric 	(*editfcn)(mfile, m);
3732898Seric 	fclose(mfile);
374294Seric 
375294Seric 	/*
376294Seric 	**  Wait for child to die and report status.
377294Seric 	**	We should never get fatal errors (e.g., segmentation
378294Seric 	**	violation), so we report those specially.  For other
379294Seric 	**	errors, we choose a status message (into statmsg),
380294Seric 	**	and if it represents an error, we print it.
381294Seric 	*/
382294Seric 
383294Seric 	while ((i = wait(&st)) > 0 && i != pid)
384294Seric 		continue;
385294Seric 	if (i < 0)
386294Seric 	{
387294Seric 		syserr("wait");
388294Seric 		return (-1);
389294Seric 	}
390294Seric 	if ((st & 0377) != 0)
391294Seric 	{
392294Seric 		syserr("%s: stat %o", pvp[0], st);
3931597Seric 		ExitStat = EX_UNAVAILABLE;
394294Seric 		return (-1);
395294Seric 	}
396294Seric 	i = (st >> 8) & 0377;
3972343Seric 	giveresponse(i, TRUE, m);
398294Seric 	return (i);
399294Seric }
400294Seric /*
401294Seric **  GIVERESPONSE -- Interpret an error response from a mailer
402294Seric **
403294Seric **	Parameters:
404294Seric **		stat -- the status code from the mailer (high byte
405294Seric **			only; core dumps must have been taken care of
406294Seric **			already).
407294Seric **		force -- if set, force an error message output, even
408294Seric **			if the mailer seems to like to print its own
409294Seric **			messages.
410294Seric **		m -- the mailer descriptor for this mailer.
411294Seric **
412294Seric **	Returns:
4132968Seric **		stat.
414294Seric **
415294Seric **	Side Effects:
4161518Seric **		Errors may be incremented.
417294Seric **		ExitStat may be set.
418294Seric **
419294Seric **	Called By:
420294Seric **		deliver
421294Seric */
422294Seric 
423294Seric giveresponse(stat, force, m)
424294Seric 	int stat;
425294Seric 	int force;
426294Seric 	register struct mailer *m;
427294Seric {
428294Seric 	register char *statmsg;
429294Seric 	extern char *SysExMsg[];
430294Seric 	register int i;
431294Seric 	extern int N_SysEx;
4321624Seric 	extern long MsgSize;
4331624Seric 	char buf[30];
4343044Seric 	extern char *sprintf();
435294Seric 
436294Seric 	i = stat - EX__BASE;
437294Seric 	if (i < 0 || i > N_SysEx)
438294Seric 		statmsg = NULL;
439294Seric 	else
440294Seric 		statmsg = SysExMsg[i];
441294Seric 	if (stat == 0)
442294Seric 		statmsg = "ok";
443294Seric 	else
444294Seric 	{
4451518Seric 		Errors++;
446294Seric 		if (statmsg == NULL && m->m_badstat != 0)
447294Seric 		{
448294Seric 			stat = m->m_badstat;
449294Seric 			i = stat - EX__BASE;
450294Seric # ifdef DEBUG
451294Seric 			if (i < 0 || i >= N_SysEx)
452294Seric 				syserr("Bad m_badstat %d", stat);
453294Seric 			else
454294Seric # endif DEBUG
455294Seric 			statmsg = SysExMsg[i];
456294Seric 		}
457294Seric 		if (statmsg == NULL)
458294Seric 			usrerr("unknown mailer response %d", stat);
4592968Seric 		else if (force || !bitset(M_QUIET, m->m_flags))
460294Seric 			usrerr("%s", statmsg);
461294Seric 	}
462294Seric 
463294Seric 	/*
464294Seric 	**  Final cleanup.
465294Seric 	**	Log a record of the transaction.  Compute the new
466294Seric 	**	ExitStat -- if we already had an error, stick with
467294Seric 	**	that.
468294Seric 	*/
469294Seric 
4701624Seric 	if (statmsg == NULL)
4711624Seric 	{
4721624Seric 		sprintf(buf, "error %d", stat);
4731624Seric 		statmsg = buf;
4741624Seric 	}
4751624Seric 
476294Seric # ifdef LOG
4772774Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
478294Seric # endif LOG
4791389Seric 	setstat(stat);
480294Seric 	return (stat);
481294Seric }
482294Seric /*
4832898Seric **  PUTMESSAGE -- output a message to the final mailer.
484294Seric **
4852898Seric **	This routine takes care of recreating the header from the
4862898Seric **	in-core copy, etc.
487294Seric **
488294Seric **	Parameters:
4892898Seric **		fp -- file to output onto.
4902898Seric **		m -- a mailer descriptor.
491294Seric **
492294Seric **	Returns:
4932898Seric **		none.
494294Seric **
495294Seric **	Side Effects:
4962898Seric **		The message is written onto fp.
497294Seric */
498294Seric 
4992898Seric putmessage(fp, m)
5002898Seric 	FILE *fp;
5012898Seric 	struct mailer *m;
502294Seric {
5032898Seric 	char buf[BUFSIZ];
5042898Seric 	register int i;
5052898Seric 	HDR *h;
5061828Seric 	register char *p;
5072898Seric 	extern char *arpadate();
5082898Seric 	bool anyheader = FALSE;
5093186Seric 	extern char *expand();
5103044Seric 	extern char *capitalize();
511294Seric 
5123186Seric 	/* output "From" line unless supressed */
5133186Seric 	if (!bitset(M_NHDR, m->m_flags))
5143186Seric 		fprintf(fp, "%s\n", FromLine);
5153186Seric 
5163385Seric 	/* output all header lines */
5172898Seric 	for (h = Header; h != NULL; h = h->h_link)
5181828Seric 	{
519*3389Seric 		if (bitset(H_DELETE, h->h_flags))
5203385Seric 			continue;
521*3389Seric 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags))
522*3389Seric 			continue;
5233385Seric 		if (bitset(H_DEFAULT, h->h_flags))
5243385Seric 		{
5253385Seric 			expand(h->h_value, buf, &buf[sizeof buf]);
5263385Seric 			p = buf;
5273385Seric 		}
5282898Seric 		else
5293385Seric 			p = h->h_value;
530*3389Seric 		if (*p == '\0')
531*3389Seric 			continue;
5323385Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), p);
5332898Seric 		h->h_flags |= H_USED;
5342898Seric 		anyheader = TRUE;
5352898Seric 	}
5362898Seric 
5372898Seric 	if (anyheader)
5382898Seric 		fprintf(fp, "\n");
5392898Seric 
5402898Seric 	/* output the body of the message */
5412898Seric 	while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0)
5422898Seric 		fwrite(buf, 1, i, fp);
5432898Seric 
544294Seric 	if (ferror(fp))
545294Seric 	{
5462898Seric 		syserr("putmessage: write error");
547294Seric 		setstat(EX_IOERR);
548294Seric 	}
549294Seric }
550294Seric /*
551294Seric **  PIPESIG -- Handle broken pipe signals
552294Seric **
553294Seric **	This just logs an error.
554294Seric **
555294Seric **	Parameters:
556294Seric **		none
557294Seric **
558294Seric **	Returns:
559294Seric **		none
560294Seric **
561294Seric **	Side Effects:
562294Seric **		logs an error message.
563294Seric */
564294Seric 
565294Seric pipesig()
566294Seric {
567294Seric 	syserr("Broken pipe");
5681621Seric 	signal(SIGPIPE, SIG_IGN);
569294Seric }
570294Seric /*
571294Seric **  SENDTO -- Designate a send list.
572294Seric **
573294Seric **	The parameter is a comma-separated list of people to send to.
574294Seric **	This routine arranges to send to all of them.
575294Seric **
576294Seric **	Parameters:
577294Seric **		list -- the send list.
578294Seric **		copyf -- the copy flag; passed to parse.
579294Seric **
580294Seric **	Returns:
581294Seric **		none
582294Seric **
583294Seric **	Side Effects:
584294Seric **		none.
585294Seric */
586294Seric 
587294Seric sendto(list, copyf)
588294Seric 	char *list;
589294Seric 	int copyf;
590294Seric {
591294Seric 	register char *p;
592294Seric 	register char *q;
593294Seric 	register char c;
5942968Seric 	ADDRESS *a;
5952968Seric 	extern ADDRESS *parse();
596294Seric 	bool more;
597294Seric 
598294Seric 	/* more keeps track of what the previous delimiter was */
599294Seric 	more = TRUE;
600294Seric 	for (p = list; more; )
601294Seric 	{
602294Seric 		/* find the end of this address */
603294Seric 		q = p;
604294Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
605294Seric 			continue;
606294Seric 		more = c != '\0';
607294Seric 		*--p = '\0';
608294Seric 		if (more)
609294Seric 			p++;
610294Seric 
611294Seric 		/* parse the address */
6122968Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
613294Seric 			continue;
614294Seric 
615294Seric 		/* arrange to send to this person */
6163186Seric 		recipient(a);
617294Seric 	}
618294Seric 	To = NULL;
619294Seric }
620294Seric /*
621294Seric **  RECIPIENT -- Designate a message recipient
622294Seric **
623294Seric **	Saves the named person for future mailing.
624294Seric **
625294Seric **	Parameters:
626294Seric **		a -- the (preparsed) address header for the recipient.
627294Seric **
628294Seric **	Returns:
629294Seric **		none.
630294Seric **
631294Seric **	Side Effects:
632294Seric **		none.
633294Seric */
634294Seric 
6353186Seric recipient(a)
6362968Seric 	register ADDRESS *a;
637294Seric {
6382968Seric 	register ADDRESS *q;
639294Seric 	register struct mailer *m;
640294Seric 	extern bool forward();
641294Seric 	extern int errno;
642294Seric 	extern bool sameaddr();
643294Seric 
644294Seric 	To = a->q_paddr;
6453047Seric 	m = Mailer[a->q_mailer];
646294Seric 	errno = 0;
647294Seric # ifdef DEBUG
648294Seric 	if (Debug)
649294Seric 		printf("recipient(%s)\n", To);
650294Seric # endif DEBUG
651294Seric 
652294Seric 	/*
6533186Seric 	**  Do sickly crude mapping for program mailing, etc.
6543186Seric 	*/
6553186Seric 
6563186Seric 	if (a->q_mailer == 0 && a->q_user[0] == '|')
6573186Seric 	{
6583186Seric 		a->q_mailer = 1;
6593186Seric 		m++;
6603186Seric 		a->q_user++;
6613186Seric 	}
6623186Seric 
6633186Seric 	/*
664294Seric 	**  Look up this person in the recipient list.  If they
665294Seric 	**  are there already, return, otherwise continue.
6663186Seric 	**  If the list is empty, just add it.
667294Seric 	*/
668294Seric 
6693186Seric 	if (m->m_sendq == NULL)
670294Seric 	{
6713186Seric 		m->m_sendq = a;
6723186Seric 	}
6733186Seric 	else
6743186Seric 	{
6753186Seric 		ADDRESS *pq;
6763186Seric 
6773186Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
6783186Seric 		{
6793186Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
680294Seric 			{
681294Seric # ifdef DEBUG
682294Seric 				if (Debug)
6833186Seric 					printf("(%s in sendq)\n", a->q_paddr);
684294Seric # endif DEBUG
685294Seric 				return;
686294Seric 			}
6873186Seric 		}
6883186Seric 
6893186Seric 		/* add address on list */
6903186Seric 		q = pq;
6913233Seric 		q->q_next = a;
692294Seric 	}
6933186Seric 	a->q_next = NULL;
694294Seric 
695294Seric 	/*
696294Seric 	**  See if the user wants hir mail forwarded.
697294Seric 	**	`Forward' must do the forwarding recursively.
698294Seric 	*/
699294Seric 
7003186Seric 	if (m == Mailer[0] && !NoAlias && forward(a))
7013186Seric 		setbit(QDONTSEND, a->q_flags);
702294Seric 
703294Seric 	return;
704294Seric }
705294Seric /*
706294Seric **  MAILFILE -- Send a message to a file.
707294Seric **
708294Seric **	Parameters:
709294Seric **		filename -- the name of the file to send to.
710294Seric **
711294Seric **	Returns:
712294Seric **		The exit code associated with the operation.
713294Seric **
714294Seric **	Side Effects:
715294Seric **		none.
716294Seric **
717294Seric **	Called By:
718294Seric **		deliver
719294Seric */
720294Seric 
721294Seric mailfile(filename)
722294Seric 	char *filename;
723294Seric {
724294Seric 	register FILE *f;
725294Seric 
726294Seric 	f = fopen(filename, "a");
727294Seric 	if (f == NULL)
728294Seric 		return (EX_CANTCREAT);
729294Seric 
7303186Seric 	putmessage(f, Mailer[1]);
731294Seric 	fputs("\n", f);
732294Seric 	fclose(f);
733294Seric 	return (EX_OK);
734294Seric }
735