125a99e2eSeric # include <stdio.h>
225a99e2eSeric # include <pwd.h>
325a99e2eSeric # include <signal.h>
4*6328bdf7Seric # include <ctype.h>
525a99e2eSeric # include "dlvrmail.h"
625a99e2eSeric # ifdef LOG
7e374fd72Seric # include <syslog.h>
825a99e2eSeric # endif LOG
925a99e2eSeric 
10*6328bdf7Seric static char SccsId[] = "@(#)deliver.c	3.1	03/04/81";
11259cace7Seric 
1225a99e2eSeric /*
1325a99e2eSeric **  DELIVER -- Deliver a message to a particular address.
1425a99e2eSeric **
1525a99e2eSeric **	Algorithm:
1625a99e2eSeric **		Compute receiving network (i.e., mailer), host, & user.
1725a99e2eSeric **		If local, see if this is really a program name.
1825a99e2eSeric **		Build argument for the mailer.
1925a99e2eSeric **		Create pipe through edit fcn if appropriate.
2025a99e2eSeric **		Fork.
2125a99e2eSeric **			Child: call mailer
2225a99e2eSeric **		Parent: call editfcn if specified.
2325a99e2eSeric **		Wait for mailer to finish.
2425a99e2eSeric **		Interpret exit status.
2525a99e2eSeric **
2625a99e2eSeric **	Parameters:
2725a99e2eSeric **		to -- the address to deliver the message to.
2825a99e2eSeric **		editfcn -- if non-NULL, we want to call this function
2925a99e2eSeric **			to output the letter (instead of just out-
3025a99e2eSeric **			putting it raw).
3125a99e2eSeric **
3225a99e2eSeric **	Returns:
3325a99e2eSeric **		zero -- successfully delivered.
3425a99e2eSeric **		else -- some failure, see ExitStat for more info.
3525a99e2eSeric **
3625a99e2eSeric **	Side Effects:
3725a99e2eSeric **		The standard input is passed off to someone.
3825a99e2eSeric **
3925a99e2eSeric **	WARNING:
4025a99e2eSeric **		The standard input is shared amongst all children,
4125a99e2eSeric **		including the file pointer.  It is critical that the
4225a99e2eSeric **		parent waits for the child to finish before forking
4325a99e2eSeric **		another child.
4425a99e2eSeric **
4525a99e2eSeric **	Called By:
4625a99e2eSeric **		main
4725a99e2eSeric **		savemail
4825a99e2eSeric **
4925a99e2eSeric **	Files:
50a2ee7369Seric **		standard input -- must be opened to the message to
5125a99e2eSeric **			deliver.
5225a99e2eSeric */
5325a99e2eSeric 
5425a99e2eSeric deliver(to, editfcn)
5525a99e2eSeric 	addrq *to;
5625a99e2eSeric 	int (*editfcn)();
5725a99e2eSeric {
5825a99e2eSeric 	register struct mailer *m;
5925a99e2eSeric 	char *host;
6025a99e2eSeric 	char *user;
6125a99e2eSeric 	extern struct passwd *getpwnam();
6225a99e2eSeric 	char **pvp;
6325a99e2eSeric 	extern char **buildargv();
6425a99e2eSeric 	auto int st;
6525a99e2eSeric 	register int i;
6625a99e2eSeric 	register char *p;
6725a99e2eSeric 	int pid;
6825a99e2eSeric 	int pvect[2];
6925a99e2eSeric 	extern FILE *fdopen();
7025a99e2eSeric 	extern int errno;
7125a99e2eSeric 	FILE *mfile;
72*6328bdf7Seric 	extern putmessage();
7325a99e2eSeric 	extern pipesig();
74b07ac16bSeric 	extern char *index();
7525a99e2eSeric 
7625a99e2eSeric 	/*
7725a99e2eSeric 	**  Compute receiving mailer, host, and to addreses.
7825a99e2eSeric 	**	Do some initialization first.  To is the to address
7925a99e2eSeric 	**	for error messages.
8025a99e2eSeric 	*/
8125a99e2eSeric 
8225a99e2eSeric 	To = to->q_paddr;
8325a99e2eSeric 	m = to->q_mailer;
8425a99e2eSeric 	user = to->q_user;
8525a99e2eSeric 	host = to->q_host;
86c1f9df2cSeric 	Errors = 0;
8725a99e2eSeric 	errno = 0;
8825a99e2eSeric # ifdef DEBUG
8925a99e2eSeric 	if (Debug)
9025a99e2eSeric 		printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
9125a99e2eSeric # endif DEBUG
9225a99e2eSeric 
9325a99e2eSeric 	/*
9425a99e2eSeric 	**  Remove quote bits from user/host.
9525a99e2eSeric 	*/
9625a99e2eSeric 
9725a99e2eSeric 	for (p = user; (*p++ &= 0177) != '\0'; )
9825a99e2eSeric 		continue;
9925a99e2eSeric 	if (host != NULL)
10025a99e2eSeric 		for (p = host; (*p++ &= 0177) != '\0'; )
10125a99e2eSeric 			continue;
10225a99e2eSeric 
10325a99e2eSeric 	/*
10425a99e2eSeric 	**  Strip quote bits from names if the mailer wants it.
10525a99e2eSeric 	*/
10625a99e2eSeric 
10725a99e2eSeric 	if (flagset(M_STRIPQ, m->m_flags))
10825a99e2eSeric 	{
10925a99e2eSeric 		stripquotes(user);
11025a99e2eSeric 		stripquotes(host);
11125a99e2eSeric 	}
11225a99e2eSeric 
11325a99e2eSeric 	/*
11425a99e2eSeric 	**  See if this user name is "special".
11525a99e2eSeric 	**	If the user is a program, diddle with the mailer spec.
11625a99e2eSeric 	**	If the user name has a slash in it, assume that this
11725a99e2eSeric 	**		is a file -- send it off without further ado.
11825a99e2eSeric 	**		Note that this means that editfcn's will not
11925a99e2eSeric 	**		be applied to the message.
12025a99e2eSeric 	*/
12125a99e2eSeric 
12225a99e2eSeric 	if (m == &Mailer[0])
12325a99e2eSeric 	{
12425a99e2eSeric 		if (*user == '|')
12525a99e2eSeric 		{
12625a99e2eSeric 			user++;
12725a99e2eSeric 			m = &Mailer[1];
12825a99e2eSeric 		}
12925a99e2eSeric 		else
13025a99e2eSeric 		{
13125a99e2eSeric 			if (index(user, '/') != NULL)
13225a99e2eSeric 			{
13325a99e2eSeric 				i = mailfile(user);
13425a99e2eSeric 				giveresponse(i, TRUE, m);
13525a99e2eSeric 				return (i);
13625a99e2eSeric 			}
13725a99e2eSeric 		}
13825a99e2eSeric 	}
13925a99e2eSeric 
14025a99e2eSeric 	/*
141243921eeSeric 	**  See if the user exists.
142243921eeSeric 	**	Strictly, this is only needed to print a pretty
14325a99e2eSeric 	**	error message.
144243921eeSeric 	**
145243921eeSeric 	**	>>>>>>>>>> This clause assumes that the local mailer
146243921eeSeric 	**	>> NOTE >> cannot do any further aliasing; that
147243921eeSeric 	**	>>>>>>>>>> function is subsumed by delivermail.
14825a99e2eSeric 	*/
14925a99e2eSeric 
15025a99e2eSeric 	if (m == &Mailer[0])
15125a99e2eSeric 	{
15225a99e2eSeric 		if (getpwnam(user) == NULL)
15325a99e2eSeric 		{
15425a99e2eSeric 			giveresponse(EX_NOUSER, TRUE, m);
15525a99e2eSeric 			return (EX_NOUSER);
15625a99e2eSeric 		}
15725a99e2eSeric 	}
15825a99e2eSeric 
15925a99e2eSeric 	/*
16025a99e2eSeric 	**  Call the mailer.
161*6328bdf7Seric 	**	The argument vector gets built, pipes
16225a99e2eSeric 	**	are created as necessary, and we fork & exec as
163*6328bdf7Seric 	**	appropriate.
16425a99e2eSeric 	*/
16525a99e2eSeric 
166*6328bdf7Seric 	pvp = buildargv(m, host, user, From.q_paddr);
16725a99e2eSeric 	if (pvp == NULL)
16825a99e2eSeric 	{
16925a99e2eSeric 		usrerr("name too long");
17025a99e2eSeric 		return (-1);
17125a99e2eSeric 	}
17225a99e2eSeric 	rewind(stdin);
17325a99e2eSeric 
174*6328bdf7Seric 	/* create a pipe to shove the mail through */
175*6328bdf7Seric 	if (pipe(pvect) < 0)
17625a99e2eSeric 	{
17725a99e2eSeric 		syserr("pipe");
17825a99e2eSeric 		return (-1);
17925a99e2eSeric 	}
180ea235328Smark # ifdef VFORK
181ea235328Smark 	pid = vfork();
182ea235328Smark # else
18325a99e2eSeric 	pid = fork();
184ea235328Smark # endif
18525a99e2eSeric 	if (pid < 0)
18625a99e2eSeric 	{
18725a99e2eSeric 		syserr("Cannot fork");
18825a99e2eSeric 		close(pvect[0]);
18925a99e2eSeric 		close(pvect[1]);
19025a99e2eSeric 		return (-1);
19125a99e2eSeric 	}
19225a99e2eSeric 	else if (pid == 0)
19325a99e2eSeric 	{
19425a99e2eSeric 		/* child -- set up input & exec mailer */
19503ab8e55Seric 		/* make diagnostic output be standard output */
19603ab8e55Seric 		close(2);
19703ab8e55Seric 		dup(1);
19825a99e2eSeric 		signal(SIGINT, SIG_IGN);
19925a99e2eSeric 		close(0);
20025a99e2eSeric 		if (dup(pvect[0]) < 0)
20125a99e2eSeric 		{
20225a99e2eSeric 			syserr("Cannot dup to zero!");
203a590b978Seric 			_exit(EX_OSERR);
20425a99e2eSeric 		}
20525a99e2eSeric 		close(pvect[0]);
20625a99e2eSeric 		close(pvect[1]);
20725a99e2eSeric 		if (!flagset(M_RESTR, m->m_flags))
20825a99e2eSeric 			setuid(getuid());
209e374fd72Seric # ifndef VFORK
210e374fd72Seric 		/*
211e374fd72Seric 		**  We have to be careful with vfork - we can't mung up the
212e374fd72Seric 		**  memory but we don't want the mailer to inherit any extra
213e374fd72Seric 		**  open files.  Chances are the mailer won't
214e374fd72Seric 		**  care about an extra file, but then again you never know.
215e374fd72Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
216e374fd72Seric 		**  declared static so we can't.  But if we fclose(pwf), which
217e374fd72Seric 		**  is what endpwent does, it closes it in the parent too and
218e374fd72Seric 		**  the next getpwnam will be slower.  If you have a weird
219e374fd72Seric 		**  mailer that chokes on the extra file you should do the
220e374fd72Seric 		**  endpwent().
221e374fd72Seric 		**
222e374fd72Seric 		**  Similar comments apply to log.  However, openlog is
223e374fd72Seric 		**  clever enough to set the FIOCLEX mode on the file,
224e374fd72Seric 		**  so it will be closed automatically on the exec.
225e374fd72Seric 		*/
226e374fd72Seric 
227e374fd72Seric 		endpwent();
22825a99e2eSeric # ifdef LOG
229f9fe028fSeric 		closelog();
23025a99e2eSeric # endif LOG
231e374fd72Seric # endif VFORK
23225a99e2eSeric 		execv(m->m_mailer, pvp);
23325a99e2eSeric 		/* syserr fails because log is closed */
23425a99e2eSeric 		/* syserr("Cannot exec %s", m->m_mailer); */
2352ac087dbSeric 		printf("Cannot exec %s\n", m->m_mailer);
2362ac087dbSeric 		fflush(stdout);
237a590b978Seric 		_exit(EX_UNAVAILABLE);
23825a99e2eSeric 	}
23925a99e2eSeric 
240*6328bdf7Seric 	/* write out message to mailer */
24125a99e2eSeric 	close(pvect[0]);
24225a99e2eSeric 	signal(SIGPIPE, pipesig);
24325a99e2eSeric 	mfile = fdopen(pvect[1], "w");
244*6328bdf7Seric 	if (editfcn == NULL)
245*6328bdf7Seric 		editfcn = putmessage;
246*6328bdf7Seric 	(*editfcn)(mfile, m);
24725a99e2eSeric 	fclose(mfile);
24825a99e2eSeric 
24925a99e2eSeric 	/*
25025a99e2eSeric 	**  Wait for child to die and report status.
25125a99e2eSeric 	**	We should never get fatal errors (e.g., segmentation
25225a99e2eSeric 	**	violation), so we report those specially.  For other
25325a99e2eSeric 	**	errors, we choose a status message (into statmsg),
25425a99e2eSeric 	**	and if it represents an error, we print it.
25525a99e2eSeric 	*/
25625a99e2eSeric 
25725a99e2eSeric 	while ((i = wait(&st)) > 0 && i != pid)
25825a99e2eSeric 		continue;
25925a99e2eSeric 	if (i < 0)
26025a99e2eSeric 	{
26125a99e2eSeric 		syserr("wait");
26225a99e2eSeric 		return (-1);
26325a99e2eSeric 	}
26425a99e2eSeric 	if ((st & 0377) != 0)
26525a99e2eSeric 	{
26625a99e2eSeric 		syserr("%s: stat %o", pvp[0], st);
267df2792f7Seric 		ExitStat = EX_UNAVAILABLE;
26825a99e2eSeric 		return (-1);
26925a99e2eSeric 	}
27025a99e2eSeric 	i = (st >> 8) & 0377;
2712ac087dbSeric 	giveresponse(i, TRUE, m);
27225a99e2eSeric 	return (i);
27325a99e2eSeric }
27425a99e2eSeric /*
27525a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
27625a99e2eSeric **
27725a99e2eSeric **	Parameters:
27825a99e2eSeric **		stat -- the status code from the mailer (high byte
27925a99e2eSeric **			only; core dumps must have been taken care of
28025a99e2eSeric **			already).
28125a99e2eSeric **		force -- if set, force an error message output, even
28225a99e2eSeric **			if the mailer seems to like to print its own
28325a99e2eSeric **			messages.
28425a99e2eSeric **		m -- the mailer descriptor for this mailer.
28525a99e2eSeric **
28625a99e2eSeric **	Returns:
28725a99e2eSeric **		none.
28825a99e2eSeric **
28925a99e2eSeric **	Side Effects:
290c1f9df2cSeric **		Errors may be incremented.
29125a99e2eSeric **		ExitStat may be set.
29225a99e2eSeric **
29325a99e2eSeric **	Called By:
29425a99e2eSeric **		deliver
29525a99e2eSeric */
29625a99e2eSeric 
29725a99e2eSeric giveresponse(stat, force, m)
29825a99e2eSeric 	int stat;
29925a99e2eSeric 	int force;
30025a99e2eSeric 	register struct mailer *m;
30125a99e2eSeric {
30225a99e2eSeric 	register char *statmsg;
30325a99e2eSeric 	extern char *SysExMsg[];
30425a99e2eSeric 	register int i;
30525a99e2eSeric 	extern int N_SysEx;
30629dd97a3Seric 	extern long MsgSize;
30729dd97a3Seric 	char buf[30];
30825a99e2eSeric 
30925a99e2eSeric 	i = stat - EX__BASE;
31025a99e2eSeric 	if (i < 0 || i > N_SysEx)
31125a99e2eSeric 		statmsg = NULL;
31225a99e2eSeric 	else
31325a99e2eSeric 		statmsg = SysExMsg[i];
31425a99e2eSeric 	if (stat == 0)
31525a99e2eSeric 		statmsg = "ok";
31625a99e2eSeric 	else
31725a99e2eSeric 	{
318c1f9df2cSeric 		Errors++;
31925a99e2eSeric 		if (statmsg == NULL && m->m_badstat != 0)
32025a99e2eSeric 		{
32125a99e2eSeric 			stat = m->m_badstat;
32225a99e2eSeric 			i = stat - EX__BASE;
32325a99e2eSeric # ifdef DEBUG
32425a99e2eSeric 			if (i < 0 || i >= N_SysEx)
32525a99e2eSeric 				syserr("Bad m_badstat %d", stat);
32625a99e2eSeric 			else
32725a99e2eSeric # endif DEBUG
32825a99e2eSeric 			statmsg = SysExMsg[i];
32925a99e2eSeric 		}
33025a99e2eSeric 		if (statmsg == NULL)
33125a99e2eSeric 			usrerr("unknown mailer response %d", stat);
33225a99e2eSeric 		else if (force || !flagset(M_QUIET, m->m_flags))
33325a99e2eSeric 			usrerr("%s", statmsg);
33425a99e2eSeric 	}
33525a99e2eSeric 
33625a99e2eSeric 	/*
33725a99e2eSeric 	**  Final cleanup.
33825a99e2eSeric 	**	Log a record of the transaction.  Compute the new
33925a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
34025a99e2eSeric 	**	that.
34125a99e2eSeric 	*/
34225a99e2eSeric 
34325a99e2eSeric 	if (statmsg == NULL)
34429dd97a3Seric 	{
34529dd97a3Seric 		sprintf(buf, "error %d", stat);
34629dd97a3Seric 		statmsg = buf;
34729dd97a3Seric 	}
34829dd97a3Seric 
34929dd97a3Seric # ifdef LOG
350e374fd72Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
35125a99e2eSeric # endif LOG
352243921eeSeric 	setstat(stat);
35325a99e2eSeric 	return (stat);
35425a99e2eSeric }
35525a99e2eSeric /*
356*6328bdf7Seric **  PUTMESSAGE -- output a message to the final mailer.
35725a99e2eSeric **
358*6328bdf7Seric **	This routine takes care of recreating the header from the
359*6328bdf7Seric **	in-core copy, etc.
36025a99e2eSeric **
36125a99e2eSeric **	Parameters:
362*6328bdf7Seric **		fp -- file to output onto.
363*6328bdf7Seric **		m -- a mailer descriptor.
36425a99e2eSeric **
36525a99e2eSeric **	Returns:
366*6328bdf7Seric **		none.
36725a99e2eSeric **
36825a99e2eSeric **	Side Effects:
369*6328bdf7Seric **		The message is written onto fp.
37025a99e2eSeric */
37125a99e2eSeric 
372*6328bdf7Seric putmessage(fp, m)
373*6328bdf7Seric 	FILE *fp;
374*6328bdf7Seric 	struct mailer *m;
37525a99e2eSeric {
376*6328bdf7Seric 	char buf[BUFSIZ];
377*6328bdf7Seric 	register int i;
378*6328bdf7Seric 	HDR *h;
379b07ac16bSeric 	register char *p;
380*6328bdf7Seric 	extern char *arpadate();
381*6328bdf7Seric 	extern char *hvalue();
382*6328bdf7Seric 	bool anyheader = FALSE;
383*6328bdf7Seric 	extern char *translate();
38425a99e2eSeric 
385*6328bdf7Seric 	/* clear all "used" bits */
386*6328bdf7Seric 	for (h = Header; h != NULL; h = h->h_link)
387*6328bdf7Seric 		h->h_flags &= ~H_USED;
388*6328bdf7Seric 
389*6328bdf7Seric 	/* output date if needed by mailer */
390*6328bdf7Seric 	p = hvalue("date");
391*6328bdf7Seric 	if (flagset(M_NEEDDATE, m->m_flags) && p == NULL)
392*6328bdf7Seric 		p = arpadate(Date);
393*6328bdf7Seric 	if (p != NULL)
394b07ac16bSeric 	{
395*6328bdf7Seric 		fprintf(fp, "Date: %s\n", p);
396*6328bdf7Seric 		anyheader = TRUE;
397b07ac16bSeric 	}
398b07ac16bSeric 
399*6328bdf7Seric 	/* output from line if needed by mailer */
400*6328bdf7Seric 	p = hvalue("from");
401*6328bdf7Seric 	if (flagset(M_NEEDFROM, m->m_flags) && p == NULL)
402*6328bdf7Seric 	{
403*6328bdf7Seric 		char frombuf[MAXLINE];
404*6328bdf7Seric 		extern char *FullName;
405*6328bdf7Seric 
406*6328bdf7Seric 		p = translate("$f", From.q_mailer, From.q_paddr, NULL, NULL);
407*6328bdf7Seric 		if (FullName != NULL)
408*6328bdf7Seric 			fprintf(fp, "From: %s <%s>\n", FullName, p);
409*6328bdf7Seric 		else
410*6328bdf7Seric 			fprintf(fp, "From: %s\n", p);
411*6328bdf7Seric 		free(p);
412*6328bdf7Seric 		anyheader = TRUE;
413*6328bdf7Seric 	}
414*6328bdf7Seric 	else if (p != NULL)
415*6328bdf7Seric 	{
416*6328bdf7Seric 		fprintf(fp, "From: %s\n", p);
417*6328bdf7Seric 		anyheader = TRUE;
418*6328bdf7Seric 	}
419*6328bdf7Seric 
420*6328bdf7Seric 	/* output message-id field if needed */
421*6328bdf7Seric 	p = hvalue("message-id");
422*6328bdf7Seric 	if (flagset(M_MSGID, m->m_flags) && p == NULL)
423*6328bdf7Seric 		p = MsgId;
424*6328bdf7Seric 	if (p != NULL)
425*6328bdf7Seric 	{
426*6328bdf7Seric 		fprintf(fp, "Message-Id: %s\n", p);
427*6328bdf7Seric 		anyheader = TRUE;
428*6328bdf7Seric 	}
429*6328bdf7Seric 
430*6328bdf7Seric 	/* output any other header lines */
431*6328bdf7Seric 	for (h = Header; h != NULL; h = h->h_link)
432*6328bdf7Seric 	{
433*6328bdf7Seric 		if (flagset(H_USED, h->h_flags))
434*6328bdf7Seric 			continue;
435*6328bdf7Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), h->h_value);
436*6328bdf7Seric 		h->h_flags |= H_USED;
437*6328bdf7Seric 		anyheader = TRUE;
438*6328bdf7Seric 	}
439*6328bdf7Seric 
440*6328bdf7Seric 	if (anyheader)
441*6328bdf7Seric 		fprintf(fp, "\n");
442*6328bdf7Seric 
443*6328bdf7Seric 	/* output the body of the message */
444*6328bdf7Seric 	while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0)
445*6328bdf7Seric 		fwrite(buf, 1, i, fp);
446*6328bdf7Seric 
44725a99e2eSeric 	if (ferror(fp))
44825a99e2eSeric 	{
449*6328bdf7Seric 		syserr("putmessage: write error");
45025a99e2eSeric 		setstat(EX_IOERR);
45125a99e2eSeric 	}
45225a99e2eSeric }
45325a99e2eSeric /*
45425a99e2eSeric **  PIPESIG -- Handle broken pipe signals
45525a99e2eSeric **
45625a99e2eSeric **	This just logs an error.
45725a99e2eSeric **
45825a99e2eSeric **	Parameters:
45925a99e2eSeric **		none
46025a99e2eSeric **
46125a99e2eSeric **	Returns:
46225a99e2eSeric **		none
46325a99e2eSeric **
46425a99e2eSeric **	Side Effects:
46525a99e2eSeric **		logs an error message.
46625a99e2eSeric */
46725a99e2eSeric 
46825a99e2eSeric pipesig()
46925a99e2eSeric {
47025a99e2eSeric 	syserr("Broken pipe");
47103ab8e55Seric 	signal(SIGPIPE, SIG_IGN);
47225a99e2eSeric }
47325a99e2eSeric /*
47425a99e2eSeric **  SENDTO -- Designate a send list.
47525a99e2eSeric **
47625a99e2eSeric **	The parameter is a comma-separated list of people to send to.
47725a99e2eSeric **	This routine arranges to send to all of them.
47825a99e2eSeric **
47925a99e2eSeric **	Parameters:
48025a99e2eSeric **		list -- the send list.
48125a99e2eSeric **		copyf -- the copy flag; passed to parse.
48225a99e2eSeric **
48325a99e2eSeric **	Returns:
48425a99e2eSeric **		none
48525a99e2eSeric **
48625a99e2eSeric **	Side Effects:
48725a99e2eSeric **		none.
48825a99e2eSeric **
48925a99e2eSeric **	Called By:
49025a99e2eSeric **		main
49125a99e2eSeric **		alias
49225a99e2eSeric */
49325a99e2eSeric 
49425a99e2eSeric sendto(list, copyf)
49525a99e2eSeric 	char *list;
49625a99e2eSeric 	int copyf;
49725a99e2eSeric {
49825a99e2eSeric 	register char *p;
49925a99e2eSeric 	register char *q;
50025a99e2eSeric 	register char c;
50125a99e2eSeric 	addrq *a;
50225a99e2eSeric 	extern addrq *parse();
50325a99e2eSeric 	bool more;
50425a99e2eSeric 
50525a99e2eSeric 	/* more keeps track of what the previous delimiter was */
50625a99e2eSeric 	more = TRUE;
50725a99e2eSeric 	for (p = list; more; )
50825a99e2eSeric 	{
50925a99e2eSeric 		/* find the end of this address */
51025a99e2eSeric 		q = p;
51125a99e2eSeric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
51225a99e2eSeric 			continue;
51325a99e2eSeric 		more = c != '\0';
51425a99e2eSeric 		*--p = '\0';
51525a99e2eSeric 		if (more)
51625a99e2eSeric 			p++;
51725a99e2eSeric 
51825a99e2eSeric 		/* parse the address */
51925a99e2eSeric 		if ((a = parse(q, (addrq *) NULL, copyf)) == NULL)
52025a99e2eSeric 			continue;
52125a99e2eSeric 
52225a99e2eSeric 		/* arrange to send to this person */
52325a99e2eSeric 		recipient(a, &SendQ);
52425a99e2eSeric 	}
52525a99e2eSeric 	To = NULL;
52625a99e2eSeric }
52725a99e2eSeric /*
52825a99e2eSeric **  RECIPIENT -- Designate a message recipient
52925a99e2eSeric **
53025a99e2eSeric **	Saves the named person for future mailing.
53125a99e2eSeric **
53225a99e2eSeric **	Designates a person as a recipient.  This routine
53325a99e2eSeric **	does the initial parsing, and checks to see if
53425a99e2eSeric **	this person has already received the mail.
53525a99e2eSeric **	It also supresses local network names and turns them into
53625a99e2eSeric **	local names.
53725a99e2eSeric **
53825a99e2eSeric **	Parameters:
53925a99e2eSeric **		a -- the (preparsed) address header for the recipient.
54025a99e2eSeric **		targetq -- the queue to add the name to.
54125a99e2eSeric **
54225a99e2eSeric **	Returns:
54325a99e2eSeric **		none.
54425a99e2eSeric **
54525a99e2eSeric **	Side Effects:
54625a99e2eSeric **		none.
54725a99e2eSeric **
54825a99e2eSeric **	Called By:
54925a99e2eSeric **		sendto
55025a99e2eSeric **		main
55125a99e2eSeric */
55225a99e2eSeric 
55325a99e2eSeric recipient(a, targetq)
55425a99e2eSeric 	register addrq *a;
55525a99e2eSeric 	addrq *targetq;
55625a99e2eSeric {
55725a99e2eSeric 	register addrq *q;
55825a99e2eSeric 	register struct mailer *m;
55925a99e2eSeric 	register char **pvp;
56025a99e2eSeric 	extern char *xalloc();
56125a99e2eSeric 	extern bool forward();
56225a99e2eSeric 	extern int errno;
56325a99e2eSeric 	extern bool sameaddr();
56425a99e2eSeric 
56525a99e2eSeric 	To = a->q_paddr;
56625a99e2eSeric 	m = a->q_mailer;
56725a99e2eSeric 	errno = 0;
56825a99e2eSeric # ifdef DEBUG
56925a99e2eSeric 	if (Debug)
57025a99e2eSeric 		printf("recipient(%s)\n", To);
57125a99e2eSeric # endif DEBUG
57225a99e2eSeric 
57325a99e2eSeric 	/*
57425a99e2eSeric 	**  Look up this person in the recipient list.  If they
57525a99e2eSeric 	**  are there already, return, otherwise continue.
57625a99e2eSeric 	*/
57725a99e2eSeric 
57825a99e2eSeric 	if (!ForceMail)
57925a99e2eSeric 	{
58025a99e2eSeric 		for (q = &SendQ; (q = nxtinq(q)) != NULL; )
58125a99e2eSeric 			if (sameaddr(q, a, FALSE))
58225a99e2eSeric 			{
58325a99e2eSeric # ifdef DEBUG
58425a99e2eSeric 				if (Debug)
58525a99e2eSeric 					printf("(%s in SendQ)\n", a->q_paddr);
58625a99e2eSeric # endif DEBUG
58725a99e2eSeric 				return;
58825a99e2eSeric 			}
58925a99e2eSeric 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
59025a99e2eSeric 			if (sameaddr(q, a, FALSE))
59125a99e2eSeric 			{
59225a99e2eSeric # ifdef DEBUG
59325a99e2eSeric 				if (Debug)
59425a99e2eSeric 					printf("(%s in AliasQ)\n", a->q_paddr);
59525a99e2eSeric # endif DEBUG
59625a99e2eSeric 				return;
59725a99e2eSeric 			}
59825a99e2eSeric 	}
59925a99e2eSeric 
60025a99e2eSeric 	/*
60125a99e2eSeric 	**  See if the user wants hir mail forwarded.
60225a99e2eSeric 	**	`Forward' must do the forwarding recursively.
60325a99e2eSeric 	*/
60425a99e2eSeric 
60525a99e2eSeric 	if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a))
60625a99e2eSeric 		return;
60725a99e2eSeric 
60825a99e2eSeric 	/*
60925a99e2eSeric 	**  Put the user onto the target queue.
61025a99e2eSeric 	*/
61125a99e2eSeric 
61225a99e2eSeric 	if (targetq != NULL)
61325a99e2eSeric 	{
61425a99e2eSeric 		putonq(a, targetq);
61525a99e2eSeric 	}
61625a99e2eSeric 
61725a99e2eSeric 	return;
61825a99e2eSeric }
61925a99e2eSeric /*
62025a99e2eSeric **  BUILDARGV -- Build an argument vector for a mail server.
62125a99e2eSeric **
62225a99e2eSeric **	Using a template defined in config.c, an argv is built.
62325a99e2eSeric **	The format of the template is already a vector.  The
62425a99e2eSeric **	items of this vector are copied, unless a dollar sign
62525a99e2eSeric **	is encountered.  In this case, the next character
62625a99e2eSeric **	specifies something else to copy in.  These can be
62725a99e2eSeric **		$f	The from address.
62825a99e2eSeric **		$h	The host.
62925a99e2eSeric **		$u	The user.
63025a99e2eSeric **		$c	The hop count.
63125a99e2eSeric **	The vector is built in a local buffer.  A pointer to
63225a99e2eSeric **	the static argv is returned.
63325a99e2eSeric **
63425a99e2eSeric **	Parameters:
635*6328bdf7Seric **		m -- a pointer to the mailer descriptor.
63625a99e2eSeric **		host -- the host name to send to.
63725a99e2eSeric **		user -- the user name to send to.
63825a99e2eSeric **		from -- the person this mail is from.
63925a99e2eSeric **
64025a99e2eSeric **	Returns:
64125a99e2eSeric **		A pointer to an argv.
64225a99e2eSeric **
64325a99e2eSeric **	Side Effects:
64425a99e2eSeric **		none
64525a99e2eSeric **
64625a99e2eSeric **	WARNING:
64725a99e2eSeric **		Since the argv is staticly allocated, any subsequent
64825a99e2eSeric **		calls will clobber the old argv.
64925a99e2eSeric **
65025a99e2eSeric **	Called By:
65125a99e2eSeric **		deliver
65225a99e2eSeric */
65325a99e2eSeric 
65425a99e2eSeric char **
655*6328bdf7Seric buildargv(m, host, user, from)
656*6328bdf7Seric 	struct mailer *m;
65725a99e2eSeric 	char *host;
65825a99e2eSeric 	char *user;
65925a99e2eSeric 	char *from;
66025a99e2eSeric {
66125a99e2eSeric 	register char *p;
66225a99e2eSeric 	register char *q;
66325a99e2eSeric 	static char *pv[MAXPV+1];
66425a99e2eSeric 	char **pvp;
66525a99e2eSeric 	char **mvp;
66625a99e2eSeric 	static char buf[512];
66725a99e2eSeric 	register char *bp;
668*6328bdf7Seric 	extern char *translate();
66925a99e2eSeric 
67025a99e2eSeric 	/*
67125a99e2eSeric 	**  Do initial argv setup.
67225a99e2eSeric 	**	Insert the mailer name.  Notice that $x expansion is
67325a99e2eSeric 	**	NOT done on the mailer name.  Then, if the mailer has
67425a99e2eSeric 	**	a picky -f flag, we insert it as appropriate.  This
67525a99e2eSeric 	**	code does not check for 'pv' overflow; this places a
67625a99e2eSeric 	**	manifest lower limit of 4 for MAXPV.
67725a99e2eSeric 	*/
67825a99e2eSeric 
67925a99e2eSeric 	pvp = pv;
68025a99e2eSeric 	bp = buf;
68125a99e2eSeric 
682*6328bdf7Seric 	*pvp++ = m->m_argv[0];
68325a99e2eSeric 
68425a99e2eSeric 	/* insert -f or -r flag as appropriate */
685*6328bdf7Seric 	if (flagset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
68625a99e2eSeric 	{
687*6328bdf7Seric 		if (flagset(M_FOPT, m->m_flags))
68825a99e2eSeric 			*pvp++ = "-f";
68925a99e2eSeric 		else
69025a99e2eSeric 			*pvp++ = "-r";
691*6328bdf7Seric 		*pvp++ = translate(from, m, from, user, host);
69225a99e2eSeric 	}
69325a99e2eSeric 
69425a99e2eSeric 	/*
69525a99e2eSeric 	**  Build the rest of argv.
69625a99e2eSeric 	**	For each prototype parameter, the prototype is
69725a99e2eSeric 	**	scanned character at a time.  If a dollar-sign is
69825a99e2eSeric 	**	found, 'q' is set to the appropriate expansion,
69925a99e2eSeric 	**	otherwise it is null.  Then either the string
70025a99e2eSeric 	**	pointed to by q, or the original character, is
70125a99e2eSeric 	**	interpolated into the buffer.  Buffer overflow is
70225a99e2eSeric 	**	checked.
70325a99e2eSeric 	*/
70425a99e2eSeric 
705*6328bdf7Seric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
70625a99e2eSeric 	{
70725a99e2eSeric 		if (pvp >= &pv[MAXPV])
70825a99e2eSeric 		{
70925a99e2eSeric 			syserr("Too many parameters to %s", pv[0]);
71025a99e2eSeric 			return (NULL);
71125a99e2eSeric 		}
712*6328bdf7Seric 		*pvp++ = translate(p, m, from, user, host);
713*6328bdf7Seric 	}
714*6328bdf7Seric 	*pvp = NULL;
715*6328bdf7Seric 
716*6328bdf7Seric # ifdef DEBUG
717*6328bdf7Seric 	if (Debug)
718*6328bdf7Seric 	{
719*6328bdf7Seric 		printf("Interpolated argv is:\n");
720*6328bdf7Seric 		for (mvp = pv; *mvp != NULL; mvp++)
721*6328bdf7Seric 			printf("\t%s\n", *mvp);
722*6328bdf7Seric 	}
723*6328bdf7Seric # endif DEBUG
724*6328bdf7Seric 
725*6328bdf7Seric 	return (pv);
726*6328bdf7Seric }
727*6328bdf7Seric /*
728*6328bdf7Seric **  TRANSLATE -- translate a string using $x escapes.
729*6328bdf7Seric **
730*6328bdf7Seric **	Parameters:
731*6328bdf7Seric **		s -- string to translate.
732*6328bdf7Seric **		m -- pointer to mailer descriptor.
733*6328bdf7Seric **
734*6328bdf7Seric **	Returns:
735*6328bdf7Seric **		pointer to translated string.
736*6328bdf7Seric **
737*6328bdf7Seric **	Side Effects:
738*6328bdf7Seric **		none.
739*6328bdf7Seric */
740*6328bdf7Seric 
741*6328bdf7Seric char *
742*6328bdf7Seric translate(s, m, from, user, host)
743*6328bdf7Seric 	register char *s;
744*6328bdf7Seric 	struct mailer *m;
745*6328bdf7Seric 	char *from;
746*6328bdf7Seric 	char *user;
747*6328bdf7Seric 	char *host;
748*6328bdf7Seric {
749*6328bdf7Seric 	register char *q;
750*6328bdf7Seric 	char buf[MAXNAME];
751*6328bdf7Seric 	register char *bp;
752*6328bdf7Seric 	char *stack = NULL;
753*6328bdf7Seric 	char pbuf[10];
754*6328bdf7Seric 	extern char *newstr();
755*6328bdf7Seric 	extern char *Macro[];
756*6328bdf7Seric 
757*6328bdf7Seric 	bp = buf;
758*6328bdf7Seric restart:
759*6328bdf7Seric 
760*6328bdf7Seric # ifdef DEBUG
761*6328bdf7Seric 	if (Debug)
762*6328bdf7Seric 		printf("translate(%s)\n", s);
763*6328bdf7Seric # endif DEBUG
764*6328bdf7Seric 	for (; *s != '\0'; s++)
76525a99e2eSeric 	{
76625a99e2eSeric 		/* q will be the interpolated quantity */
76725a99e2eSeric 		q = NULL;
768*6328bdf7Seric 		if (*s == '$')
76925a99e2eSeric 		{
770*6328bdf7Seric 			if (isupper(*++s))
771*6328bdf7Seric 				q = Macro[*s - 'A'];
772*6328bdf7Seric 			else
773*6328bdf7Seric 			{
774*6328bdf7Seric 				switch (*s)
77525a99e2eSeric 				{
77625a99e2eSeric 				  case 'f':	/* from person */
777*6328bdf7Seric 					if (stack == NULL && m != NULL)
778*6328bdf7Seric 					{
779*6328bdf7Seric 						stack = s;
780*6328bdf7Seric 						s = m->m_from;
781*6328bdf7Seric 						goto restart;
782*6328bdf7Seric 					}
78325a99e2eSeric 					q = from;
78425a99e2eSeric 					break;
78525a99e2eSeric 
78625a99e2eSeric 				  case 'u':	/* user */
78725a99e2eSeric 					q = user;
78825a99e2eSeric 					break;
78925a99e2eSeric 
79025a99e2eSeric 				  case 'h':	/* host */
79125a99e2eSeric 					q = host;
79225a99e2eSeric 					break;
79325a99e2eSeric 
79425a99e2eSeric 				  case 'c':	/* hop count */
79525a99e2eSeric 					sprintf(pbuf, "%d", HopCount);
79625a99e2eSeric 					q = pbuf;
79725a99e2eSeric 					break;
79825a99e2eSeric 				}
79925a99e2eSeric 			}
800*6328bdf7Seric 		}
80125a99e2eSeric 
80225a99e2eSeric 		/*
80325a99e2eSeric 		**  Interpolate q or output one character
80425a99e2eSeric 		**	Strip quote bits as we proceed.....
80525a99e2eSeric 		*/
80625a99e2eSeric 
80725a99e2eSeric 		if (q != NULL)
80825a99e2eSeric 		{
80925a99e2eSeric 			while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0')
81025a99e2eSeric 				continue;
81125a99e2eSeric 			bp--;
81225a99e2eSeric 		}
81325a99e2eSeric 		else if (bp < &buf[sizeof buf - 1])
814*6328bdf7Seric 			*bp++ = *s;
815*6328bdf7Seric 	}
816*6328bdf7Seric 	if (stack != NULL)
817*6328bdf7Seric 	{
818*6328bdf7Seric 		s = stack;
819*6328bdf7Seric 		s++;
820*6328bdf7Seric 		stack = NULL;
821*6328bdf7Seric 		goto restart;
82225a99e2eSeric 	}
82325a99e2eSeric 	*bp++ = '\0';
82425a99e2eSeric 	if (bp >= &buf[sizeof buf - 1])
82525a99e2eSeric 		return (NULL);
82625a99e2eSeric # ifdef DEBUG
82725a99e2eSeric 	if (Debug)
828*6328bdf7Seric 		printf("translate ==> '%s'\n", buf);
82925a99e2eSeric # endif DEBUG
830*6328bdf7Seric 	return (newstr(buf));
83125a99e2eSeric }
83225a99e2eSeric /*
83325a99e2eSeric **  MAILFILE -- Send a message to a file.
83425a99e2eSeric **
83525a99e2eSeric **	Parameters:
83625a99e2eSeric **		filename -- the name of the file to send to.
83725a99e2eSeric **
83825a99e2eSeric **	Returns:
83925a99e2eSeric **		The exit code associated with the operation.
84025a99e2eSeric **
84125a99e2eSeric **	Side Effects:
84225a99e2eSeric **		none.
84325a99e2eSeric **
84425a99e2eSeric **	Called By:
84525a99e2eSeric **		deliver
84625a99e2eSeric */
84725a99e2eSeric 
84825a99e2eSeric mailfile(filename)
84925a99e2eSeric 	char *filename;
85025a99e2eSeric {
85125a99e2eSeric 	char buf[MAXLINE];
85225a99e2eSeric 	register FILE *f;
85325a99e2eSeric 	auto long tim;
85425a99e2eSeric 	extern char *ctime();
85525a99e2eSeric 
85625a99e2eSeric 	f = fopen(filename, "a");
85725a99e2eSeric 	if (f == NULL)
85825a99e2eSeric 		return (EX_CANTCREAT);
85925a99e2eSeric 
86025a99e2eSeric 	/* output the timestamp */
86125a99e2eSeric 	time(&tim);
86225a99e2eSeric 	fprintf(f, "From %s %s", From.q_paddr, ctime(&tim));
86325a99e2eSeric 	rewind(stdin);
86425a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL)
86525a99e2eSeric 	{
86625a99e2eSeric 		fputs(buf, f);
86725a99e2eSeric 		if (ferror(f))
86825a99e2eSeric 		{
86925a99e2eSeric 			fclose(f);
87025a99e2eSeric 			return (EX_IOERR);
87125a99e2eSeric 		}
87225a99e2eSeric 	}
87325a99e2eSeric 	fputs("\n", f);
87425a99e2eSeric 	fclose(f);
87525a99e2eSeric 	return (EX_OK);
87625a99e2eSeric }
877