quit.c revision 1.3 1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "from: @(#)quit.c 8.1 (Berkeley) 6/6/93";
36 static char rcsid[] = "$Id: quit.c,v 1.3 1994/06/29 05:09:39 deraadt Exp $";
37 #endif /* not lint */
38
39 #include "rcv.h"
40 #include <fcntl.h>
41 #include "extern.h"
42
43 /*
44 * Rcv -- receive mail rationally.
45 *
46 * Termination processing.
47 */
48
49 /*
50 * The "quit" command.
51 */
52 int
53 quitcmd()
54 {
55 /*
56 * If we are sourcing, then return 1 so execute() can handle it.
57 * Otherwise, return -1 to abort command loop.
58 */
59 if (sourcing)
60 return 1;
61 return -1;
62 }
63
64 /*
65 * Save all of the undetermined messages at the top of "mbox"
66 * Save all untouched messages back in the system mailbox.
67 * Remove the system mailbox, if none saved there.
68 */
69 void
70 quit()
71 {
72 int mcount, p, modify, autohold, anystat, holdbit, nohold;
73 FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
74 register struct message *mp;
75 register int c;
76 extern char tempQuit[], tempResid[];
77 struct stat minfo;
78 char *mbox;
79
80 /*
81 * If we are read only, we can't do anything,
82 * so just return quickly.
83 */
84 if (readonly)
85 return;
86 /*
87 * If editing (not reading system mail box), then do the work
88 * in edstop()
89 */
90 if (edit) {
91 edstop();
92 return;
93 }
94
95 /*
96 * See if there any messages to save in mbox. If no, we
97 * can save copying mbox to /tmp and back.
98 *
99 * Check also to see if any files need to be preserved.
100 * Delete all untouched messages to keep them out of mbox.
101 * If all the messages are to be preserved, just exit with
102 * a message.
103 */
104
105 fbuf = Fopen(mailname, "r");
106 if (fbuf == NULL)
107 goto newmail;
108 flock(fileno(fbuf), LOCK_EX);
109 rbuf = NULL;
110 if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
111 printf("New mail has arrived.\n");
112 rbuf = Fopen(tempResid, "w");
113 if (rbuf == NULL || fbuf == NULL)
114 goto newmail;
115 #ifdef APPEND
116 fseek(fbuf, (long)mailsize, 0);
117 while ((c = getc(fbuf)) != EOF)
118 (void) putc(c, rbuf);
119 #else
120 p = minfo.st_size - mailsize;
121 while (p-- > 0) {
122 c = getc(fbuf);
123 if (c == EOF)
124 goto newmail;
125 (void) putc(c, rbuf);
126 }
127 #endif
128 Fclose(rbuf);
129 if ((rbuf = Fopen(tempResid, "r")) == NULL)
130 goto newmail;
131 rm(tempResid);
132 }
133
134 /*
135 * Adjust the message flags in each message.
136 */
137
138 anystat = 0;
139 autohold = value("hold") != NOSTR;
140 holdbit = autohold ? MPRESERVE : MBOX;
141 nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
142 if (value("keepsave") != NOSTR)
143 nohold &= ~MSAVED;
144 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
145 if (mp->m_flag & MNEW) {
146 mp->m_flag &= ~MNEW;
147 mp->m_flag |= MSTATUS;
148 }
149 if (mp->m_flag & MSTATUS)
150 anystat++;
151 if ((mp->m_flag & MTOUCH) == 0)
152 mp->m_flag |= MPRESERVE;
153 if ((mp->m_flag & nohold) == 0)
154 mp->m_flag |= holdbit;
155 }
156 modify = 0;
157 if (Tflag != NOSTR) {
158 if ((readstat = Fopen(Tflag, "w")) == NULL)
159 Tflag = NOSTR;
160 }
161 for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
162 if (mp->m_flag & MBOX)
163 c++;
164 if (mp->m_flag & MPRESERVE)
165 p++;
166 if (mp->m_flag & MODIFY)
167 modify++;
168 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
169 char *id;
170
171 if ((id = hfield("article-id", mp)) != NOSTR)
172 fprintf(readstat, "%s\n", id);
173 }
174 }
175 if (Tflag != NOSTR)
176 Fclose(readstat);
177 if (p == msgCount && !modify && !anystat) {
178 printf("Held %d message%s in %s\n",
179 p, p == 1 ? "" : "s", mailname);
180 Fclose(fbuf);
181 return;
182 }
183 if (c == 0) {
184 if (p != 0) {
185 writeback(rbuf);
186 Fclose(fbuf);
187 return;
188 }
189 goto cream;
190 }
191
192 /*
193 * Create another temporary file and copy user's mbox file
194 * darin. If there is no mbox, copy nothing.
195 * If he has specified "append" don't copy his mailbox,
196 * just copy saveable entries at the end.
197 */
198
199 mbox = expand("&");
200 mcount = c;
201 if (value("append") == NOSTR) {
202 if ((obuf = Fopen(tempQuit, "w")) == NULL) {
203 perror(tempQuit);
204 Fclose(fbuf);
205 return;
206 }
207 if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
208 perror(tempQuit);
209 rm(tempQuit);
210 Fclose(obuf);
211 Fclose(fbuf);
212 return;
213 }
214 rm(tempQuit);
215 if ((abuf = Fopen(mbox, "r")) != NULL) {
216 while ((c = getc(abuf)) != EOF)
217 (void) putc(c, obuf);
218 Fclose(abuf);
219 }
220 if (ferror(obuf)) {
221 perror(tempQuit);
222 Fclose(ibuf);
223 Fclose(obuf);
224 Fclose(fbuf);
225 return;
226 }
227 Fclose(obuf);
228 close(creat(mbox, 0600));
229 if ((obuf = Fopen(mbox, "r+")) == NULL) {
230 perror(mbox);
231 Fclose(ibuf);
232 Fclose(fbuf);
233 return;
234 }
235 }
236 if (value("append") != NOSTR) {
237 if ((obuf = Fopen(mbox, "a")) == NULL) {
238 perror(mbox);
239 Fclose(fbuf);
240 return;
241 }
242 fchmod(fileno(obuf), 0600);
243 }
244 for (mp = &message[0]; mp < &message[msgCount]; mp++)
245 if (mp->m_flag & MBOX)
246 if (send(mp, obuf, saveignore, NOSTR) < 0) {
247 perror(mbox);
248 Fclose(ibuf);
249 Fclose(obuf);
250 Fclose(fbuf);
251 return;
252 }
253
254 /*
255 * Copy the user's old mbox contents back
256 * to the end of the stuff we just saved.
257 * If we are appending, this is unnecessary.
258 */
259
260 if (value("append") == NOSTR) {
261 rewind(ibuf);
262 c = getc(ibuf);
263 while (c != EOF) {
264 (void) putc(c, obuf);
265 if (ferror(obuf))
266 break;
267 c = getc(ibuf);
268 }
269 Fclose(ibuf);
270 fflush(obuf);
271 }
272 trunc(obuf);
273 if (ferror(obuf)) {
274 perror(mbox);
275 Fclose(obuf);
276 Fclose(fbuf);
277 return;
278 }
279 Fclose(obuf);
280 if (mcount == 1)
281 printf("Saved 1 message in mbox\n");
282 else
283 printf("Saved %d messages in mbox\n", mcount);
284
285 /*
286 * Now we are ready to copy back preserved files to
287 * the system mailbox, if any were requested.
288 */
289
290 if (p != 0) {
291 writeback(rbuf);
292 Fclose(fbuf);
293 return;
294 }
295
296 /*
297 * Finally, remove his /usr/mail file.
298 * If new mail has arrived, copy it back.
299 */
300
301 cream:
302 if (rbuf != NULL) {
303 abuf = Fopen(mailname, "r+");
304 if (abuf == NULL)
305 goto newmail;
306 while ((c = getc(rbuf)) != EOF)
307 (void) putc(c, abuf);
308 Fclose(rbuf);
309 trunc(abuf);
310 Fclose(abuf);
311 alter(mailname);
312 Fclose(fbuf);
313 return;
314 }
315 demail();
316 Fclose(fbuf);
317 return;
318
319 newmail:
320 printf("Thou hast new mail.\n");
321 if (fbuf != NULL)
322 Fclose(fbuf);
323 }
324
325 /*
326 * Preserve all the appropriate messages back in the system
327 * mailbox, and print a nice message indicated how many were
328 * saved. On any error, just return -1. Else return 0.
329 * Incorporate the any new mail that we found.
330 */
331 int
332 writeback(res)
333 register FILE *res;
334 {
335 register struct message *mp;
336 register int p, c;
337 FILE *obuf;
338
339 p = 0;
340 if ((obuf = Fopen(mailname, "r+")) == NULL) {
341 perror(mailname);
342 return(-1);
343 }
344 #ifndef APPEND
345 if (res != NULL)
346 while ((c = getc(res)) != EOF)
347 (void) putc(c, obuf);
348 #endif
349 for (mp = &message[0]; mp < &message[msgCount]; mp++)
350 if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
351 p++;
352 if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
353 perror(mailname);
354 Fclose(obuf);
355 return(-1);
356 }
357 }
358 #ifdef APPEND
359 if (res != NULL)
360 while ((c = getc(res)) != EOF)
361 (void) putc(c, obuf);
362 #endif
363 fflush(obuf);
364 trunc(obuf);
365 if (ferror(obuf)) {
366 perror(mailname);
367 Fclose(obuf);
368 return(-1);
369 }
370 if (res != NULL)
371 Fclose(res);
372 Fclose(obuf);
373 alter(mailname);
374 if (p == 1)
375 printf("Held 1 message in %s\n", mailname);
376 else
377 printf("Held %d messages in %s\n", p, mailname);
378 return(0);
379 }
380
381 /*
382 * Terminate an editing session by attempting to write out the user's
383 * file from the temporary. Save any new stuff appended to the file.
384 */
385 void
386 edstop()
387 {
388 extern char *tmpdir;
389 register int gotcha, c;
390 register struct message *mp;
391 FILE *obuf, *ibuf, *readstat;
392 struct stat statb;
393 char tempname[30];
394 char *mktemp();
395
396 if (readonly)
397 return;
398 holdsigs();
399 if (Tflag != NOSTR) {
400 if ((readstat = Fopen(Tflag, "w")) == NULL)
401 Tflag = NOSTR;
402 }
403 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
404 if (mp->m_flag & MNEW) {
405 mp->m_flag &= ~MNEW;
406 mp->m_flag |= MSTATUS;
407 }
408 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
409 gotcha++;
410 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
411 char *id;
412
413 if ((id = hfield("article-id", mp)) != NOSTR)
414 fprintf(readstat, "%s\n", id);
415 }
416 }
417 if (Tflag != NOSTR)
418 Fclose(readstat);
419 if (!gotcha || Tflag != NOSTR)
420 goto done;
421 ibuf = NULL;
422 if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
423 strcpy(tempname, tmpdir);
424 strcat(tempname, "mboxXXXXXX");
425 mktemp(tempname);
426 if ((obuf = Fopen(tempname, "w")) == NULL) {
427 perror(tempname);
428 relsesigs();
429 reset(0);
430 }
431 if ((ibuf = Fopen(mailname, "r")) == NULL) {
432 perror(mailname);
433 Fclose(obuf);
434 rm(tempname);
435 relsesigs();
436 reset(0);
437 }
438 fseek(ibuf, (long)mailsize, 0);
439 while ((c = getc(ibuf)) != EOF)
440 (void) putc(c, obuf);
441 Fclose(ibuf);
442 Fclose(obuf);
443 if ((ibuf = Fopen(tempname, "r")) == NULL) {
444 perror(tempname);
445 rm(tempname);
446 relsesigs();
447 reset(0);
448 }
449 rm(tempname);
450 }
451 printf("\"%s\" ", mailname);
452 fflush(stdout);
453 if ((obuf = Fopen(mailname, "r+")) == NULL) {
454 perror(mailname);
455 relsesigs();
456 reset(0);
457 }
458 trunc(obuf);
459 c = 0;
460 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
461 if ((mp->m_flag & MDELETED) != 0)
462 continue;
463 c++;
464 if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) {
465 perror(mailname);
466 relsesigs();
467 reset(0);
468 }
469 }
470 gotcha = (c == 0 && ibuf == NULL);
471 if (ibuf != NULL) {
472 while ((c = getc(ibuf)) != EOF)
473 (void) putc(c, obuf);
474 Fclose(ibuf);
475 }
476 fflush(obuf);
477 if (ferror(obuf)) {
478 perror(mailname);
479 relsesigs();
480 reset(0);
481 }
482 Fclose(obuf);
483 if (gotcha) {
484 rm(mailname);
485 printf("removed\n");
486 } else
487 printf("complete\n");
488 fflush(stdout);
489
490 done:
491 relsesigs();
492 }
493