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