125a99e2eSeric # include <stdio.h>
225a99e2eSeric # include <pwd.h>
325a99e2eSeric # include <signal.h>
46328bdf7Seric # include <ctype.h>
52a6e0786Seric # include "postbox.h"
625a99e2eSeric # ifdef LOG
7e374fd72Seric # include <syslog.h>
825a99e2eSeric # endif LOG
925a99e2eSeric 
10*5dfc646bSeric static char SccsId[] = "@(#)deliver.c	3.7	03/12/81";
11259cace7Seric 
1225a99e2eSeric /*
1325a99e2eSeric **  DELIVER -- Deliver a message to a particular address.
1425a99e2eSeric **
1525a99e2eSeric **	Parameters:
1625a99e2eSeric **		to -- the address to deliver the message to.
1725a99e2eSeric **		editfcn -- if non-NULL, we want to call this function
1825a99e2eSeric **			to output the letter (instead of just out-
1925a99e2eSeric **			putting it raw).
2025a99e2eSeric **
2125a99e2eSeric **	Returns:
2225a99e2eSeric **		zero -- successfully delivered.
2325a99e2eSeric **		else -- some failure, see ExitStat for more info.
2425a99e2eSeric **
2525a99e2eSeric **	Side Effects:
2625a99e2eSeric **		The standard input is passed off to someone.
2725a99e2eSeric */
2825a99e2eSeric 
2925a99e2eSeric deliver(to, editfcn)
302a6e0786Seric 	ADDRESS *to;
3125a99e2eSeric 	int (*editfcn)();
3225a99e2eSeric {
3325a99e2eSeric 	char *host;
3425a99e2eSeric 	char *user;
3525a99e2eSeric 	extern struct passwd *getpwnam();
3625a99e2eSeric 	char **pvp;
37*5dfc646bSeric 	register char **mvp;
3825a99e2eSeric 	register char *p;
39*5dfc646bSeric 	register struct mailer *m;
40*5dfc646bSeric 	register int i;
4125a99e2eSeric 	extern int errno;
426328bdf7Seric 	extern putmessage();
43b07ac16bSeric 	extern char *index();
442a6e0786Seric 	extern bool checkcompat();
45*5dfc646bSeric 	char *pv[MAXPV+1];
46*5dfc646bSeric 	extern char *newstr();
47*5dfc646bSeric 	char tobuf[MAXLINE];
48*5dfc646bSeric 	char buf[MAXNAME];
49*5dfc646bSeric 	extern char *expand();
50*5dfc646bSeric 	bool firstone;
5125a99e2eSeric 
52*5dfc646bSeric 	if (bitset(QDONTSEND, to->q_flags))
53*5dfc646bSeric 		return (0);
5425a99e2eSeric 
5525a99e2eSeric # ifdef DEBUG
5625a99e2eSeric 	if (Debug)
57*5dfc646bSeric 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
58*5dfc646bSeric 			to->q_mailer, to->q_host, to->q_user);
5925a99e2eSeric # endif DEBUG
6025a99e2eSeric 
6125a99e2eSeric 	/*
62*5dfc646bSeric 	**  Do initial argv setup.
63*5dfc646bSeric 	**	Insert the mailer name.  Notice that $x expansion is
64*5dfc646bSeric 	**	NOT done on the mailer name.  Then, if the mailer has
65*5dfc646bSeric 	**	a picky -f flag, we insert it as appropriate.  This
66*5dfc646bSeric 	**	code does not check for 'pv' overflow; this places a
67*5dfc646bSeric 	**	manifest lower limit of 4 for MAXPV.
68*5dfc646bSeric 	*/
69*5dfc646bSeric 
70*5dfc646bSeric 	m = Mailer[to->q_mailer];
71*5dfc646bSeric 	host = to->q_host;
72*5dfc646bSeric 	define('g', m->m_from);		/* translated from address */
73*5dfc646bSeric 	define('h', host);		/* to host */
74*5dfc646bSeric 	Errors = 0;
75*5dfc646bSeric 	errno = 0;
76*5dfc646bSeric 	pvp = pv;
77*5dfc646bSeric 	*pvp++ = m->m_argv[0];
78*5dfc646bSeric 
79*5dfc646bSeric 	/* insert -f or -r flag as appropriate */
80*5dfc646bSeric 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
81*5dfc646bSeric 	{
82*5dfc646bSeric 		if (bitset(M_FOPT, m->m_flags))
83*5dfc646bSeric 			*pvp++ = "-f";
84*5dfc646bSeric 		else
85*5dfc646bSeric 			*pvp++ = "-r";
86*5dfc646bSeric 		expand("$g", buf, &buf[sizeof buf - 1]);
87*5dfc646bSeric 		*pvp++ = newstr(buf);
88*5dfc646bSeric 	}
89*5dfc646bSeric 
90*5dfc646bSeric 	/*
91*5dfc646bSeric 	**  Append the other fixed parts of the argv.  These run
92*5dfc646bSeric 	**  up to the first entry containing "$u".  There can only
93*5dfc646bSeric 	**  be one of these, and there are only a few more slots
94*5dfc646bSeric 	**  in the pv after it.
95*5dfc646bSeric 	*/
96*5dfc646bSeric 
97*5dfc646bSeric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
98*5dfc646bSeric 	{
99*5dfc646bSeric 		while ((p = index(p, '$')) != NULL)
100*5dfc646bSeric 			if (*++p == 'u')
101*5dfc646bSeric 				break;
102*5dfc646bSeric 		if (p != NULL)
103*5dfc646bSeric 			break;
104*5dfc646bSeric 
105*5dfc646bSeric 		/* this entry is safe -- go ahead and process it */
106*5dfc646bSeric 		expand(*mvp, buf, &buf[sizeof buf - 1]);
107*5dfc646bSeric 		*pvp++ = newstr(buf);
108*5dfc646bSeric 		if (pvp >= &pv[MAXPV - 3])
109*5dfc646bSeric 		{
110*5dfc646bSeric 			syserr("Too many parameters to %s before $u", pv[0]);
111*5dfc646bSeric 			return (-1);
112*5dfc646bSeric 		}
113*5dfc646bSeric 	}
114*5dfc646bSeric 	if (*mvp == NULL)
115*5dfc646bSeric 		syserr("No $u in mailer argv for %s", pv[0]);
116*5dfc646bSeric 
117*5dfc646bSeric 	/*
118*5dfc646bSeric 	**  At this point *mvp points to the argument with $u.  We
119*5dfc646bSeric 	**  run through our address list and append all the addresses
120*5dfc646bSeric 	**  we can.  If we run out of space, do not fret!  We can
121*5dfc646bSeric 	**  always send another copy later.
122*5dfc646bSeric 	*/
123*5dfc646bSeric 
124*5dfc646bSeric 	tobuf[0] = '\0';
125*5dfc646bSeric 	firstone = TRUE;
126*5dfc646bSeric 	To = tobuf;
127*5dfc646bSeric 	for (; to != NULL; to = to->q_next)
128*5dfc646bSeric 	{
129*5dfc646bSeric 		/* avoid sending multiple recipients to dumb mailers */
130*5dfc646bSeric 		if (!firstone && !bitset(M_MUSER, m->m_flags))
131*5dfc646bSeric 			break;
132*5dfc646bSeric 
133*5dfc646bSeric 		/* if already sent or not for this host, don't send */
134*5dfc646bSeric 		if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0)
135*5dfc646bSeric 			continue;
136*5dfc646bSeric 		user = to->q_user;
137*5dfc646bSeric 		To = to->q_paddr;
138*5dfc646bSeric 		to->q_flags |= QDONTSEND;
139*5dfc646bSeric 		firstone = FALSE;
140*5dfc646bSeric 
141*5dfc646bSeric # ifdef DEBUG
142*5dfc646bSeric 		if (Debug)
143*5dfc646bSeric 			printf("   send to `%s'\n", user);
144*5dfc646bSeric # endif DEBUG
145*5dfc646bSeric 
146*5dfc646bSeric 		/*
147*5dfc646bSeric 		**  Check to see that these people are allowed to
148*5dfc646bSeric 		**  talk to each other.
1492a6e0786Seric 		*/
1502a6e0786Seric 
1512a6e0786Seric 		if (!checkcompat(to))
152*5dfc646bSeric 		{
153*5dfc646bSeric 			giveresponse(EX_UNAVAILABLE, TRUE, m);
154*5dfc646bSeric 			continue;
155*5dfc646bSeric 		}
1562a6e0786Seric 
1572a6e0786Seric 		/*
15825a99e2eSeric 		**  Remove quote bits from user/host.
15925a99e2eSeric 		*/
16025a99e2eSeric 
16125a99e2eSeric 		for (p = user; (*p++ &= 0177) != '\0'; )
16225a99e2eSeric 			continue;
16325a99e2eSeric 		if (host != NULL)
16425a99e2eSeric 			for (p = host; (*p++ &= 0177) != '\0'; )
16525a99e2eSeric 				continue;
16625a99e2eSeric 
16725a99e2eSeric 		/*
16825a99e2eSeric 		**  Strip quote bits from names if the mailer wants it.
16925a99e2eSeric 		*/
17025a99e2eSeric 
1712a6e0786Seric 		if (bitset(M_STRIPQ, m->m_flags))
17225a99e2eSeric 		{
17325a99e2eSeric 			stripquotes(user);
17425a99e2eSeric 			stripquotes(host);
17525a99e2eSeric 		}
17625a99e2eSeric 
17725a99e2eSeric 		/*
17825a99e2eSeric 		**  See if this user name is "special".
17925a99e2eSeric 		**	If the user name has a slash in it, assume that this
18025a99e2eSeric 		**	is a file -- send it off without further ado.
18125a99e2eSeric 		**	Note that this means that editfcn's will not
182*5dfc646bSeric 		**	be applied to the message.  Also note that
183*5dfc646bSeric 		**	this type of addresses is not processed along
184*5dfc646bSeric 		**	with the others, so we fudge on the To person.
18525a99e2eSeric 		*/
18625a99e2eSeric 
18786f2b423Seric 		if (m == Mailer[0])
18825a99e2eSeric 		{
18925a99e2eSeric 			if (index(user, '/') != NULL)
19025a99e2eSeric 			{
19125a99e2eSeric 				i = mailfile(user);
19225a99e2eSeric 				giveresponse(i, TRUE, m);
193*5dfc646bSeric 				continue;
19425a99e2eSeric 			}
19525a99e2eSeric 		}
19625a99e2eSeric 
19725a99e2eSeric 		/*
198243921eeSeric 		**  See if the user exists.
199243921eeSeric 		**	Strictly, this is only needed to print a pretty
20025a99e2eSeric 		**	error message.
201243921eeSeric 		**
202243921eeSeric 		**	>>>>>>>>>> This clause assumes that the local mailer
203243921eeSeric 		**	>> NOTE >> cannot do any further aliasing; that
2042a6e0786Seric 		**	>>>>>>>>>> function is subsumed by postbox.
20525a99e2eSeric 		*/
20625a99e2eSeric 
20786f2b423Seric 		if (m == Mailer[0])
20825a99e2eSeric 		{
20925a99e2eSeric 			if (getpwnam(user) == NULL)
21025a99e2eSeric 			{
21125a99e2eSeric 				giveresponse(EX_NOUSER, TRUE, m);
212*5dfc646bSeric 				continue;
21325a99e2eSeric 			}
21425a99e2eSeric 		}
21525a99e2eSeric 
216*5dfc646bSeric 		/* create list of users for error messages */
217*5dfc646bSeric 		if (tobuf[0] != '\0')
218*5dfc646bSeric 			strcat(tobuf, ",");
219*5dfc646bSeric 		strcat(tobuf, to->q_paddr);
220*5dfc646bSeric 		define('u', user);		/* to user */
221*5dfc646bSeric 
222*5dfc646bSeric 		/* expand out this user */
223*5dfc646bSeric 		expand(user, buf, &buf[sizeof buf - 1]);
224*5dfc646bSeric 		*pvp++ = newstr(buf);
225*5dfc646bSeric 		if (pvp >= &pv[MAXPV - 2])
226*5dfc646bSeric 		{
227*5dfc646bSeric 			/* allow some space for trailing parms */
228*5dfc646bSeric 			break;
229*5dfc646bSeric 		}
230*5dfc646bSeric 	}
231*5dfc646bSeric 
232*5dfc646bSeric 	/* print out messages as full list */
233*5dfc646bSeric 	To = tobuf;
234*5dfc646bSeric 
235*5dfc646bSeric 	/*
236*5dfc646bSeric 	**  Fill out any parameters after the $u parameter.
237*5dfc646bSeric 	*/
238*5dfc646bSeric 
239*5dfc646bSeric 	while (*++mvp != NULL)
240*5dfc646bSeric 	{
241*5dfc646bSeric 		expand(*mvp, buf, &buf[sizeof buf - 1]);
242*5dfc646bSeric 		*pvp++ = newstr(buf);
243*5dfc646bSeric 		if (pvp >= &pv[MAXPV])
244*5dfc646bSeric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
245*5dfc646bSeric 	}
246*5dfc646bSeric 	*pvp++ = NULL;
247*5dfc646bSeric 
24825a99e2eSeric 	/*
24925a99e2eSeric 	**  Call the mailer.
2506328bdf7Seric 	**	The argument vector gets built, pipes
25125a99e2eSeric 	**	are created as necessary, and we fork & exec as
2526328bdf7Seric 	**	appropriate.
25325a99e2eSeric 	*/
25425a99e2eSeric 
255*5dfc646bSeric 	if (editfcn == NULL)
256*5dfc646bSeric 		editfcn = putmessage;
257*5dfc646bSeric 	i = sendoff(m, pv, editfcn);
258*5dfc646bSeric 
259*5dfc646bSeric 	return (i);
26025a99e2eSeric }
261*5dfc646bSeric /*
262*5dfc646bSeric **  SENDOFF -- send off call to mailer & collect response.
263*5dfc646bSeric **
264*5dfc646bSeric **	Parameters:
265*5dfc646bSeric **		m -- mailer descriptor.
266*5dfc646bSeric **		pvp -- parameter vector to send to it.
267*5dfc646bSeric **		editfcn -- function to pipe it through.
268*5dfc646bSeric **
269*5dfc646bSeric **	Returns:
270*5dfc646bSeric **		exit status of mailer.
271*5dfc646bSeric **
272*5dfc646bSeric **	Side Effects:
273*5dfc646bSeric **		none.
274*5dfc646bSeric */
275*5dfc646bSeric 
276*5dfc646bSeric sendoff(m, pvp, editfcn)
277*5dfc646bSeric 	struct mailer *m;
278*5dfc646bSeric 	char **pvp;
279*5dfc646bSeric 	int (*editfcn)();
280*5dfc646bSeric {
281*5dfc646bSeric 	auto int st;
282*5dfc646bSeric 	register int i;
283*5dfc646bSeric 	int pid;
284*5dfc646bSeric 	int pvect[2];
285*5dfc646bSeric 	FILE *mfile;
286*5dfc646bSeric 	extern putmessage();
287*5dfc646bSeric 	extern pipesig();
288*5dfc646bSeric 	extern FILE *fdopen();
289*5dfc646bSeric 
290*5dfc646bSeric # ifdef DEBUG
291*5dfc646bSeric 	if (Debug)
292*5dfc646bSeric 	{
293*5dfc646bSeric 		printf("Sendoff:\n");
294*5dfc646bSeric 		printav(pvp);
295*5dfc646bSeric 	}
296*5dfc646bSeric # endif DEBUG
297*5dfc646bSeric 
29825a99e2eSeric 	rewind(stdin);
29925a99e2eSeric 
3006328bdf7Seric 	/* create a pipe to shove the mail through */
3016328bdf7Seric 	if (pipe(pvect) < 0)
30225a99e2eSeric 	{
30325a99e2eSeric 		syserr("pipe");
30425a99e2eSeric 		return (-1);
30525a99e2eSeric 	}
306ea235328Smark # ifdef VFORK
307ea235328Smark 	pid = vfork();
308ea235328Smark # else
30925a99e2eSeric 	pid = fork();
310ea235328Smark # endif
31125a99e2eSeric 	if (pid < 0)
31225a99e2eSeric 	{
31325a99e2eSeric 		syserr("Cannot fork");
31425a99e2eSeric 		close(pvect[0]);
31525a99e2eSeric 		close(pvect[1]);
31625a99e2eSeric 		return (-1);
31725a99e2eSeric 	}
31825a99e2eSeric 	else if (pid == 0)
31925a99e2eSeric 	{
32025a99e2eSeric 		/* child -- set up input & exec mailer */
32103ab8e55Seric 		/* make diagnostic output be standard output */
32203ab8e55Seric 		close(2);
32303ab8e55Seric 		dup(1);
32425a99e2eSeric 		signal(SIGINT, SIG_IGN);
32525a99e2eSeric 		close(0);
32625a99e2eSeric 		if (dup(pvect[0]) < 0)
32725a99e2eSeric 		{
32825a99e2eSeric 			syserr("Cannot dup to zero!");
329a590b978Seric 			_exit(EX_OSERR);
33025a99e2eSeric 		}
33125a99e2eSeric 		close(pvect[0]);
33225a99e2eSeric 		close(pvect[1]);
3332a6e0786Seric 		if (!bitset(M_RESTR, m->m_flags))
33425a99e2eSeric 			setuid(getuid());
335e374fd72Seric # ifndef VFORK
336e374fd72Seric 		/*
337e374fd72Seric 		**  We have to be careful with vfork - we can't mung up the
338e374fd72Seric 		**  memory but we don't want the mailer to inherit any extra
339e374fd72Seric 		**  open files.  Chances are the mailer won't
340e374fd72Seric 		**  care about an extra file, but then again you never know.
341e374fd72Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
342e374fd72Seric 		**  declared static so we can't.  But if we fclose(pwf), which
343e374fd72Seric 		**  is what endpwent does, it closes it in the parent too and
344e374fd72Seric 		**  the next getpwnam will be slower.  If you have a weird
345e374fd72Seric 		**  mailer that chokes on the extra file you should do the
346e374fd72Seric 		**  endpwent().
347e374fd72Seric 		**
348e374fd72Seric 		**  Similar comments apply to log.  However, openlog is
349e374fd72Seric 		**  clever enough to set the FIOCLEX mode on the file,
350e374fd72Seric 		**  so it will be closed automatically on the exec.
351e374fd72Seric 		*/
352e374fd72Seric 
353e374fd72Seric 		endpwent();
35425a99e2eSeric # ifdef LOG
355f9fe028fSeric 		closelog();
35625a99e2eSeric # endif LOG
357e374fd72Seric # endif VFORK
35825a99e2eSeric 		execv(m->m_mailer, pvp);
35925a99e2eSeric 		/* syserr fails because log is closed */
36025a99e2eSeric 		/* syserr("Cannot exec %s", m->m_mailer); */
3612ac087dbSeric 		printf("Cannot exec %s\n", m->m_mailer);
3622ac087dbSeric 		fflush(stdout);
363a590b978Seric 		_exit(EX_UNAVAILABLE);
36425a99e2eSeric 	}
36525a99e2eSeric 
3666328bdf7Seric 	/* write out message to mailer */
36725a99e2eSeric 	close(pvect[0]);
36825a99e2eSeric 	signal(SIGPIPE, pipesig);
36925a99e2eSeric 	mfile = fdopen(pvect[1], "w");
3706328bdf7Seric 	if (editfcn == NULL)
3716328bdf7Seric 		editfcn = putmessage;
3726328bdf7Seric 	(*editfcn)(mfile, m);
37325a99e2eSeric 	fclose(mfile);
37425a99e2eSeric 
37525a99e2eSeric 	/*
37625a99e2eSeric 	**  Wait for child to die and report status.
37725a99e2eSeric 	**	We should never get fatal errors (e.g., segmentation
37825a99e2eSeric 	**	violation), so we report those specially.  For other
37925a99e2eSeric 	**	errors, we choose a status message (into statmsg),
38025a99e2eSeric 	**	and if it represents an error, we print it.
38125a99e2eSeric 	*/
38225a99e2eSeric 
38325a99e2eSeric 	while ((i = wait(&st)) > 0 && i != pid)
38425a99e2eSeric 		continue;
38525a99e2eSeric 	if (i < 0)
38625a99e2eSeric 	{
38725a99e2eSeric 		syserr("wait");
38825a99e2eSeric 		return (-1);
38925a99e2eSeric 	}
39025a99e2eSeric 	if ((st & 0377) != 0)
39125a99e2eSeric 	{
39225a99e2eSeric 		syserr("%s: stat %o", pvp[0], st);
393df2792f7Seric 		ExitStat = EX_UNAVAILABLE;
39425a99e2eSeric 		return (-1);
39525a99e2eSeric 	}
39625a99e2eSeric 	i = (st >> 8) & 0377;
3972ac087dbSeric 	giveresponse(i, TRUE, m);
39825a99e2eSeric 	return (i);
39925a99e2eSeric }
40025a99e2eSeric /*
40125a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
40225a99e2eSeric **
40325a99e2eSeric **	Parameters:
40425a99e2eSeric **		stat -- the status code from the mailer (high byte
40525a99e2eSeric **			only; core dumps must have been taken care of
40625a99e2eSeric **			already).
40725a99e2eSeric **		force -- if set, force an error message output, even
40825a99e2eSeric **			if the mailer seems to like to print its own
40925a99e2eSeric **			messages.
41025a99e2eSeric **		m -- the mailer descriptor for this mailer.
41125a99e2eSeric **
41225a99e2eSeric **	Returns:
4132a6e0786Seric **		stat.
41425a99e2eSeric **
41525a99e2eSeric **	Side Effects:
416c1f9df2cSeric **		Errors may be incremented.
41725a99e2eSeric **		ExitStat may be set.
41825a99e2eSeric **
41925a99e2eSeric **	Called By:
42025a99e2eSeric **		deliver
42125a99e2eSeric */
42225a99e2eSeric 
42325a99e2eSeric giveresponse(stat, force, m)
42425a99e2eSeric 	int stat;
42525a99e2eSeric 	int force;
42625a99e2eSeric 	register struct mailer *m;
42725a99e2eSeric {
42825a99e2eSeric 	register char *statmsg;
42925a99e2eSeric 	extern char *SysExMsg[];
43025a99e2eSeric 	register int i;
43125a99e2eSeric 	extern int N_SysEx;
43229dd97a3Seric 	extern long MsgSize;
43329dd97a3Seric 	char buf[30];
434e9ff65b0Seric 	extern char *sprintf();
43525a99e2eSeric 
43625a99e2eSeric 	i = stat - EX__BASE;
43725a99e2eSeric 	if (i < 0 || i > N_SysEx)
43825a99e2eSeric 		statmsg = NULL;
43925a99e2eSeric 	else
44025a99e2eSeric 		statmsg = SysExMsg[i];
44125a99e2eSeric 	if (stat == 0)
44225a99e2eSeric 		statmsg = "ok";
44325a99e2eSeric 	else
44425a99e2eSeric 	{
445c1f9df2cSeric 		Errors++;
44625a99e2eSeric 		if (statmsg == NULL && m->m_badstat != 0)
44725a99e2eSeric 		{
44825a99e2eSeric 			stat = m->m_badstat;
44925a99e2eSeric 			i = stat - EX__BASE;
45025a99e2eSeric # ifdef DEBUG
45125a99e2eSeric 			if (i < 0 || i >= N_SysEx)
45225a99e2eSeric 				syserr("Bad m_badstat %d", stat);
45325a99e2eSeric 			else
45425a99e2eSeric # endif DEBUG
45525a99e2eSeric 			statmsg = SysExMsg[i];
45625a99e2eSeric 		}
45725a99e2eSeric 		if (statmsg == NULL)
45825a99e2eSeric 			usrerr("unknown mailer response %d", stat);
4592a6e0786Seric 		else if (force || !bitset(M_QUIET, m->m_flags))
46025a99e2eSeric 			usrerr("%s", statmsg);
46125a99e2eSeric 	}
46225a99e2eSeric 
46325a99e2eSeric 	/*
46425a99e2eSeric 	**  Final cleanup.
46525a99e2eSeric 	**	Log a record of the transaction.  Compute the new
46625a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
46725a99e2eSeric 	**	that.
46825a99e2eSeric 	*/
46925a99e2eSeric 
47025a99e2eSeric 	if (statmsg == NULL)
47129dd97a3Seric 	{
47229dd97a3Seric 		sprintf(buf, "error %d", stat);
47329dd97a3Seric 		statmsg = buf;
47429dd97a3Seric 	}
47529dd97a3Seric 
47629dd97a3Seric # ifdef LOG
477e374fd72Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
47825a99e2eSeric # endif LOG
479243921eeSeric 	setstat(stat);
48025a99e2eSeric 	return (stat);
48125a99e2eSeric }
48225a99e2eSeric /*
4836328bdf7Seric **  PUTMESSAGE -- output a message to the final mailer.
48425a99e2eSeric **
4856328bdf7Seric **	This routine takes care of recreating the header from the
4866328bdf7Seric **	in-core copy, etc.
48725a99e2eSeric **
48825a99e2eSeric **	Parameters:
4896328bdf7Seric **		fp -- file to output onto.
4906328bdf7Seric **		m -- a mailer descriptor.
49125a99e2eSeric **
49225a99e2eSeric **	Returns:
4936328bdf7Seric **		none.
49425a99e2eSeric **
49525a99e2eSeric **	Side Effects:
4966328bdf7Seric **		The message is written onto fp.
49725a99e2eSeric */
49825a99e2eSeric 
4996328bdf7Seric putmessage(fp, m)
5006328bdf7Seric 	FILE *fp;
5016328bdf7Seric 	struct mailer *m;
50225a99e2eSeric {
5036328bdf7Seric 	char buf[BUFSIZ];
5046328bdf7Seric 	register int i;
5056328bdf7Seric 	HDR *h;
506b07ac16bSeric 	register char *p;
5076328bdf7Seric 	extern char *arpadate();
5086328bdf7Seric 	extern char *hvalue();
5096328bdf7Seric 	bool anyheader = FALSE;
51040e4ab56Seric 	extern char *expand();
511e9ff65b0Seric 	extern char *capitalize();
51225a99e2eSeric 
51340e4ab56Seric 	/* output "From" line unless supressed */
51440e4ab56Seric 	if (!bitset(M_NHDR, m->m_flags))
51540e4ab56Seric 		fprintf(fp, "%s\n", FromLine);
51640e4ab56Seric 
5176328bdf7Seric 	/* clear all "used" bits */
5186328bdf7Seric 	for (h = Header; h != NULL; h = h->h_link)
5196328bdf7Seric 		h->h_flags &= ~H_USED;
5206328bdf7Seric 
5216328bdf7Seric 	/* output date if needed by mailer */
5226328bdf7Seric 	p = hvalue("date");
5232a6e0786Seric 	if (bitset(M_NEEDDATE, m->m_flags) && p == NULL)
5246328bdf7Seric 		p = arpadate(Date);
5256328bdf7Seric 	if (p != NULL)
526b07ac16bSeric 	{
5276328bdf7Seric 		fprintf(fp, "Date: %s\n", p);
5286328bdf7Seric 		anyheader = TRUE;
529b07ac16bSeric 	}
530b07ac16bSeric 
5316328bdf7Seric 	/* output from line if needed by mailer */
5326328bdf7Seric 	p = hvalue("from");
5332a6e0786Seric 	if (bitset(M_NEEDFROM, m->m_flags) && p == NULL)
5346328bdf7Seric 	{
5356328bdf7Seric 		extern char *FullName;
5366328bdf7Seric 
53740e4ab56Seric 		expand("$g", buf, &buf[sizeof buf - 1]);
5386328bdf7Seric 		if (FullName != NULL)
53940e4ab56Seric 			fprintf(fp, "From: %s <%s>\n", FullName, buf);
5406328bdf7Seric 		else
54140e4ab56Seric 			fprintf(fp, "From: %s\n", buf);
5426328bdf7Seric 		anyheader = TRUE;
5436328bdf7Seric 	}
5446328bdf7Seric 	else if (p != NULL)
5456328bdf7Seric 	{
5466328bdf7Seric 		fprintf(fp, "From: %s\n", p);
5476328bdf7Seric 		anyheader = TRUE;
5486328bdf7Seric 	}
5496328bdf7Seric 
5506328bdf7Seric 	/* output message-id field if needed */
5516328bdf7Seric 	p = hvalue("message-id");
5522a6e0786Seric 	if (bitset(M_MSGID, m->m_flags) && p == NULL)
5536328bdf7Seric 		p = MsgId;
5546328bdf7Seric 	if (p != NULL)
5556328bdf7Seric 	{
5566328bdf7Seric 		fprintf(fp, "Message-Id: %s\n", p);
5576328bdf7Seric 		anyheader = TRUE;
5586328bdf7Seric 	}
5596328bdf7Seric 
5606328bdf7Seric 	/* output any other header lines */
5616328bdf7Seric 	for (h = Header; h != NULL; h = h->h_link)
5626328bdf7Seric 	{
5632a6e0786Seric 		if (bitset(H_USED, h->h_flags))
5646328bdf7Seric 			continue;
5656328bdf7Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), h->h_value);
5666328bdf7Seric 		h->h_flags |= H_USED;
5676328bdf7Seric 		anyheader = TRUE;
5686328bdf7Seric 	}
5696328bdf7Seric 
5706328bdf7Seric 	if (anyheader)
5716328bdf7Seric 		fprintf(fp, "\n");
5726328bdf7Seric 
5736328bdf7Seric 	/* output the body of the message */
5746328bdf7Seric 	while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0)
5756328bdf7Seric 		fwrite(buf, 1, i, fp);
5766328bdf7Seric 
57725a99e2eSeric 	if (ferror(fp))
57825a99e2eSeric 	{
5796328bdf7Seric 		syserr("putmessage: write error");
58025a99e2eSeric 		setstat(EX_IOERR);
58125a99e2eSeric 	}
58225a99e2eSeric }
58325a99e2eSeric /*
58425a99e2eSeric **  PIPESIG -- Handle broken pipe signals
58525a99e2eSeric **
58625a99e2eSeric **	This just logs an error.
58725a99e2eSeric **
58825a99e2eSeric **	Parameters:
58925a99e2eSeric **		none
59025a99e2eSeric **
59125a99e2eSeric **	Returns:
59225a99e2eSeric **		none
59325a99e2eSeric **
59425a99e2eSeric **	Side Effects:
59525a99e2eSeric **		logs an error message.
59625a99e2eSeric */
59725a99e2eSeric 
59825a99e2eSeric pipesig()
59925a99e2eSeric {
60025a99e2eSeric 	syserr("Broken pipe");
60103ab8e55Seric 	signal(SIGPIPE, SIG_IGN);
60225a99e2eSeric }
60325a99e2eSeric /*
60425a99e2eSeric **  SENDTO -- Designate a send list.
60525a99e2eSeric **
60625a99e2eSeric **	The parameter is a comma-separated list of people to send to.
60725a99e2eSeric **	This routine arranges to send to all of them.
60825a99e2eSeric **
60925a99e2eSeric **	Parameters:
61025a99e2eSeric **		list -- the send list.
61125a99e2eSeric **		copyf -- the copy flag; passed to parse.
61225a99e2eSeric **
61325a99e2eSeric **	Returns:
61425a99e2eSeric **		none
61525a99e2eSeric **
61625a99e2eSeric **	Side Effects:
61725a99e2eSeric **		none.
61825a99e2eSeric */
61925a99e2eSeric 
62025a99e2eSeric sendto(list, copyf)
62125a99e2eSeric 	char *list;
62225a99e2eSeric 	int copyf;
62325a99e2eSeric {
62425a99e2eSeric 	register char *p;
62525a99e2eSeric 	register char *q;
62625a99e2eSeric 	register char c;
6272a6e0786Seric 	ADDRESS *a;
6282a6e0786Seric 	extern ADDRESS *parse();
62925a99e2eSeric 	bool more;
63025a99e2eSeric 
63125a99e2eSeric 	/* more keeps track of what the previous delimiter was */
63225a99e2eSeric 	more = TRUE;
63325a99e2eSeric 	for (p = list; more; )
63425a99e2eSeric 	{
63525a99e2eSeric 		/* find the end of this address */
63625a99e2eSeric 		q = p;
63725a99e2eSeric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
63825a99e2eSeric 			continue;
63925a99e2eSeric 		more = c != '\0';
64025a99e2eSeric 		*--p = '\0';
64125a99e2eSeric 		if (more)
64225a99e2eSeric 			p++;
64325a99e2eSeric 
64425a99e2eSeric 		/* parse the address */
6452a6e0786Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
64625a99e2eSeric 			continue;
64725a99e2eSeric 
64825a99e2eSeric 		/* arrange to send to this person */
64940e4ab56Seric 		recipient(a);
65025a99e2eSeric 	}
65125a99e2eSeric 	To = NULL;
65225a99e2eSeric }
65325a99e2eSeric /*
65425a99e2eSeric **  RECIPIENT -- Designate a message recipient
65525a99e2eSeric **
65625a99e2eSeric **	Saves the named person for future mailing.
65725a99e2eSeric **
65825a99e2eSeric **	Parameters:
65925a99e2eSeric **		a -- the (preparsed) address header for the recipient.
66025a99e2eSeric **
66125a99e2eSeric **	Returns:
66225a99e2eSeric **		none.
66325a99e2eSeric **
66425a99e2eSeric **	Side Effects:
66525a99e2eSeric **		none.
66625a99e2eSeric */
66725a99e2eSeric 
66840e4ab56Seric recipient(a)
6692a6e0786Seric 	register ADDRESS *a;
67025a99e2eSeric {
6712a6e0786Seric 	register ADDRESS *q;
67225a99e2eSeric 	register struct mailer *m;
67325a99e2eSeric 	extern bool forward();
67425a99e2eSeric 	extern int errno;
67525a99e2eSeric 	extern bool sameaddr();
67625a99e2eSeric 
67725a99e2eSeric 	To = a->q_paddr;
67886f2b423Seric 	m = Mailer[a->q_mailer];
67925a99e2eSeric 	errno = 0;
68025a99e2eSeric # ifdef DEBUG
68125a99e2eSeric 	if (Debug)
68225a99e2eSeric 		printf("recipient(%s)\n", To);
68325a99e2eSeric # endif DEBUG
68425a99e2eSeric 
68525a99e2eSeric 	/*
68640e4ab56Seric 	**  Do sickly crude mapping for program mailing, etc.
68725a99e2eSeric 	*/
68825a99e2eSeric 
68940e4ab56Seric 	if (a->q_mailer == 0 && a->q_user[0] == '|')
69025a99e2eSeric 	{
69140e4ab56Seric 		a->q_mailer = 1;
69240e4ab56Seric 		m++;
69340e4ab56Seric 		a->q_user++;
69425a99e2eSeric 	}
69540e4ab56Seric 
69640e4ab56Seric 	/*
69740e4ab56Seric 	**  Look up this person in the recipient list.  If they
69840e4ab56Seric 	**  are there already, return, otherwise continue.
69940e4ab56Seric 	**  If the list is empty, just add it.
70040e4ab56Seric 	*/
70140e4ab56Seric 
70240e4ab56Seric 	if (m->m_sendq == NULL)
70340e4ab56Seric 	{
70440e4ab56Seric 		m->m_sendq = a;
70540e4ab56Seric 	}
70640e4ab56Seric 	else
70740e4ab56Seric 	{
70840e4ab56Seric 		ADDRESS *pq;
70940e4ab56Seric 
71040e4ab56Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
71140e4ab56Seric 		{
71240e4ab56Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
71325a99e2eSeric 			{
71425a99e2eSeric # ifdef DEBUG
71525a99e2eSeric 				if (Debug)
71640e4ab56Seric 					printf("(%s in sendq)\n", a->q_paddr);
71725a99e2eSeric # endif DEBUG
71825a99e2eSeric 				return;
71925a99e2eSeric 			}
72025a99e2eSeric 		}
72125a99e2eSeric 
72240e4ab56Seric 		/* add address on list */
72340e4ab56Seric 		q = pq;
724*5dfc646bSeric 		q->q_next = a;
72540e4ab56Seric 	}
72640e4ab56Seric 	a->q_next = NULL;
72740e4ab56Seric 
72825a99e2eSeric 	/*
72925a99e2eSeric 	**  See if the user wants hir mail forwarded.
73025a99e2eSeric 	**	`Forward' must do the forwarding recursively.
73125a99e2eSeric 	*/
73225a99e2eSeric 
73340e4ab56Seric 	if (m == Mailer[0] && !NoAlias && forward(a))
73440e4ab56Seric 		setbit(QDONTSEND, a->q_flags);
73525a99e2eSeric 
73625a99e2eSeric 	return;
73725a99e2eSeric }
73825a99e2eSeric /*
73925a99e2eSeric **  MAILFILE -- Send a message to a file.
74025a99e2eSeric **
74125a99e2eSeric **	Parameters:
74225a99e2eSeric **		filename -- the name of the file to send to.
74325a99e2eSeric **
74425a99e2eSeric **	Returns:
74525a99e2eSeric **		The exit code associated with the operation.
74625a99e2eSeric **
74725a99e2eSeric **	Side Effects:
74825a99e2eSeric **		none.
74925a99e2eSeric **
75025a99e2eSeric **	Called By:
75125a99e2eSeric **		deliver
75225a99e2eSeric */
75325a99e2eSeric 
75425a99e2eSeric mailfile(filename)
75525a99e2eSeric 	char *filename;
75625a99e2eSeric {
75725a99e2eSeric 	register FILE *f;
75825a99e2eSeric 
75925a99e2eSeric 	f = fopen(filename, "a");
76025a99e2eSeric 	if (f == NULL)
76125a99e2eSeric 		return (EX_CANTCREAT);
76225a99e2eSeric 
76340e4ab56Seric 	putmessage(f, Mailer[1]);
76425a99e2eSeric 	fputs("\n", f);
76525a99e2eSeric 	fclose(f);
76625a99e2eSeric 	return (EX_OK);
76725a99e2eSeric }
768