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