1 # include <pwd.h>
2 # include "sendmail.h"
3 
4 static char	SccsId[] = "@(#)savemail.c	3.13	08/20/81";
5 
6 /*
7 **  SAVEMAIL -- Save mail on error
8 **
9 **	If the MailBack flag is set, mail it back to the originator
10 **	together with an error message; otherwise, just put it in
11 **	dead.letter in the user's home directory (if he exists on
12 **	this machine).
13 **
14 **	Parameters:
15 **		none
16 **
17 **	Returns:
18 **		none
19 **
20 **	Side Effects:
21 **		Saves the letter, by writing or mailing it back to the
22 **		sender, or by putting it in dead.letter in her home
23 **		directory.
24 **
25 **		WARNING: the user id is reset to the original user.
26 */
27 
28 savemail()
29 {
30 	register struct passwd *pw;
31 	register FILE *xfile;
32 	char buf[MAXLINE+1];
33 	extern errhdr();
34 	auto ADDRESS to_addr;
35 	extern struct passwd *getpwnam();
36 	register char *p;
37 	register int i;
38 	extern char *ttypath();
39 	static int exclusive;
40 
41 	if (exclusive++ || TempFile == NULL)
42 		return;
43 
44 	/*
45 	**  In the unhappy event we don't know who to return the mail
46 	**  to, make someone up.
47 	*/
48 
49 	if (From.q_paddr == NULL)
50 	{
51 		if (parse("root", &From, 0) == NULL)
52 		{
53 			syserr("Cannot parse root!");
54 			ExitStat = EX_SOFTWARE;
55 			finis();
56 		}
57 	}
58 	To = NULL;
59 
60 	/*
61 	**  If called from Eric Schmidt's network, do special mailback.
62 	**	Fundamentally, this is the mailback case except that
63 	**	it returns an OK exit status (assuming the return
64 	**	worked).
65 	*/
66 
67 	if (BerkNet)
68 	{
69 		ExitStat = EX_OK;
70 		MailBack++;
71 	}
72 
73 	/*
74 	**  If writing back, do it.
75 	**	If the user is still logged in on the same terminal,
76 	**	then write the error messages back to hir (sic).
77 	**	If not, set the MailBack flag so that it will get
78 	**	mailed back instead.
79 	*/
80 
81 	if (WriteBack)
82 	{
83 		p = ttypath();
84 		if (p == NULL || freopen(p, "w", stdout) == NULL)
85 		{
86 			MailBack++;
87 			errno = 0;
88 		}
89 		else
90 		{
91 			xfile = fopen(Transcript, "r");
92 			if (xfile == NULL)
93 				syserr("Cannot open %s", Transcript);
94 			(void) expand("$n", buf, &buf[sizeof buf - 1]);
95 			printf("\r\nMessage from %s...\r\n", buf);
96 			printf("Errors occurred while sending mail, transcript follows:\r\n");
97 			while (fgets(buf, sizeof buf, xfile) != NULL && !ferror(stdout))
98 				fputs(buf, stdout);
99 			if (ferror(stdout))
100 				(void) syserr("savemail: stdout: write err");
101 			(void) fclose(xfile);
102 		}
103 	}
104 
105 	/*
106 	**  If mailing back, do it.
107 	**	Throw away all further output.  Don't do aliases, since
108 	**	this could cause loops, e.g., if joe mails to x:joe,
109 	**	and for some reason the network for x: is down, then
110 	**	the response gets sent to x:joe, which gives a
111 	**	response, etc.  Also force the mail to be delivered
112 	**	even if a version of it has already been sent to the
113 	**	sender.
114 	*/
115 
116 	if (MailBack)
117 	{
118 		(void) freopen("/dev/null", "w", stdout);
119 		NoAlias++;
120 		ForceMail++;
121 
122 		/* fake up an address header for the from person */
123 		bmove((char *) &From, (char *) &to_addr, sizeof to_addr);
124 		(void) expand("$n", buf, &buf[sizeof buf - 1]);
125 		if (parse(buf, &From, -1) == NULL)
126 		{
127 			syserr("Can't parse myself!");
128 			ExitStat = EX_SOFTWARE;
129 			finis();
130 		}
131 		i = deliver(&to_addr, errhdr);
132 		bmove((char *) &to_addr, (char *) &From, sizeof From);
133 		if (i != 0)
134 			syserr("Can't return mail to %s", p);
135 		else
136 			return;
137 	}
138 
139 	/*
140 	**  Save the message in dead.letter.
141 	**	If we weren't mailing back, and the user is local, we
142 	**	should save the message in dead.letter so that the
143 	**	poor person doesn't have to type it over again --
144 	**	and we all know what poor typists programmers are.
145 	*/
146 
147 	if (ArpaMode != ARPA_NONE)
148 		return;
149 	p = NULL;
150 	if (From.q_mailer == M_LOCAL)
151 	{
152 		if (From.q_home != NULL)
153 			p = From.q_home;
154 		else if ((pw = getpwnam(From.q_user)) != NULL)
155 			p = pw->pw_dir;
156 	}
157 	if (p == NULL)
158 	{
159 		syserr("Can't return mail to %s", From.q_paddr);
160 # ifdef DEBUG
161 		p = "/usr/tmp";
162 # else
163 		p = NULL;
164 # endif
165 	}
166 	if (p != NULL)
167 	{
168 		/* we have a home directory; open dead.letter */
169 		message(Arpa_Info, "Saving message in dead.letter");
170 		define('z', p);
171 		(void) expand("$z/dead.letter", buf, &buf[sizeof buf - 1]);
172 		To = buf;
173 		i = mailfile(buf);
174 		giveresponse(i, TRUE, Mailer[M_LOCAL]);
175 	}
176 
177 	/* add terminator to writeback message */
178 	if (WriteBack)
179 		printf("-----\r\n");
180 }
181 /*
182 **  ERRHDR -- Output the header for error mail.
183 **
184 **	This is the edit filter to error mailbacks.
185 **
186 **	Algorithm:
187 **		Output fixed header.
188 **		Output the transcript part.
189 **		Output the original message.
190 **
191 **	Parameters:
192 **		xfile -- the transcript file.
193 **		fp -- the output file.
194 **
195 **	Returns:
196 **		none
197 **
198 **	Side Effects:
199 **		input from xfile
200 **		output to fp
201 **
202 **	Called By:
203 **		deliver
204 */
205 
206 
207 errhdr(fp)
208 	register FILE *fp;
209 {
210 	char buf[MAXLINE];
211 	register FILE *xfile;
212 
213 	(void) fflush(stdout);
214 	if ((xfile = fopen(Transcript, "r")) == NULL)
215 		syserr("Cannot open %s", Transcript);
216 	errno = 0;
217 	fprintf(fp, "To: %s\n", To);
218 	fprintf(fp, "Subject: Unable to deliver mail\n");
219 	fprintf(fp, "\n   ----- Transcript of session follows -----\n");
220 	while (fgets(buf, sizeof buf, xfile) != NULL)
221 		fputs(buf, fp);
222 	fprintf(fp, "\n   ----- Unsent message follows -----\n");
223 	(void) fflush(fp);
224 	putmessage(fp, Mailer[1]);
225 	(void) fclose(xfile);
226 	if (errno != 0)
227 		syserr("errhdr: I/O error");
228 }
229