11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 3288150Smikehstatic char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <fcntl.h> 401590Srgrimes#include "extern.h" 411590Srgrimes 421590Srgrimes/* 431590Srgrimes * Rcv -- receive mail rationally. 441590Srgrimes * 451590Srgrimes * Termination processing. 461590Srgrimes */ 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * The "quit" command. 501590Srgrimes */ 511590Srgrimesint 52216564Scharnierquitcmd(void) 531590Srgrimes{ 541590Srgrimes /* 551590Srgrimes * If we are sourcing, then return 1 so execute() can handle it. 561590Srgrimes * Otherwise, return -1 to abort command loop. 571590Srgrimes */ 581590Srgrimes if (sourcing) 5977274Smikeh return (1); 6077274Smikeh return (-1); 611590Srgrimes} 621590Srgrimes 631590Srgrimes/* 641590Srgrimes * Save all of the undetermined messages at the top of "mbox" 651590Srgrimes * Save all untouched messages back in the system mailbox. 661590Srgrimes * Remove the system mailbox, if none saved there. 671590Srgrimes */ 681590Srgrimesvoid 69216564Scharnierquit(void) 701590Srgrimes{ 711590Srgrimes int mcount, p, modify, autohold, anystat, holdbit, nohold; 721590Srgrimes FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf; 7377274Smikeh struct message *mp; 7477274Smikeh int c, fd; 751590Srgrimes struct stat minfo; 7674769Smikeh char *mbox, tempname[PATHSIZE]; 771590Srgrimes 781590Srgrimes /* 791590Srgrimes * If we are read only, we can't do anything, 801590Srgrimes * so just return quickly. 811590Srgrimes */ 821590Srgrimes if (readonly) 831590Srgrimes return; 841590Srgrimes /* 851590Srgrimes * If editing (not reading system mail box), then do the work 861590Srgrimes * in edstop() 871590Srgrimes */ 881590Srgrimes if (edit) { 891590Srgrimes edstop(); 901590Srgrimes return; 911590Srgrimes } 921590Srgrimes 931590Srgrimes /* 941590Srgrimes * See if there any messages to save in mbox. If no, we 951590Srgrimes * can save copying mbox to /tmp and back. 961590Srgrimes * 971590Srgrimes * Check also to see if any files need to be preserved. 981590Srgrimes * Delete all untouched messages to keep them out of mbox. 991590Srgrimes * If all the messages are to be preserved, just exit with 1001590Srgrimes * a message. 1011590Srgrimes */ 1021590Srgrimes 1031590Srgrimes fbuf = Fopen(mailname, "r"); 1041590Srgrimes if (fbuf == NULL) 1051590Srgrimes goto newmail; 10677274Smikeh (void)flock(fileno(fbuf), LOCK_EX); 1071590Srgrimes rbuf = NULL; 1081590Srgrimes if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) { 1091590Srgrimes printf("New mail has arrived.\n"); 11077274Smikeh (void)snprintf(tempname, sizeof(tempname), 11177274Smikeh "%s/mail.RqXXXXXXXXXX", tmpdir); 11274769Smikeh if ((fd = mkstemp(tempname)) == -1 || 11374769Smikeh (rbuf = Fdopen(fd, "w")) == NULL) 1141590Srgrimes goto newmail; 1151590Srgrimes#ifdef APPEND 11682793Sache (void)fseeko(fbuf, mailsize, SEEK_SET); 1171590Srgrimes while ((c = getc(fbuf)) != EOF) 11877274Smikeh (void)putc(c, rbuf); 1191590Srgrimes#else 1201590Srgrimes p = minfo.st_size - mailsize; 1211590Srgrimes while (p-- > 0) { 1221590Srgrimes c = getc(fbuf); 1231590Srgrimes if (c == EOF) 1241590Srgrimes goto newmail; 12577274Smikeh (void)putc(c, rbuf); 1261590Srgrimes } 1271590Srgrimes#endif 12877274Smikeh (void)Fclose(rbuf); 12974769Smikeh if ((rbuf = Fopen(tempname, "r")) == NULL) 1301590Srgrimes goto newmail; 13177274Smikeh (void)rm(tempname); 1321590Srgrimes } 1331590Srgrimes 1341590Srgrimes /* 1351590Srgrimes * Adjust the message flags in each message. 1361590Srgrimes */ 1371590Srgrimes 1381590Srgrimes anystat = 0; 13977274Smikeh autohold = value("hold") != NULL; 1401590Srgrimes holdbit = autohold ? MPRESERVE : MBOX; 1411590Srgrimes nohold = MBOX|MSAVED|MDELETED|MPRESERVE; 14277274Smikeh if (value("keepsave") != NULL) 1431590Srgrimes nohold &= ~MSAVED; 1441590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) { 1451590Srgrimes if (mp->m_flag & MNEW) { 1461590Srgrimes mp->m_flag &= ~MNEW; 1471590Srgrimes mp->m_flag |= MSTATUS; 1481590Srgrimes } 1491590Srgrimes if (mp->m_flag & MSTATUS) 1501590Srgrimes anystat++; 1511590Srgrimes if ((mp->m_flag & MTOUCH) == 0) 1521590Srgrimes mp->m_flag |= MPRESERVE; 1531590Srgrimes if ((mp->m_flag & nohold) == 0) 1541590Srgrimes mp->m_flag |= holdbit; 1551590Srgrimes } 1561590Srgrimes modify = 0; 15777274Smikeh if (Tflag != NULL) { 1581590Srgrimes if ((readstat = Fopen(Tflag, "w")) == NULL) 15977274Smikeh Tflag = NULL; 1601590Srgrimes } 1611590Srgrimes for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) { 1621590Srgrimes if (mp->m_flag & MBOX) 1631590Srgrimes c++; 1641590Srgrimes if (mp->m_flag & MPRESERVE) 1651590Srgrimes p++; 1661590Srgrimes if (mp->m_flag & MODIFY) 1671590Srgrimes modify++; 16877274Smikeh if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) { 1691590Srgrimes char *id; 1701590Srgrimes 17177274Smikeh if ((id = hfield("article-id", mp)) != NULL) 1721590Srgrimes fprintf(readstat, "%s\n", id); 1731590Srgrimes } 1741590Srgrimes } 17577274Smikeh if (Tflag != NULL) 17677274Smikeh (void)Fclose(readstat); 1771590Srgrimes if (p == msgCount && !modify && !anystat) { 1781590Srgrimes printf("Held %d message%s in %s\n", 1791590Srgrimes p, p == 1 ? "" : "s", mailname); 18077274Smikeh (void)Fclose(fbuf); 1811590Srgrimes return; 1821590Srgrimes } 1831590Srgrimes if (c == 0) { 1841590Srgrimes if (p != 0) { 1851590Srgrimes writeback(rbuf); 18677274Smikeh (void)Fclose(fbuf); 1871590Srgrimes return; 1881590Srgrimes } 1891590Srgrimes goto cream; 1901590Srgrimes } 1911590Srgrimes 1921590Srgrimes /* 1931590Srgrimes * Create another temporary file and copy user's mbox file 1941590Srgrimes * darin. If there is no mbox, copy nothing. 1951590Srgrimes * If he has specified "append" don't copy his mailbox, 1961590Srgrimes * just copy saveable entries at the end. 1971590Srgrimes */ 1981590Srgrimes 1991590Srgrimes mbox = expand("&"); 2001590Srgrimes mcount = c; 20177274Smikeh if (value("append") == NULL) { 20277274Smikeh (void)snprintf(tempname, sizeof(tempname), 20377274Smikeh "%s/mail.RmXXXXXXXXXX", tmpdir); 20474769Smikeh if ((fd = mkstemp(tempname)) == -1 || 20574769Smikeh (obuf = Fdopen(fd, "w")) == NULL) { 20674769Smikeh warn("%s", tempname); 20777274Smikeh (void)Fclose(fbuf); 2081590Srgrimes return; 2091590Srgrimes } 21074769Smikeh if ((ibuf = Fopen(tempname, "r")) == NULL) { 21174769Smikeh warn("%s", tempname); 21277274Smikeh (void)rm(tempname); 21377274Smikeh (void)Fclose(obuf); 21477274Smikeh (void)Fclose(fbuf); 2151590Srgrimes return; 2161590Srgrimes } 21777274Smikeh (void)rm(tempname); 2181590Srgrimes if ((abuf = Fopen(mbox, "r")) != NULL) { 2191590Srgrimes while ((c = getc(abuf)) != EOF) 22077274Smikeh (void)putc(c, obuf); 22177274Smikeh (void)Fclose(abuf); 2221590Srgrimes } 2231590Srgrimes if (ferror(obuf)) { 22474769Smikeh warnx("%s", tempname); 22577274Smikeh (void)Fclose(ibuf); 22677274Smikeh (void)Fclose(obuf); 22777274Smikeh (void)Fclose(fbuf); 2281590Srgrimes return; 2291590Srgrimes } 23077274Smikeh (void)Fclose(obuf); 231303303Spfg if ((fd = open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600)) >= 0) 232303303Spfg (void)close(fd); 2331590Srgrimes if ((obuf = Fopen(mbox, "r+")) == NULL) { 23474769Smikeh warn("%s", mbox); 23577274Smikeh (void)Fclose(ibuf); 23677274Smikeh (void)Fclose(fbuf); 2371590Srgrimes return; 2381590Srgrimes } 2391590Srgrimes } 24077274Smikeh if (value("append") != NULL) { 2411590Srgrimes if ((obuf = Fopen(mbox, "a")) == NULL) { 24274769Smikeh warn("%s", mbox); 24377274Smikeh (void)Fclose(fbuf); 2441590Srgrimes return; 2451590Srgrimes } 24677274Smikeh (void)fchmod(fileno(obuf), 0600); 2471590Srgrimes } 2481590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 2491590Srgrimes if (mp->m_flag & MBOX) 25077274Smikeh if (sendmessage(mp, obuf, saveignore, NULL) < 0) { 25174769Smikeh warnx("%s", mbox); 25277274Smikeh (void)Fclose(ibuf); 25377274Smikeh (void)Fclose(obuf); 25477274Smikeh (void)Fclose(fbuf); 2551590Srgrimes return; 2561590Srgrimes } 2571590Srgrimes 2581590Srgrimes /* 2591590Srgrimes * Copy the user's old mbox contents back 2601590Srgrimes * to the end of the stuff we just saved. 2611590Srgrimes * If we are appending, this is unnecessary. 2621590Srgrimes */ 2631590Srgrimes 26477274Smikeh if (value("append") == NULL) { 2651590Srgrimes rewind(ibuf); 2661590Srgrimes c = getc(ibuf); 2671590Srgrimes while (c != EOF) { 26877274Smikeh (void)putc(c, obuf); 2691590Srgrimes if (ferror(obuf)) 2701590Srgrimes break; 2711590Srgrimes c = getc(ibuf); 2721590Srgrimes } 27377274Smikeh (void)Fclose(ibuf); 2741590Srgrimes } 27588150Smikeh (void)fflush(obuf); 2761590Srgrimes trunc(obuf); 2771590Srgrimes if (ferror(obuf)) { 27874769Smikeh warn("%s", mbox); 27977274Smikeh (void)Fclose(obuf); 28077274Smikeh (void)Fclose(fbuf); 2811590Srgrimes return; 2821590Srgrimes } 28377274Smikeh (void)Fclose(obuf); 2841590Srgrimes if (mcount == 1) 2851590Srgrimes printf("Saved 1 message in mbox\n"); 2861590Srgrimes else 2871590Srgrimes printf("Saved %d messages in mbox\n", mcount); 2881590Srgrimes 2891590Srgrimes /* 2901590Srgrimes * Now we are ready to copy back preserved files to 2911590Srgrimes * the system mailbox, if any were requested. 2921590Srgrimes */ 2931590Srgrimes 2941590Srgrimes if (p != 0) { 2951590Srgrimes writeback(rbuf); 29677274Smikeh (void)Fclose(fbuf); 2971590Srgrimes return; 2981590Srgrimes } 2991590Srgrimes 3001590Srgrimes /* 30177274Smikeh * Finally, remove his /var/mail file. 3021590Srgrimes * If new mail has arrived, copy it back. 3031590Srgrimes */ 3041590Srgrimes 3051590Srgrimescream: 3061590Srgrimes if (rbuf != NULL) { 3071590Srgrimes abuf = Fopen(mailname, "r+"); 3081590Srgrimes if (abuf == NULL) 3091590Srgrimes goto newmail; 3101590Srgrimes while ((c = getc(rbuf)) != EOF) 31177274Smikeh (void)putc(c, abuf); 31277274Smikeh (void)Fclose(rbuf); 3131590Srgrimes trunc(abuf); 31477274Smikeh (void)Fclose(abuf); 3151590Srgrimes alter(mailname); 31677274Smikeh (void)Fclose(fbuf); 3171590Srgrimes return; 3181590Srgrimes } 3191590Srgrimes demail(); 32077274Smikeh (void)Fclose(fbuf); 3211590Srgrimes return; 3221590Srgrimes 3231590Srgrimesnewmail: 3241590Srgrimes printf("Thou hast new mail.\n"); 3251590Srgrimes if (fbuf != NULL) 32677274Smikeh (void)Fclose(fbuf); 3271590Srgrimes} 3281590Srgrimes 3291590Srgrimes/* 3301590Srgrimes * Preserve all the appropriate messages back in the system 3311590Srgrimes * mailbox, and print a nice message indicated how many were 3321590Srgrimes * saved. On any error, just return -1. Else return 0. 3331590Srgrimes * Incorporate the any new mail that we found. 3341590Srgrimes */ 3351590Srgrimesint 336216564Scharnierwriteback(FILE *res) 3371590Srgrimes{ 33877274Smikeh struct message *mp; 33977274Smikeh int p, c; 3401590Srgrimes FILE *obuf; 3411590Srgrimes 3421590Srgrimes p = 0; 3431590Srgrimes if ((obuf = Fopen(mailname, "r+")) == NULL) { 34474769Smikeh warn("%s", mailname); 34577274Smikeh return (-1); 3461590Srgrimes } 3471590Srgrimes#ifndef APPEND 3481590Srgrimes if (res != NULL) 3491590Srgrimes while ((c = getc(res)) != EOF) 35077274Smikeh (void)putc(c, obuf); 3511590Srgrimes#endif 3521590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 3531590Srgrimes if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) { 3541590Srgrimes p++; 35577274Smikeh if (sendmessage(mp, obuf, NULL, NULL) < 0) { 35674769Smikeh warnx("%s", mailname); 35777274Smikeh (void)Fclose(obuf); 35877274Smikeh return (-1); 3591590Srgrimes } 3601590Srgrimes } 3611590Srgrimes#ifdef APPEND 3621590Srgrimes if (res != NULL) 3631590Srgrimes while ((c = getc(res)) != EOF) 36477274Smikeh (void)putc(c, obuf); 3651590Srgrimes#endif 36677274Smikeh (void)fflush(obuf); 3671590Srgrimes trunc(obuf); 3681590Srgrimes if (ferror(obuf)) { 36974769Smikeh warn("%s", mailname); 37077274Smikeh (void)Fclose(obuf); 37177274Smikeh return (-1); 3721590Srgrimes } 3731590Srgrimes if (res != NULL) 37477274Smikeh (void)Fclose(res); 37577274Smikeh (void)Fclose(obuf); 3761590Srgrimes alter(mailname); 3771590Srgrimes if (p == 1) 3781590Srgrimes printf("Held 1 message in %s\n", mailname); 3791590Srgrimes else 3801590Srgrimes printf("Held %d messages in %s\n", p, mailname); 38177274Smikeh return (0); 3821590Srgrimes} 3831590Srgrimes 3841590Srgrimes/* 3851590Srgrimes * Terminate an editing session by attempting to write out the user's 3861590Srgrimes * file from the temporary. Save any new stuff appended to the file. 3871590Srgrimes */ 3881590Srgrimesvoid 389216564Scharnieredstop(void) 3901590Srgrimes{ 39177274Smikeh int gotcha, c; 39277274Smikeh struct message *mp; 3931590Srgrimes FILE *obuf, *ibuf, *readstat; 3941590Srgrimes struct stat statb; 39574769Smikeh char tempname[PATHSIZE]; 3961590Srgrimes 3971590Srgrimes if (readonly) 3981590Srgrimes return; 3991590Srgrimes holdsigs(); 40077274Smikeh if (Tflag != NULL) { 4011590Srgrimes if ((readstat = Fopen(Tflag, "w")) == NULL) 40277274Smikeh Tflag = NULL; 4031590Srgrimes } 4041590Srgrimes for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { 4051590Srgrimes if (mp->m_flag & MNEW) { 4061590Srgrimes mp->m_flag &= ~MNEW; 4071590Srgrimes mp->m_flag |= MSTATUS; 4081590Srgrimes } 4091590Srgrimes if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) 4101590Srgrimes gotcha++; 41177274Smikeh if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) { 4121590Srgrimes char *id; 4131590Srgrimes 41477274Smikeh if ((id = hfield("article-id", mp)) != NULL) 4151590Srgrimes fprintf(readstat, "%s\n", id); 4161590Srgrimes } 4171590Srgrimes } 41877274Smikeh if (Tflag != NULL) 41977274Smikeh (void)Fclose(readstat); 42077274Smikeh if (!gotcha || Tflag != NULL) 4211590Srgrimes goto done; 4221590Srgrimes ibuf = NULL; 4231590Srgrimes if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { 42474769Smikeh int fd; 42574769Smikeh 42677274Smikeh (void)snprintf(tempname, sizeof(tempname), 42777274Smikeh "%s/mbox.XXXXXXXXXX", tmpdir); 42877274Smikeh if ((fd = mkstemp(tempname)) == -1 || 42977274Smikeh (obuf = Fdopen(fd, "w")) == NULL) { 43074769Smikeh warn("%s", tempname); 4311590Srgrimes relsesigs(); 4321590Srgrimes reset(0); 4331590Srgrimes } 4341590Srgrimes if ((ibuf = Fopen(mailname, "r")) == NULL) { 43574769Smikeh warn("%s", mailname); 43677274Smikeh (void)Fclose(obuf); 43777274Smikeh (void)rm(tempname); 4381590Srgrimes relsesigs(); 4391590Srgrimes reset(0); 4401590Srgrimes } 44182793Sache (void)fseeko(ibuf, mailsize, SEEK_SET); 4421590Srgrimes while ((c = getc(ibuf)) != EOF) 44377274Smikeh (void)putc(c, obuf); 44477274Smikeh (void)Fclose(ibuf); 44577274Smikeh (void)Fclose(obuf); 4461590Srgrimes if ((ibuf = Fopen(tempname, "r")) == NULL) { 44774769Smikeh warn("%s", tempname); 44877274Smikeh (void)rm(tempname); 4491590Srgrimes relsesigs(); 4501590Srgrimes reset(0); 4511590Srgrimes } 45277274Smikeh (void)rm(tempname); 4531590Srgrimes } 4541590Srgrimes printf("\"%s\" ", mailname); 45577274Smikeh (void)fflush(stdout); 4561590Srgrimes if ((obuf = Fopen(mailname, "r+")) == NULL) { 45774769Smikeh warn("%s", mailname); 4581590Srgrimes relsesigs(); 4591590Srgrimes reset(0); 4601590Srgrimes } 4611590Srgrimes trunc(obuf); 4621590Srgrimes c = 0; 4631590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) { 4641590Srgrimes if ((mp->m_flag & MDELETED) != 0) 4651590Srgrimes continue; 4661590Srgrimes c++; 46777274Smikeh if (sendmessage(mp, obuf, NULL, NULL) < 0) { 46874769Smikeh warnx("%s", mailname); 4691590Srgrimes relsesigs(); 4701590Srgrimes reset(0); 4711590Srgrimes } 4721590Srgrimes } 4731590Srgrimes gotcha = (c == 0 && ibuf == NULL); 4741590Srgrimes if (ibuf != NULL) { 4751590Srgrimes while ((c = getc(ibuf)) != EOF) 47677274Smikeh (void)putc(c, obuf); 47777274Smikeh (void)Fclose(ibuf); 4781590Srgrimes } 47977274Smikeh (void)fflush(obuf); 4801590Srgrimes if (ferror(obuf)) { 48174769Smikeh warn("%s", mailname); 4821590Srgrimes relsesigs(); 4831590Srgrimes reset(0); 4841590Srgrimes } 48577274Smikeh (void)Fclose(obuf); 4861590Srgrimes if (gotcha) { 48777274Smikeh (void)rm(mailname); 4881590Srgrimes printf("removed\n"); 4891590Srgrimes } else 4901590Srgrimes printf("complete\n"); 49177274Smikeh (void)fflush(stdout); 4921590Srgrimes 4931590Srgrimesdone: 4941590Srgrimes relsesigs(); 4951590Srgrimes} 496