/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "rcv.h"
#include <locale.h>
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*
* Rcv -- receive mail rationally.
*
* Termination processing.
*/
static void writeback(int noremove);
#define PRIV(x) setgid(myegid), (x), setgid(myrgid);
/*
* Save all of the undetermined messages at the top of "mbox"
* Save all untouched messages back in the system mailbox.
* Remove the system mailbox, if none saved there.
*/
void
quit(
int noremove /* don't remove system mailbox, trunc it instead */
)
{
int mcount, p, modify, autohold, anystat, holdbit, nohold, fd;
FILE *ibuf, *obuf, *fbuf, *readstat;
register struct message *mp;
register int c;
char *id;
int appending;
char *mbox = Getf("MBOX");
/*
* If we are read only, we can't do anything,
* so just return quickly.
*/
mcount = 0;
if (readonly)
return;
/*
* See if there any messages to save in mbox. If no, we
* can save copying mbox to /tmp and back.
*
* Check also to see if any files need to be preserved.
* Delete all untouched messages to keep them out of mbox.
* If all the messages are to be preserved, just exit with
* a message.
*
* If the luser has sent mail to himself, refuse to do
* anything with the mailbox, unless mail locking works.
*/
#ifndef CANLOCK
if (selfsent) {
printf(gettext("You have new mail.\n"));
return;
}
#endif
/*
* Adjust the message flags in each message.
*/
anystat = 0;
autohold = value("hold") != NOSTR;
appending = value("append") != NOSTR;
holdbit = autohold ? MPRESERVE : MBOX;
nohold = MBOXED|MBOX|MSAVED|MDELETED|MPRESERVE;
if (value("keepsave") != NOSTR)
nohold &= ~MSAVED;
for (mp = &message[0]; mp < &message[msgCount]; mp++) {
if (mp->m_flag & MNEW) {
receipt(mp);
mp->m_flag &= ~MNEW;
mp->m_flag |= MSTATUS;
}
if (mp->m_flag & MSTATUS)
anystat++;
if ((mp->m_flag & MTOUCH) == 0)
mp->m_flag |= MPRESERVE;
if ((mp->m_flag & nohold) == 0)
mp->m_flag |= holdbit;
}
modify = 0;
if (Tflag != NOSTR) {
if ((readstat = fopen(Tflag, "w")) == NULL)
Tflag = NOSTR;
}
for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
if (mp->m_flag & MBOX)
c++;
if (mp->m_flag & MPRESERVE)
p++;
if (mp->m_flag & MODIFY)
modify++;
if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
id = hfield("message-id", mp, addone);
if (id != NOSTR)
fprintf(readstat, "%s\n", id);
else {
id = hfield("article-id", mp, addone);
if (id != NOSTR)
fprintf(readstat, "%s\n", id);
}
}
}
if (Tflag != NOSTR)
fclose(readstat);
if (p == msgCount && !modify && !anystat) {
if (p == 1)
printf(gettext("Held 1 message in %s\n"), mailname);
else
printf(gettext("Held %d messages in %s\n"), p,
mailname);
return;
}
if (c == 0) {
writeback(noremove);
return;
}
/*
* Create another temporary file and copy user's mbox file
* therein. If there is no mbox, copy nothing.
* If s/he has specified "append" don't copy the mailbox,
* just copy saveable entries at the end.
*/
mcount = c;
if (!appending) {
if ((fd = open(tempQuit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
(obuf = fdopen(fd, "w")) == NULL) {
perror(tempQuit);
return;
}
if ((ibuf = fopen(tempQuit, "r")) == NULL) {
perror(tempQuit);
removefile(tempQuit);
fclose(obuf);
return;
}
removefile(tempQuit);
if ((fbuf = fopen(mbox, "r")) != NULL) {
while ((c = getc(fbuf)) != EOF)
putc(c, obuf);
fclose(fbuf);
}
fflush(obuf);
if (fferror(obuf)) {
perror(tempQuit);
fclose(ibuf);
fclose(obuf);
return;
}
fclose(obuf);
if ((fd = open(mbox, O_RDWR|O_CREAT|O_TRUNC, MBOXPERM)) < 0 ||
(obuf = fdopen(fd, "r+")) == NULL) {
perror(mbox);
fclose(ibuf);
return;
}
if (issysmbox)
touchlock();
} else { /* we are appending */
if ((fd = open(mbox, O_RDWR|O_CREAT, MBOXPERM)) < 0 ||
(obuf = fdopen(fd, "a")) == NULL) {
perror(mbox);
return;
}
}
for (mp = &message[0]; mp < &message[msgCount]; mp++)
if (mp->m_flag & MBOX) {
if (msend(mp, obuf, (int)value("alwaysignore") ?
M_IGNORE|M_SAVING : M_SAVING, fputs) < 0) {
perror(mbox);
if (!appending)
fclose(ibuf);
fclose(obuf);
return;
}
mp->m_flag &= ~MBOX;
mp->m_flag |= MBOXED;
if (issysmbox)
touchlock();
}
/*
* Copy the user's old mbox contents back
* to the end of the stuff we just saved.
* If we are appending, this is unnecessary.
*/
if (!appending) {
rewind(ibuf);
c = getc(ibuf);
while (c != EOF) {
putc(c, obuf);
if (ferror(obuf))
break;
c = getc(ibuf);
}
fclose(ibuf);
fflush(obuf);
}
trunc(obuf);
if (fferror(obuf)) {
perror(mbox);
fclose(obuf);
return;
}
fclose(obuf);
if (mcount == 1)
printf(gettext("Saved 1 message in %s\n"), mbox);
else
printf(gettext("Saved %d messages in %s\n"), mcount, mbox);
/*
* Now we are ready to copy back preserved files to
* the system mailbox, if any were requested.
*/
writeback(noremove);
}
/*
* Preserve all the appropriate messages back in the system
* mailbox, and print a nice message indicating how many were
* saved. Incorporate any new mail that we found.
*/
static void
writeback(int noremove)
{
register struct message *mp;
register int p, c;
struct stat st;
FILE *obuf = 0, *fbuf = 0, *rbuf = 0;
void (*fhup)(int), (*fint)(int), (*fquit)(int);
int fd = -1;
fhup = sigset(SIGHUP, SIG_IGN);
fint = sigset(SIGINT, SIG_IGN);
fquit = sigset(SIGQUIT, SIG_IGN);
if (issysmbox)
lockmail();
if ((fbuf = fopen(mailname, "r+")) == NULL) {
perror(mailname);
goto die;
}
if (!issysmbox)
lock(fbuf, "r+", 1);
fstat(fileno(fbuf), &st);
if (st.st_size > mailsize) {
printf(gettext("New mail has arrived.\n"));
snprintf(tempResid, PATHSIZE, "%s/:saved/%s", maildir, myname);
PRIV(rbuf = fopen(tempResid, "w+"));
if (rbuf == NULL) {
snprintf(tempResid, PATHSIZE, "/tmp/Rq%-ld", mypid);
fd = open(tempResid,O_RDWR|O_CREAT|O_EXCL, 0600);
PRIV(rbuf = fdopen(fd, "w+"));
if (rbuf == NULL) {
snprintf(tempResid, PATHSIZE,
"%s/:saved/%s", maildir,
myname);
perror(tempResid);
fclose(fbuf);
goto die;
}
}
#ifdef APPEND
fseek(fbuf, mailsize, 0);
while ((c = getc(fbuf)) != EOF)
putc(c, rbuf);
#else
p = st.st_size - mailsize;
while (p-- > 0) {
c = getc(fbuf);
if (c == EOF) {
perror(mailname);
fclose(fbuf);
goto die;
}
putc(c, rbuf);
}
#endif
fclose(fbuf);
fseek(rbuf, 0L, 0);
if (issysmbox)
touchlock();
}
if ((obuf = fopen(mailname, "r+")) == NULL) {
perror(mailname);
goto die;
}
#ifndef APPEND
if (rbuf != NULL)
while ((c = getc(rbuf)) != EOF)
putc(c, obuf);
#endif
p = 0;
for (mp = &message[0]; mp < &message[msgCount]; mp++)
if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
p++;
if (msend(mp, obuf, 0, fputs) < 0) {
perror(mailname);
goto die;
}
if (issysmbox)
touchlock();
}
#ifdef APPEND
if (rbuf != NULL)
while ((c = getc(rbuf)) != EOF)
putc(c, obuf);
#endif
fflush(obuf);
trunc(obuf);
if (fferror(obuf)) {
perror(mailname);
goto die;
}
alter(mailname);
if (p) {
if (p == 1)
printf(gettext("Held 1 message in %s\n"), mailname);
else
printf(gettext("Held %d messages in %s\n"), p,
mailname);
}
if (!noremove && (fsize(obuf) == 0) && (value("keep") == NOSTR)) {
if (stat(mailname, &st) >= 0)
PRIV(delempty(st.st_mode, mailname));
}
die:
if (rbuf) {
fclose(rbuf);
PRIV(removefile(tempResid));
}
if (obuf)
fclose(obuf);
if (issysmbox)
unlockmail();
sigset(SIGHUP, fhup);
sigset(SIGINT, fint);
sigset(SIGQUIT, fquit);
}
void
lockmail(void)
{
PRIV(maillock(lockname,10));
}
void
unlockmail(void)
{
PRIV(mailunlock());
}