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