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