1*25a99e2eSeric # include <stdio.h>
2*25a99e2eSeric # include <pwd.h>
3*25a99e2eSeric # include <signal.h>
4*25a99e2eSeric # include "dlvrmail.h"
5*25a99e2eSeric # ifdef LOG
6*25a99e2eSeric # include <log.h>
7*25a99e2eSeric # endif LOG
8*25a99e2eSeric 
9*25a99e2eSeric /*
10*25a99e2eSeric **  DELIVER -- Deliver a message to a particular address.
11*25a99e2eSeric **
12*25a99e2eSeric **	Algorithm:
13*25a99e2eSeric **		Compute receiving network (i.e., mailer), host, & user.
14*25a99e2eSeric **		If local, see if this is really a program name.
15*25a99e2eSeric **		Build argument for the mailer.
16*25a99e2eSeric **		Create pipe through edit fcn if appropriate.
17*25a99e2eSeric **		Fork.
18*25a99e2eSeric **			Child: call mailer
19*25a99e2eSeric **		Parent: call editfcn if specified.
20*25a99e2eSeric **		Wait for mailer to finish.
21*25a99e2eSeric **		Interpret exit status.
22*25a99e2eSeric **
23*25a99e2eSeric **	Parameters:
24*25a99e2eSeric **		to -- the address to deliver the message to.
25*25a99e2eSeric **		editfcn -- if non-NULL, we want to call this function
26*25a99e2eSeric **			to output the letter (instead of just out-
27*25a99e2eSeric **			putting it raw).
28*25a99e2eSeric **
29*25a99e2eSeric **	Returns:
30*25a99e2eSeric **		zero -- successfully delivered.
31*25a99e2eSeric **		else -- some failure, see ExitStat for more info.
32*25a99e2eSeric **
33*25a99e2eSeric **	Side Effects:
34*25a99e2eSeric **		The standard input is passed off to someone.
35*25a99e2eSeric **
36*25a99e2eSeric **	WARNING:
37*25a99e2eSeric **		The standard input is shared amongst all children,
38*25a99e2eSeric **		including the file pointer.  It is critical that the
39*25a99e2eSeric **		parent waits for the child to finish before forking
40*25a99e2eSeric **		another child.
41*25a99e2eSeric **
42*25a99e2eSeric **	Requires:
43*25a99e2eSeric **		buildargv
44*25a99e2eSeric **		giveresponse
45*25a99e2eSeric **		fork (sys)
46*25a99e2eSeric **		rewind (sys)
47*25a99e2eSeric **		execv (sys)
48*25a99e2eSeric **		exit (sys)
49*25a99e2eSeric **		wait (sys)
50*25a99e2eSeric **		syserr
51*25a99e2eSeric **		getpwnam (sys)
52*25a99e2eSeric **		endpwent (sys)
53*25a99e2eSeric **		initlog
54*25a99e2eSeric **		flagset
55*25a99e2eSeric **		usrerr
56*25a99e2eSeric **		pipe (sys)
57*25a99e2eSeric **		close (sys)
58*25a99e2eSeric **		dup (sys)
59*25a99e2eSeric **		setuid (sys)
60*25a99e2eSeric **		getuid (sys)
61*25a99e2eSeric **		signal (sys)
62*25a99e2eSeric **		fdopen (sys[v7] or conf.c[v6])
63*25a99e2eSeric **		fclose (sys)
64*25a99e2eSeric **		printf (sys)
65*25a99e2eSeric **		stripquotes
66*25a99e2eSeric **		mailfile
67*25a99e2eSeric **		index (sys)
68*25a99e2eSeric **
69*25a99e2eSeric **	Called By:
70*25a99e2eSeric **		main
71*25a99e2eSeric **		savemail
72*25a99e2eSeric **
73*25a99e2eSeric **	Files:
74*25a99e2eSeric **		standard input -- must be openned to the message to
75*25a99e2eSeric **			deliver.
76*25a99e2eSeric **
77*25a99e2eSeric **	History:
78*25a99e2eSeric **		3/5/80 -- modified rather extensively to change the
79*25a99e2eSeric **			internal form of addresses.
80*25a99e2eSeric **		12/26/79 -- written.
81*25a99e2eSeric */
82*25a99e2eSeric 
83*25a99e2eSeric deliver(to, editfcn)
84*25a99e2eSeric 	addrq *to;
85*25a99e2eSeric 	int (*editfcn)();
86*25a99e2eSeric {
87*25a99e2eSeric 	register struct mailer *m;
88*25a99e2eSeric 	char *host;
89*25a99e2eSeric 	char *user;
90*25a99e2eSeric 	extern struct passwd *getpwnam();
91*25a99e2eSeric 	char **pvp;
92*25a99e2eSeric 	extern char **buildargv();
93*25a99e2eSeric 	auto int st;
94*25a99e2eSeric 	register int i;
95*25a99e2eSeric 	register char *p;
96*25a99e2eSeric 	int pid;
97*25a99e2eSeric 	int pvect[2];
98*25a99e2eSeric 	extern FILE *fdopen();
99*25a99e2eSeric 	extern int errno;
100*25a99e2eSeric 	FILE *mfile;
101*25a99e2eSeric 	extern putheader();
102*25a99e2eSeric 	extern pipesig();
103*25a99e2eSeric 
104*25a99e2eSeric 	/*
105*25a99e2eSeric 	**  Compute receiving mailer, host, and to addreses.
106*25a99e2eSeric 	**	Do some initialization first.  To is the to address
107*25a99e2eSeric 	**	for error messages.
108*25a99e2eSeric 	*/
109*25a99e2eSeric 
110*25a99e2eSeric 	To = to->q_paddr;
111*25a99e2eSeric 	m = to->q_mailer;
112*25a99e2eSeric 	user = to->q_user;
113*25a99e2eSeric 	host = to->q_host;
114*25a99e2eSeric 	Error = 0;
115*25a99e2eSeric 	errno = 0;
116*25a99e2eSeric # ifdef DEBUG
117*25a99e2eSeric 	if (Debug)
118*25a99e2eSeric 		printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
119*25a99e2eSeric # endif DEBUG
120*25a99e2eSeric 
121*25a99e2eSeric 	/*
122*25a99e2eSeric 	**  Remove quote bits from user/host.
123*25a99e2eSeric 	*/
124*25a99e2eSeric 
125*25a99e2eSeric 	for (p = user; (*p++ &= 0177) != '\0'; )
126*25a99e2eSeric 		continue;
127*25a99e2eSeric 	if (host != NULL)
128*25a99e2eSeric 		for (p = host; (*p++ &= 0177) != '\0'; )
129*25a99e2eSeric 			continue;
130*25a99e2eSeric 
131*25a99e2eSeric 	/*
132*25a99e2eSeric 	**  Strip quote bits from names if the mailer wants it.
133*25a99e2eSeric 	*/
134*25a99e2eSeric 
135*25a99e2eSeric 	if (flagset(M_STRIPQ, m->m_flags))
136*25a99e2eSeric 	{
137*25a99e2eSeric 		stripquotes(user);
138*25a99e2eSeric 		stripquotes(host);
139*25a99e2eSeric 	}
140*25a99e2eSeric 
141*25a99e2eSeric 	/*
142*25a99e2eSeric 	**  See if this user name is "special".
143*25a99e2eSeric 	**	If the user is a program, diddle with the mailer spec.
144*25a99e2eSeric 	**	If the user name has a slash in it, assume that this
145*25a99e2eSeric 	**		is a file -- send it off without further ado.
146*25a99e2eSeric 	**		Note that this means that editfcn's will not
147*25a99e2eSeric 	**		be applied to the message.
148*25a99e2eSeric 	*/
149*25a99e2eSeric 
150*25a99e2eSeric 	if (m == &Mailer[0])
151*25a99e2eSeric 	{
152*25a99e2eSeric 		if (*user == '|')
153*25a99e2eSeric 		{
154*25a99e2eSeric 			user++;
155*25a99e2eSeric 			m = &Mailer[1];
156*25a99e2eSeric 		}
157*25a99e2eSeric 		else
158*25a99e2eSeric 		{
159*25a99e2eSeric 			if (index(user, '/') != NULL)
160*25a99e2eSeric 			{
161*25a99e2eSeric 				i = mailfile(user);
162*25a99e2eSeric 				giveresponse(i, TRUE, m);
163*25a99e2eSeric 				return (i);
164*25a99e2eSeric 			}
165*25a99e2eSeric 		}
166*25a99e2eSeric 	}
167*25a99e2eSeric 
168*25a99e2eSeric # ifdef BADMAIL
169*25a99e2eSeric 	/*
170*25a99e2eSeric 	**  If the mailer doesn't return the proper
171*25a99e2eSeric 	**  exit statuses, check here to see if the
172*25a99e2eSeric 	**  user exists so that we can give a pretty
173*25a99e2eSeric 	**  error message.
174*25a99e2eSeric 	*/
175*25a99e2eSeric 
176*25a99e2eSeric 	if (m == &Mailer[0])
177*25a99e2eSeric 	{
178*25a99e2eSeric 		if (getpwnam(user) == NULL)
179*25a99e2eSeric 		{
180*25a99e2eSeric 			giveresponse(EX_NOUSER, TRUE, m);
181*25a99e2eSeric 			return (EX_NOUSER);
182*25a99e2eSeric 		}
183*25a99e2eSeric 	}
184*25a99e2eSeric # endif BADMAIL
185*25a99e2eSeric 
186*25a99e2eSeric 	/*
187*25a99e2eSeric 	**  If the mailer wants a From line, insert a new editfcn.
188*25a99e2eSeric 	*/
189*25a99e2eSeric 
190*25a99e2eSeric 	if (flagset(M_HDR, m->m_flags) && editfcn == NULL)
191*25a99e2eSeric 		editfcn = putheader;
192*25a99e2eSeric 
193*25a99e2eSeric 	/*
194*25a99e2eSeric 	**  Call the mailer.
195*25a99e2eSeric 	**	The argument vector gets built, pipes through 'editfcn'
196*25a99e2eSeric 	**	are created as necessary, and we fork & exec as
197*25a99e2eSeric 	**	appropriate.  In the parent, we call 'editfcn'.
198*25a99e2eSeric 	*/
199*25a99e2eSeric 
200*25a99e2eSeric 	pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr);
201*25a99e2eSeric 	if (pvp == NULL)
202*25a99e2eSeric 	{
203*25a99e2eSeric 		usrerr("name too long");
204*25a99e2eSeric 		return (-1);
205*25a99e2eSeric 	}
206*25a99e2eSeric 	rewind(stdin);
207*25a99e2eSeric 
208*25a99e2eSeric 	/* create a pipe if we will need one */
209*25a99e2eSeric 	if (editfcn != NULL && pipe(pvect) < 0)
210*25a99e2eSeric 	{
211*25a99e2eSeric 		syserr("pipe");
212*25a99e2eSeric 		return (-1);
213*25a99e2eSeric 	}
214*25a99e2eSeric 	pid = fork();
215*25a99e2eSeric 	if (pid < 0)
216*25a99e2eSeric 	{
217*25a99e2eSeric 		syserr("Cannot fork");
218*25a99e2eSeric 		if (editfcn != NULL)
219*25a99e2eSeric 		{
220*25a99e2eSeric 			close(pvect[0]);
221*25a99e2eSeric 			close(pvect[1]);
222*25a99e2eSeric 		}
223*25a99e2eSeric 		return (-1);
224*25a99e2eSeric 	}
225*25a99e2eSeric 	else if (pid == 0)
226*25a99e2eSeric 	{
227*25a99e2eSeric 		/* child -- set up input & exec mailer */
228*25a99e2eSeric 		signal(SIGINT, SIG_IGN);
229*25a99e2eSeric 		if (editfcn != NULL)
230*25a99e2eSeric 		{
231*25a99e2eSeric 			close(0);
232*25a99e2eSeric 			if (dup(pvect[0]) < 0)
233*25a99e2eSeric 			{
234*25a99e2eSeric 				syserr("Cannot dup to zero!");
235*25a99e2eSeric 				exit(EX_OSERR);
236*25a99e2eSeric 			}
237*25a99e2eSeric 			close(pvect[0]);
238*25a99e2eSeric 			close(pvect[1]);
239*25a99e2eSeric 		}
240*25a99e2eSeric 		if (!flagset(M_RESTR, m->m_flags))
241*25a99e2eSeric 			setuid(getuid());
242*25a99e2eSeric # ifdef LOG
243*25a99e2eSeric 		initlog(NULL, 0, LOG_CLOSE);
244*25a99e2eSeric # endif LOG
245*25a99e2eSeric 		endpwent();
246*25a99e2eSeric 		execv(m->m_mailer, pvp);
247*25a99e2eSeric 		/* syserr fails because log is closed */
248*25a99e2eSeric 		/* syserr("Cannot exec %s", m->m_mailer); */
249*25a99e2eSeric 		exit(EX_UNAVAIL);
250*25a99e2eSeric 	}
251*25a99e2eSeric 
252*25a99e2eSeric 	/* arrange to write out header message if error */
253*25a99e2eSeric 	if (editfcn != NULL)
254*25a99e2eSeric 	{
255*25a99e2eSeric 		close(pvect[0]);
256*25a99e2eSeric 		signal(SIGPIPE, pipesig);
257*25a99e2eSeric 		mfile = fdopen(pvect[1], "w");
258*25a99e2eSeric 		(*editfcn)(mfile);
259*25a99e2eSeric 		fclose(mfile);
260*25a99e2eSeric 	}
261*25a99e2eSeric 
262*25a99e2eSeric 	/*
263*25a99e2eSeric 	**  Wait for child to die and report status.
264*25a99e2eSeric 	**	We should never get fatal errors (e.g., segmentation
265*25a99e2eSeric 	**	violation), so we report those specially.  For other
266*25a99e2eSeric 	**	errors, we choose a status message (into statmsg),
267*25a99e2eSeric 	**	and if it represents an error, we print it.
268*25a99e2eSeric 	*/
269*25a99e2eSeric 
270*25a99e2eSeric 	while ((i = wait(&st)) > 0 && i != pid)
271*25a99e2eSeric 		continue;
272*25a99e2eSeric 	if (i < 0)
273*25a99e2eSeric 	{
274*25a99e2eSeric 		syserr("wait");
275*25a99e2eSeric 		return (-1);
276*25a99e2eSeric 	}
277*25a99e2eSeric 	if ((st & 0377) != 0)
278*25a99e2eSeric 	{
279*25a99e2eSeric 		syserr("%s: stat %o", pvp[0], st);
280*25a99e2eSeric 		ExitStat = EX_UNAVAIL;
281*25a99e2eSeric 		return (-1);
282*25a99e2eSeric 	}
283*25a99e2eSeric 	i = (st >> 8) & 0377;
284*25a99e2eSeric 	giveresponse(i, FALSE, m);
285*25a99e2eSeric 	return (i);
286*25a99e2eSeric }
287*25a99e2eSeric /*
288*25a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
289*25a99e2eSeric **
290*25a99e2eSeric **	Parameters:
291*25a99e2eSeric **		stat -- the status code from the mailer (high byte
292*25a99e2eSeric **			only; core dumps must have been taken care of
293*25a99e2eSeric **			already).
294*25a99e2eSeric **		force -- if set, force an error message output, even
295*25a99e2eSeric **			if the mailer seems to like to print its own
296*25a99e2eSeric **			messages.
297*25a99e2eSeric **		m -- the mailer descriptor for this mailer.
298*25a99e2eSeric **
299*25a99e2eSeric **	Returns:
300*25a99e2eSeric **		none.
301*25a99e2eSeric **
302*25a99e2eSeric **	Side Effects:
303*25a99e2eSeric **		Error may be set.
304*25a99e2eSeric **		ExitStat may be set.
305*25a99e2eSeric **
306*25a99e2eSeric **	Requires:
307*25a99e2eSeric **		usrerr
308*25a99e2eSeric **		syserr
309*25a99e2eSeric **		flagset
310*25a99e2eSeric **		logmsg (sys)
311*25a99e2eSeric **
312*25a99e2eSeric **	Called By:
313*25a99e2eSeric **		deliver
314*25a99e2eSeric **
315*25a99e2eSeric **	History:
316*25a99e2eSeric **		2/18/80 -- broken from deliver.
317*25a99e2eSeric */
318*25a99e2eSeric 
319*25a99e2eSeric giveresponse(stat, force, m)
320*25a99e2eSeric 	int stat;
321*25a99e2eSeric 	int force;
322*25a99e2eSeric 	register struct mailer *m;
323*25a99e2eSeric {
324*25a99e2eSeric 	register char *statmsg;
325*25a99e2eSeric 	extern char *SysExMsg[];
326*25a99e2eSeric 	register int i;
327*25a99e2eSeric 	extern int N_SysEx;
328*25a99e2eSeric 
329*25a99e2eSeric 	i = stat - EX__BASE;
330*25a99e2eSeric 	if (i < 0 || i > N_SysEx)
331*25a99e2eSeric 		statmsg = NULL;
332*25a99e2eSeric 	else
333*25a99e2eSeric 		statmsg = SysExMsg[i];
334*25a99e2eSeric 	if (stat == 0)
335*25a99e2eSeric 		statmsg = "ok";
336*25a99e2eSeric 	else
337*25a99e2eSeric 	{
338*25a99e2eSeric 		Error++;
339*25a99e2eSeric 		if (statmsg == NULL && m->m_badstat != 0)
340*25a99e2eSeric 		{
341*25a99e2eSeric 			stat = m->m_badstat;
342*25a99e2eSeric 			i = stat - EX__BASE;
343*25a99e2eSeric # ifdef DEBUG
344*25a99e2eSeric 			if (i < 0 || i >= N_SysEx)
345*25a99e2eSeric 				syserr("Bad m_badstat %d", stat);
346*25a99e2eSeric 			else
347*25a99e2eSeric # endif DEBUG
348*25a99e2eSeric 			statmsg = SysExMsg[i];
349*25a99e2eSeric 		}
350*25a99e2eSeric 		if (statmsg == NULL)
351*25a99e2eSeric 			usrerr("unknown mailer response %d", stat);
352*25a99e2eSeric 		else if (force || !flagset(M_QUIET, m->m_flags))
353*25a99e2eSeric 			usrerr("%s", statmsg);
354*25a99e2eSeric 	}
355*25a99e2eSeric 
356*25a99e2eSeric 	/*
357*25a99e2eSeric 	**  Final cleanup.
358*25a99e2eSeric 	**	Log a record of the transaction.  Compute the new
359*25a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
360*25a99e2eSeric 	**	that.
361*25a99e2eSeric 	*/
362*25a99e2eSeric 
363*25a99e2eSeric # ifdef LOG
364*25a99e2eSeric 	if (statmsg == NULL)
365*25a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: error %d", From.q_paddr, To, stat);
366*25a99e2eSeric 	else
367*25a99e2eSeric 		logmsg(LOG_INFO, "%s->%s: %s", From.q_paddr, To, statmsg);
368*25a99e2eSeric # endif LOG
369*25a99e2eSeric 	if (ExitStat == EX_OK)
370*25a99e2eSeric 		ExitStat = stat;
371*25a99e2eSeric 	return (stat);
372*25a99e2eSeric }
373*25a99e2eSeric /*
374*25a99e2eSeric **  PUTHEADER -- insert the From header into some mail
375*25a99e2eSeric **
376*25a99e2eSeric **	For mailers such as 'msgs' that want the header inserted
377*25a99e2eSeric **	into the mail, this edit filter inserts the From line and
378*25a99e2eSeric **	then passes the rest of the message through.
379*25a99e2eSeric **
380*25a99e2eSeric **	Parameters:
381*25a99e2eSeric **		fp -- the file pointer for the output.
382*25a99e2eSeric **
383*25a99e2eSeric **	Returns:
384*25a99e2eSeric **		none
385*25a99e2eSeric **
386*25a99e2eSeric **	Side Effects:
387*25a99e2eSeric **		Puts a "From" line in UNIX format, and then
388*25a99e2eSeric **			outputs the rest of the message.
389*25a99e2eSeric **
390*25a99e2eSeric **	Requires:
391*25a99e2eSeric **		fprintf (sys)
392*25a99e2eSeric **		fgets (sys)
393*25a99e2eSeric **		fputs (sys)
394*25a99e2eSeric **		time (sys)
395*25a99e2eSeric **		ctime (sys)
396*25a99e2eSeric **		ferror (sys)
397*25a99e2eSeric **		syserr
398*25a99e2eSeric **		setstat
399*25a99e2eSeric **
400*25a99e2eSeric **	Called By:
401*25a99e2eSeric **		deliver
402*25a99e2eSeric **
403*25a99e2eSeric **	History:
404*25a99e2eSeric **		1/8/80 -- written.
405*25a99e2eSeric */
406*25a99e2eSeric 
407*25a99e2eSeric putheader(fp)
408*25a99e2eSeric 	register FILE *fp;
409*25a99e2eSeric {
410*25a99e2eSeric 	char buf[MAXLINE + 1];
411*25a99e2eSeric 	long tim;
412*25a99e2eSeric 	extern char *ctime();
413*25a99e2eSeric 
414*25a99e2eSeric 	time(&tim);
415*25a99e2eSeric 	fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim));
416*25a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp))
417*25a99e2eSeric 		fputs(buf, fp);
418*25a99e2eSeric 	if (ferror(fp))
419*25a99e2eSeric 	{
420*25a99e2eSeric 		syserr("putheader: write error");
421*25a99e2eSeric 		setstat(EX_IOERR);
422*25a99e2eSeric 	}
423*25a99e2eSeric }
424*25a99e2eSeric /*
425*25a99e2eSeric **  PIPESIG -- Handle broken pipe signals
426*25a99e2eSeric **
427*25a99e2eSeric **	This just logs an error.
428*25a99e2eSeric **
429*25a99e2eSeric **	Parameters:
430*25a99e2eSeric **		none
431*25a99e2eSeric **
432*25a99e2eSeric **	Returns:
433*25a99e2eSeric **		none
434*25a99e2eSeric **
435*25a99e2eSeric **	Side Effects:
436*25a99e2eSeric **		logs an error message.
437*25a99e2eSeric **
438*25a99e2eSeric **	Requires:
439*25a99e2eSeric **		syserr
440*25a99e2eSeric **
441*25a99e2eSeric **	History:
442*25a99e2eSeric **		1/17/80 -- written.
443*25a99e2eSeric */
444*25a99e2eSeric 
445*25a99e2eSeric pipesig()
446*25a99e2eSeric {
447*25a99e2eSeric 	syserr("Broken pipe");
448*25a99e2eSeric }
449*25a99e2eSeric /*
450*25a99e2eSeric **  SENDTO -- Designate a send list.
451*25a99e2eSeric **
452*25a99e2eSeric **	The parameter is a comma-separated list of people to send to.
453*25a99e2eSeric **	This routine arranges to send to all of them.
454*25a99e2eSeric **
455*25a99e2eSeric **	Parameters:
456*25a99e2eSeric **		list -- the send list.
457*25a99e2eSeric **		copyf -- the copy flag; passed to parse.
458*25a99e2eSeric **
459*25a99e2eSeric **	Returns:
460*25a99e2eSeric **		none
461*25a99e2eSeric **
462*25a99e2eSeric **	Side Effects:
463*25a99e2eSeric **		none.
464*25a99e2eSeric **
465*25a99e2eSeric **	Requires:
466*25a99e2eSeric **		parse
467*25a99e2eSeric **		recipient
468*25a99e2eSeric **
469*25a99e2eSeric **	Called By:
470*25a99e2eSeric **		main
471*25a99e2eSeric **		alias
472*25a99e2eSeric **
473*25a99e2eSeric **	History:
474*25a99e2eSeric **		1/11/80 -- written.
475*25a99e2eSeric */
476*25a99e2eSeric 
477*25a99e2eSeric sendto(list, copyf)
478*25a99e2eSeric 	char *list;
479*25a99e2eSeric 	int copyf;
480*25a99e2eSeric {
481*25a99e2eSeric 	register char *p;
482*25a99e2eSeric 	register char *q;
483*25a99e2eSeric 	register char c;
484*25a99e2eSeric 	addrq *a;
485*25a99e2eSeric 	extern addrq *parse();
486*25a99e2eSeric 	bool more;
487*25a99e2eSeric 
488*25a99e2eSeric 	/* more keeps track of what the previous delimiter was */
489*25a99e2eSeric 	more = TRUE;
490*25a99e2eSeric 	for (p = list; more; )
491*25a99e2eSeric 	{
492*25a99e2eSeric 		/* find the end of this address */
493*25a99e2eSeric 		q = p;
494*25a99e2eSeric 		while ((c = *p++) != '\0' && c != ',' && c != '\n')
495*25a99e2eSeric 			continue;
496*25a99e2eSeric 		more = c != '\0';
497*25a99e2eSeric 		*--p = '\0';
498*25a99e2eSeric 		if (more)
499*25a99e2eSeric 			p++;
500*25a99e2eSeric 
501*25a99e2eSeric 		/* parse the address */
502*25a99e2eSeric 		if ((a = parse(q, (addrq *) NULL, copyf)) == NULL)
503*25a99e2eSeric 			continue;
504*25a99e2eSeric 
505*25a99e2eSeric 		/* arrange to send to this person */
506*25a99e2eSeric 		recipient(a, &SendQ);
507*25a99e2eSeric 	}
508*25a99e2eSeric 	To = NULL;
509*25a99e2eSeric }
510*25a99e2eSeric /*
511*25a99e2eSeric **  RECIPIENT -- Designate a message recipient
512*25a99e2eSeric **
513*25a99e2eSeric **	Saves the named person for future mailing.
514*25a99e2eSeric **
515*25a99e2eSeric **	Designates a person as a recipient.  This routine
516*25a99e2eSeric **	does the initial parsing, and checks to see if
517*25a99e2eSeric **	this person has already received the mail.
518*25a99e2eSeric **	It also supresses local network names and turns them into
519*25a99e2eSeric **	local names.
520*25a99e2eSeric **
521*25a99e2eSeric **	Parameters:
522*25a99e2eSeric **		a -- the (preparsed) address header for the recipient.
523*25a99e2eSeric **		targetq -- the queue to add the name to.
524*25a99e2eSeric **
525*25a99e2eSeric **	Returns:
526*25a99e2eSeric **		none.
527*25a99e2eSeric **
528*25a99e2eSeric **	Side Effects:
529*25a99e2eSeric **		none.
530*25a99e2eSeric **
531*25a99e2eSeric **	Requires:
532*25a99e2eSeric **		sameaddr
533*25a99e2eSeric **		parse
534*25a99e2eSeric **		forward
535*25a99e2eSeric **		printf (sys)
536*25a99e2eSeric **		strcmp (sys)
537*25a99e2eSeric **		nxtinq
538*25a99e2eSeric **		putonq
539*25a99e2eSeric **
540*25a99e2eSeric **	Called By:
541*25a99e2eSeric **		sendto
542*25a99e2eSeric **		main
543*25a99e2eSeric **
544*25a99e2eSeric **	History:
545*25a99e2eSeric **		3/5/80 -- modified to know about new internal form
546*25a99e2eSeric **			for addresses.
547*25a99e2eSeric **		12/31/79 -- written.
548*25a99e2eSeric */
549*25a99e2eSeric 
550*25a99e2eSeric recipient(a, targetq)
551*25a99e2eSeric 	register addrq *a;
552*25a99e2eSeric 	addrq *targetq;
553*25a99e2eSeric {
554*25a99e2eSeric 	register addrq *q;
555*25a99e2eSeric 	register struct mailer *m;
556*25a99e2eSeric 	register char **pvp;
557*25a99e2eSeric 	extern char *xalloc();
558*25a99e2eSeric 	extern bool forward();
559*25a99e2eSeric 	extern int errno;
560*25a99e2eSeric 	extern bool sameaddr();
561*25a99e2eSeric 
562*25a99e2eSeric 	To = a->q_paddr;
563*25a99e2eSeric 	m = a->q_mailer;
564*25a99e2eSeric 	errno = 0;
565*25a99e2eSeric # ifdef DEBUG
566*25a99e2eSeric 	if (Debug)
567*25a99e2eSeric 		printf("recipient(%s)\n", To);
568*25a99e2eSeric # endif DEBUG
569*25a99e2eSeric 
570*25a99e2eSeric 	/*
571*25a99e2eSeric 	**  Don't go to the net if already on the target host.
572*25a99e2eSeric 	**	This is important on the berkeley network, since
573*25a99e2eSeric 	**	it get confused if we ask to send to ourselves.
574*25a99e2eSeric 	**	For nets like the ARPANET, we probably will have
575*25a99e2eSeric 	**	the local list set to NULL to simplify testing.
576*25a99e2eSeric 	**	The canonical representation of the name is also set
577*25a99e2eSeric 	**	to be just the local name so the duplicate letter
578*25a99e2eSeric 	**	suppression algorithm will work.
579*25a99e2eSeric 	*/
580*25a99e2eSeric 
581*25a99e2eSeric 	if ((pvp = m->m_local) != NULL)
582*25a99e2eSeric 	{
583*25a99e2eSeric 		while (*pvp != NULL)
584*25a99e2eSeric 		{
585*25a99e2eSeric 			if (strcmp(*pvp++, a->q_host) == 0)
586*25a99e2eSeric 			{
587*25a99e2eSeric 				a->q_mailer = m = &Mailer[0];
588*25a99e2eSeric 				break;
589*25a99e2eSeric 			}
590*25a99e2eSeric 		}
591*25a99e2eSeric 	}
592*25a99e2eSeric 
593*25a99e2eSeric 	/*
594*25a99e2eSeric 	**  Look up this person in the recipient list.  If they
595*25a99e2eSeric 	**  are there already, return, otherwise continue.
596*25a99e2eSeric 	*/
597*25a99e2eSeric 
598*25a99e2eSeric 	if (!ForceMail)
599*25a99e2eSeric 	{
600*25a99e2eSeric 		for (q = &SendQ; (q = nxtinq(q)) != NULL; )
601*25a99e2eSeric 			if (sameaddr(q, a, FALSE))
602*25a99e2eSeric 			{
603*25a99e2eSeric # ifdef DEBUG
604*25a99e2eSeric 				if (Debug)
605*25a99e2eSeric 					printf("(%s in SendQ)\n", a->q_paddr);
606*25a99e2eSeric # endif DEBUG
607*25a99e2eSeric 				return;
608*25a99e2eSeric 			}
609*25a99e2eSeric 		for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
610*25a99e2eSeric 			if (sameaddr(q, a, FALSE))
611*25a99e2eSeric 			{
612*25a99e2eSeric # ifdef DEBUG
613*25a99e2eSeric 				if (Debug)
614*25a99e2eSeric 					printf("(%s in AliasQ)\n", a->q_paddr);
615*25a99e2eSeric # endif DEBUG
616*25a99e2eSeric 				return;
617*25a99e2eSeric 			}
618*25a99e2eSeric 	}
619*25a99e2eSeric 
620*25a99e2eSeric 	/*
621*25a99e2eSeric 	**  See if the user wants hir mail forwarded.
622*25a99e2eSeric 	**	`Forward' must do the forwarding recursively.
623*25a99e2eSeric 	*/
624*25a99e2eSeric 
625*25a99e2eSeric 	if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a))
626*25a99e2eSeric 		return;
627*25a99e2eSeric 
628*25a99e2eSeric 	/*
629*25a99e2eSeric 	**  Put the user onto the target queue.
630*25a99e2eSeric 	*/
631*25a99e2eSeric 
632*25a99e2eSeric 	if (targetq != NULL)
633*25a99e2eSeric 	{
634*25a99e2eSeric 		putonq(a, targetq);
635*25a99e2eSeric 	}
636*25a99e2eSeric 
637*25a99e2eSeric 	return;
638*25a99e2eSeric }
639*25a99e2eSeric /*
640*25a99e2eSeric **  BUILDARGV -- Build an argument vector for a mail server.
641*25a99e2eSeric **
642*25a99e2eSeric **	Using a template defined in config.c, an argv is built.
643*25a99e2eSeric **	The format of the template is already a vector.  The
644*25a99e2eSeric **	items of this vector are copied, unless a dollar sign
645*25a99e2eSeric **	is encountered.  In this case, the next character
646*25a99e2eSeric **	specifies something else to copy in.  These can be
647*25a99e2eSeric **		$f	The from address.
648*25a99e2eSeric **		$h	The host.
649*25a99e2eSeric **		$u	The user.
650*25a99e2eSeric **		$c	The hop count.
651*25a99e2eSeric **	The vector is built in a local buffer.  A pointer to
652*25a99e2eSeric **	the static argv is returned.
653*25a99e2eSeric **
654*25a99e2eSeric **	Parameters:
655*25a99e2eSeric **		tmplt -- a template for an argument vector.
656*25a99e2eSeric **		flags -- the flags for this server.
657*25a99e2eSeric **		host -- the host name to send to.
658*25a99e2eSeric **		user -- the user name to send to.
659*25a99e2eSeric **		from -- the person this mail is from.
660*25a99e2eSeric **
661*25a99e2eSeric **	Returns:
662*25a99e2eSeric **		A pointer to an argv.
663*25a99e2eSeric **
664*25a99e2eSeric **	Side Effects:
665*25a99e2eSeric **		none
666*25a99e2eSeric **
667*25a99e2eSeric **	WARNING:
668*25a99e2eSeric **		Since the argv is staticly allocated, any subsequent
669*25a99e2eSeric **		calls will clobber the old argv.
670*25a99e2eSeric **
671*25a99e2eSeric **	Requires:
672*25a99e2eSeric **		printf (sys)
673*25a99e2eSeric **		sprintf (sys)
674*25a99e2eSeric **		flagset
675*25a99e2eSeric **		syserr
676*25a99e2eSeric **
677*25a99e2eSeric **	Called By:
678*25a99e2eSeric **		deliver
679*25a99e2eSeric **
680*25a99e2eSeric **	History:
681*25a99e2eSeric **		12/26/79 -- written.
682*25a99e2eSeric */
683*25a99e2eSeric 
684*25a99e2eSeric char **
685*25a99e2eSeric buildargv(tmplt, flags, host, user, from)
686*25a99e2eSeric 	char **tmplt;
687*25a99e2eSeric 	int flags;
688*25a99e2eSeric 	char *host;
689*25a99e2eSeric 	char *user;
690*25a99e2eSeric 	char *from;
691*25a99e2eSeric {
692*25a99e2eSeric 	register char *p;
693*25a99e2eSeric 	register char *q;
694*25a99e2eSeric 	static char *pv[MAXPV+1];
695*25a99e2eSeric 	char **pvp;
696*25a99e2eSeric 	char **mvp;
697*25a99e2eSeric 	static char buf[512];
698*25a99e2eSeric 	register char *bp;
699*25a99e2eSeric 	char pbuf[30];
700*25a99e2eSeric 
701*25a99e2eSeric 	/*
702*25a99e2eSeric 	**  Do initial argv setup.
703*25a99e2eSeric 	**	Insert the mailer name.  Notice that $x expansion is
704*25a99e2eSeric 	**	NOT done on the mailer name.  Then, if the mailer has
705*25a99e2eSeric 	**	a picky -f flag, we insert it as appropriate.  This
706*25a99e2eSeric 	**	code does not check for 'pv' overflow; this places a
707*25a99e2eSeric 	**	manifest lower limit of 4 for MAXPV.
708*25a99e2eSeric 	*/
709*25a99e2eSeric 
710*25a99e2eSeric 	pvp = pv;
711*25a99e2eSeric 	bp = buf;
712*25a99e2eSeric 
713*25a99e2eSeric 	*pvp++ = tmplt[0];
714*25a99e2eSeric 
715*25a99e2eSeric 	/* insert -f or -r flag as appropriate */
716*25a99e2eSeric 	if (flagset(M_FOPT|M_ROPT, flags) && FromFlag)
717*25a99e2eSeric 	{
718*25a99e2eSeric 		if (flagset(M_FOPT, flags))
719*25a99e2eSeric 			*pvp++ = "-f";
720*25a99e2eSeric 		else
721*25a99e2eSeric 			*pvp++ = "-r";
722*25a99e2eSeric 		*pvp++ = From.q_paddr;
723*25a99e2eSeric 	}
724*25a99e2eSeric 
725*25a99e2eSeric 	/*
726*25a99e2eSeric 	**  Build the rest of argv.
727*25a99e2eSeric 	**	For each prototype parameter, the prototype is
728*25a99e2eSeric 	**	scanned character at a time.  If a dollar-sign is
729*25a99e2eSeric 	**	found, 'q' is set to the appropriate expansion,
730*25a99e2eSeric 	**	otherwise it is null.  Then either the string
731*25a99e2eSeric 	**	pointed to by q, or the original character, is
732*25a99e2eSeric 	**	interpolated into the buffer.  Buffer overflow is
733*25a99e2eSeric 	**	checked.
734*25a99e2eSeric 	*/
735*25a99e2eSeric 
736*25a99e2eSeric 	for (mvp = tmplt; (p = *++mvp) != NULL; )
737*25a99e2eSeric 	{
738*25a99e2eSeric 		if (pvp >= &pv[MAXPV])
739*25a99e2eSeric 		{
740*25a99e2eSeric 			syserr("Too many parameters to %s", pv[0]);
741*25a99e2eSeric 			return (NULL);
742*25a99e2eSeric 		}
743*25a99e2eSeric 		*pvp++ = bp;
744*25a99e2eSeric 		for (; *p != '\0'; p++)
745*25a99e2eSeric 		{
746*25a99e2eSeric 			/* q will be the interpolated quantity */
747*25a99e2eSeric 			q = NULL;
748*25a99e2eSeric 			if (*p == '$')
749*25a99e2eSeric 			{
750*25a99e2eSeric 				switch (*++p)
751*25a99e2eSeric 				{
752*25a99e2eSeric 				  case 'f':	/* from person */
753*25a99e2eSeric 					q = from;
754*25a99e2eSeric 					break;
755*25a99e2eSeric 
756*25a99e2eSeric 				  case 'u':	/* user */
757*25a99e2eSeric 					q = user;
758*25a99e2eSeric 					break;
759*25a99e2eSeric 
760*25a99e2eSeric 				  case 'h':	/* host */
761*25a99e2eSeric 					q = host;
762*25a99e2eSeric 					break;
763*25a99e2eSeric 
764*25a99e2eSeric 				  case 'c':	/* hop count */
765*25a99e2eSeric 					sprintf(pbuf, "%d", HopCount);
766*25a99e2eSeric 					q = pbuf;
767*25a99e2eSeric 					break;
768*25a99e2eSeric 				}
769*25a99e2eSeric 			}
770*25a99e2eSeric 
771*25a99e2eSeric 			/*
772*25a99e2eSeric 			**  Interpolate q or output one character
773*25a99e2eSeric 			**	Strip quote bits as we proceed.....
774*25a99e2eSeric 			*/
775*25a99e2eSeric 
776*25a99e2eSeric 			if (q != NULL)
777*25a99e2eSeric 			{
778*25a99e2eSeric 				while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0')
779*25a99e2eSeric 					continue;
780*25a99e2eSeric 				bp--;
781*25a99e2eSeric 				if (q[-2] == '"')
782*25a99e2eSeric 					bp--;
783*25a99e2eSeric 			}
784*25a99e2eSeric 			else if (bp < &buf[sizeof buf - 1])
785*25a99e2eSeric 				*bp++ = *p;
786*25a99e2eSeric 		}
787*25a99e2eSeric 		*bp++ = '\0';
788*25a99e2eSeric 		if (bp >= &buf[sizeof buf - 1])
789*25a99e2eSeric 			return (NULL);
790*25a99e2eSeric 	}
791*25a99e2eSeric 	*pvp = NULL;
792*25a99e2eSeric 
793*25a99e2eSeric # ifdef DEBUG
794*25a99e2eSeric 	if (Debug)
795*25a99e2eSeric 	{
796*25a99e2eSeric 		printf("Interpolated argv is:\n");
797*25a99e2eSeric 		for (mvp = pv; *mvp != NULL; mvp++)
798*25a99e2eSeric 			printf("\t%s\n", *mvp);
799*25a99e2eSeric 	}
800*25a99e2eSeric # endif DEBUG
801*25a99e2eSeric 
802*25a99e2eSeric 	return (pv);
803*25a99e2eSeric }
804*25a99e2eSeric /*
805*25a99e2eSeric **  MAILFILE -- Send a message to a file.
806*25a99e2eSeric **
807*25a99e2eSeric **	Parameters:
808*25a99e2eSeric **		filename -- the name of the file to send to.
809*25a99e2eSeric **
810*25a99e2eSeric **	Returns:
811*25a99e2eSeric **		The exit code associated with the operation.
812*25a99e2eSeric **
813*25a99e2eSeric **	Side Effects:
814*25a99e2eSeric **		none.
815*25a99e2eSeric **
816*25a99e2eSeric **	Requires:
817*25a99e2eSeric **		fgets (sys)
818*25a99e2eSeric **		fputs (sys)
819*25a99e2eSeric **		fprintf (sys)
820*25a99e2eSeric **		fopen (sys)
821*25a99e2eSeric **		fclose (sys)
822*25a99e2eSeric **		ferror (sys)
823*25a99e2eSeric **		time (sys)
824*25a99e2eSeric **		ctime (sys)
825*25a99e2eSeric **		rewind (sys)
826*25a99e2eSeric **
827*25a99e2eSeric **	Called By:
828*25a99e2eSeric **		deliver
829*25a99e2eSeric **
830*25a99e2eSeric **	History:
831*25a99e2eSeric **		3/5/80 -- written.
832*25a99e2eSeric */
833*25a99e2eSeric 
834*25a99e2eSeric mailfile(filename)
835*25a99e2eSeric 	char *filename;
836*25a99e2eSeric {
837*25a99e2eSeric 	char buf[MAXLINE];
838*25a99e2eSeric 	register FILE *f;
839*25a99e2eSeric 	auto long tim;
840*25a99e2eSeric 	extern char *ctime();
841*25a99e2eSeric 
842*25a99e2eSeric 	f = fopen(filename, "a");
843*25a99e2eSeric 	if (f == NULL)
844*25a99e2eSeric 		return (EX_CANTCREAT);
845*25a99e2eSeric 
846*25a99e2eSeric 	/* output the timestamp */
847*25a99e2eSeric 	time(&tim);
848*25a99e2eSeric 	fprintf(f, "From %s %s", From.q_paddr, ctime(&tim));
849*25a99e2eSeric 	rewind(stdin);
850*25a99e2eSeric 	while (fgets(buf, sizeof buf, stdin) != NULL)
851*25a99e2eSeric 	{
852*25a99e2eSeric 		fputs(buf, f);
853*25a99e2eSeric 		if (ferror(f))
854*25a99e2eSeric 		{
855*25a99e2eSeric 			fclose(f);
856*25a99e2eSeric 			return (EX_IOERR);
857*25a99e2eSeric 		}
858*25a99e2eSeric 	}
859*25a99e2eSeric 	fputs("\n", f);
860*25a99e2eSeric 	fclose(f);
861*25a99e2eSeric 	return (EX_OK);
862*25a99e2eSeric }
863