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