125a99e2eSeric # include <stdio.h>
225a99e2eSeric # include <pwd.h>
325a99e2eSeric # include <signal.h>
425a99e2eSeric # include "dlvrmail.h"
525a99e2eSeric # ifdef LOG
625a99e2eSeric # include <log.h>
725a99e2eSeric # endif LOG
825a99e2eSeric 
9*03ab8e55Seric static char SccsId[] = "@(#)deliver.c	1.10	10/27/80";
10259cace7Seric 
1125a99e2eSeric /*
1225a99e2eSeric **  DELIVER -- Deliver a message to a particular address.
1325a99e2eSeric **
1425a99e2eSeric **	Algorithm:
1525a99e2eSeric **		Compute receiving network (i.e., mailer), host, & user.
1625a99e2eSeric **		If local, see if this is really a program name.
1725a99e2eSeric **		Build argument for the mailer.
1825a99e2eSeric **		Create pipe through edit fcn if appropriate.
1925a99e2eSeric **		Fork.
2025a99e2eSeric **			Child: call mailer
2125a99e2eSeric **		Parent: call editfcn if specified.
2225a99e2eSeric **		Wait for mailer to finish.
2325a99e2eSeric **		Interpret exit status.
2425a99e2eSeric **
2525a99e2eSeric **	Parameters:
2625a99e2eSeric **		to -- the address to deliver the message to.
2725a99e2eSeric **		editfcn -- if non-NULL, we want to call this function
2825a99e2eSeric **			to output the letter (instead of just out-
2925a99e2eSeric **			putting it raw).
3025a99e2eSeric **
3125a99e2eSeric **	Returns:
3225a99e2eSeric **		zero -- successfully delivered.
3325a99e2eSeric **		else -- some failure, see ExitStat for more info.
3425a99e2eSeric **
3525a99e2eSeric **	Side Effects:
3625a99e2eSeric **		The standard input is passed off to someone.
3725a99e2eSeric **
3825a99e2eSeric **	WARNING:
3925a99e2eSeric **		The standard input is shared amongst all children,
4025a99e2eSeric **		including the file pointer.  It is critical that the
4125a99e2eSeric **		parent waits for the child to finish before forking
4225a99e2eSeric **		another child.
4325a99e2eSeric **
4425a99e2eSeric **	Called By:
4525a99e2eSeric **		main
4625a99e2eSeric **		savemail
4725a99e2eSeric **
4825a99e2eSeric **	Files:
49a2ee7369Seric **		standard input -- must be opened to the message to
5025a99e2eSeric **			deliver.
5125a99e2eSeric */
5225a99e2eSeric 
5325a99e2eSeric deliver(to, editfcn)
5425a99e2eSeric 	addrq *to;
5525a99e2eSeric 	int (*editfcn)();
5625a99e2eSeric {
5725a99e2eSeric 	register struct mailer *m;
5825a99e2eSeric 	char *host;
5925a99e2eSeric 	char *user;
6025a99e2eSeric 	extern struct passwd *getpwnam();
6125a99e2eSeric 	char **pvp;
6225a99e2eSeric 	extern char **buildargv();
6325a99e2eSeric 	auto int st;
6425a99e2eSeric 	register int i;
6525a99e2eSeric 	register char *p;
6625a99e2eSeric 	int pid;
6725a99e2eSeric 	int pvect[2];
6825a99e2eSeric 	extern FILE *fdopen();
6925a99e2eSeric 	extern int errno;
7025a99e2eSeric 	FILE *mfile;
7125a99e2eSeric 	extern putheader();
7225a99e2eSeric 	extern pipesig();
7325a99e2eSeric 
7425a99e2eSeric 	/*
7525a99e2eSeric 	**  Compute receiving mailer, host, and to addreses.
7625a99e2eSeric 	**	Do some initialization first.  To is the to address
7725a99e2eSeric 	**	for error messages.
7825a99e2eSeric 	*/
7925a99e2eSeric 
8025a99e2eSeric 	To = to->q_paddr;
8125a99e2eSeric 	m = to->q_mailer;
8225a99e2eSeric 	user = to->q_user;
8325a99e2eSeric 	host = to->q_host;
84c1f9df2cSeric 	Errors = 0;
8525a99e2eSeric 	errno = 0;
8625a99e2eSeric # ifdef DEBUG
8725a99e2eSeric 	if (Debug)
8825a99e2eSeric 		printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
8925a99e2eSeric # endif DEBUG
9025a99e2eSeric 
9125a99e2eSeric 	/*
9225a99e2eSeric 	**  Remove quote bits from user/host.
9325a99e2eSeric 	*/
9425a99e2eSeric 
9525a99e2eSeric 	for (p = user; (*p++ &= 0177) != '\0'; )
9625a99e2eSeric 		continue;
9725a99e2eSeric 	if (host != NULL)
9825a99e2eSeric 		for (p = host; (*p++ &= 0177) != '\0'; )
9925a99e2eSeric 			continue;
10025a99e2eSeric 
10125a99e2eSeric 	/*
10225a99e2eSeric 	**  Strip quote bits from names if the mailer wants it.
10325a99e2eSeric 	*/
10425a99e2eSeric 
10525a99e2eSeric 	if (flagset(M_STRIPQ, m->m_flags))
10625a99e2eSeric 	{
10725a99e2eSeric 		stripquotes(user);
10825a99e2eSeric 		stripquotes(host);
10925a99e2eSeric 	}
11025a99e2eSeric 
11125a99e2eSeric 	/*
11225a99e2eSeric 	**  See if this user name is "special".
11325a99e2eSeric 	**	If the user is a program, diddle with the mailer spec.
11425a99e2eSeric 	**	If the user name has a slash in it, assume that this
11525a99e2eSeric 	**		is a file -- send it off without further ado.
11625a99e2eSeric 	**		Note that this means that editfcn's will not
11725a99e2eSeric 	**		be applied to the message.
11825a99e2eSeric 	*/
11925a99e2eSeric 
12025a99e2eSeric 	if (m == &Mailer[0])
12125a99e2eSeric 	{
12225a99e2eSeric 		if (*user == '|')
12325a99e2eSeric 		{
12425a99e2eSeric 			user++;
12525a99e2eSeric 			m = &Mailer[1];
12625a99e2eSeric 		}
12725a99e2eSeric 		else
12825a99e2eSeric 		{
12925a99e2eSeric 			if (index(user, '/') != NULL)
13025a99e2eSeric 			{
13125a99e2eSeric 				i = mailfile(user);
13225a99e2eSeric 				giveresponse(i, TRUE, m);
13325a99e2eSeric 				return (i);
13425a99e2eSeric 			}
13525a99e2eSeric 		}
13625a99e2eSeric 	}
13725a99e2eSeric 
13825a99e2eSeric 	/*
139243921eeSeric 	**  See if the user exists.
140243921eeSeric 	**	Strictly, this is only needed to print a pretty
14125a99e2eSeric 	**	error message.
142243921eeSeric 	**
143243921eeSeric 	**	>>>>>>>>>> This clause assumes that the local mailer
144243921eeSeric 	**	>> NOTE >> cannot do any further aliasing; that
145243921eeSeric 	**	>>>>>>>>>> function is subsumed by delivermail.
14625a99e2eSeric 	*/
14725a99e2eSeric 
14825a99e2eSeric 	if (m == &Mailer[0])
14925a99e2eSeric 	{
15025a99e2eSeric 		if (getpwnam(user) == NULL)
15125a99e2eSeric 		{
15225a99e2eSeric 			giveresponse(EX_NOUSER, TRUE, m);
15325a99e2eSeric 			return (EX_NOUSER);
15425a99e2eSeric 		}
15525a99e2eSeric 	}
15625a99e2eSeric 
15725a99e2eSeric 	/*
15825a99e2eSeric 	**  If the mailer wants a From line, insert a new editfcn.
15925a99e2eSeric 	*/
16025a99e2eSeric 
16125a99e2eSeric 	if (flagset(M_HDR, m->m_flags) && editfcn == NULL)
16225a99e2eSeric 		editfcn = putheader;
16325a99e2eSeric 
16425a99e2eSeric 	/*
16525a99e2eSeric 	**  Call the mailer.
16625a99e2eSeric 	**	The argument vector gets built, pipes through 'editfcn'
16725a99e2eSeric 	**	are created as necessary, and we fork & exec as
16825a99e2eSeric 	**	appropriate.  In the parent, we call 'editfcn'.
16925a99e2eSeric 	*/
17025a99e2eSeric 
17125a99e2eSeric 	pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr);
17225a99e2eSeric 	if (pvp == NULL)
17325a99e2eSeric 	{
17425a99e2eSeric 		usrerr("name too long");
17525a99e2eSeric 		return (-1);
17625a99e2eSeric 	}
17725a99e2eSeric 	rewind(stdin);
17825a99e2eSeric 
17925a99e2eSeric 	/* create a pipe if we will need one */
18025a99e2eSeric 	if (editfcn != NULL && pipe(pvect) < 0)
18125a99e2eSeric 	{
18225a99e2eSeric 		syserr("pipe");
18325a99e2eSeric 		return (-1);
18425a99e2eSeric 	}
185ea235328Smark # ifdef VFORK
186ea235328Smark 	pid = vfork();
187ea235328Smark # else
18825a99e2eSeric 	pid = fork();
189ea235328Smark # endif
19025a99e2eSeric 	if (pid < 0)
19125a99e2eSeric 	{
19225a99e2eSeric 		syserr("Cannot fork");
19325a99e2eSeric 		if (editfcn != NULL)
19425a99e2eSeric 		{
19525a99e2eSeric 			close(pvect[0]);
19625a99e2eSeric 			close(pvect[1]);
19725a99e2eSeric 		}
19825a99e2eSeric 		return (-1);
19925a99e2eSeric 	}
20025a99e2eSeric 	else if (pid == 0)
20125a99e2eSeric 	{
20225a99e2eSeric 		/* child -- set up input & exec mailer */
203*03ab8e55Seric 		/* make diagnostic output be standard output */
204*03ab8e55Seric 		close(2);
205*03ab8e55Seric 		dup(1);
20625a99e2eSeric 		signal(SIGINT, SIG_IGN);
20725a99e2eSeric 		if (editfcn != NULL)
20825a99e2eSeric 		{
20925a99e2eSeric 			close(0);
21025a99e2eSeric 			if (dup(pvect[0]) < 0)
21125a99e2eSeric 			{
21225a99e2eSeric 				syserr("Cannot dup to zero!");
213a590b978Seric 				_exit(EX_OSERR);
21425a99e2eSeric 			}
21525a99e2eSeric 			close(pvect[0]);
21625a99e2eSeric 			close(pvect[1]);
21725a99e2eSeric 		}
21825a99e2eSeric 		if (!flagset(M_RESTR, m->m_flags))
21925a99e2eSeric 			setuid(getuid());
22025a99e2eSeric # ifdef LOG
22125a99e2eSeric 		initlog(NULL, 0, LOG_CLOSE);
22225a99e2eSeric # endif LOG
223ea235328Smark # ifndef VFORK
224ea235328Smark 		/*
225ea235328Smark 		 * We have to be careful with vfork - we can't mung up the
226ea235328Smark 		 * memory but we don't want the mailer to inherit any extra
227ea235328Smark 		 * open files.  Chances are the mailer won't
228ea235328Smark 		 * care about an extra file, but then again you never know.
229ea235328Smark 		 * Actually, we would like to close(fileno(pwf)), but it's
230ea235328Smark 		 * declared static so we can't.  But if we fclose(pwf), which
231ea235328Smark 		 * is what endpwent does, it closes it in the parent too and
232ea235328Smark 		 * the next getpwnam will be slower.  If you have a weird mailer
233ea235328Smark 		 * that chokes on the extra file you should do the endpwent().
234ea235328Smark 		 */
23525a99e2eSeric 		endpwent();
236ea235328Smark # endif
23725a99e2eSeric 		execv(m->m_mailer, pvp);
23825a99e2eSeric 		/* syserr fails because log is closed */
23925a99e2eSeric 		/* syserr("Cannot exec %s", m->m_mailer); */
240a590b978Seric 		_exit(EX_UNAVAILABLE);
24125a99e2eSeric 	}
24225a99e2eSeric 
24325a99e2eSeric 	/* arrange to write out header message if error */
24425a99e2eSeric 	if (editfcn != NULL)
24525a99e2eSeric 	{
24625a99e2eSeric 		close(pvect[0]);
24725a99e2eSeric 		signal(SIGPIPE, pipesig);
24825a99e2eSeric 		mfile = fdopen(pvect[1], "w");
24925a99e2eSeric 		(*editfcn)(mfile);
25025a99e2eSeric 		fclose(mfile);
25125a99e2eSeric 	}
25225a99e2eSeric 
25325a99e2eSeric 	/*
25425a99e2eSeric 	**  Wait for child to die and report status.
25525a99e2eSeric 	**	We should never get fatal errors (e.g., segmentation
25625a99e2eSeric 	**	violation), so we report those specially.  For other
25725a99e2eSeric 	**	errors, we choose a status message (into statmsg),
25825a99e2eSeric 	**	and if it represents an error, we print it.
25925a99e2eSeric 	*/
26025a99e2eSeric 
26125a99e2eSeric 	while ((i = wait(&st)) > 0 && i != pid)
26225a99e2eSeric 		continue;
26325a99e2eSeric 	if (i < 0)
26425a99e2eSeric 	{
26525a99e2eSeric 		syserr("wait");
26625a99e2eSeric 		return (-1);
26725a99e2eSeric 	}
26825a99e2eSeric 	if ((st & 0377) != 0)
26925a99e2eSeric 	{
27025a99e2eSeric 		syserr("%s: stat %o", pvp[0], st);
271df2792f7Seric 		ExitStat = EX_UNAVAILABLE;
27225a99e2eSeric 		return (-1);
27325a99e2eSeric 	}
27425a99e2eSeric 	i = (st >> 8) & 0377;
27525a99e2eSeric 	giveresponse(i, FALSE, m);
27625a99e2eSeric 	return (i);
27725a99e2eSeric }
27825a99e2eSeric /*
27925a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
28025a99e2eSeric **
28125a99e2eSeric **	Parameters:
28225a99e2eSeric **		stat -- the status code from the mailer (high byte
28325a99e2eSeric **			only; core dumps must have been taken care of
28425a99e2eSeric **			already).
28525a99e2eSeric **		force -- if set, force an error message output, even
28625a99e2eSeric **			if the mailer seems to like to print its own
28725a99e2eSeric **			messages.
28825a99e2eSeric **		m -- the mailer descriptor for this mailer.
28925a99e2eSeric **
29025a99e2eSeric **	Returns:
29125a99e2eSeric **		none.
29225a99e2eSeric **
29325a99e2eSeric **	Side Effects:
294c1f9df2cSeric **		Errors may be incremented.
29525a99e2eSeric **		ExitStat may be set.
29625a99e2eSeric **
29725a99e2eSeric **	Called By:
29825a99e2eSeric **		deliver
29925a99e2eSeric */
30025a99e2eSeric 
30125a99e2eSeric giveresponse(stat, force, m)
30225a99e2eSeric 	int stat;
30325a99e2eSeric 	int force;
30425a99e2eSeric 	register struct mailer *m;
30525a99e2eSeric {
30625a99e2eSeric 	register char *statmsg;
30725a99e2eSeric 	extern char *SysExMsg[];
30825a99e2eSeric 	register int i;
30925a99e2eSeric 	extern int N_SysEx;
31025a99e2eSeric 
31125a99e2eSeric 	i = stat - EX__BASE;
31225a99e2eSeric 	if (i < 0 || i > N_SysEx)
31325a99e2eSeric 		statmsg = NULL;
31425a99e2eSeric 	else
31525a99e2eSeric 		statmsg = SysExMsg[i];
31625a99e2eSeric 	if (stat == 0)
31725a99e2eSeric 		statmsg = "ok";
31825a99e2eSeric 	else
31925a99e2eSeric 	{
320c1f9df2cSeric 		Errors++;
32125a99e2eSeric 		if (statmsg == NULL && m->m_badstat != 0)
32225a99e2eSeric 		{
32325a99e2eSeric 			stat = m->m_badstat;
32425a99e2eSeric 			i = stat - EX__BASE;
32525a99e2eSeric # ifdef DEBUG
32625a99e2eSeric 			if (i < 0 || i >= N_SysEx)
32725a99e2eSeric 				syserr("Bad m_badstat %d", stat);
32825a99e2eSeric 			else
32925a99e2eSeric # endif DEBUG
33025a99e2eSeric 			statmsg = SysExMsg[i];
33125a99e2eSeric 		}
33225a99e2eSeric 		if (statmsg == NULL)
33325a99e2eSeric 			usrerr("unknown mailer response %d", stat);
33425a99e2eSeric 		else if (force || !flagset(M_QUIET, m->m_flags))
33525a99e2eSeric 			usrerr("%s", statmsg);
33625a99e2eSeric 	}
33725a99e2eSeric 
33825a99e2eSeric 	/*
33925a99e2eSeric 	**  Final cleanup.
34025a99e2eSeric 	**	Log a record of the transaction.  Compute the new
34125a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
34225a99e2eSeric 	**	that.
34325a99e2eSeric 	*/
34425a99e2eSeric 
34525a99e2eSeric # ifdef LOG
34625a99e2eSeric 	if (statmsg == NULL)
34725a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat);
34825a99e2eSeric 	else
34925a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg);
35025a99e2eSeric # endif LOG
351243921eeSeric 	setstat(stat);
35225a99e2eSeric 	return (stat);
35325a99e2eSeric }
35425a99e2eSeric /*
35525a99e2eSeric **  PUTHEADER -- insert the From header into some mail
35625a99e2eSeric **
35725a99e2eSeric **	For mailers such as 'msgs' that want the header inserted
35825a99e2eSeric **	into the mail, this edit filter inserts the From line and
35925a99e2eSeric **	then passes the rest of the message through.
36025a99e2eSeric **
36125a99e2eSeric **	Parameters:
36225a99e2eSeric **		fp -- the file pointer for the output.
36325a99e2eSeric **
36425a99e2eSeric **	Returns:
36525a99e2eSeric **		none
36625a99e2eSeric **
36725a99e2eSeric **	Side Effects:
36825a99e2eSeric **		Puts a "From" line in UNIX format, and then
36925a99e2eSeric **			outputs the rest of the message.
37025a99e2eSeric **
37125a99e2eSeric **	Called By:
37225a99e2eSeric **		deliver
37325a99e2eSeric */
37425a99e2eSeric 
37525a99e2eSeric putheader(fp)
37625a99e2eSeric 	register FILE *fp;
37725a99e2eSeric {
37825a99e2eSeric 	char buf[MAXLINE + 1];
37925a99e2eSeric 	long tim;
38025a99e2eSeric 	extern char *ctime();
38125a99e2eSeric 
38225a99e2eSeric 	time(&tim);
38325a99e2eSeric 	fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim));
38425a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp))
38525a99e2eSeric 		fputs(buf, fp);
38625a99e2eSeric 	if (ferror(fp))
38725a99e2eSeric 	{
38825a99e2eSeric 		syserr("putheader: write error");
38925a99e2eSeric 		setstat(EX_IOERR);
39025a99e2eSeric 	}
39125a99e2eSeric }
39225a99e2eSeric /*
39325a99e2eSeric **  PIPESIG -- Handle broken pipe signals
39425a99e2eSeric **
39525a99e2eSeric **	This just logs an error.
39625a99e2eSeric **
39725a99e2eSeric **	Parameters:
39825a99e2eSeric **		none
39925a99e2eSeric **
40025a99e2eSeric **	Returns:
40125a99e2eSeric **		none
40225a99e2eSeric **
40325a99e2eSeric **	Side Effects:
40425a99e2eSeric **		logs an error message.
40525a99e2eSeric */
40625a99e2eSeric 
40725a99e2eSeric pipesig()
40825a99e2eSeric {
40925a99e2eSeric 	syserr("Broken pipe");
410*03ab8e55Seric 	signal(SIGPIPE, SIG_IGN);
41125a99e2eSeric }
41225a99e2eSeric /*
41325a99e2eSeric **  SENDTO -- Designate a send list.
41425a99e2eSeric **
41525a99e2eSeric **	The parameter is a comma-separated list of people to send to.
41625a99e2eSeric **	This routine arranges to send to all of them.
41725a99e2eSeric **
41825a99e2eSeric **	Parameters:
41925a99e2eSeric **		list -- the send list.
42025a99e2eSeric **		copyf -- the copy flag; passed to parse.
42125a99e2eSeric **
42225a99e2eSeric **	Returns:
42325a99e2eSeric **		none
42425a99e2eSeric **
42525a99e2eSeric **	Side Effects:
42625a99e2eSeric **		none.
42725a99e2eSeric **
42825a99e2eSeric **	Called By:
42925a99e2eSeric **		main
43025a99e2eSeric **		alias
43125a99e2eSeric */
43225a99e2eSeric 
43325a99e2eSeric sendto(list, copyf)
43425a99e2eSeric 	char *list;
43525a99e2eSeric 	int copyf;
43625a99e2eSeric {
43725a99e2eSeric 	register char *p;
43825a99e2eSeric 	register char *q;
43925a99e2eSeric 	register char c;
44025a99e2eSeric 	addrq *a;
44125a99e2eSeric 	extern addrq *parse();
44225a99e2eSeric 	bool more;
44325a99e2eSeric 
44425a99e2eSeric 	/* more keeps track of what the previous delimiter was */
44525a99e2eSeric 	more = TRUE;
44625a99e2eSeric 	for (p = list; more; )
44725a99e2eSeric 	{
44825a99e2eSeric 		/* find the end of this address */
44925a99e2eSeric 		q = p;
45025a99e2eSeric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
45125a99e2eSeric 			continue;
45225a99e2eSeric 		more = c != '\0';
45325a99e2eSeric 		*--p = '\0';
45425a99e2eSeric 		if (more)
45525a99e2eSeric 			p++;
45625a99e2eSeric 
45725a99e2eSeric 		/* parse the address */
45825a99e2eSeric 		if ((a = parse(q, (addrq *) NULL, copyf)) == NULL)
45925a99e2eSeric 			continue;
46025a99e2eSeric 
46125a99e2eSeric 		/* arrange to send to this person */
46225a99e2eSeric 		recipient(a, &SendQ);
46325a99e2eSeric 	}
46425a99e2eSeric 	To = NULL;
46525a99e2eSeric }
46625a99e2eSeric /*
46725a99e2eSeric **  RECIPIENT -- Designate a message recipient
46825a99e2eSeric **
46925a99e2eSeric **	Saves the named person for future mailing.
47025a99e2eSeric **
47125a99e2eSeric **	Designates a person as a recipient.  This routine
47225a99e2eSeric **	does the initial parsing, and checks to see if
47325a99e2eSeric **	this person has already received the mail.
47425a99e2eSeric **	It also supresses local network names and turns them into
47525a99e2eSeric **	local names.
47625a99e2eSeric **
47725a99e2eSeric **	Parameters:
47825a99e2eSeric **		a -- the (preparsed) address header for the recipient.
47925a99e2eSeric **		targetq -- the queue to add the name to.
48025a99e2eSeric **
48125a99e2eSeric **	Returns:
48225a99e2eSeric **		none.
48325a99e2eSeric **
48425a99e2eSeric **	Side Effects:
48525a99e2eSeric **		none.
48625a99e2eSeric **
48725a99e2eSeric **	Called By:
48825a99e2eSeric **		sendto
48925a99e2eSeric **		main
49025a99e2eSeric */
49125a99e2eSeric 
49225a99e2eSeric recipient(a, targetq)
49325a99e2eSeric 	register addrq *a;
49425a99e2eSeric 	addrq *targetq;
49525a99e2eSeric {
49625a99e2eSeric 	register addrq *q;
49725a99e2eSeric 	register struct mailer *m;
49825a99e2eSeric 	register char **pvp;
49925a99e2eSeric 	extern char *xalloc();
50025a99e2eSeric 	extern bool forward();
50125a99e2eSeric 	extern int errno;
50225a99e2eSeric 	extern bool sameaddr();
50325a99e2eSeric 
50425a99e2eSeric 	To = a->q_paddr;
50525a99e2eSeric 	m = a->q_mailer;
50625a99e2eSeric 	errno = 0;
50725a99e2eSeric # ifdef DEBUG
50825a99e2eSeric 	if (Debug)
50925a99e2eSeric 		printf("recipient(%s)\n", To);
51025a99e2eSeric # endif DEBUG
51125a99e2eSeric 
51225a99e2eSeric 	/*
51325a99e2eSeric 	**  Look up this person in the recipient list.  If they
51425a99e2eSeric 	**  are there already, return, otherwise continue.
51525a99e2eSeric 	*/
51625a99e2eSeric 
51725a99e2eSeric 	if (!ForceMail)
51825a99e2eSeric 	{
51925a99e2eSeric 		for (q = &SendQ; (q = nxtinq(q)) != NULL; )
52025a99e2eSeric 			if (sameaddr(q, a, FALSE))
52125a99e2eSeric 			{
52225a99e2eSeric # ifdef DEBUG
52325a99e2eSeric 				if (Debug)
52425a99e2eSeric 					printf("(%s in SendQ)\n", a->q_paddr);
52525a99e2eSeric # endif DEBUG
52625a99e2eSeric 				return;
52725a99e2eSeric 			}
52825a99e2eSeric 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
52925a99e2eSeric 			if (sameaddr(q, a, FALSE))
53025a99e2eSeric 			{
53125a99e2eSeric # ifdef DEBUG
53225a99e2eSeric 				if (Debug)
53325a99e2eSeric 					printf("(%s in AliasQ)\n", a->q_paddr);
53425a99e2eSeric # endif DEBUG
53525a99e2eSeric 				return;
53625a99e2eSeric 			}
53725a99e2eSeric 	}
53825a99e2eSeric 
53925a99e2eSeric 	/*
54025a99e2eSeric 	**  See if the user wants hir mail forwarded.
54125a99e2eSeric 	**	`Forward' must do the forwarding recursively.
54225a99e2eSeric 	*/
54325a99e2eSeric 
54425a99e2eSeric 	if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a))
54525a99e2eSeric 		return;
54625a99e2eSeric 
54725a99e2eSeric 	/*
54825a99e2eSeric 	**  Put the user onto the target queue.
54925a99e2eSeric 	*/
55025a99e2eSeric 
55125a99e2eSeric 	if (targetq != NULL)
55225a99e2eSeric 	{
55325a99e2eSeric 		putonq(a, targetq);
55425a99e2eSeric 	}
55525a99e2eSeric 
55625a99e2eSeric 	return;
55725a99e2eSeric }
55825a99e2eSeric /*
55925a99e2eSeric **  BUILDARGV -- Build an argument vector for a mail server.
56025a99e2eSeric **
56125a99e2eSeric **	Using a template defined in config.c, an argv is built.
56225a99e2eSeric **	The format of the template is already a vector.  The
56325a99e2eSeric **	items of this vector are copied, unless a dollar sign
56425a99e2eSeric **	is encountered.  In this case, the next character
56525a99e2eSeric **	specifies something else to copy in.  These can be
56625a99e2eSeric **		$f	The from address.
56725a99e2eSeric **		$h	The host.
56825a99e2eSeric **		$u	The user.
56925a99e2eSeric **		$c	The hop count.
57025a99e2eSeric **	The vector is built in a local buffer.  A pointer to
57125a99e2eSeric **	the static argv is returned.
57225a99e2eSeric **
57325a99e2eSeric **	Parameters:
57425a99e2eSeric **		tmplt -- a template for an argument vector.
57525a99e2eSeric **		flags -- the flags for this server.
57625a99e2eSeric **		host -- the host name to send to.
57725a99e2eSeric **		user -- the user name to send to.
57825a99e2eSeric **		from -- the person this mail is from.
57925a99e2eSeric **
58025a99e2eSeric **	Returns:
58125a99e2eSeric **		A pointer to an argv.
58225a99e2eSeric **
58325a99e2eSeric **	Side Effects:
58425a99e2eSeric **		none
58525a99e2eSeric **
58625a99e2eSeric **	WARNING:
58725a99e2eSeric **		Since the argv is staticly allocated, any subsequent
58825a99e2eSeric **		calls will clobber the old argv.
58925a99e2eSeric **
59025a99e2eSeric **	Called By:
59125a99e2eSeric **		deliver
59225a99e2eSeric */
59325a99e2eSeric 
59425a99e2eSeric char **
59525a99e2eSeric buildargv(tmplt, flags, host, user, from)
59625a99e2eSeric 	char **tmplt;
59725a99e2eSeric 	int flags;
59825a99e2eSeric 	char *host;
59925a99e2eSeric 	char *user;
60025a99e2eSeric 	char *from;
60125a99e2eSeric {
60225a99e2eSeric 	register char *p;
60325a99e2eSeric 	register char *q;
60425a99e2eSeric 	static char *pv[MAXPV+1];
60525a99e2eSeric 	char **pvp;
60625a99e2eSeric 	char **mvp;
60725a99e2eSeric 	static char buf[512];
60825a99e2eSeric 	register char *bp;
60925a99e2eSeric 	char pbuf[30];
61025a99e2eSeric 
61125a99e2eSeric 	/*
61225a99e2eSeric 	**  Do initial argv setup.
61325a99e2eSeric 	**	Insert the mailer name.  Notice that $x expansion is
61425a99e2eSeric 	**	NOT done on the mailer name.  Then, if the mailer has
61525a99e2eSeric 	**	a picky -f flag, we insert it as appropriate.  This
61625a99e2eSeric 	**	code does not check for 'pv' overflow; this places a
61725a99e2eSeric 	**	manifest lower limit of 4 for MAXPV.
61825a99e2eSeric 	*/
61925a99e2eSeric 
62025a99e2eSeric 	pvp = pv;
62125a99e2eSeric 	bp = buf;
62225a99e2eSeric 
62325a99e2eSeric 	*pvp++ = tmplt[0];
62425a99e2eSeric 
62525a99e2eSeric 	/* insert -f or -r flag as appropriate */
62625a99e2eSeric 	if (flagset(M_FOPT|M_ROPT, flags) && FromFlag)
62725a99e2eSeric 	{
62825a99e2eSeric 		if (flagset(M_FOPT, flags))
62925a99e2eSeric 			*pvp++ = "-f";
63025a99e2eSeric 		else
63125a99e2eSeric 			*pvp++ = "-r";
63225a99e2eSeric 		*pvp++ = From.q_paddr;
63325a99e2eSeric 	}
63425a99e2eSeric 
63525a99e2eSeric 	/*
63625a99e2eSeric 	**  Build the rest of argv.
63725a99e2eSeric 	**	For each prototype parameter, the prototype is
63825a99e2eSeric 	**	scanned character at a time.  If a dollar-sign is
63925a99e2eSeric 	**	found, 'q' is set to the appropriate expansion,
64025a99e2eSeric 	**	otherwise it is null.  Then either the string
64125a99e2eSeric 	**	pointed to by q, or the original character, is
64225a99e2eSeric 	**	interpolated into the buffer.  Buffer overflow is
64325a99e2eSeric 	**	checked.
64425a99e2eSeric 	*/
64525a99e2eSeric 
64625a99e2eSeric 	for (mvp = tmplt; (p = *++mvp) != NULL; )
64725a99e2eSeric 	{
64825a99e2eSeric 		if (pvp >= &pv[MAXPV])
64925a99e2eSeric 		{
65025a99e2eSeric 			syserr("Too many parameters to %s", pv[0]);
65125a99e2eSeric 			return (NULL);
65225a99e2eSeric 		}
65325a99e2eSeric 		*pvp++ = bp;
65425a99e2eSeric 		for (; *p != '\0'; p++)
65525a99e2eSeric 		{
65625a99e2eSeric 			/* q will be the interpolated quantity */
65725a99e2eSeric 			q = NULL;
65825a99e2eSeric 			if (*p == '$')
65925a99e2eSeric 			{
66025a99e2eSeric 				switch (*++p)
66125a99e2eSeric 				{
66225a99e2eSeric 				  case 'f':	/* from person */
66325a99e2eSeric 					q = from;
66425a99e2eSeric 					break;
66525a99e2eSeric 
66625a99e2eSeric 				  case 'u':	/* user */
66725a99e2eSeric 					q = user;
66825a99e2eSeric 					break;
66925a99e2eSeric 
67025a99e2eSeric 				  case 'h':	/* host */
67125a99e2eSeric 					q = host;
67225a99e2eSeric 					break;
67325a99e2eSeric 
67425a99e2eSeric 				  case 'c':	/* hop count */
67525a99e2eSeric 					sprintf(pbuf, "%d", HopCount);
67625a99e2eSeric 					q = pbuf;
67725a99e2eSeric 					break;
67825a99e2eSeric 				}
67925a99e2eSeric 			}
68025a99e2eSeric 
68125a99e2eSeric 			/*
68225a99e2eSeric 			**  Interpolate q or output one character
68325a99e2eSeric 			**	Strip quote bits as we proceed.....
68425a99e2eSeric 			*/
68525a99e2eSeric 
68625a99e2eSeric 			if (q != NULL)
68725a99e2eSeric 			{
68825a99e2eSeric 				while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0')
68925a99e2eSeric 					continue;
69025a99e2eSeric 				bp--;
69125a99e2eSeric 			}
69225a99e2eSeric 			else if (bp < &buf[sizeof buf - 1])
69325a99e2eSeric 				*bp++ = *p;
69425a99e2eSeric 		}
69525a99e2eSeric 		*bp++ = '\0';
69625a99e2eSeric 		if (bp >= &buf[sizeof buf - 1])
69725a99e2eSeric 			return (NULL);
69825a99e2eSeric 	}
69925a99e2eSeric 	*pvp = NULL;
70025a99e2eSeric 
70125a99e2eSeric # ifdef DEBUG
70225a99e2eSeric 	if (Debug)
70325a99e2eSeric 	{
70425a99e2eSeric 		printf("Interpolated argv is:\n");
70525a99e2eSeric 		for (mvp = pv; *mvp != NULL; mvp++)
70625a99e2eSeric 			printf("\t%s\n", *mvp);
70725a99e2eSeric 	}
70825a99e2eSeric # endif DEBUG
70925a99e2eSeric 
71025a99e2eSeric 	return (pv);
71125a99e2eSeric }
71225a99e2eSeric /*
71325a99e2eSeric **  MAILFILE -- Send a message to a file.
71425a99e2eSeric **
71525a99e2eSeric **	Parameters:
71625a99e2eSeric **		filename -- the name of the file to send to.
71725a99e2eSeric **
71825a99e2eSeric **	Returns:
71925a99e2eSeric **		The exit code associated with the operation.
72025a99e2eSeric **
72125a99e2eSeric **	Side Effects:
72225a99e2eSeric **		none.
72325a99e2eSeric **
72425a99e2eSeric **	Called By:
72525a99e2eSeric **		deliver
72625a99e2eSeric */
72725a99e2eSeric 
72825a99e2eSeric mailfile(filename)
72925a99e2eSeric 	char *filename;
73025a99e2eSeric {
73125a99e2eSeric 	char buf[MAXLINE];
73225a99e2eSeric 	register FILE *f;
73325a99e2eSeric 	auto long tim;
73425a99e2eSeric 	extern char *ctime();
73525a99e2eSeric 
73625a99e2eSeric 	f = fopen(filename, "a");
73725a99e2eSeric 	if (f == NULL)
73825a99e2eSeric 		return (EX_CANTCREAT);
73925a99e2eSeric 
74025a99e2eSeric 	/* output the timestamp */
74125a99e2eSeric 	time(&tim);
74225a99e2eSeric 	fprintf(f, "From %s %s", From.q_paddr, ctime(&tim));
74325a99e2eSeric 	rewind(stdin);
74425a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL)
74525a99e2eSeric 	{
74625a99e2eSeric 		fputs(buf, f);
74725a99e2eSeric 		if (ferror(f))
74825a99e2eSeric 		{
74925a99e2eSeric 			fclose(f);
75025a99e2eSeric 			return (EX_IOERR);
75125a99e2eSeric 		}
75225a99e2eSeric 	}
75325a99e2eSeric 	fputs("\n", f);
75425a99e2eSeric 	fclose(f);
75525a99e2eSeric 	return (EX_OK);
75625a99e2eSeric }
757