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