#pragma prototyped
#include "mailx.h"
void
tempinit(void)
{
register char* cp;
if (!(state.tmp.dir = tempnam(NiL, NiL)) || !*state.tmp.dir || !(cp = strrchr(state.tmp.dir, '/')) && !(cp = strrchr(state.tmp.dir, '\\')))
state.tmp.dir = _PATH_TMP;
else {
*++cp = 0;
if (!(cp = (char*)malloc(cp - state.tmp.dir + 1)))
note(ERROR|FATAL, "Out of space");
strcpy(cp, state.tmp.dir);
state.tmp.dir = cp;
}
filetemp(state.tmp.edit, sizeof(state.tmp.edit), 'E', 0);
filetemp(state.tmp.mail, sizeof(state.tmp.mail), 'M', 0);
filetemp(state.tmp.mesg, sizeof(state.tmp.mesg), 'G', 0);
filetemp(state.tmp.more, sizeof(state.tmp.more), 'X', 0);
filetemp(state.tmp.quit, sizeof(state.tmp.quit), 'Q', 0);
}
int
cmdquit(void)
{
return state.sourcing ? 1 : -1;
}
static void
edstop(void)
{
register int gotcha;
register int c;
register struct msg* mp;
int update;
char* s;
char* temp;
char* move;
FILE* obuf;
FILE* ibuf;
FILE* news;
struct mhcontext mh;
struct stat st;
if (state.readonly)
return;
holdsigs();
news = state.var.news && *state.var.news ? fileopen(state.var.news, "w") : (FILE*)0;
update = MODIFY|MDELETE|MSTATUS;
if (!state.var.keepsave)
update |= MSAVE;
for (mp = state.msg.list, gotcha = 0; mp < state.msg.list + state.msg.count; mp++) {
if (!(mp->m_flag & MNONE)) {
if (mp->m_flag & MNEW)
msgflags(mp, MSTATUS, MNEW);
if (mp->m_flag & update)
gotcha++;
if (news && (mp->m_flag & (MREAD|MDELETE)) && (s = grab(mp, GNEWS, NiL)))
fprintf(news, "%s\n", s);
}
}
if (news) {
fileclose(news);
goto done;
}
if (!gotcha)
goto done;
if (state.folder == FMH) {
if (!state.incorporating)
note(PROMPT, "\"%s\" ", state.path.mail);
mhgetcontext(&mh, state.path.mail, 1);
mh.dot = state.msg.dot - state.msg.list + 1;
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
if ((mp->m_flag & update) && !(mp->m_flag & MNONE)) {
sfprintf(state.path.temp, "%s/%d", state.path.mail, mp - state.msg.list + 1);
temp = struse(state.path.temp);
if (mp->m_flag & (MDELETE|MSAVE))
rm(temp);
else {
sfprintf(state.path.move, "%s/%d~", state.path.mail, mp - state.msg.list + 1);
move = struse(state.path.move);
if (obuf = fileopen(move, "Ew")) {
if (copy(mp, obuf, NiL, NiL, 0) < 0) {
note(SYSTEM, "%s", temp);
rm(move);
relsesigs();
reset(0);
}
rm(temp);
if (rename(move, temp))
note(SYSTEM, "%s", temp);
fileclose(obuf);
}
}
}
}
mhputcontext(&mh, state.path.mail);
if (!state.incorporating)
note(0, "complete");
}
else {
ibuf = 0;
if (stat(state.path.mail, &st) >= 0 && st.st_size > state.mailsize) {
temp = state.path.path;
filetemp(temp, sizeof(state.path.path), 'B', 0);
if (!(obuf = fileopen(temp, "Ew"))) {
relsesigs();
reset(0);
}
if (!(ibuf = fileopen(state.path.mail, "Er"))) {
fileclose(obuf);
rm(temp);
relsesigs();
reset(0);
}
fseek(ibuf, state.mailsize, SEEK_SET);
filecopy(NiL, ibuf, NiL, obuf, NiL, (off_t)0, NiL, NiL, 0);
fileclose(ibuf);
fileclose(obuf);
if (!(ibuf = fileopen(temp, "Er"))) {
rm(temp);
relsesigs();
reset(0);
}
rm(temp);
}
if (!state.incorporating)
note(PROMPT, "\"%s\" ", state.path.mail);
if (!(obuf = fileopen(state.path.mail, "Er+"))) {
relsesigs();
reset(0);
}
filetrunc(obuf);
update &= (MDELETE|MSAVE);
update |= MNONE;
c = 0;
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++)
if (!(mp->m_flag & update)) {
c = 1;
if (copy(mp, obuf, NiL, NiL, 0) < 0) {
note(SYSTEM, "%s", state.path.mail);
relsesigs();
reset(0);
}
}
gotcha = !c && !ibuf;
if (ibuf) {
filecopy(NiL, ibuf, NiL, obuf, NiL, (off_t)0, NiL, NiL, 0);
fileclose(ibuf);
}
if (fileclose(obuf)) {
note(SYSTEM, "%s", state.path.mail);
relsesigs();
reset(0);
}
if (!state.incorporating) {
if (gotcha) {
rm(state.path.mail);
note(0, "removed");
}
else
note(0, "complete");
}
}
done:
relsesigs();
}
static int
writeback(register FILE* res)
{
register struct msg* mp;
register int p;
FILE* obuf;
p = 0;
if (!(obuf = fileopen(state.path.mail, "Er+")))
return -1;
#if !APPEND_MAILBOX
if (res)
filecopy(NiL, res, NiL, obuf, NiL, (off_t)0, NiL, NiL, 0);
#endif
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++)
if ((mp->m_flag&MPRESERVE) || !(mp->m_flag&MTOUCH)) {
p++;
if (copy(mp, obuf, NiL, NiL, 0) < 0) {
note(SYSTEM, "%s", state.path.mail);
fileclose(obuf);
return -1;
}
}
#if APPEND_MAILBOX
if (res && filecopy(NiL, res, state.path.mail, obuf, NiL, (off_t)0, NiL, NiL, 0)) {
fileclose(obuf);
return -1;
}
#endif
if (filetrunc(obuf)) {
note(SYSTEM, "%s", state.path.mail);
fileclose(obuf);
return -1;
}
fileclose(obuf);
if (res)
fileclose(res);
alter(state.path.mail);
note(0, "Held %d message%s in %s", p, p == 1 ? "" : "s", state.path.mail);
return 0;
}
void
quit(void)
{
register struct msg* mp;
register int c;
off_t size;
char* mbox;
char* s;
char* xbox;
int anystat;
int holdbit;
int mcount;
int modify;
int nohold;
int p;
int x;
int set;
int clr;
FILE* abuf;
FILE* fbuf;
FILE* ibuf;
FILE* news;
FILE* obuf;
FILE* rbuf;
FILE* xbuf;
if (state.readonly)
return;
if (state.edit) {
edstop();
return;
}
if (state.folder != FIMAP) {
if (!(fbuf = fileopen(state.path.mail, "r+")))
goto newmail;
size = state.openstat.st_size;
filelock(state.path.mail, fbuf, 1);
rbuf = 0;
if (size > state.mailsize) {
note(0, "New mail has arrived");
if (!(rbuf = fileopen(state.tmp.more, "w")) || !fbuf)
goto newmail;
#if APPEND_MAILBOX
fseek(fbuf, state.mailsize, SEEK_SET);
filecopy(NiL, fbuf, NiL, rbuf, NiL, (off_t)0, NiL, NiL, 0);
#else
if (filecopy(NiL, fbuf, NiL, rbuf, NiL, (off_t)(size - state.mailsize), NiL, NiL, 0))
goto newmail;
#endif
fileclose(rbuf);
if (!(rbuf = fileopen(state.tmp.more, "r")))
goto newmail;
rm(state.tmp.more);
}
}
else
fbuf = 0;
anystat = 0;
holdbit = state.var.hold ? MPRESERVE : MBOX;
nohold = MBOX|MSAVE|MDELETE|MPRESERVE;
if (state.var.keepsave)
nohold &= ~MSAVE;
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
set = clr = 0;
if (mp->m_flag & (MBOX|MDELETE|MPRESERVE|MSAVE))
clr |= MSPAM;
if (mp->m_flag & MNEW) {
set |= MSTATUS;
clr |= MNEW;
}
if ((mp->m_flag | set) & MSTATUS)
anystat++;
if (!(mp->m_flag & MTOUCH))
set |= MPRESERVE;
if (!(mp->m_flag & nohold))
set |= holdbit;
if (set || clr)
msgflags(mp, set, clr);
}
modify = 0;
news = state.var.news && *state.var.news ? fileopen(state.var.news, "w") : (FILE*)0;
for (c = p = x = 0, mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
if (mp->m_flag & MSPAM) {
msgflags(mp, MDELETE|MTOUCH, MBOX|MPRESERVE|MODIFY);
x++;
}
if (mp->m_flag & MBOX)
c++;
if (mp->m_flag & MPRESERVE)
p++;
if (mp->m_flag & MODIFY)
modify++;
if (news && (mp->m_flag & (MREAD|MDELETE)) &&
(s = grab(mp, GNEWS, NiL)))
fprintf(news, "%s\n", s);
}
if (news)
fileclose(news);
if (p == state.msg.count && !modify && !anystat) {
note(0, "Held %d message%s in %s", p, p == 1 ? "" : "s", state.path.mail);
if (fbuf)
fileclose(fbuf);
return;
}
xbuf = 0;
if (x && (!state.var.spamlog || !*state.var.spamlog || !(xbuf = fileopen(xbox = expand(state.var.spamlog, 1), "a"))))
x = 0;
if (state.folder == FIMAP) {
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
if (mp->m_flag & MSAVE)
msgflags(mp, MDELETE, 0);
if (xbuf && (mp->m_flag & (MSPAM|MDELETE)) == (MSPAM|MDELETE)) {
if (copy(mp, xbuf, &state.saveignore, NiL, 0) < 0) {
msgflags(mp, MPRESERVE, MSPAM|MDELETE|MTOUCH);
x--;
}
}
}
if (xbuf) {
fileclose(xbuf);
if (x)
note(0, "Saved %d message%s in %s", x, x == 1 ? "" : "s", xbox);
}
}
if (state.msg.imap.state) {
imap_quit();
if (state.folder == FIMAP)
return;
}
if (!c && !x) {
if (p) {
writeback(rbuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
goto cream;
}
mbox = expand("&", 1);
mcount = c;
if (state.var.append) {
if (!(obuf = fileopen(mbox, "Ea"))) {
fileclose(fbuf);
fileclose(xbuf);
return;
}
chmod(mbox, MAILMODE);
}
else {
if (!(obuf = fileopen(state.tmp.quit, "Ew"))) {
fileclose(fbuf);
fileclose(xbuf);
return;
}
if (!(ibuf = fileopen(state.tmp.quit, "Er"))) {
rm(state.tmp.quit);
fileclose(obuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
rm(state.tmp.quit);
if (abuf = fileopen(mbox, "r")) {
if (filecopy(mbox, abuf, state.tmp.quit, obuf, NiL, (off_t)0, NiL, NiL, 0)) {
fileclose(abuf);
fileclose(ibuf);
fileclose(obuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
fileclose(abuf);
}
if (fileclose(obuf)) {
note(SYSTEM, "%s", state.tmp.quit);
fileclose(ibuf);
fileclose(obuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
close(open(mbox, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_cloexec, MAILMODE));
if (!(obuf = fileopen(mbox, "Er+"))) {
fileclose(ibuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
}
for (mp = state.msg.list; mp < state.msg.list + state.msg.count; mp++) {
if (mp->m_flag & MBOX) {
if (copy(mp, obuf, &state.saveignore, NiL, 0) < 0) {
note(SYSTEM, "%s", mbox);
fileclose(ibuf);
fileclose(obuf);
fileclose(fbuf);
fileclose(xbuf);
return;
}
}
else if (xbuf && (mp->m_flag & (MSPAM|MDELETE)) == (MSPAM|MDELETE)) {
if (copy(mp, xbuf, &state.saveignore, NiL, 0) < 0) {
msgflags(mp, MPRESERVE, MSPAM|MDELETE|MTOUCH);
x--;
}
}
}
if (xbuf) {
fileclose(xbuf);
if (x)
note(0, "Saved %d message%s in %s", x, x == 1 ? "" : "s", xbox);
}
if (!state.var.append) {
rewind(ibuf);
filecopy(NiL, ibuf, NiL, obuf, NiL, (off_t)0, NiL, NiL, 0);
fileclose(ibuf);
}
if (filetrunc(obuf)) {
note(SYSTEM, "%s", mbox);
fileclose(obuf);
fileclose(fbuf);
return;
}
fileclose(obuf);
if (mcount)
note(0, "Saved %d message%s in %s", mcount, mcount == 1 ? "" : "s", mbox);
if (p) {
writeback(rbuf);
fileclose(fbuf);
return;
}
cream:
if (rbuf) {
if (!(abuf = fileopen(state.path.mail, "r+")))
goto newmail;
filecopy(NiL, rbuf, NiL, abuf, NiL, (off_t)0, NiL, NiL, 0);
fileclose(rbuf);
filetrunc(abuf);
fileclose(abuf);
alter(state.path.mail);
fileclose(fbuf);
return;
}
demail();
if (fbuf)
fileclose(fbuf);
return;
newmail:
note(0, "Thou hast new mail");
if (fbuf)
fileclose(fbuf);
}