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