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); 23177274Smikeh (void)close(open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600)); 2321590Srgrimes if ((obuf = Fopen(mbox, "r+")) == NULL) { 23374769Smikeh warn("%s", mbox); 23477274Smikeh (void)Fclose(ibuf); 23577274Smikeh (void)Fclose(fbuf); 2361590Srgrimes return; 2371590Srgrimes } 2381590Srgrimes } 23977274Smikeh if (value("append") != NULL) { 2401590Srgrimes if ((obuf = Fopen(mbox, "a")) == NULL) { 24174769Smikeh warn("%s", mbox); 24277274Smikeh (void)Fclose(fbuf); 2431590Srgrimes return; 2441590Srgrimes } 24577274Smikeh (void)fchmod(fileno(obuf), 0600); 2461590Srgrimes } 2471590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 2481590Srgrimes if (mp->m_flag & MBOX) 24977274Smikeh if (sendmessage(mp, obuf, saveignore, NULL) < 0) { 25074769Smikeh warnx("%s", mbox); 25177274Smikeh (void)Fclose(ibuf); 25277274Smikeh (void)Fclose(obuf); 25377274Smikeh (void)Fclose(fbuf); 2541590Srgrimes return; 2551590Srgrimes } 2561590Srgrimes 2571590Srgrimes /* 2581590Srgrimes * Copy the user's old mbox contents back 2591590Srgrimes * to the end of the stuff we just saved. 2601590Srgrimes * If we are appending, this is unnecessary. 2611590Srgrimes */ 2621590Srgrimes 26377274Smikeh if (value("append") == NULL) { 2641590Srgrimes rewind(ibuf); 2651590Srgrimes c = getc(ibuf); 2661590Srgrimes while (c != EOF) { 26777274Smikeh (void)putc(c, obuf); 2681590Srgrimes if (ferror(obuf)) 2691590Srgrimes break; 2701590Srgrimes c = getc(ibuf); 2711590Srgrimes } 27277274Smikeh (void)Fclose(ibuf); 2731590Srgrimes } 27488150Smikeh (void)fflush(obuf); 2751590Srgrimes trunc(obuf); 2761590Srgrimes if (ferror(obuf)) { 27774769Smikeh warn("%s", mbox); 27877274Smikeh (void)Fclose(obuf); 27977274Smikeh (void)Fclose(fbuf); 2801590Srgrimes return; 2811590Srgrimes } 28277274Smikeh (void)Fclose(obuf); 2831590Srgrimes if (mcount == 1) 2841590Srgrimes printf("Saved 1 message in mbox\n"); 2851590Srgrimes else 2861590Srgrimes printf("Saved %d messages in mbox\n", mcount); 2871590Srgrimes 2881590Srgrimes /* 2891590Srgrimes * Now we are ready to copy back preserved files to 2901590Srgrimes * the system mailbox, if any were requested. 2911590Srgrimes */ 2921590Srgrimes 2931590Srgrimes if (p != 0) { 2941590Srgrimes writeback(rbuf); 29577274Smikeh (void)Fclose(fbuf); 2961590Srgrimes return; 2971590Srgrimes } 2981590Srgrimes 2991590Srgrimes /* 30077274Smikeh * Finally, remove his /var/mail file. 3011590Srgrimes * If new mail has arrived, copy it back. 3021590Srgrimes */ 3031590Srgrimes 3041590Srgrimescream: 3051590Srgrimes if (rbuf != NULL) { 3061590Srgrimes abuf = Fopen(mailname, "r+"); 3071590Srgrimes if (abuf == NULL) 3081590Srgrimes goto newmail; 3091590Srgrimes while ((c = getc(rbuf)) != EOF) 31077274Smikeh (void)putc(c, abuf); 31177274Smikeh (void)Fclose(rbuf); 3121590Srgrimes trunc(abuf); 31377274Smikeh (void)Fclose(abuf); 3141590Srgrimes alter(mailname); 31577274Smikeh (void)Fclose(fbuf); 3161590Srgrimes return; 3171590Srgrimes } 3181590Srgrimes demail(); 31977274Smikeh (void)Fclose(fbuf); 3201590Srgrimes return; 3211590Srgrimes 3221590Srgrimesnewmail: 3231590Srgrimes printf("Thou hast new mail.\n"); 3241590Srgrimes if (fbuf != NULL) 32577274Smikeh (void)Fclose(fbuf); 3261590Srgrimes} 3271590Srgrimes 3281590Srgrimes/* 3291590Srgrimes * Preserve all the appropriate messages back in the system 3301590Srgrimes * mailbox, and print a nice message indicated how many were 3311590Srgrimes * saved. On any error, just return -1. Else return 0. 3321590Srgrimes * Incorporate the any new mail that we found. 3331590Srgrimes */ 3341590Srgrimesint 335216564Scharnierwriteback(FILE *res) 3361590Srgrimes{ 33777274Smikeh struct message *mp; 33877274Smikeh int p, c; 3391590Srgrimes FILE *obuf; 3401590Srgrimes 3411590Srgrimes p = 0; 3421590Srgrimes if ((obuf = Fopen(mailname, "r+")) == NULL) { 34374769Smikeh warn("%s", mailname); 34477274Smikeh return (-1); 3451590Srgrimes } 3461590Srgrimes#ifndef APPEND 3471590Srgrimes if (res != NULL) 3481590Srgrimes while ((c = getc(res)) != EOF) 34977274Smikeh (void)putc(c, obuf); 3501590Srgrimes#endif 3511590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 3521590Srgrimes if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) { 3531590Srgrimes p++; 35477274Smikeh if (sendmessage(mp, obuf, NULL, NULL) < 0) { 35574769Smikeh warnx("%s", mailname); 35677274Smikeh (void)Fclose(obuf); 35777274Smikeh return (-1); 3581590Srgrimes } 3591590Srgrimes } 3601590Srgrimes#ifdef APPEND 3611590Srgrimes if (res != NULL) 3621590Srgrimes while ((c = getc(res)) != EOF) 36377274Smikeh (void)putc(c, obuf); 3641590Srgrimes#endif 36577274Smikeh (void)fflush(obuf); 3661590Srgrimes trunc(obuf); 3671590Srgrimes if (ferror(obuf)) { 36874769Smikeh warn("%s", mailname); 36977274Smikeh (void)Fclose(obuf); 37077274Smikeh return (-1); 3711590Srgrimes } 3721590Srgrimes if (res != NULL) 37377274Smikeh (void)Fclose(res); 37477274Smikeh (void)Fclose(obuf); 3751590Srgrimes alter(mailname); 3761590Srgrimes if (p == 1) 3771590Srgrimes printf("Held 1 message in %s\n", mailname); 3781590Srgrimes else 3791590Srgrimes printf("Held %d messages in %s\n", p, mailname); 38077274Smikeh return (0); 3811590Srgrimes} 3821590Srgrimes 3831590Srgrimes/* 3841590Srgrimes * Terminate an editing session by attempting to write out the user's 3851590Srgrimes * file from the temporary. Save any new stuff appended to the file. 3861590Srgrimes */ 3871590Srgrimesvoid 388216564Scharnieredstop(void) 3891590Srgrimes{ 39077274Smikeh int gotcha, c; 39177274Smikeh struct message *mp; 3921590Srgrimes FILE *obuf, *ibuf, *readstat; 3931590Srgrimes struct stat statb; 39474769Smikeh char tempname[PATHSIZE]; 3951590Srgrimes 3961590Srgrimes if (readonly) 3971590Srgrimes return; 3981590Srgrimes holdsigs(); 39977274Smikeh if (Tflag != NULL) { 4001590Srgrimes if ((readstat = Fopen(Tflag, "w")) == NULL) 40177274Smikeh Tflag = NULL; 4021590Srgrimes } 4031590Srgrimes for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { 4041590Srgrimes if (mp->m_flag & MNEW) { 4051590Srgrimes mp->m_flag &= ~MNEW; 4061590Srgrimes mp->m_flag |= MSTATUS; 4071590Srgrimes } 4081590Srgrimes if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) 4091590Srgrimes gotcha++; 41077274Smikeh if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) { 4111590Srgrimes char *id; 4121590Srgrimes 41377274Smikeh if ((id = hfield("article-id", mp)) != NULL) 4141590Srgrimes fprintf(readstat, "%s\n", id); 4151590Srgrimes } 4161590Srgrimes } 41777274Smikeh if (Tflag != NULL) 41877274Smikeh (void)Fclose(readstat); 41977274Smikeh if (!gotcha || Tflag != NULL) 4201590Srgrimes goto done; 4211590Srgrimes ibuf = NULL; 4221590Srgrimes if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { 42374769Smikeh int fd; 42474769Smikeh 42577274Smikeh (void)snprintf(tempname, sizeof(tempname), 42677274Smikeh "%s/mbox.XXXXXXXXXX", tmpdir); 42777274Smikeh if ((fd = mkstemp(tempname)) == -1 || 42877274Smikeh (obuf = Fdopen(fd, "w")) == NULL) { 42974769Smikeh warn("%s", tempname); 4301590Srgrimes relsesigs(); 4311590Srgrimes reset(0); 4321590Srgrimes } 4331590Srgrimes if ((ibuf = Fopen(mailname, "r")) == NULL) { 43474769Smikeh warn("%s", mailname); 43577274Smikeh (void)Fclose(obuf); 43677274Smikeh (void)rm(tempname); 4371590Srgrimes relsesigs(); 4381590Srgrimes reset(0); 4391590Srgrimes } 44082793Sache (void)fseeko(ibuf, mailsize, SEEK_SET); 4411590Srgrimes while ((c = getc(ibuf)) != EOF) 44277274Smikeh (void)putc(c, obuf); 44377274Smikeh (void)Fclose(ibuf); 44477274Smikeh (void)Fclose(obuf); 4451590Srgrimes if ((ibuf = Fopen(tempname, "r")) == NULL) { 44674769Smikeh warn("%s", tempname); 44777274Smikeh (void)rm(tempname); 4481590Srgrimes relsesigs(); 4491590Srgrimes reset(0); 4501590Srgrimes } 45177274Smikeh (void)rm(tempname); 4521590Srgrimes } 4531590Srgrimes printf("\"%s\" ", mailname); 45477274Smikeh (void)fflush(stdout); 4551590Srgrimes if ((obuf = Fopen(mailname, "r+")) == NULL) { 45674769Smikeh warn("%s", mailname); 4571590Srgrimes relsesigs(); 4581590Srgrimes reset(0); 4591590Srgrimes } 4601590Srgrimes trunc(obuf); 4611590Srgrimes c = 0; 4621590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) { 4631590Srgrimes if ((mp->m_flag & MDELETED) != 0) 4641590Srgrimes continue; 4651590Srgrimes c++; 46677274Smikeh if (sendmessage(mp, obuf, NULL, NULL) < 0) { 46774769Smikeh warnx("%s", mailname); 4681590Srgrimes relsesigs(); 4691590Srgrimes reset(0); 4701590Srgrimes } 4711590Srgrimes } 4721590Srgrimes gotcha = (c == 0 && ibuf == NULL); 4731590Srgrimes if (ibuf != NULL) { 4741590Srgrimes while ((c = getc(ibuf)) != EOF) 47577274Smikeh (void)putc(c, obuf); 47677274Smikeh (void)Fclose(ibuf); 4771590Srgrimes } 47877274Smikeh (void)fflush(obuf); 4791590Srgrimes if (ferror(obuf)) { 48074769Smikeh warn("%s", mailname); 4811590Srgrimes relsesigs(); 4821590Srgrimes reset(0); 4831590Srgrimes } 48477274Smikeh (void)Fclose(obuf); 4851590Srgrimes if (gotcha) { 48677274Smikeh (void)rm(mailname); 4871590Srgrimes printf("removed\n"); 4881590Srgrimes } else 4891590Srgrimes printf("complete\n"); 49077274Smikeh (void)fflush(stdout); 4911590Srgrimes 4921590Srgrimesdone: 4931590Srgrimes relsesigs(); 4941590Srgrimes} 495