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