Commit | Line | Data |
---|---|---|
b3cbe40f | 1 | # include <pwd.h> |
96faada8 | 2 | # include "sendmail.h" |
b3cbe40f | 3 | |
f7eb07a3 | 4 | SCCSID(@(#)savemail.c 3.36 %G%); |
916b3375 | 5 | |
b3cbe40f EA |
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. | |
b3cbe40f EA |
24 | */ |
25 | ||
b3cbe40f EA |
26 | savemail() |
27 | { | |
28 | register struct passwd *pw; | |
29 | register FILE *xfile; | |
30 | char buf[MAXLINE+1]; | |
b3cbe40f EA |
31 | extern struct passwd *getpwnam(); |
32 | register char *p; | |
b3cbe40f | 33 | extern char *ttypath(); |
b3cbe40f | 34 | static int exclusive; |
40e27d12 | 35 | typedef int (*fnptr)(); |
dd1fe05b | 36 | extern ENVELOPE *newenvelope(); |
b3cbe40f | 37 | |
dd1fe05b | 38 | if (exclusive++) |
b3cbe40f | 39 | return; |
dd1fe05b EA |
40 | if (CurEnv->e_class <= PRI_JUNK) |
41 | { | |
91f69adf | 42 | message(Arpa_Info, "Dumping junk mail"); |
dd1fe05b EA |
43 | return; |
44 | } | |
91f69adf | 45 | ForceMail = TRUE; |
b3cbe40f EA |
46 | |
47 | /* | |
48 | ** In the unhappy event we don't know who to return the mail | |
49 | ** to, make someone up. | |
50 | */ | |
51 | ||
1bcdf0a2 | 52 | if (CurEnv->e_returnto == NULL) |
b3cbe40f | 53 | { |
1bcdf0a2 EA |
54 | CurEnv->e_returnto = parse("root", (ADDRESS *) NULL, 0); |
55 | if (CurEnv->e_returnto == NULL) | |
b3cbe40f EA |
56 | { |
57 | syserr("Cannot parse root!"); | |
58 | ExitStat = EX_SOFTWARE; | |
59 | finis(); | |
60 | } | |
61 | } | |
2654b031 | 62 | CurEnv->e_to = NULL; |
b3cbe40f EA |
63 | |
64 | /* | |
3b661a43 EA |
65 | ** If called from Eric Schmidt's network, do special mailback. |
66 | ** Fundamentally, this is the mailback case except that | |
67 | ** it returns an OK exit status (assuming the return | |
68 | ** worked). | |
1ff06f70 | 69 | ** Also, if the from address is not local, mail it back. |
b3cbe40f EA |
70 | */ |
71 | ||
3b661a43 | 72 | if (BerkNet) |
b3cbe40f | 73 | { |
3b661a43 | 74 | ExitStat = EX_OK; |
1ff06f70 | 75 | MailBack = TRUE; |
b3cbe40f | 76 | } |
1bcdf0a2 | 77 | if (!bitset(M_LOCAL, CurEnv->e_returnto->q_mailer->m_flags)) |
1ff06f70 | 78 | MailBack = TRUE; |
b3cbe40f EA |
79 | |
80 | /* | |
81 | ** If writing back, do it. | |
82 | ** If the user is still logged in on the same terminal, | |
83 | ** then write the error messages back to hir (sic). | |
84 | ** If not, set the MailBack flag so that it will get | |
85 | ** mailed back instead. | |
86 | */ | |
87 | ||
88 | if (WriteBack) | |
89 | { | |
90 | p = ttypath(); | |
91 | if (p == NULL || freopen(p, "w", stdout) == NULL) | |
92 | { | |
1ff06f70 | 93 | MailBack = TRUE; |
b3cbe40f EA |
94 | errno = 0; |
95 | } | |
96 | else | |
97 | { | |
49086753 | 98 | (void) fflush(Xscript); |
3b661a43 EA |
99 | xfile = fopen(Transcript, "r"); |
100 | if (xfile == NULL) | |
101 | syserr("Cannot open %s", Transcript); | |
dd1fe05b | 102 | expand("$n", buf, &buf[sizeof buf - 1], CurEnv); |
dc39c568 | 103 | printf("\r\nMessage from %s...\r\n", buf); |
74c5fe7c | 104 | printf("Errors occurred while sending mail; transcript follows:\r\n"); |
29871fef | 105 | while (fgets(buf, sizeof buf, xfile) != NULL && !ferror(stdout)) |
b3cbe40f EA |
106 | fputs(buf, stdout); |
107 | if (ferror(stdout)) | |
29871fef EA |
108 | (void) syserr("savemail: stdout: write err"); |
109 | (void) fclose(xfile); | |
b3cbe40f EA |
110 | } |
111 | } | |
112 | ||
b3cbe40f EA |
113 | /* |
114 | ** If mailing back, do it. | |
115 | ** Throw away all further output. Don't do aliases, since | |
116 | ** this could cause loops, e.g., if joe mails to x:joe, | |
117 | ** and for some reason the network for x: is down, then | |
118 | ** the response gets sent to x:joe, which gives a | |
119 | ** response, etc. Also force the mail to be delivered | |
120 | ** even if a version of it has already been sent to the | |
121 | ** sender. | |
122 | */ | |
123 | ||
6708a5e3 | 124 | if (MailBack) |
b3cbe40f | 125 | { |
3aa1c35f | 126 | if (CurEnv->e_errorqueue == NULL) |
f7eb07a3 | 127 | sendto(CurEnv->e_from.q_paddr, 1, (ADDRESS *) NULL, &CurEnv->e_errorqueue); |
1bcdf0a2 | 128 | if (returntosender("Unable to deliver mail", CurEnv->e_returnto, TRUE) == 0) |
b3cbe40f EA |
129 | return; |
130 | } | |
131 | ||
132 | /* | |
133 | ** Save the message in dead.letter. | |
134 | ** If we weren't mailing back, and the user is local, we | |
135 | ** should save the message in dead.letter so that the | |
136 | ** poor person doesn't have to type it over again -- | |
137 | ** and we all know what poor typists programmers are. | |
138 | */ | |
139 | ||
49086753 | 140 | if (ArpaMode) |
dc39c568 | 141 | return; |
4bb4503e | 142 | p = NULL; |
1bcdf0a2 | 143 | if (CurEnv->e_returnto->q_mailer == LocalMailer) |
b3cbe40f | 144 | { |
1bcdf0a2 EA |
145 | if (CurEnv->e_returnto->q_home != NULL) |
146 | p = CurEnv->e_returnto->q_home; | |
147 | else if ((pw = getpwnam(CurEnv->e_returnto->q_user)) != NULL) | |
4bb4503e | 148 | p = pw->pw_dir; |
b3cbe40f | 149 | } |
4bb4503e | 150 | if (p == NULL) |
b3cbe40f | 151 | { |
1bcdf0a2 | 152 | syserr("Can't return mail to %s", CurEnv->e_returnto->q_paddr); |
b3cbe40f EA |
153 | # ifdef DEBUG |
154 | p = "/usr/tmp"; | |
155 | # else | |
156 | p = NULL; | |
157 | # endif | |
158 | } | |
738043e8 | 159 | if (p != NULL && TempFile != NULL) |
b3cbe40f | 160 | { |
de9d070c | 161 | auto ADDRESS *q; |
91f69adf | 162 | bool oldverb = Verbose; |
de9d070c | 163 | |
b3cbe40f | 164 | /* we have a home directory; open dead.letter */ |
91f69adf | 165 | Verbose = TRUE; |
15b28570 | 166 | message(Arpa_Info, "Saving message in dead.letter"); |
91f69adf | 167 | Verbose = oldverb; |
4bb4503e | 168 | define('z', p); |
dd1fe05b | 169 | expand("$z/dead.letter", buf, &buf[sizeof buf - 1], CurEnv); |
2654b031 | 170 | CurEnv->e_to = buf; |
de9d070c | 171 | q = NULL; |
40e27d12 | 172 | sendto(buf, -1, (ADDRESS *) NULL, &q); |
dd1fe05b | 173 | (void) deliver(q); |
b3cbe40f | 174 | } |
b3cbe40f EA |
175 | |
176 | /* add terminator to writeback message */ | |
177 | if (WriteBack) | |
178 | printf("-----\r\n"); | |
179 | } | |
180 | \f/* | |
aba51985 EA |
181 | ** RETURNTOSENDER -- return a message to the sender with an error. |
182 | ** | |
183 | ** Parameters: | |
184 | ** msg -- the explanatory message. | |
3c7fe765 | 185 | ** returnto -- the queue of people to send the message to. |
79bd7c07 EA |
186 | ** sendbody -- if TRUE, also send back the body of the |
187 | ** message; otherwise just send the header. | |
aba51985 EA |
188 | ** |
189 | ** Returns: | |
190 | ** zero -- if everything went ok. | |
191 | ** else -- some error. | |
192 | ** | |
193 | ** Side Effects: | |
194 | ** Returns the current message to the sender via | |
195 | ** mail. | |
196 | */ | |
197 | ||
79bd7c07 | 198 | static bool SendBody; |
aba51985 | 199 | |
3c7fe765 EA |
200 | #define MAXRETURNS 6 /* max depth of returning messages */ |
201 | ||
dd1fe05b | 202 | returntosender(msg, returnto, sendbody) |
aba51985 | 203 | char *msg; |
dd1fe05b | 204 | ADDRESS *returnto; |
79bd7c07 | 205 | bool sendbody; |
aba51985 | 206 | { |
aba51985 | 207 | char buf[MAXNAME]; |
dd1fe05b EA |
208 | extern putheader(), errbody(); |
209 | register ENVELOPE *ee; | |
210 | extern ENVELOPE *newenvelope(); | |
211 | ENVELOPE errenvelope; | |
3c7fe765 EA |
212 | static int returndepth; |
213 | ||
214 | if (++returndepth >= MAXRETURNS) | |
215 | { | |
216 | if (returndepth != MAXRETURNS) | |
217 | syserr("returntosender: infinite recursion on %s", returnto->q_paddr); | |
218 | /* don't "unrecurse" and fake a clean exit */ | |
219 | /* returndepth--; */ | |
220 | return (0); | |
221 | } | |
aba51985 | 222 | |
1ff06f70 | 223 | NoAlias = TRUE; |
79bd7c07 | 224 | SendBody = sendbody; |
dd1fe05b EA |
225 | ee = newenvelope(&errenvelope); |
226 | ee->e_puthdr = putheader; | |
227 | ee->e_putbody = errbody; | |
228 | addheader("date", "$b", ee); | |
229 | addheader("from", "$g (Mail Delivery Subsystem)", ee); | |
230 | addheader("to", returnto->q_paddr, ee); | |
231 | addheader("subject", msg, ee); | |
aba51985 EA |
232 | |
233 | /* fake up an address header for the from person */ | |
dd1fe05b EA |
234 | expand("$n", buf, &buf[sizeof buf - 1], CurEnv); |
235 | if (parse(buf, &ee->e_from, -1) == NULL) | |
aba51985 EA |
236 | { |
237 | syserr("Can't parse myself!"); | |
238 | ExitStat = EX_SOFTWARE; | |
3c7fe765 | 239 | returndepth--; |
aba51985 EA |
240 | return (-1); |
241 | } | |
3c7fe765 | 242 | ee->e_sendqueue = returnto; |
79bd7c07 | 243 | |
dd1fe05b EA |
244 | /* push state into submessage */ |
245 | CurEnv = ee; | |
246 | define('f', "$n"); | |
247 | define('x', "Mail Delivery Subsystem"); | |
248 | ||
249 | /* actually deliver the error message */ | |
3c7fe765 | 250 | sendall(ee, FALSE); |
dd1fe05b | 251 | |
3c7fe765 EA |
252 | /* do any closing error processing */ |
253 | checkerrors(ee); | |
dd1fe05b EA |
254 | |
255 | /* restore state */ | |
256 | CurEnv = CurEnv->e_parent; | |
3c7fe765 | 257 | returndepth--; |
79bd7c07 | 258 | |
3c7fe765 | 259 | /* should check for delivery errors here */ |
aba51985 EA |
260 | return (0); |
261 | } | |
262 | \f/* | |
dd1fe05b | 263 | ** ERRBODY -- output the body of an error message. |
b3cbe40f | 264 | ** |
dd1fe05b EA |
265 | ** Typically this is a copy of the transcript plus a copy of the |
266 | ** original offending message. | |
b3cbe40f | 267 | ** |
b3cbe40f EA |
268 | ** Parameters: |
269 | ** xfile -- the transcript file. | |
270 | ** fp -- the output file. | |
dd1fe05b | 271 | ** xdot -- if set, use the SMTP hidden dot algorithm. |
b3cbe40f EA |
272 | ** |
273 | ** Returns: | |
274 | ** none | |
275 | ** | |
276 | ** Side Effects: | |
dd1fe05b | 277 | ** Outputs the body of an error message. |
b3cbe40f EA |
278 | */ |
279 | ||
dd1fe05b | 280 | errbody(fp, m, xdot) |
b3cbe40f | 281 | register FILE *fp; |
74c5fe7c | 282 | register struct mailer *m; |
e6b0a75b | 283 | bool xdot; |
b3cbe40f | 284 | { |
9e3c0a28 | 285 | register FILE *xfile; |
dd1fe05b | 286 | char buf[MAXLINE]; |
b85ad418 | 287 | bool fullsmtp = bitset(M_FULLSMTP, m->m_flags); |
b3cbe40f | 288 | |
29871fef | 289 | (void) fflush(stdout); |
9e3c0a28 EA |
290 | if ((xfile = fopen(Transcript, "r")) == NULL) |
291 | syserr("Cannot open %s", Transcript); | |
b3cbe40f | 292 | errno = 0; |
74c5fe7c | 293 | |
74c5fe7c EA |
294 | /* |
295 | ** Output transcript of errors | |
296 | */ | |
297 | ||
dd1fe05b | 298 | fprintf(fp, " ----- Transcript of session follows -----\n"); |
49086753 | 299 | (void) fflush(Xscript); |
29871fef | 300 | while (fgets(buf, sizeof buf, xfile) != NULL) |
b85ad418 | 301 | putline(buf, fp, fullsmtp); |
74c5fe7c EA |
302 | |
303 | /* | |
304 | ** Output text of original message | |
305 | */ | |
306 | ||
46b14b48 EA |
307 | if (NoReturn) |
308 | fprintf(fp, "\n ----- Return message suppressed -----\n\n"); | |
309 | else if (TempFile != NULL) | |
738043e8 | 310 | { |
79bd7c07 EA |
311 | if (SendBody) |
312 | { | |
313 | fprintf(fp, "\n ----- Unsent message follows -----\n"); | |
314 | (void) fflush(fp); | |
f9566d23 | 315 | putheader(fp, m, CurEnv->e_parent); |
dd1fe05b | 316 | fprintf(fp, "\n"); |
f9566d23 | 317 | putbody(fp, m, xdot); |
79bd7c07 EA |
318 | } |
319 | else | |
320 | { | |
321 | fprintf(fp, "\n ----- Message header follows -----\n"); | |
322 | (void) fflush(fp); | |
f9566d23 | 323 | putheader(fp, m, CurEnv); |
79bd7c07 | 324 | } |
738043e8 EA |
325 | } |
326 | else | |
327 | fprintf(fp, "\n ----- No message was collected -----\n\n"); | |
74c5fe7c EA |
328 | |
329 | /* | |
330 | ** Cleanup and exit | |
331 | */ | |
332 | ||
29871fef | 333 | (void) fclose(xfile); |
b3cbe40f | 334 | if (errno != 0) |
dd1fe05b | 335 | syserr("errbody: I/O error"); |
b3cbe40f | 336 | } |