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