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