1294Seric # include <stdio.h>
2294Seric # include <pwd.h>
3294Seric # include <signal.h>
42898Seric # include <ctype.h>
52968Seric # include "postbox.h"
6294Seric # ifdef LOG
72774Seric # include <syslog.h>
8294Seric # endif LOG
9294Seric 
10*3186Seric static char SccsId[] = "@(#)deliver.c	3.6	03/11/81";
11405Seric 
12294Seric /*
13294Seric **  DELIVER -- Deliver a message to a particular address.
14294Seric **
15294Seric **	Algorithm:
16294Seric **		Compute receiving network (i.e., mailer), host, & user.
17294Seric **		If local, see if this is really a program name.
18294Seric **		Build argument for the mailer.
19294Seric **		Create pipe through edit fcn if appropriate.
20294Seric **		Fork.
21294Seric **			Child: call mailer
22294Seric **		Parent: call editfcn if specified.
23294Seric **		Wait for mailer to finish.
24294Seric **		Interpret exit status.
25294Seric **
26294Seric **	Parameters:
27294Seric **		to -- the address to deliver the message to.
28294Seric **		editfcn -- if non-NULL, we want to call this function
29294Seric **			to output the letter (instead of just out-
30294Seric **			putting it raw).
31294Seric **
32294Seric **	Returns:
33294Seric **		zero -- successfully delivered.
34294Seric **		else -- some failure, see ExitStat for more info.
35294Seric **
36294Seric **	Side Effects:
37294Seric **		The standard input is passed off to someone.
38294Seric **
39294Seric **	WARNING:
40294Seric **		The standard input is shared amongst all children,
41294Seric **		including the file pointer.  It is critical that the
42294Seric **		parent waits for the child to finish before forking
43294Seric **		another child.
44294Seric */
45294Seric 
46294Seric deliver(to, editfcn)
472968Seric 	ADDRESS *to;
48294Seric 	int (*editfcn)();
49294Seric {
50294Seric 	register struct mailer *m;
51294Seric 	char *host;
52294Seric 	char *user;
53294Seric 	extern struct passwd *getpwnam();
54294Seric 	char **pvp;
55294Seric 	extern char **buildargv();
56294Seric 	auto int st;
57294Seric 	register int i;
58294Seric 	register char *p;
59294Seric 	int pid;
60294Seric 	int pvect[2];
61294Seric 	extern FILE *fdopen();
62294Seric 	extern int errno;
63294Seric 	FILE *mfile;
642898Seric 	extern putmessage();
65294Seric 	extern pipesig();
661828Seric 	extern char *index();
672968Seric 	extern bool checkcompat();
68294Seric 
69294Seric 	/*
70294Seric 	**  Compute receiving mailer, host, and to addreses.
71294Seric 	**	Do some initialization first.  To is the to address
72294Seric 	**	for error messages.
73*3186Seric 	**	Also, define the standard per-address macros.
74294Seric 	*/
75294Seric 
76294Seric 	To = to->q_paddr;
773047Seric 	m = Mailer[to->q_mailer];
78294Seric 	user = to->q_user;
79294Seric 	host = to->q_host;
801518Seric 	Errors = 0;
81294Seric 	errno = 0;
82*3186Seric 	define('u', user);		/* to user */
83*3186Seric 	define('h', host);		/* to host */
84*3186Seric 	define('g', m->m_from);		/* translated from address */
85294Seric # ifdef DEBUG
86294Seric 	if (Debug)
87294Seric 		printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
88294Seric # endif DEBUG
89294Seric 
90294Seric 	/*
912968Seric 	**  Check to see that these people are allowed to talk to each other.
922968Seric 	*/
932968Seric 
942968Seric 	if (!checkcompat(to))
952968Seric 		return(giveresponse(EX_UNAVAILABLE, TRUE, m));
962968Seric 
972968Seric 	/*
98294Seric 	**  Remove quote bits from user/host.
99294Seric 	*/
100294Seric 
101294Seric 	for (p = user; (*p++ &= 0177) != '\0'; )
102294Seric 		continue;
103294Seric 	if (host != NULL)
104294Seric 		for (p = host; (*p++ &= 0177) != '\0'; )
105294Seric 			continue;
106294Seric 
107294Seric 	/*
108294Seric 	**  Strip quote bits from names if the mailer wants it.
109294Seric 	*/
110294Seric 
1112968Seric 	if (bitset(M_STRIPQ, m->m_flags))
112294Seric 	{
113294Seric 		stripquotes(user);
114294Seric 		stripquotes(host);
115294Seric 	}
116294Seric 
117294Seric 	/*
118294Seric 	**  See if this user name is "special".
119294Seric 	**	If the user is a program, diddle with the mailer spec.
120294Seric 	**	If the user name has a slash in it, assume that this
121294Seric 	**		is a file -- send it off without further ado.
122294Seric 	**		Note that this means that editfcn's will not
123294Seric 	**		be applied to the message.
124294Seric 	*/
125294Seric 
1263047Seric 	if (m == Mailer[0])
127294Seric 	{
128294Seric 		if (*user == '|')
129294Seric 		{
130294Seric 			user++;
1313047Seric 			m = Mailer[1];
132294Seric 		}
133294Seric 		else
134294Seric 		{
135294Seric 			if (index(user, '/') != NULL)
136294Seric 			{
137294Seric 				i = mailfile(user);
138294Seric 				giveresponse(i, TRUE, m);
139294Seric 				return (i);
140294Seric 			}
141294Seric 		}
142294Seric 	}
143294Seric 
144294Seric 	/*
1451389Seric 	**  See if the user exists.
1461389Seric 	**	Strictly, this is only needed to print a pretty
1471389Seric 	**	error message.
1481389Seric 	**
1491389Seric 	**	>>>>>>>>>> This clause assumes that the local mailer
1501389Seric 	**	>> NOTE >> cannot do any further aliasing; that
1512968Seric 	**	>>>>>>>>>> function is subsumed by postbox.
152294Seric 	*/
153294Seric 
1543047Seric 	if (m == Mailer[0])
155294Seric 	{
156294Seric 		if (getpwnam(user) == NULL)
157294Seric 		{
158294Seric 			giveresponse(EX_NOUSER, TRUE, m);
159294Seric 			return (EX_NOUSER);
160294Seric 		}
161294Seric 	}
162294Seric 
163294Seric 	/*
164294Seric 	**  Call the mailer.
1652898Seric 	**	The argument vector gets built, pipes
166294Seric 	**	are created as necessary, and we fork & exec as
1672898Seric 	**	appropriate.
168294Seric 	*/
169294Seric 
1702898Seric 	pvp = buildargv(m, host, user, From.q_paddr);
171294Seric 	if (pvp == NULL)
172294Seric 	{
173294Seric 		usrerr("name too long");
174294Seric 		return (-1);
175294Seric 	}
176294Seric 	rewind(stdin);
177294Seric 
1782898Seric 	/* create a pipe to shove the mail through */
1792898Seric 	if (pipe(pvect) < 0)
180294Seric 	{
181294Seric 		syserr("pipe");
182294Seric 		return (-1);
183294Seric 	}
1841504Smark # ifdef VFORK
1851504Smark 	pid = vfork();
1861504Smark # else
187294Seric 	pid = fork();
1881504Smark # endif
189294Seric 	if (pid < 0)
190294Seric 	{
191294Seric 		syserr("Cannot fork");
1922898Seric 		close(pvect[0]);
1932898Seric 		close(pvect[1]);
194294Seric 		return (-1);
195294Seric 	}
196294Seric 	else if (pid == 0)
197294Seric 	{
198294Seric 		/* child -- set up input & exec mailer */
1991621Seric 		/* make diagnostic output be standard output */
2001621Seric 		close(2);
2011621Seric 		dup(1);
202294Seric 		signal(SIGINT, SIG_IGN);
2032898Seric 		close(0);
2042898Seric 		if (dup(pvect[0]) < 0)
205294Seric 		{
2062898Seric 			syserr("Cannot dup to zero!");
2072898Seric 			_exit(EX_OSERR);
208294Seric 		}
2092898Seric 		close(pvect[0]);
2102898Seric 		close(pvect[1]);
2112968Seric 		if (!bitset(M_RESTR, m->m_flags))
212294Seric 			setuid(getuid());
2132774Seric # ifndef VFORK
2142774Seric 		/*
2152774Seric 		**  We have to be careful with vfork - we can't mung up the
2162774Seric 		**  memory but we don't want the mailer to inherit any extra
2172774Seric 		**  open files.  Chances are the mailer won't
2182774Seric 		**  care about an extra file, but then again you never know.
2192774Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
2202774Seric 		**  declared static so we can't.  But if we fclose(pwf), which
2212774Seric 		**  is what endpwent does, it closes it in the parent too and
2222774Seric 		**  the next getpwnam will be slower.  If you have a weird
2232774Seric 		**  mailer that chokes on the extra file you should do the
2242774Seric 		**  endpwent().
2252774Seric 		**
2262774Seric 		**  Similar comments apply to log.  However, openlog is
2272774Seric 		**  clever enough to set the FIOCLEX mode on the file,
2282774Seric 		**  so it will be closed automatically on the exec.
2292774Seric 		*/
2302774Seric 
2312774Seric 		endpwent();
232294Seric # ifdef LOG
2332089Seric 		closelog();
234294Seric # endif LOG
2352774Seric # endif VFORK
236294Seric 		execv(m->m_mailer, pvp);
237294Seric 		/* syserr fails because log is closed */
238294Seric 		/* syserr("Cannot exec %s", m->m_mailer); */
2392343Seric 		printf("Cannot exec %s\n", m->m_mailer);
2402343Seric 		fflush(stdout);
2411619Seric 		_exit(EX_UNAVAILABLE);
242294Seric 	}
243294Seric 
2442898Seric 	/* write out message to mailer */
2452898Seric 	close(pvect[0]);
2462898Seric 	signal(SIGPIPE, pipesig);
2472898Seric 	mfile = fdopen(pvect[1], "w");
2482898Seric 	if (editfcn == NULL)
2492898Seric 		editfcn = putmessage;
2502898Seric 	(*editfcn)(mfile, m);
2512898Seric 	fclose(mfile);
252294Seric 
253294Seric 	/*
254294Seric 	**  Wait for child to die and report status.
255294Seric 	**	We should never get fatal errors (e.g., segmentation
256294Seric 	**	violation), so we report those specially.  For other
257294Seric 	**	errors, we choose a status message (into statmsg),
258294Seric 	**	and if it represents an error, we print it.
259294Seric 	*/
260294Seric 
261294Seric 	while ((i = wait(&st)) > 0 && i != pid)
262294Seric 		continue;
263294Seric 	if (i < 0)
264294Seric 	{
265294Seric 		syserr("wait");
266294Seric 		return (-1);
267294Seric 	}
268294Seric 	if ((st & 0377) != 0)
269294Seric 	{
270294Seric 		syserr("%s: stat %o", pvp[0], st);
2711597Seric 		ExitStat = EX_UNAVAILABLE;
272294Seric 		return (-1);
273294Seric 	}
274294Seric 	i = (st >> 8) & 0377;
2752343Seric 	giveresponse(i, TRUE, m);
276294Seric 	return (i);
277294Seric }
278294Seric /*
279294Seric **  GIVERESPONSE -- Interpret an error response from a mailer
280294Seric **
281294Seric **	Parameters:
282294Seric **		stat -- the status code from the mailer (high byte
283294Seric **			only; core dumps must have been taken care of
284294Seric **			already).
285294Seric **		force -- if set, force an error message output, even
286294Seric **			if the mailer seems to like to print its own
287294Seric **			messages.
288294Seric **		m -- the mailer descriptor for this mailer.
289294Seric **
290294Seric **	Returns:
2912968Seric **		stat.
292294Seric **
293294Seric **	Side Effects:
2941518Seric **		Errors may be incremented.
295294Seric **		ExitStat may be set.
296294Seric **
297294Seric **	Called By:
298294Seric **		deliver
299294Seric */
300294Seric 
301294Seric giveresponse(stat, force, m)
302294Seric 	int stat;
303294Seric 	int force;
304294Seric 	register struct mailer *m;
305294Seric {
306294Seric 	register char *statmsg;
307294Seric 	extern char *SysExMsg[];
308294Seric 	register int i;
309294Seric 	extern int N_SysEx;
3101624Seric 	extern long MsgSize;
3111624Seric 	char buf[30];
3123044Seric 	extern char *sprintf();
313294Seric 
314294Seric 	i = stat - EX__BASE;
315294Seric 	if (i < 0 || i > N_SysEx)
316294Seric 		statmsg = NULL;
317294Seric 	else
318294Seric 		statmsg = SysExMsg[i];
319294Seric 	if (stat == 0)
320294Seric 		statmsg = "ok";
321294Seric 	else
322294Seric 	{
3231518Seric 		Errors++;
324294Seric 		if (statmsg == NULL && m->m_badstat != 0)
325294Seric 		{
326294Seric 			stat = m->m_badstat;
327294Seric 			i = stat - EX__BASE;
328294Seric # ifdef DEBUG
329294Seric 			if (i < 0 || i >= N_SysEx)
330294Seric 				syserr("Bad m_badstat %d", stat);
331294Seric 			else
332294Seric # endif DEBUG
333294Seric 			statmsg = SysExMsg[i];
334294Seric 		}
335294Seric 		if (statmsg == NULL)
336294Seric 			usrerr("unknown mailer response %d", stat);
3372968Seric 		else if (force || !bitset(M_QUIET, m->m_flags))
338294Seric 			usrerr("%s", statmsg);
339294Seric 	}
340294Seric 
341294Seric 	/*
342294Seric 	**  Final cleanup.
343294Seric 	**	Log a record of the transaction.  Compute the new
344294Seric 	**	ExitStat -- if we already had an error, stick with
345294Seric 	**	that.
346294Seric 	*/
347294Seric 
3481624Seric 	if (statmsg == NULL)
3491624Seric 	{
3501624Seric 		sprintf(buf, "error %d", stat);
3511624Seric 		statmsg = buf;
3521624Seric 	}
3531624Seric 
354294Seric # ifdef LOG
3552774Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
356294Seric # endif LOG
3571389Seric 	setstat(stat);
358294Seric 	return (stat);
359294Seric }
360294Seric /*
3612898Seric **  PUTMESSAGE -- output a message to the final mailer.
362294Seric **
3632898Seric **	This routine takes care of recreating the header from the
3642898Seric **	in-core copy, etc.
365294Seric **
366294Seric **	Parameters:
3672898Seric **		fp -- file to output onto.
3682898Seric **		m -- a mailer descriptor.
369294Seric **
370294Seric **	Returns:
3712898Seric **		none.
372294Seric **
373294Seric **	Side Effects:
3742898Seric **		The message is written onto fp.
375294Seric */
376294Seric 
3772898Seric putmessage(fp, m)
3782898Seric 	FILE *fp;
3792898Seric 	struct mailer *m;
380294Seric {
3812898Seric 	char buf[BUFSIZ];
3822898Seric 	register int i;
3832898Seric 	HDR *h;
3841828Seric 	register char *p;
3852898Seric 	extern char *arpadate();
3862898Seric 	extern char *hvalue();
3872898Seric 	bool anyheader = FALSE;
388*3186Seric 	extern char *expand();
3893044Seric 	extern char *capitalize();
390294Seric 
391*3186Seric 	/* output "From" line unless supressed */
392*3186Seric 	if (!bitset(M_NHDR, m->m_flags))
393*3186Seric 		fprintf(fp, "%s\n", FromLine);
394*3186Seric 
3952898Seric 	/* clear all "used" bits */
3962898Seric 	for (h = Header; h != NULL; h = h->h_link)
3972898Seric 		h->h_flags &= ~H_USED;
3982898Seric 
3992898Seric 	/* output date if needed by mailer */
4002898Seric 	p = hvalue("date");
4012968Seric 	if (bitset(M_NEEDDATE, m->m_flags) && p == NULL)
4022898Seric 		p = arpadate(Date);
4032898Seric 	if (p != NULL)
4041828Seric 	{
4052898Seric 		fprintf(fp, "Date: %s\n", p);
4062898Seric 		anyheader = TRUE;
4071828Seric 	}
4081828Seric 
4092898Seric 	/* output from line if needed by mailer */
4102898Seric 	p = hvalue("from");
4112968Seric 	if (bitset(M_NEEDFROM, m->m_flags) && p == NULL)
4122898Seric 	{
4132898Seric 		extern char *FullName;
4142898Seric 
415*3186Seric 		expand("$g", buf, &buf[sizeof buf - 1]);
4162898Seric 		if (FullName != NULL)
417*3186Seric 			fprintf(fp, "From: %s <%s>\n", FullName, buf);
4182898Seric 		else
419*3186Seric 			fprintf(fp, "From: %s\n", buf);
4202898Seric 		anyheader = TRUE;
4212898Seric 	}
4222898Seric 	else if (p != NULL)
4232898Seric 	{
4242898Seric 		fprintf(fp, "From: %s\n", p);
4252898Seric 		anyheader = TRUE;
4262898Seric 	}
4272898Seric 
4282898Seric 	/* output message-id field if needed */
4292898Seric 	p = hvalue("message-id");
4302968Seric 	if (bitset(M_MSGID, m->m_flags) && p == NULL)
4312898Seric 		p = MsgId;
4322898Seric 	if (p != NULL)
4332898Seric 	{
4342898Seric 		fprintf(fp, "Message-Id: %s\n", p);
4352898Seric 		anyheader = TRUE;
4362898Seric 	}
4372898Seric 
4382898Seric 	/* output any other header lines */
4392898Seric 	for (h = Header; h != NULL; h = h->h_link)
4402898Seric 	{
4412968Seric 		if (bitset(H_USED, h->h_flags))
4422898Seric 			continue;
4432898Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), h->h_value);
4442898Seric 		h->h_flags |= H_USED;
4452898Seric 		anyheader = TRUE;
4462898Seric 	}
4472898Seric 
4482898Seric 	if (anyheader)
4492898Seric 		fprintf(fp, "\n");
4502898Seric 
4512898Seric 	/* output the body of the message */
4522898Seric 	while (!ferror(fp) && (i = read(0, buf, BUFSIZ)) > 0)
4532898Seric 		fwrite(buf, 1, i, fp);
4542898Seric 
455294Seric 	if (ferror(fp))
456294Seric 	{
4572898Seric 		syserr("putmessage: write error");
458294Seric 		setstat(EX_IOERR);
459294Seric 	}
460294Seric }
461294Seric /*
462294Seric **  PIPESIG -- Handle broken pipe signals
463294Seric **
464294Seric **	This just logs an error.
465294Seric **
466294Seric **	Parameters:
467294Seric **		none
468294Seric **
469294Seric **	Returns:
470294Seric **		none
471294Seric **
472294Seric **	Side Effects:
473294Seric **		logs an error message.
474294Seric */
475294Seric 
476294Seric pipesig()
477294Seric {
478294Seric 	syserr("Broken pipe");
4791621Seric 	signal(SIGPIPE, SIG_IGN);
480294Seric }
481294Seric /*
482294Seric **  SENDTO -- Designate a send list.
483294Seric **
484294Seric **	The parameter is a comma-separated list of people to send to.
485294Seric **	This routine arranges to send to all of them.
486294Seric **
487294Seric **	Parameters:
488294Seric **		list -- the send list.
489294Seric **		copyf -- the copy flag; passed to parse.
490294Seric **
491294Seric **	Returns:
492294Seric **		none
493294Seric **
494294Seric **	Side Effects:
495294Seric **		none.
496294Seric **
497294Seric **	Called By:
498294Seric **		main
499294Seric **		alias
500294Seric */
501294Seric 
502294Seric sendto(list, copyf)
503294Seric 	char *list;
504294Seric 	int copyf;
505294Seric {
506294Seric 	register char *p;
507294Seric 	register char *q;
508294Seric 	register char c;
5092968Seric 	ADDRESS *a;
5102968Seric 	extern ADDRESS *parse();
511294Seric 	bool more;
512294Seric 
513294Seric 	/* more keeps track of what the previous delimiter was */
514294Seric 	more = TRUE;
515294Seric 	for (p = list; more; )
516294Seric 	{
517294Seric 		/* find the end of this address */
518294Seric 		q = p;
519294Seric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
520294Seric 			continue;
521294Seric 		more = c != '\0';
522294Seric 		*--p = '\0';
523294Seric 		if (more)
524294Seric 			p++;
525294Seric 
526294Seric 		/* parse the address */
5272968Seric 		if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL)
528294Seric 			continue;
529294Seric 
530294Seric 		/* arrange to send to this person */
531*3186Seric 		recipient(a);
532294Seric 	}
533294Seric 	To = NULL;
534294Seric }
535294Seric /*
536294Seric **  RECIPIENT -- Designate a message recipient
537294Seric **
538294Seric **	Saves the named person for future mailing.
539294Seric **
540294Seric **	Parameters:
541294Seric **		a -- the (preparsed) address header for the recipient.
542294Seric **
543294Seric **	Returns:
544294Seric **		none.
545294Seric **
546294Seric **	Side Effects:
547294Seric **		none.
548294Seric **
549294Seric **	Called By:
550294Seric **		sendto
551294Seric **		main
552294Seric */
553294Seric 
554*3186Seric recipient(a)
5552968Seric 	register ADDRESS *a;
556294Seric {
5572968Seric 	register ADDRESS *q;
558294Seric 	register struct mailer *m;
559294Seric 	extern bool forward();
560294Seric 	extern int errno;
561294Seric 	extern bool sameaddr();
562294Seric 
563294Seric 	To = a->q_paddr;
5643047Seric 	m = Mailer[a->q_mailer];
565294Seric 	errno = 0;
566294Seric # ifdef DEBUG
567294Seric 	if (Debug)
568294Seric 		printf("recipient(%s)\n", To);
569294Seric # endif DEBUG
570294Seric 
571294Seric 	/*
572*3186Seric 	**  Do sickly crude mapping for program mailing, etc.
573*3186Seric 	*/
574*3186Seric 
575*3186Seric 	if (a->q_mailer == 0 && a->q_user[0] == '|')
576*3186Seric 	{
577*3186Seric 		a->q_mailer = 1;
578*3186Seric 		m++;
579*3186Seric 		a->q_user++;
580*3186Seric 	}
581*3186Seric 
582*3186Seric 	/*
583294Seric 	**  Look up this person in the recipient list.  If they
584294Seric 	**  are there already, return, otherwise continue.
585*3186Seric 	**  If the list is empty, just add it.
586294Seric 	*/
587294Seric 
588*3186Seric 	if (m->m_sendq == NULL)
589294Seric 	{
590*3186Seric 		m->m_sendq = a;
591*3186Seric 	}
592*3186Seric 	else
593*3186Seric 	{
594*3186Seric 		ADDRESS *pq;
595*3186Seric 
596*3186Seric 		for (q = m->m_sendq; q != NULL; pq = q, q = q->q_next)
597*3186Seric 		{
598*3186Seric 			if (!ForceMail && sameaddr(q, a, FALSE))
599294Seric 			{
600294Seric # ifdef DEBUG
601294Seric 				if (Debug)
602*3186Seric 					printf("(%s in sendq)\n", a->q_paddr);
603294Seric # endif DEBUG
604294Seric 				return;
605294Seric 			}
606*3186Seric 		}
607*3186Seric 
608*3186Seric 		/* add address on list */
609*3186Seric 		q = pq;
610*3186Seric 		q->q_next = NULL;
611294Seric 	}
612*3186Seric 	a->q_next = NULL;
613294Seric 
614294Seric 	/*
615294Seric 	**  See if the user wants hir mail forwarded.
616294Seric 	**	`Forward' must do the forwarding recursively.
617294Seric 	*/
618294Seric 
619*3186Seric 	if (m == Mailer[0] && !NoAlias && forward(a))
620*3186Seric 		setbit(QDONTSEND, a->q_flags);
621294Seric 
622294Seric 	return;
623294Seric }
624294Seric /*
625294Seric **  BUILDARGV -- Build an argument vector for a mail server.
626294Seric **
627294Seric **	Using a template defined in config.c, an argv is built.
628294Seric **	The format of the template is already a vector.  The
629294Seric **	items of this vector are copied, unless a dollar sign
630294Seric **	is encountered.  In this case, the next character
631294Seric **	specifies something else to copy in.  These can be
632*3186Seric **	any macros.  System defined macros are:
633294Seric **		$f	The from address.
634294Seric **		$h	The host.
635294Seric **		$u	The user.
636294Seric **		$c	The hop count.
637*3186Seric **	among others.
638294Seric **	The vector is built in a local buffer.  A pointer to
639294Seric **	the static argv is returned.
640294Seric **
641294Seric **	Parameters:
6422898Seric **		m -- a pointer to the mailer descriptor.
643294Seric **		host -- the host name to send to.
644294Seric **		user -- the user name to send to.
645294Seric **		from -- the person this mail is from.
646294Seric **
647294Seric **	Returns:
648294Seric **		A pointer to an argv.
649294Seric **
650294Seric **	Side Effects:
651294Seric **		none
652294Seric **
653294Seric **	WARNING:
654294Seric **		Since the argv is staticly allocated, any subsequent
655294Seric **		calls will clobber the old argv.
656294Seric **
657294Seric **	Called By:
658294Seric **		deliver
659294Seric */
660294Seric 
661294Seric char **
6622898Seric buildargv(m, host, user, from)
6632898Seric 	struct mailer *m;
664294Seric 	char *host;
665294Seric 	char *user;
666294Seric 	char *from;
667294Seric {
668294Seric 	register char *p;
669294Seric 	static char *pv[MAXPV+1];
670294Seric 	char **pvp;
671294Seric 	char **mvp;
672294Seric 	static char buf[512];
673*3186Seric 	extern char *expand();
674*3186Seric 	extern char *newstr();
675294Seric 
676294Seric 	/*
677294Seric 	**  Do initial argv setup.
678294Seric 	**	Insert the mailer name.  Notice that $x expansion is
679294Seric 	**	NOT done on the mailer name.  Then, if the mailer has
680294Seric 	**	a picky -f flag, we insert it as appropriate.  This
681294Seric 	**	code does not check for 'pv' overflow; this places a
682294Seric 	**	manifest lower limit of 4 for MAXPV.
683294Seric 	*/
684294Seric 
685294Seric 	pvp = pv;
6862898Seric 	*pvp++ = m->m_argv[0];
687294Seric 
688294Seric 	/* insert -f or -r flag as appropriate */
6892968Seric 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
690294Seric 	{
6912968Seric 		if (bitset(M_FOPT, m->m_flags))
692294Seric 			*pvp++ = "-f";
693294Seric 		else
694294Seric 			*pvp++ = "-r";
695*3186Seric 		expand(from, buf, &buf[sizeof buf - 1]);
696*3186Seric 		*pvp++ = newstr(buf);
697294Seric 	}
698294Seric 
699294Seric 	/*
700294Seric 	**  Build the rest of argv.
701294Seric 	**	For each prototype parameter, the prototype is
702*3186Seric 	**	scanned character at a time.  Buffer overflow is
703294Seric 	**	checked.
704294Seric 	*/
705294Seric 
7062898Seric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
707294Seric 	{
708294Seric 		if (pvp >= &pv[MAXPV])
709294Seric 		{
710294Seric 			syserr("Too many parameters to %s", pv[0]);
711294Seric 			return (NULL);
712294Seric 		}
713*3186Seric 		expand(p, buf, &buf[sizeof buf - 1]);
714*3186Seric 		*pvp++ = newstr(buf);
7152898Seric 	}
7162898Seric 	*pvp = NULL;
7172898Seric 
7182898Seric # ifdef DEBUG
7192898Seric 	if (Debug)
7202898Seric 	{
7212898Seric 		printf("Interpolated argv is:\n");
7222898Seric 		for (mvp = pv; *mvp != NULL; mvp++)
7232898Seric 			printf("\t%s\n", *mvp);
7242898Seric 	}
7252898Seric # endif DEBUG
7262898Seric 
7272898Seric 	return (pv);
7282898Seric }
7292898Seric /*
730294Seric **  MAILFILE -- Send a message to a file.
731294Seric **
732294Seric **	Parameters:
733294Seric **		filename -- the name of the file to send to.
734294Seric **
735294Seric **	Returns:
736294Seric **		The exit code associated with the operation.
737294Seric **
738294Seric **	Side Effects:
739294Seric **		none.
740294Seric **
741294Seric **	Called By:
742294Seric **		deliver
743294Seric */
744294Seric 
745294Seric mailfile(filename)
746294Seric 	char *filename;
747294Seric {
748294Seric 	register FILE *f;
749294Seric 
750294Seric 	f = fopen(filename, "a");
751294Seric 	if (f == NULL)
752294Seric 		return (EX_CANTCREAT);
753294Seric 
754*3186Seric 	putmessage(f, Mailer[1]);
755294Seric 	fputs("\n", f);
756294Seric 	fclose(f);
757294Seric 	return (EX_OK);
758294Seric }
759