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*243921eeSeric static char SccsId[] = "@(#)deliver.c	1.5	10/11/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;
8425a99e2eSeric 	Error = 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 	/*
139*243921eeSeric 	**  See if the user exists.
140*243921eeSeric 	**	Strictly, this is only needed to print a pretty
14125a99e2eSeric 	**	error message.
142*243921eeSeric 	**
143*243921eeSeric 	**	>>>>>>>>>> This clause assumes that the local mailer
144*243921eeSeric 	**	>> NOTE >> cannot do any further aliasing; that
145*243921eeSeric 	**	>>>>>>>>>> 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 	}
18525a99e2eSeric 	pid = fork();
18625a99e2eSeric 	if (pid < 0)
18725a99e2eSeric 	{
18825a99e2eSeric 		syserr("Cannot fork");
18925a99e2eSeric 		if (editfcn != NULL)
19025a99e2eSeric 		{
19125a99e2eSeric 			close(pvect[0]);
19225a99e2eSeric 			close(pvect[1]);
19325a99e2eSeric 		}
19425a99e2eSeric 		return (-1);
19525a99e2eSeric 	}
19625a99e2eSeric 	else if (pid == 0)
19725a99e2eSeric 	{
19825a99e2eSeric 		/* child -- set up input & exec mailer */
19925a99e2eSeric 		signal(SIGINT, SIG_IGN);
20025a99e2eSeric 		if (editfcn != NULL)
20125a99e2eSeric 		{
20225a99e2eSeric 			close(0);
20325a99e2eSeric 			if (dup(pvect[0]) < 0)
20425a99e2eSeric 			{
20525a99e2eSeric 				syserr("Cannot dup to zero!");
20625a99e2eSeric 				exit(EX_OSERR);
20725a99e2eSeric 			}
20825a99e2eSeric 			close(pvect[0]);
20925a99e2eSeric 			close(pvect[1]);
21025a99e2eSeric 		}
21125a99e2eSeric 		if (!flagset(M_RESTR, m->m_flags))
21225a99e2eSeric 			setuid(getuid());
21325a99e2eSeric # ifdef LOG
21425a99e2eSeric 		initlog(NULL, 0, LOG_CLOSE);
21525a99e2eSeric # endif LOG
21625a99e2eSeric 		endpwent();
21725a99e2eSeric 		execv(m->m_mailer, pvp);
21825a99e2eSeric 		/* syserr fails because log is closed */
21925a99e2eSeric 		/* syserr("Cannot exec %s", m->m_mailer); */
22025a99e2eSeric 		exit(EX_UNAVAIL);
22125a99e2eSeric 	}
22225a99e2eSeric 
22325a99e2eSeric 	/* arrange to write out header message if error */
22425a99e2eSeric 	if (editfcn != NULL)
22525a99e2eSeric 	{
22625a99e2eSeric 		close(pvect[0]);
22725a99e2eSeric 		signal(SIGPIPE, pipesig);
22825a99e2eSeric 		mfile = fdopen(pvect[1], "w");
22925a99e2eSeric 		(*editfcn)(mfile);
23025a99e2eSeric 		fclose(mfile);
23125a99e2eSeric 	}
23225a99e2eSeric 
23325a99e2eSeric 	/*
23425a99e2eSeric 	**  Wait for child to die and report status.
23525a99e2eSeric 	**	We should never get fatal errors (e.g., segmentation
23625a99e2eSeric 	**	violation), so we report those specially.  For other
23725a99e2eSeric 	**	errors, we choose a status message (into statmsg),
23825a99e2eSeric 	**	and if it represents an error, we print it.
23925a99e2eSeric 	*/
24025a99e2eSeric 
24125a99e2eSeric 	while ((i = wait(&st)) > 0 && i != pid)
24225a99e2eSeric 		continue;
24325a99e2eSeric 	if (i < 0)
24425a99e2eSeric 	{
24525a99e2eSeric 		syserr("wait");
24625a99e2eSeric 		return (-1);
24725a99e2eSeric 	}
24825a99e2eSeric 	if ((st & 0377) != 0)
24925a99e2eSeric 	{
25025a99e2eSeric 		syserr("%s: stat %o", pvp[0], st);
25125a99e2eSeric 		ExitStat = EX_UNAVAIL;
25225a99e2eSeric 		return (-1);
25325a99e2eSeric 	}
25425a99e2eSeric 	i = (st >> 8) & 0377;
25525a99e2eSeric 	giveresponse(i, FALSE, m);
25625a99e2eSeric 	return (i);
25725a99e2eSeric }
25825a99e2eSeric /*
25925a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
26025a99e2eSeric **
26125a99e2eSeric **	Parameters:
26225a99e2eSeric **		stat -- the status code from the mailer (high byte
26325a99e2eSeric **			only; core dumps must have been taken care of
26425a99e2eSeric **			already).
26525a99e2eSeric **		force -- if set, force an error message output, even
26625a99e2eSeric **			if the mailer seems to like to print its own
26725a99e2eSeric **			messages.
26825a99e2eSeric **		m -- the mailer descriptor for this mailer.
26925a99e2eSeric **
27025a99e2eSeric **	Returns:
27125a99e2eSeric **		none.
27225a99e2eSeric **
27325a99e2eSeric **	Side Effects:
27425a99e2eSeric **		Error may be set.
27525a99e2eSeric **		ExitStat may be set.
27625a99e2eSeric **
27725a99e2eSeric **	Called By:
27825a99e2eSeric **		deliver
27925a99e2eSeric */
28025a99e2eSeric 
28125a99e2eSeric giveresponse(stat, force, m)
28225a99e2eSeric 	int stat;
28325a99e2eSeric 	int force;
28425a99e2eSeric 	register struct mailer *m;
28525a99e2eSeric {
28625a99e2eSeric 	register char *statmsg;
28725a99e2eSeric 	extern char *SysExMsg[];
28825a99e2eSeric 	register int i;
28925a99e2eSeric 	extern int N_SysEx;
29025a99e2eSeric 
29125a99e2eSeric 	i = stat - EX__BASE;
29225a99e2eSeric 	if (i < 0 || i > N_SysEx)
29325a99e2eSeric 		statmsg = NULL;
29425a99e2eSeric 	else
29525a99e2eSeric 		statmsg = SysExMsg[i];
29625a99e2eSeric 	if (stat == 0)
29725a99e2eSeric 		statmsg = "ok";
29825a99e2eSeric 	else
29925a99e2eSeric 	{
30025a99e2eSeric 		Error++;
30125a99e2eSeric 		if (statmsg == NULL && m->m_badstat != 0)
30225a99e2eSeric 		{
30325a99e2eSeric 			stat = m->m_badstat;
30425a99e2eSeric 			i = stat - EX__BASE;
30525a99e2eSeric # ifdef DEBUG
30625a99e2eSeric 			if (i < 0 || i >= N_SysEx)
30725a99e2eSeric 				syserr("Bad m_badstat %d", stat);
30825a99e2eSeric 			else
30925a99e2eSeric # endif DEBUG
31025a99e2eSeric 			statmsg = SysExMsg[i];
31125a99e2eSeric 		}
31225a99e2eSeric 		if (statmsg == NULL)
31325a99e2eSeric 			usrerr("unknown mailer response %d", stat);
31425a99e2eSeric 		else if (force || !flagset(M_QUIET, m->m_flags))
31525a99e2eSeric 			usrerr("%s", statmsg);
31625a99e2eSeric 	}
31725a99e2eSeric 
31825a99e2eSeric 	/*
31925a99e2eSeric 	**  Final cleanup.
32025a99e2eSeric 	**	Log a record of the transaction.  Compute the new
32125a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
32225a99e2eSeric 	**	that.
32325a99e2eSeric 	*/
32425a99e2eSeric 
32525a99e2eSeric # ifdef LOG
32625a99e2eSeric 	if (statmsg == NULL)
32725a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat);
32825a99e2eSeric 	else
32925a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg);
33025a99e2eSeric # endif LOG
331*243921eeSeric 	setstat(stat);
33225a99e2eSeric 	return (stat);
33325a99e2eSeric }
33425a99e2eSeric /*
33525a99e2eSeric **  PUTHEADER -- insert the From header into some mail
33625a99e2eSeric **
33725a99e2eSeric **	For mailers such as 'msgs' that want the header inserted
33825a99e2eSeric **	into the mail, this edit filter inserts the From line and
33925a99e2eSeric **	then passes the rest of the message through.
34025a99e2eSeric **
34125a99e2eSeric **	Parameters:
34225a99e2eSeric **		fp -- the file pointer for the output.
34325a99e2eSeric **
34425a99e2eSeric **	Returns:
34525a99e2eSeric **		none
34625a99e2eSeric **
34725a99e2eSeric **	Side Effects:
34825a99e2eSeric **		Puts a "From" line in UNIX format, and then
34925a99e2eSeric **			outputs the rest of the message.
35025a99e2eSeric **
35125a99e2eSeric **	Called By:
35225a99e2eSeric **		deliver
35325a99e2eSeric */
35425a99e2eSeric 
35525a99e2eSeric putheader(fp)
35625a99e2eSeric 	register FILE *fp;
35725a99e2eSeric {
35825a99e2eSeric 	char buf[MAXLINE + 1];
35925a99e2eSeric 	long tim;
36025a99e2eSeric 	extern char *ctime();
36125a99e2eSeric 
36225a99e2eSeric 	time(&tim);
36325a99e2eSeric 	fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim));
36425a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp))
36525a99e2eSeric 		fputs(buf, fp);
36625a99e2eSeric 	if (ferror(fp))
36725a99e2eSeric 	{
36825a99e2eSeric 		syserr("putheader: write error");
36925a99e2eSeric 		setstat(EX_IOERR);
37025a99e2eSeric 	}
37125a99e2eSeric }
37225a99e2eSeric /*
37325a99e2eSeric **  PIPESIG -- Handle broken pipe signals
37425a99e2eSeric **
37525a99e2eSeric **	This just logs an error.
37625a99e2eSeric **
37725a99e2eSeric **	Parameters:
37825a99e2eSeric **		none
37925a99e2eSeric **
38025a99e2eSeric **	Returns:
38125a99e2eSeric **		none
38225a99e2eSeric **
38325a99e2eSeric **	Side Effects:
38425a99e2eSeric **		logs an error message.
38525a99e2eSeric */
38625a99e2eSeric 
38725a99e2eSeric pipesig()
38825a99e2eSeric {
38925a99e2eSeric 	syserr("Broken pipe");
39025a99e2eSeric }
39125a99e2eSeric /*
39225a99e2eSeric **  SENDTO -- Designate a send list.
39325a99e2eSeric **
39425a99e2eSeric **	The parameter is a comma-separated list of people to send to.
39525a99e2eSeric **	This routine arranges to send to all of them.
39625a99e2eSeric **
39725a99e2eSeric **	Parameters:
39825a99e2eSeric **		list -- the send list.
39925a99e2eSeric **		copyf -- the copy flag; passed to parse.
40025a99e2eSeric **
40125a99e2eSeric **	Returns:
40225a99e2eSeric **		none
40325a99e2eSeric **
40425a99e2eSeric **	Side Effects:
40525a99e2eSeric **		none.
40625a99e2eSeric **
40725a99e2eSeric **	Called By:
40825a99e2eSeric **		main
40925a99e2eSeric **		alias
41025a99e2eSeric */
41125a99e2eSeric 
41225a99e2eSeric sendto(list, copyf)
41325a99e2eSeric 	char *list;
41425a99e2eSeric 	int copyf;
41525a99e2eSeric {
41625a99e2eSeric 	register char *p;
41725a99e2eSeric 	register char *q;
41825a99e2eSeric 	register char c;
41925a99e2eSeric 	addrq *a;
42025a99e2eSeric 	extern addrq *parse();
42125a99e2eSeric 	bool more;
42225a99e2eSeric 
42325a99e2eSeric 	/* more keeps track of what the previous delimiter was */
42425a99e2eSeric 	more = TRUE;
42525a99e2eSeric 	for (p = list; more; )
42625a99e2eSeric 	{
42725a99e2eSeric 		/* find the end of this address */
42825a99e2eSeric 		q = p;
42925a99e2eSeric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
43025a99e2eSeric 			continue;
43125a99e2eSeric 		more = c != '\0';
43225a99e2eSeric 		*--p = '\0';
43325a99e2eSeric 		if (more)
43425a99e2eSeric 			p++;
43525a99e2eSeric 
43625a99e2eSeric 		/* parse the address */
43725a99e2eSeric 		if ((a = parse(q, (addrq *) NULL, copyf)) == NULL)
43825a99e2eSeric 			continue;
43925a99e2eSeric 
44025a99e2eSeric 		/* arrange to send to this person */
44125a99e2eSeric 		recipient(a, &SendQ);
44225a99e2eSeric 	}
44325a99e2eSeric 	To = NULL;
44425a99e2eSeric }
44525a99e2eSeric /*
44625a99e2eSeric **  RECIPIENT -- Designate a message recipient
44725a99e2eSeric **
44825a99e2eSeric **	Saves the named person for future mailing.
44925a99e2eSeric **
45025a99e2eSeric **	Designates a person as a recipient.  This routine
45125a99e2eSeric **	does the initial parsing, and checks to see if
45225a99e2eSeric **	this person has already received the mail.
45325a99e2eSeric **	It also supresses local network names and turns them into
45425a99e2eSeric **	local names.
45525a99e2eSeric **
45625a99e2eSeric **	Parameters:
45725a99e2eSeric **		a -- the (preparsed) address header for the recipient.
45825a99e2eSeric **		targetq -- the queue to add the name to.
45925a99e2eSeric **
46025a99e2eSeric **	Returns:
46125a99e2eSeric **		none.
46225a99e2eSeric **
46325a99e2eSeric **	Side Effects:
46425a99e2eSeric **		none.
46525a99e2eSeric **
46625a99e2eSeric **	Called By:
46725a99e2eSeric **		sendto
46825a99e2eSeric **		main
46925a99e2eSeric */
47025a99e2eSeric 
47125a99e2eSeric recipient(a, targetq)
47225a99e2eSeric 	register addrq *a;
47325a99e2eSeric 	addrq *targetq;
47425a99e2eSeric {
47525a99e2eSeric 	register addrq *q;
47625a99e2eSeric 	register struct mailer *m;
47725a99e2eSeric 	register char **pvp;
47825a99e2eSeric 	extern char *xalloc();
47925a99e2eSeric 	extern bool forward();
48025a99e2eSeric 	extern int errno;
48125a99e2eSeric 	extern bool sameaddr();
48225a99e2eSeric 
48325a99e2eSeric 	To = a->q_paddr;
48425a99e2eSeric 	m = a->q_mailer;
48525a99e2eSeric 	errno = 0;
48625a99e2eSeric # ifdef DEBUG
48725a99e2eSeric 	if (Debug)
48825a99e2eSeric 		printf("recipient(%s)\n", To);
48925a99e2eSeric # endif DEBUG
49025a99e2eSeric 
49125a99e2eSeric 	/*
49225a99e2eSeric 	**  Don't go to the net if already on the target host.
49325a99e2eSeric 	**	This is important on the berkeley network, since
49425a99e2eSeric 	**	it get confused if we ask to send to ourselves.
49525a99e2eSeric 	**	For nets like the ARPANET, we probably will have
49625a99e2eSeric 	**	the local list set to NULL to simplify testing.
49725a99e2eSeric 	**	The canonical representation of the name is also set
49825a99e2eSeric 	**	to be just the local name so the duplicate letter
49925a99e2eSeric 	**	suppression algorithm will work.
50025a99e2eSeric 	*/
50125a99e2eSeric 
50225a99e2eSeric 	if ((pvp = m->m_local) != NULL)
50325a99e2eSeric 	{
50425a99e2eSeric 		while (*pvp != NULL)
50525a99e2eSeric 		{
50625a99e2eSeric 			if (strcmp(*pvp++, a->q_host) == 0)
50725a99e2eSeric 			{
50825a99e2eSeric 				a->q_mailer = m = &Mailer[0];
50925a99e2eSeric 				break;
51025a99e2eSeric 			}
51125a99e2eSeric 		}
51225a99e2eSeric 	}
51325a99e2eSeric 
51425a99e2eSeric 	/*
51525a99e2eSeric 	**  Look up this person in the recipient list.  If they
51625a99e2eSeric 	**  are there already, return, otherwise continue.
51725a99e2eSeric 	*/
51825a99e2eSeric 
51925a99e2eSeric 	if (!ForceMail)
52025a99e2eSeric 	{
52125a99e2eSeric 		for (q = &SendQ; (q = nxtinq(q)) != NULL; )
52225a99e2eSeric 			if (sameaddr(q, a, FALSE))
52325a99e2eSeric 			{
52425a99e2eSeric # ifdef DEBUG
52525a99e2eSeric 				if (Debug)
52625a99e2eSeric 					printf("(%s in SendQ)\n", a->q_paddr);
52725a99e2eSeric # endif DEBUG
52825a99e2eSeric 				return;
52925a99e2eSeric 			}
53025a99e2eSeric 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
53125a99e2eSeric 			if (sameaddr(q, a, FALSE))
53225a99e2eSeric 			{
53325a99e2eSeric # ifdef DEBUG
53425a99e2eSeric 				if (Debug)
53525a99e2eSeric 					printf("(%s in AliasQ)\n", a->q_paddr);
53625a99e2eSeric # endif DEBUG
53725a99e2eSeric 				return;
53825a99e2eSeric 			}
53925a99e2eSeric 	}
54025a99e2eSeric 
54125a99e2eSeric 	/*
54225a99e2eSeric 	**  See if the user wants hir mail forwarded.
54325a99e2eSeric 	**	`Forward' must do the forwarding recursively.
54425a99e2eSeric 	*/
54525a99e2eSeric 
54625a99e2eSeric 	if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a))
54725a99e2eSeric 		return;
54825a99e2eSeric 
54925a99e2eSeric 	/*
55025a99e2eSeric 	**  Put the user onto the target queue.
55125a99e2eSeric 	*/
55225a99e2eSeric 
55325a99e2eSeric 	if (targetq != NULL)
55425a99e2eSeric 	{
55525a99e2eSeric 		putonq(a, targetq);
55625a99e2eSeric 	}
55725a99e2eSeric 
55825a99e2eSeric 	return;
55925a99e2eSeric }
56025a99e2eSeric /*
56125a99e2eSeric **  BUILDARGV -- Build an argument vector for a mail server.
56225a99e2eSeric **
56325a99e2eSeric **	Using a template defined in config.c, an argv is built.
56425a99e2eSeric **	The format of the template is already a vector.  The
56525a99e2eSeric **	items of this vector are copied, unless a dollar sign
56625a99e2eSeric **	is encountered.  In this case, the next character
56725a99e2eSeric **	specifies something else to copy in.  These can be
56825a99e2eSeric **		$f	The from address.
56925a99e2eSeric **		$h	The host.
57025a99e2eSeric **		$u	The user.
57125a99e2eSeric **		$c	The hop count.
57225a99e2eSeric **	The vector is built in a local buffer.  A pointer to
57325a99e2eSeric **	the static argv is returned.
57425a99e2eSeric **
57525a99e2eSeric **	Parameters:
57625a99e2eSeric **		tmplt -- a template for an argument vector.
57725a99e2eSeric **		flags -- the flags for this server.
57825a99e2eSeric **		host -- the host name to send to.
57925a99e2eSeric **		user -- the user name to send to.
58025a99e2eSeric **		from -- the person this mail is from.
58125a99e2eSeric **
58225a99e2eSeric **	Returns:
58325a99e2eSeric **		A pointer to an argv.
58425a99e2eSeric **
58525a99e2eSeric **	Side Effects:
58625a99e2eSeric **		none
58725a99e2eSeric **
58825a99e2eSeric **	WARNING:
58925a99e2eSeric **		Since the argv is staticly allocated, any subsequent
59025a99e2eSeric **		calls will clobber the old argv.
59125a99e2eSeric **
59225a99e2eSeric **	Called By:
59325a99e2eSeric **		deliver
59425a99e2eSeric */
59525a99e2eSeric 
59625a99e2eSeric char **
59725a99e2eSeric buildargv(tmplt, flags, host, user, from)
59825a99e2eSeric 	char **tmplt;
59925a99e2eSeric 	int flags;
60025a99e2eSeric 	char *host;
60125a99e2eSeric 	char *user;
60225a99e2eSeric 	char *from;
60325a99e2eSeric {
60425a99e2eSeric 	register char *p;
60525a99e2eSeric 	register char *q;
60625a99e2eSeric 	static char *pv[MAXPV+1];
60725a99e2eSeric 	char **pvp;
60825a99e2eSeric 	char **mvp;
60925a99e2eSeric 	static char buf[512];
61025a99e2eSeric 	register char *bp;
61125a99e2eSeric 	char pbuf[30];
61225a99e2eSeric 
61325a99e2eSeric 	/*
61425a99e2eSeric 	**  Do initial argv setup.
61525a99e2eSeric 	**	Insert the mailer name.  Notice that $x expansion is
61625a99e2eSeric 	**	NOT done on the mailer name.  Then, if the mailer has
61725a99e2eSeric 	**	a picky -f flag, we insert it as appropriate.  This
61825a99e2eSeric 	**	code does not check for 'pv' overflow; this places a
61925a99e2eSeric 	**	manifest lower limit of 4 for MAXPV.
62025a99e2eSeric 	*/
62125a99e2eSeric 
62225a99e2eSeric 	pvp = pv;
62325a99e2eSeric 	bp = buf;
62425a99e2eSeric 
62525a99e2eSeric 	*pvp++ = tmplt[0];
62625a99e2eSeric 
62725a99e2eSeric 	/* insert -f or -r flag as appropriate */
62825a99e2eSeric 	if (flagset(M_FOPT|M_ROPT, flags) && FromFlag)
62925a99e2eSeric 	{
63025a99e2eSeric 		if (flagset(M_FOPT, flags))
63125a99e2eSeric 			*pvp++ = "-f";
63225a99e2eSeric 		else
63325a99e2eSeric 			*pvp++ = "-r";
63425a99e2eSeric 		*pvp++ = From.q_paddr;
63525a99e2eSeric 	}
63625a99e2eSeric 
63725a99e2eSeric 	/*
63825a99e2eSeric 	**  Build the rest of argv.
63925a99e2eSeric 	**	For each prototype parameter, the prototype is
64025a99e2eSeric 	**	scanned character at a time.  If a dollar-sign is
64125a99e2eSeric 	**	found, 'q' is set to the appropriate expansion,
64225a99e2eSeric 	**	otherwise it is null.  Then either the string
64325a99e2eSeric 	**	pointed to by q, or the original character, is
64425a99e2eSeric 	**	interpolated into the buffer.  Buffer overflow is
64525a99e2eSeric 	**	checked.
64625a99e2eSeric 	*/
64725a99e2eSeric 
64825a99e2eSeric 	for (mvp = tmplt; (p = *++mvp) != NULL; )
64925a99e2eSeric 	{
65025a99e2eSeric 		if (pvp >= &pv[MAXPV])
65125a99e2eSeric 		{
65225a99e2eSeric 			syserr("Too many parameters to %s", pv[0]);
65325a99e2eSeric 			return (NULL);
65425a99e2eSeric 		}
65525a99e2eSeric 		*pvp++ = bp;
65625a99e2eSeric 		for (; *p != '\0'; p++)
65725a99e2eSeric 		{
65825a99e2eSeric 			/* q will be the interpolated quantity */
65925a99e2eSeric 			q = NULL;
66025a99e2eSeric 			if (*p == '$')
66125a99e2eSeric 			{
66225a99e2eSeric 				switch (*++p)
66325a99e2eSeric 				{
66425a99e2eSeric 				  case 'f':	/* from person */
66525a99e2eSeric 					q = from;
66625a99e2eSeric 					break;
66725a99e2eSeric 
66825a99e2eSeric 				  case 'u':	/* user */
66925a99e2eSeric 					q = user;
67025a99e2eSeric 					break;
67125a99e2eSeric 
67225a99e2eSeric 				  case 'h':	/* host */
67325a99e2eSeric 					q = host;
67425a99e2eSeric 					break;
67525a99e2eSeric 
67625a99e2eSeric 				  case 'c':	/* hop count */
67725a99e2eSeric 					sprintf(pbuf, "%d", HopCount);
67825a99e2eSeric 					q = pbuf;
67925a99e2eSeric 					break;
68025a99e2eSeric 				}
68125a99e2eSeric 			}
68225a99e2eSeric 
68325a99e2eSeric 			/*
68425a99e2eSeric 			**  Interpolate q or output one character
68525a99e2eSeric 			**	Strip quote bits as we proceed.....
68625a99e2eSeric 			*/
68725a99e2eSeric 
68825a99e2eSeric 			if (q != NULL)
68925a99e2eSeric 			{
69025a99e2eSeric 				while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0')
69125a99e2eSeric 					continue;
69225a99e2eSeric 				bp--;
69325a99e2eSeric 			}
69425a99e2eSeric 			else if (bp < &buf[sizeof buf - 1])
69525a99e2eSeric 				*bp++ = *p;
69625a99e2eSeric 		}
69725a99e2eSeric 		*bp++ = '\0';
69825a99e2eSeric 		if (bp >= &buf[sizeof buf - 1])
69925a99e2eSeric 			return (NULL);
70025a99e2eSeric 	}
70125a99e2eSeric 	*pvp = NULL;
70225a99e2eSeric 
70325a99e2eSeric # ifdef DEBUG
70425a99e2eSeric 	if (Debug)
70525a99e2eSeric 	{
70625a99e2eSeric 		printf("Interpolated argv is:\n");
70725a99e2eSeric 		for (mvp = pv; *mvp != NULL; mvp++)
70825a99e2eSeric 			printf("\t%s\n", *mvp);
70925a99e2eSeric 	}
71025a99e2eSeric # endif DEBUG
71125a99e2eSeric 
71225a99e2eSeric 	return (pv);
71325a99e2eSeric }
71425a99e2eSeric /*
71525a99e2eSeric **  MAILFILE -- Send a message to a file.
71625a99e2eSeric **
71725a99e2eSeric **	Parameters:
71825a99e2eSeric **		filename -- the name of the file to send to.
71925a99e2eSeric **
72025a99e2eSeric **	Returns:
72125a99e2eSeric **		The exit code associated with the operation.
72225a99e2eSeric **
72325a99e2eSeric **	Side Effects:
72425a99e2eSeric **		none.
72525a99e2eSeric **
72625a99e2eSeric **	Called By:
72725a99e2eSeric **		deliver
72825a99e2eSeric */
72925a99e2eSeric 
73025a99e2eSeric mailfile(filename)
73125a99e2eSeric 	char *filename;
73225a99e2eSeric {
73325a99e2eSeric 	char buf[MAXLINE];
73425a99e2eSeric 	register FILE *f;
73525a99e2eSeric 	auto long tim;
73625a99e2eSeric 	extern char *ctime();
73725a99e2eSeric 
73825a99e2eSeric 	f = fopen(filename, "a");
73925a99e2eSeric 	if (f == NULL)
74025a99e2eSeric 		return (EX_CANTCREAT);
74125a99e2eSeric 
74225a99e2eSeric 	/* output the timestamp */
74325a99e2eSeric 	time(&tim);
74425a99e2eSeric 	fprintf(f, "From %s %s", From.q_paddr, ctime(&tim));
74525a99e2eSeric 	rewind(stdin);
74625a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL)
74725a99e2eSeric 	{
74825a99e2eSeric 		fputs(buf, f);
74925a99e2eSeric 		if (ferror(f))
75025a99e2eSeric 		{
75125a99e2eSeric 			fclose(f);
75225a99e2eSeric 			return (EX_IOERR);
75325a99e2eSeric 		}
75425a99e2eSeric 	}
75525a99e2eSeric 	fputs("\n", f);
75625a99e2eSeric 	fclose(f);
75725a99e2eSeric 	return (EX_OK);
75825a99e2eSeric }
759