quit.c revision 1.12 1 /* $NetBSD: quit.c,v 1.12 2001/02/05 02:07:53 christos 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.12 2001/02/05 02:07:53 christos 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(v)
62 void *v;
63 {
64 /*
65 * If we are sourcing, then return 1 so execute() can handle it.
66 * Otherwise, return -1 to abort command loop.
67 */
68 if (sourcing)
69 return 1;
70 return -1;
71 }
72
73 /*
74 * Save all of the undetermined messages at the top of "mbox"
75 * Save all untouched messages back in the system mailbox.
76 * Remove the system mailbox, if none saved there.
77 */
78 void
79 quit()
80 {
81 int mcount, p, modify, autohold, anystat, holdbit, nohold;
82 FILE *ibuf = NULL, *obuf, *fbuf, *rbuf, *readstat = NULL, *abuf;
83 struct message *mp;
84 int c;
85 struct stat minfo;
86 char *mbox;
87
88 #ifdef __GNUC__
89 obuf = NULL; /* XXX gcc -Wuninitialized */
90 #endif
91
92 /*
93 * If we are read only, we can't do anything,
94 * so just return quickly.
95 */
96 if (readonly)
97 return;
98 /*
99 * If editing (not reading system mail box), then do the work
100 * in edstop()
101 */
102 if (edit) {
103 edstop();
104 return;
105 }
106
107 /*
108 * See if there any messages to save in mbox. If no, we
109 * can save copying mbox to /tmp and back.
110 *
111 * Check also to see if any files need to be preserved.
112 * Delete all untouched messages to keep them out of mbox.
113 * If all the messages are to be preserved, just exit with
114 * a message.
115 */
116
117 fbuf = Fopen(mailname, "r");
118 if (fbuf == NULL)
119 goto newmail;
120 if (flock(fileno(fbuf), LOCK_EX) == -1) {
121 nolock:
122 perror("Unable to lock mailbox");
123 Fclose(fbuf);
124 return;
125 }
126 if (dot_lock(mailname, 1, stdout, ".") == -1)
127 goto nolock;
128 rbuf = NULL;
129 if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
130 printf("New mail has arrived.\n");
131 rbuf = Fopen(tempResid, "w");
132 if (rbuf == NULL || fbuf == NULL)
133 goto newmail;
134 #ifdef APPEND
135 fseek(fbuf, (long)mailsize, 0);
136 while ((c = getc(fbuf)) != EOF)
137 (void) putc(c, rbuf);
138 #else
139 p = minfo.st_size - mailsize;
140 while (p-- > 0) {
141 c = getc(fbuf);
142 if (c == EOF)
143 goto newmail;
144 (void) putc(c, rbuf);
145 }
146 #endif
147 (void) fflush(rbuf);
148 if (ferror(rbuf)) {
149 perror(tempResid);
150 Fclose(rbuf);
151 Fclose(fbuf);
152 dot_unlock(mailname);
153 return;
154 }
155 Fclose(rbuf);
156 if ((rbuf = Fopen(tempResid, "r")) == NULL)
157 goto newmail;
158 rm(tempResid);
159 }
160
161 /*
162 * Adjust the message flags in each message.
163 */
164
165 anystat = 0;
166 autohold = value("hold") != NOSTR;
167 holdbit = autohold ? MPRESERVE : MBOX;
168 nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
169 if (value("keepsave") != NOSTR)
170 nohold &= ~MSAVED;
171 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
172 if (mp->m_flag & MNEW) {
173 mp->m_flag &= ~MNEW;
174 mp->m_flag |= MSTATUS;
175 }
176 if (mp->m_flag & MSTATUS)
177 anystat++;
178 if ((mp->m_flag & MTOUCH) == 0)
179 mp->m_flag |= MPRESERVE;
180 if ((mp->m_flag & nohold) == 0)
181 mp->m_flag |= holdbit;
182 }
183 modify = 0;
184 if (Tflag != NOSTR) {
185 if ((readstat = Fopen(Tflag, "w")) == NULL)
186 Tflag = NOSTR;
187 }
188 for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
189 if (mp->m_flag & MBOX)
190 c++;
191 if (mp->m_flag & MPRESERVE)
192 p++;
193 if (mp->m_flag & MODIFY)
194 modify++;
195 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
196 char *id;
197
198 if ((id = hfield("article-id", mp)) != NOSTR)
199 fprintf(readstat, "%s\n", id);
200 }
201 }
202 if (Tflag != NOSTR)
203 Fclose(readstat);
204 if (p == msgCount && !modify && !anystat) {
205 printf("Held %d message%s in %s\n",
206 p, p == 1 ? "" : "s", mailname);
207 Fclose(fbuf);
208 dot_unlock(mailname);
209 return;
210 }
211 if (c == 0) {
212 if (p != 0) {
213 writeback(rbuf);
214 Fclose(fbuf);
215 dot_unlock(mailname);
216 return;
217 }
218 goto cream;
219 }
220
221 /*
222 * Create another temporary file and copy user's mbox file
223 * darin. If there is no mbox, copy nothing.
224 * If he has specified "append" don't copy his mailbox,
225 * just copy saveable entries at the end.
226 */
227
228 mbox = expand("&");
229 mcount = c;
230 if (value("append") == NOSTR) {
231 if ((obuf = Fopen(tempQuit, "w")) == NULL) {
232 perror(tempQuit);
233 Fclose(fbuf);
234 dot_unlock(mailname);
235 return;
236 }
237 if ((ibuf = Fopen(tempQuit, "r")) == NULL) {
238 perror(tempQuit);
239 rm(tempQuit);
240 Fclose(obuf);
241 Fclose(fbuf);
242 dot_unlock(mailname);
243 return;
244 }
245 rm(tempQuit);
246 if ((abuf = Fopen(mbox, "r")) != NULL) {
247 while ((c = getc(abuf)) != EOF)
248 (void) putc(c, obuf);
249 Fclose(abuf);
250 }
251 if (ferror(obuf)) {
252 perror(tempQuit);
253 Fclose(ibuf);
254 Fclose(obuf);
255 Fclose(fbuf);
256 dot_unlock(mailname);
257 return;
258 }
259 Fclose(obuf);
260 close(creat(mbox, 0600));
261 if ((obuf = Fopen(mbox, "r+")) == NULL) {
262 perror(mbox);
263 Fclose(ibuf);
264 Fclose(fbuf);
265 dot_unlock(mailname);
266 return;
267 }
268 }
269 else {
270 if ((obuf = Fopen(mbox, "a")) == NULL) {
271 perror(mbox);
272 Fclose(fbuf);
273 dot_unlock(mailname);
274 return;
275 }
276 fchmod(fileno(obuf), 0600);
277 }
278 for (mp = &message[0]; mp < &message[msgCount]; mp++)
279 if (mp->m_flag & MBOX)
280 if (sendmessage(mp, obuf, saveignore, NOSTR) < 0) {
281 perror(mbox);
282 Fclose(ibuf);
283 Fclose(obuf);
284 Fclose(fbuf);
285 dot_unlock(mailname);
286 return;
287 }
288
289 /*
290 * Copy the user's old mbox contents back
291 * to the end of the stuff we just saved.
292 * If we are appending, this is unnecessary.
293 */
294
295 if (value("append") == NOSTR) {
296 rewind(ibuf);
297 c = getc(ibuf);
298 while (c != EOF) {
299 (void) putc(c, obuf);
300 if (ferror(obuf))
301 break;
302 c = getc(ibuf);
303 }
304 Fclose(ibuf);
305 }
306 fflush(obuf);
307 if (!ferror(obuf))
308 trunc(obuf); /* XXX or should we truncate? */
309 if (ferror(obuf)) {
310 perror(mbox);
311 Fclose(obuf);
312 Fclose(fbuf);
313 dot_unlock(mailname);
314 return;
315 }
316 Fclose(obuf);
317 if (mcount == 1)
318 printf("Saved 1 message in mbox\n");
319 else
320 printf("Saved %d messages in mbox\n", mcount);
321
322 /*
323 * Now we are ready to copy back preserved files to
324 * the system mailbox, if any were requested.
325 */
326
327 if (p != 0) {
328 writeback(rbuf);
329 Fclose(fbuf);
330 dot_unlock(mailname);
331 return;
332 }
333
334 /*
335 * Finally, remove his /usr/mail file.
336 * If new mail has arrived, copy it back.
337 */
338
339 cream:
340 if (rbuf != NULL) {
341 abuf = Fopen(mailname, "r+");
342 if (abuf == NULL)
343 goto newmail;
344 while ((c = getc(rbuf)) != EOF)
345 (void) putc(c, abuf);
346 (void) fflush(abuf);
347 if (ferror(abuf)) {
348 perror(mailname);
349 Fclose(abuf);
350 Fclose(fbuf);
351 dot_unlock(mailname);
352 return;
353 }
354 Fclose(rbuf);
355 trunc(abuf);
356 Fclose(abuf);
357 alter(mailname);
358 Fclose(fbuf);
359 dot_unlock(mailname);
360 return;
361 }
362 demail();
363 Fclose(fbuf);
364 dot_unlock(mailname);
365 return;
366
367 newmail:
368 printf("Thou hast new mail.\n");
369 if (fbuf != NULL) {
370 Fclose(fbuf);
371 dot_unlock(mailname);
372 }
373 }
374
375 /*
376 * Preserve all the appropriate messages back in the system
377 * mailbox, and print a nice message indicated how many were
378 * saved. On any error, just return -1. Else return 0.
379 * Incorporate the any new mail that we found.
380 */
381 int
382 writeback(res)
383 FILE *res;
384 {
385 struct message *mp;
386 int p, c;
387 FILE *obuf;
388
389 p = 0;
390 if ((obuf = Fopen(mailname, "r+")) == NULL) {
391 perror(mailname);
392 return(-1);
393 }
394 #ifndef APPEND
395 if (res != NULL) {
396 while ((c = getc(res)) != EOF)
397 (void) putc(c, obuf);
398 (void) fflush(obuf);
399 if (ferror(obuf)) {
400 perror(mailname);
401 Fclose(obuf);
402 return(-1);
403 }
404 }
405 #endif
406 for (mp = &message[0]; mp < &message[msgCount]; mp++)
407 if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
408 p++;
409 if (sendmessage(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) {
410 perror(mailname);
411 Fclose(obuf);
412 return(-1);
413 }
414 }
415 #ifdef APPEND
416 if (res != NULL)
417 while ((c = getc(res)) != EOF)
418 (void) putc(c, obuf);
419 #endif
420 fflush(obuf);
421 if (!ferror(obuf))
422 trunc(obuf); /* XXX or should we truncate? */
423 if (ferror(obuf)) {
424 perror(mailname);
425 Fclose(obuf);
426 return(-1);
427 }
428 if (res != NULL)
429 Fclose(res);
430 Fclose(obuf);
431 alter(mailname);
432 if (p == 1)
433 printf("Held 1 message in %s\n", mailname);
434 else
435 printf("Held %d messages in %s\n", p, mailname);
436 return(0);
437 }
438
439 /*
440 * Terminate an editing session by attempting to write out the user's
441 * file from the temporary. Save any new stuff appended to the file.
442 */
443 void
444 edstop()
445 {
446 int gotcha, c;
447 struct message *mp;
448 FILE *obuf, *ibuf, *readstat = NULL;
449 struct stat statb;
450 char *tempname;
451
452 if (readonly)
453 return;
454 holdsigs();
455 if (Tflag != NOSTR) {
456 if ((readstat = Fopen(Tflag, "w")) == NULL)
457 Tflag = NOSTR;
458 }
459 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
460 if (mp->m_flag & MNEW) {
461 mp->m_flag &= ~MNEW;
462 mp->m_flag |= MSTATUS;
463 }
464 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
465 gotcha++;
466 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
467 char *id;
468
469 if ((id = hfield("article-id", mp)) != NOSTR)
470 fprintf(readstat, "%s\n", id);
471 }
472 }
473 if (Tflag != NOSTR)
474 Fclose(readstat);
475 if (!gotcha || Tflag != NOSTR)
476 goto done;
477 ibuf = NULL;
478 if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
479 tempname = tempnam(tmpdir, "mbox");
480
481 if ((obuf = Fopen(tempname, "w")) == NULL) {
482 perror(tempname);
483 relsesigs();
484 reset(0);
485 }
486 if ((ibuf = Fopen(mailname, "r")) == NULL) {
487 perror(mailname);
488 Fclose(obuf);
489 rm(tempname);
490 relsesigs();
491 reset(0);
492 }
493 fseek(ibuf, (long)mailsize, 0);
494 while ((c = getc(ibuf)) != EOF)
495 (void) putc(c, obuf);
496 (void) fflush(obuf);
497 if (ferror(obuf)) {
498 perror(tempname);
499 Fclose(obuf);
500 Fclose(ibuf);
501 rm(tempname);
502 relsesigs();
503 reset(0);
504 }
505 Fclose(ibuf);
506 Fclose(obuf);
507 if ((ibuf = Fopen(tempname, "r")) == NULL) {
508 perror(tempname);
509 rm(tempname);
510 relsesigs();
511 reset(0);
512 }
513 rm(tempname);
514 free(tempname);
515 }
516 printf("\"%s\" ", mailname);
517 fflush(stdout);
518 if ((obuf = Fopen(mailname, "r+")) == NULL) {
519 perror(mailname);
520 relsesigs();
521 reset(0);
522 }
523 trunc(obuf);
524 c = 0;
525 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
526 if ((mp->m_flag & MDELETED) != 0)
527 continue;
528 c++;
529 if (sendmessage(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) {
530 perror(mailname);
531 relsesigs();
532 reset(0);
533 }
534 }
535 gotcha = (c == 0 && ibuf == NULL);
536 if (ibuf != NULL) {
537 while ((c = getc(ibuf)) != EOF)
538 (void) putc(c, obuf);
539 Fclose(ibuf);
540 }
541 fflush(obuf);
542 if (ferror(obuf)) {
543 perror(mailname);
544 relsesigs();
545 reset(0);
546 }
547 Fclose(obuf);
548 if (gotcha) {
549 rm(mailname);
550 printf("removed\n");
551 } else
552 printf("complete\n");
553 fflush(stdout);
554
555 done:
556 relsesigs();
557 }
558