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