1*297Seric # include <stdio.h>
2*297Seric # include <pwd.h>
3*297Seric # include "dlvrmail.h"
4*297Seric 
5*297Seric /*
6*297Seric **  SAVEMAIL -- Save mail on error
7*297Seric **
8*297Seric **	If the MailBack flag is set, mail it back to the originator
9*297Seric **	together with an error message; otherwise, just put it in
10*297Seric **	dead.letter in the user's home directory (if he exists on
11*297Seric **	this machine).
12*297Seric **
13*297Seric **	Parameters:
14*297Seric **		none
15*297Seric **
16*297Seric **	Returns:
17*297Seric **		none
18*297Seric **
19*297Seric **	Side Effects:
20*297Seric **		Saves the letter, by writing or mailing it back to the
21*297Seric **		sender, or by putting it in dead.letter in her home
22*297Seric **		directory.
23*297Seric **
24*297Seric **		WARNING: the user id is reset to the original user.
25*297Seric **
26*297Seric **	Requires:
27*297Seric **		fopen (sys)
28*297Seric **		bmove
29*297Seric **		parse
30*297Seric **		deliver
31*297Seric **		strcpy (sys)
32*297Seric **		strcat (sys)
33*297Seric **		fclose (sys)
34*297Seric **		fgets (sys)
35*297Seric **		fputs (sys)
36*297Seric **		setpwent (sys)
37*297Seric **		getuid (sys)
38*297Seric **		setuid (sys)
39*297Seric **		getgid (sys)
40*297Seric **		setgid (sys)
41*297Seric **		getpwnam (sys)
42*297Seric **		fprintf (sys)
43*297Seric **		ttypath
44*297Seric **		freopen (sys)
45*297Seric **		printf (sys)
46*297Seric **		syserr
47*297Seric **		rewind (sys)
48*297Seric **		time (sys)
49*297Seric **		ferror (sys)
50*297Seric **
51*297Seric **	Called By:
52*297Seric **		finis
53*297Seric **
54*297Seric **	History:
55*297Seric **		12/30/79 -- written.
56*297Seric */
57*297Seric 
58*297Seric # define MY_NAME	"~MAILER~DAEMON~"
59*297Seric 
60*297Seric savemail()
61*297Seric {
62*297Seric 	register struct passwd *pw;
63*297Seric 	register FILE *xfile;
64*297Seric 	char buf[MAXLINE+1];
65*297Seric 	extern errhdr();
66*297Seric 	auto addrq to_addr;
67*297Seric 	extern struct passwd *getpwnam();
68*297Seric 	register char *p;
69*297Seric 	register int i;
70*297Seric 	auto long tim;
71*297Seric 	extern int errno;
72*297Seric 	extern char *ttypath();
73*297Seric 	extern char *ctime();
74*297Seric 	extern addrq *parse();
75*297Seric 	static int exclusive;
76*297Seric 
77*297Seric 	if (exclusive++)
78*297Seric 		return;
79*297Seric 
80*297Seric 	/*
81*297Seric 	**  In the unhappy event we don't know who to return the mail
82*297Seric 	**  to, make someone up.
83*297Seric 	*/
84*297Seric 
85*297Seric 	if (From.q_paddr == NULL)
86*297Seric 	{
87*297Seric 		if (parse("root", &From, 0) == NULL)
88*297Seric 		{
89*297Seric 			syserr("Cannot parse root!");
90*297Seric 			ExitStat = EX_SOFTWARE;
91*297Seric 			finis();
92*297Seric 		}
93*297Seric 	}
94*297Seric 
95*297Seric 	/*
96*297Seric 	**  If echoing the bad mail, do it.
97*297Seric 	**	Output the transcript and a message saying that the
98*297Seric 	**	message will be mailed back; then fall through to
99*297Seric 	**	the MailBack case.
100*297Seric 	*/
101*297Seric 
102*297Seric 	if (EchoBack || WriteBack)
103*297Seric 	{
104*297Seric 		xfile = fopen(Transcript, "r");
105*297Seric 		if (xfile == NULL)
106*297Seric 			syserr("Cannot open %s", Transcript);
107*297Seric 		fflush(stdout);
108*297Seric 	}
109*297Seric 	else
110*297Seric 		xfile = NULL;
111*297Seric 
112*297Seric 	if (EchoBack)
113*297Seric 	{
114*297Seric 		while (fgets(buf, sizeof buf, xfile) != NULL)
115*297Seric 			fputs(buf, stderr);
116*297Seric 		fprintf(stderr, "\nThe unsent mail will be returned to you\n");
117*297Seric 		MailBack++;
118*297Seric 	}
119*297Seric 
120*297Seric 	/*
121*297Seric 	**  If writing back, do it.
122*297Seric 	**	If the user is still logged in on the same terminal,
123*297Seric 	**	then write the error messages back to hir (sic).
124*297Seric 	**	If not, set the MailBack flag so that it will get
125*297Seric 	**	mailed back instead.
126*297Seric 	*/
127*297Seric 
128*297Seric 	if (WriteBack)
129*297Seric 	{
130*297Seric 		p = ttypath();
131*297Seric 		if (p == NULL || freopen(p, "w", stdout) == NULL)
132*297Seric 		{
133*297Seric 			MailBack++;
134*297Seric 			errno = 0;
135*297Seric 		}
136*297Seric 		else
137*297Seric 		{
138*297Seric 			printf("\r\nMessage from %s\r\n", MY_NAME);
139*297Seric 			printf("Errors occurred while sending mail, transcript follows:\r\n");
140*297Seric 			while (fgets(buf, sizeof buf, xfile) && !ferror(stdout))
141*297Seric 				fputs(buf, stdout);
142*297Seric 			if (ferror(stdout))
143*297Seric 				syserr("savemail: stdout: write err");
144*297Seric 		}
145*297Seric 	}
146*297Seric 
147*297Seric 	if (xfile != NULL)
148*297Seric 		fclose(xfile);
149*297Seric 
150*297Seric 	/*
151*297Seric 	**  If mailing back, do it.
152*297Seric 	**	Throw away all further output.  Don't do aliases, since
153*297Seric 	**	this could cause loops, e.g., if joe mails to x:joe,
154*297Seric 	**	and for some reason the network for x: is down, then
155*297Seric 	**	the response gets sent to x:joe, which gives a
156*297Seric 	**	response, etc.  Also force the mail to be delivered
157*297Seric 	**	even if a version of it has already been sent to the
158*297Seric 	**	sender.
159*297Seric 	*/
160*297Seric 
161*297Seric 	if (MailBack || From.q_mailer != &Mailer[0])
162*297Seric 	{
163*297Seric 		freopen("/dev/null", "w", stdout);
164*297Seric 		NoAlias++;
165*297Seric 		ForceMail++;
166*297Seric 
167*297Seric 		/* fake up an address header for the from person */
168*297Seric 		bmove((char *) &From, (char *) &to_addr, sizeof to_addr);
169*297Seric 		if (parse(MY_NAME, &From, -1) == NULL)
170*297Seric 		{
171*297Seric 			syserr("Can't parse myself!");
172*297Seric 			ExitStat = EX_SOFTWARE;
173*297Seric 			finis();
174*297Seric 		}
175*297Seric 		i = deliver(&to_addr, errhdr);
176*297Seric 		bmove((char *) &to_addr, (char *) &From, sizeof From);
177*297Seric 		if (i != 0)
178*297Seric 			syserr("Can't return mail to %s", p);
179*297Seric 		else
180*297Seric 			return;
181*297Seric 	}
182*297Seric 
183*297Seric 	/*
184*297Seric 	**  Save the message in dead.letter.
185*297Seric 	**	If we weren't mailing back, and the user is local, we
186*297Seric 	**	should save the message in dead.letter so that the
187*297Seric 	**	poor person doesn't have to type it over again --
188*297Seric 	**	and we all know what poor typists programmers are.
189*297Seric 	*/
190*297Seric 
191*297Seric 	setuid(getuid());
192*297Seric 	setgid(getgid());
193*297Seric 	setpwent();
194*297Seric 	if (From.q_mailer == &Mailer[0] && (pw = getpwnam(From.q_user)) != NULL)
195*297Seric 	{
196*297Seric 		/* user has a home directory */
197*297Seric 		p = pw->pw_dir;
198*297Seric 	}
199*297Seric 	else
200*297Seric 	{
201*297Seric 		syserr("Can't return mail to %s (pw=%u)", From.q_paddr, pw);
202*297Seric # ifdef DEBUG
203*297Seric 		p = "/usr/tmp";
204*297Seric # else
205*297Seric 		p = NULL;
206*297Seric # endif
207*297Seric 	}
208*297Seric 	if (p != NULL)
209*297Seric 	{
210*297Seric 		/* we have a home directory; open dead.letter */
211*297Seric 		strcpy(buf, p);
212*297Seric 		strcat(buf, "/dead.letter");
213*297Seric 		xfile = fopen(buf, "a");
214*297Seric 		if (xfile == NULL)
215*297Seric 			printf("Cannot save mail, sorry\n");
216*297Seric 		else
217*297Seric 		{
218*297Seric 			rewind(stdin);
219*297Seric 			errno = 0;
220*297Seric 			time(&tim);
221*297Seric 			fprintf(xfile, "----- Mail saved at %s", ctime(&tim));
222*297Seric 			while (fgets(buf, sizeof buf, stdin) && !ferror(xfile))
223*297Seric 				fputs(buf, xfile);
224*297Seric 			fputs("\n", xfile);
225*297Seric 			if (ferror(xfile))
226*297Seric 				syserr("savemail: dead.letter: write err");
227*297Seric 			fclose(xfile);
228*297Seric 			printf("Letter saved in dead.letter\n");
229*297Seric 		}
230*297Seric 	}
231*297Seric 	else
232*297Seric 
233*297Seric 	/* add terminator to writeback message */
234*297Seric 	if (WriteBack)
235*297Seric 		printf("-----\r\n");
236*297Seric }
237*297Seric /*
238*297Seric **  ERRHDR -- Output the header for error mail.
239*297Seric **
240*297Seric **	This is the edit filter to error mailbacks.
241*297Seric **
242*297Seric **	Algorithm:
243*297Seric **		Output fixed header.
244*297Seric **		Output the transcript part.
245*297Seric **		Output the original message.
246*297Seric **
247*297Seric **	Parameters:
248*297Seric **		xfile -- the transcript file.
249*297Seric **		fp -- the output file.
250*297Seric **
251*297Seric **	Returns:
252*297Seric **		none
253*297Seric **
254*297Seric **	Side Effects:
255*297Seric **		input from xfile
256*297Seric **		output to fp
257*297Seric **
258*297Seric **	Requires:
259*297Seric **		read (sys)
260*297Seric **		write (sys)
261*297Seric **		open (sys)
262*297Seric **		close (sys)
263*297Seric **		syserr
264*297Seric **		rewind (sys)
265*297Seric **		fflush (sys)
266*297Seric **		fprintf (sys)
267*297Seric **		fileno (sys)
268*297Seric **
269*297Seric **	Called By:
270*297Seric **		deliver
271*297Seric **
272*297Seric **	History:
273*297Seric **		12/28/79 -- written.
274*297Seric */
275*297Seric 
276*297Seric 
277*297Seric errhdr(fp)
278*297Seric 	register FILE *fp;
279*297Seric {
280*297Seric 	char copybuf[512];
281*297Seric 	register int i;
282*297Seric 	register int xfile;
283*297Seric 	extern int errno;
284*297Seric 
285*297Seric 	if ((xfile = open(Transcript, 0)) < 0)
286*297Seric 		syserr("Cannot open %s", Transcript);
287*297Seric 	fflush(stdout);
288*297Seric 	errno = 0;
289*297Seric 	fprintf(fp, "To: %s\n", To);
290*297Seric 	fprintf(fp, "Subject: Unable to deliver mail\n");
291*297Seric 	fprintf(fp, "\n   ----- Transcript of session follows -----\n");
292*297Seric 	fflush(fp);
293*297Seric 	while ((i = read(xfile, copybuf, sizeof copybuf)) > 0)
294*297Seric 		write(fileno(fp), copybuf, i);
295*297Seric 	fprintf(fp, "\n   ----- Unsent message follows -----\n");
296*297Seric 	fflush(fp);
297*297Seric 	rewind(stdin);
298*297Seric 	while ((i = read(fileno(stdin), copybuf, sizeof copybuf)) > 0)
299*297Seric 		write(fileno(fp), copybuf, i);
300*297Seric 	close(xfile);
301*297Seric 	if (errno != 0)
302*297Seric 		syserr("errhdr: I/O error");
303*297Seric }
304