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