upas/fs: fix more locking bugs, remove debugging clutter, remove planb mbox code
This commit is contained in:
parent
163dccbac0
commit
508b796b27
|
@ -173,31 +173,6 @@ sanembmsg(Mailbox *mb, Message *m)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sanefid(Fid *f)
|
||||
{
|
||||
if(f->m == 0)
|
||||
return;
|
||||
if(f->mtop){
|
||||
sanemsg(f->mtop);
|
||||
assert(f->mtop->refs > 0);
|
||||
}
|
||||
sanemsg(f->m);
|
||||
if(f->m)
|
||||
if(Topmsg(f->mb, f->m))
|
||||
assert(f->m->refs > 0);
|
||||
}
|
||||
|
||||
void
|
||||
sanefids(void)
|
||||
{
|
||||
Fid *f;
|
||||
|
||||
for(f = fids; f; f = f->next)
|
||||
if(f->busy)
|
||||
sanefid(f);
|
||||
}
|
||||
|
||||
static int
|
||||
Afmt(Fmt *f)
|
||||
{
|
||||
|
@ -427,7 +402,7 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if(mboxfile != nil)
|
||||
if(err = newmbox(mboxfile, "mbox", 0, 0))
|
||||
if(err = newmbox(mboxfile, "mbox", 0, nil))
|
||||
sysfatal("opening %s: %s", mboxfile, err);
|
||||
|
||||
switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
|
||||
|
@ -856,18 +831,19 @@ doclone(Fid *f, int nfid)
|
|||
return nil;
|
||||
nf->busy = 1;
|
||||
nf->open = 0;
|
||||
if(nf->mb = f->mb)
|
||||
nf->mb = f->mb;
|
||||
if(nf->mb){
|
||||
qlock(nf->mb);
|
||||
mboxincref(nf->mb);
|
||||
}
|
||||
if(nf->m = f->m)
|
||||
msgincref(gettopmsg(nf->mb, nf->m));
|
||||
if(nf->mtop = f->mtop){
|
||||
qlock(nf->mb);
|
||||
if(nf->mtop = f->mtop)
|
||||
msgincref(nf->mtop);
|
||||
nf->qid = f->qid;
|
||||
if(nf->mb){
|
||||
qunlock(nf->mb);
|
||||
}
|
||||
nf->qid = f->qid;
|
||||
sanefid(nf);
|
||||
sanefid(f);
|
||||
return nf;
|
||||
}
|
||||
|
||||
|
@ -889,21 +865,18 @@ dowalk(Fid *f, char *name)
|
|||
{
|
||||
char *rv, *p;
|
||||
int t, t1;
|
||||
Mailbox *omb, *mb;
|
||||
Mailbox *mb;
|
||||
Hash *h;
|
||||
|
||||
t = FILE(f->qid.path);
|
||||
rv = Enotexist;
|
||||
|
||||
omb = f->mb;
|
||||
if(omb)
|
||||
qlock(omb);
|
||||
else
|
||||
qlock(&mbllock);
|
||||
qlock(&mbllock);
|
||||
if(f->mb)
|
||||
qlock(f->mb);
|
||||
|
||||
/* this must catch everything except . and .. */
|
||||
retry:
|
||||
sanefid(f);
|
||||
t1 = FILE(f->qid.path);
|
||||
if((t1 == Qmbox || t1 == Qdir) && *name >= 'a' && *name <= 'z'){
|
||||
h = hlook(f->qid.path, "xxx"); /* sleezy speedup */
|
||||
|
@ -915,15 +888,19 @@ sanefid(f);
|
|||
if(h != nil){
|
||||
if(f->m)
|
||||
msgdecref(f->mb, gettopmsg(f->mb, f->m));
|
||||
if(f->mb && f->mb != h->mb)
|
||||
if(f->mb && f->mb != h->mb){
|
||||
qunlock(f->mb);
|
||||
mboxdecref(f->mb);
|
||||
}
|
||||
if(h->mb && h->mb != f->mb)
|
||||
qlock(h->mb);
|
||||
f->mb = h->mb;
|
||||
f->m = h->m;
|
||||
if(f->m)
|
||||
msgincref(gettopmsg(f->mb, f->m));
|
||||
switch(t){
|
||||
case Qtop:
|
||||
if(f->mb != nil)
|
||||
if(f->mb)
|
||||
mboxincref(f->mb);
|
||||
break;
|
||||
case Qmbox:
|
||||
|
@ -936,17 +913,16 @@ sanefid(f);
|
|||
f->qid = h->qid;
|
||||
if(t1 < Qmax)
|
||||
f->qid.path = PATH(f->m->id, t1); /* sleezy speedup */
|
||||
sanefid(f);
|
||||
rv = nil;
|
||||
}else if((p = strchr(name, '.')) != nil && *name != '.'){
|
||||
*p = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if(omb)
|
||||
qunlock(omb);
|
||||
else
|
||||
qunlock(&mbllock);
|
||||
if(f->mb)
|
||||
qunlock(f->mb);
|
||||
qunlock(&mbllock);
|
||||
|
||||
if(rv == nil)
|
||||
return rv;
|
||||
|
||||
|
@ -967,9 +943,9 @@ sanefid(f);
|
|||
f->qid.path = PATH(0, Qtop);
|
||||
f->qid.type = QTDIR;
|
||||
f->qid.vers = 0;
|
||||
qlock(&mbllock);
|
||||
mb = f->mb;
|
||||
f->mb = nil;
|
||||
qlock(&mbllock);
|
||||
mboxdecref(mb);
|
||||
qunlock(&mbllock);
|
||||
break;
|
||||
|
@ -1003,7 +979,6 @@ rwalk(Fid *f)
|
|||
char *rv;
|
||||
int i;
|
||||
|
||||
sanefid(f);
|
||||
if(f->open)
|
||||
return Eisopen;
|
||||
|
||||
|
@ -1038,7 +1013,6 @@ sanefid(f);
|
|||
/* we only error out if no walk */
|
||||
if(i > 0)
|
||||
rv = nil;
|
||||
sanefid(f);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1056,10 +1030,12 @@ ropen(Fid *f)
|
|||
|
||||
/* make sure we've decoded */
|
||||
if(file == Qbody){
|
||||
qlock(f->mb);
|
||||
cachebody(f->mb, f->m);
|
||||
decode(f->m);
|
||||
convert(f->m);
|
||||
putcache(f->mb, f->m);
|
||||
qunlock(f->mb);
|
||||
}
|
||||
|
||||
rhdr.iounit = 0;
|
||||
|
@ -1082,20 +1058,24 @@ readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
|
|||
long pos;
|
||||
Mailbox *mb;
|
||||
|
||||
qlock(&mbllock);
|
||||
|
||||
n = 0;
|
||||
pos = 0;
|
||||
mkstat(&d, nil, nil, Qctl);
|
||||
m = convD2M(&d, &buf[n], blen);
|
||||
if(off <= pos){
|
||||
if(m <= BIT16SZ || m > cnt)
|
||||
return 0;
|
||||
goto out;
|
||||
n += m;
|
||||
cnt -= m;
|
||||
}
|
||||
pos += m;
|
||||
|
||||
for(mb = mbl; mb != nil; mb = mb->next){
|
||||
qlock(mb);
|
||||
mkstat(&d, mb, nil, Qmbox);
|
||||
qunlock(mb);
|
||||
m = convD2M(&d, &buf[n], blen - n);
|
||||
if(off <= pos){
|
||||
if(m <= BIT16SZ || m > cnt)
|
||||
|
@ -1105,6 +1085,8 @@ readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
|
|||
}
|
||||
pos += m;
|
||||
}
|
||||
out:
|
||||
qlock(&mbllock);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -1116,6 +1098,10 @@ readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
long pos;
|
||||
Message *msg;
|
||||
|
||||
qlock(f->mb);
|
||||
if(off == 0)
|
||||
syncmbox(f->mb, 1);
|
||||
|
||||
n = 0;
|
||||
if(f->mb->ctl){
|
||||
mkstat(&d, f->mb, nil, Qmboxctl);
|
||||
|
@ -1123,7 +1109,7 @@ readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
if(off == 0){
|
||||
if(m <= BIT16SZ || m > cnt){
|
||||
f->fptr = nil;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
n += m;
|
||||
cnt -= m;
|
||||
|
@ -1160,7 +1146,8 @@ readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
f->foff = pos;
|
||||
f->fptr = msg;
|
||||
f->fvers = f->mb->vers;
|
||||
|
||||
out:
|
||||
qunlock(f->mb);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -1172,6 +1159,7 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
long pos;
|
||||
Message *msg;
|
||||
|
||||
qlock(f->mb);
|
||||
n = 0;
|
||||
pos = 0;
|
||||
for(i = 0; i < Qmax; i++){
|
||||
|
@ -1179,7 +1167,7 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
m = convD2M(&d, &buf[n], blen - n);
|
||||
if(off <= pos){
|
||||
if(m <= BIT16SZ || m > cnt)
|
||||
return n;
|
||||
goto out;
|
||||
n += m;
|
||||
cnt -= m;
|
||||
}
|
||||
|
@ -1196,7 +1184,8 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
|
|||
}
|
||||
pos += m;
|
||||
}
|
||||
|
||||
out:
|
||||
qunlock(f->mb);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -1223,20 +1212,13 @@ rread(Fid *f)
|
|||
cnt = messagesize - IOHDRSZ;
|
||||
rhdr.data = (char*)mbuf;
|
||||
|
||||
sanefid(f);
|
||||
t = FILE(f->qid.path);
|
||||
if(f->qid.type & QTDIR){
|
||||
if(t == Qtop){
|
||||
qlock(&mbllock);
|
||||
if(t == Qtop)
|
||||
n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
|
||||
qunlock(&mbllock);
|
||||
}else if(t == Qmbox) {
|
||||
qlock(f->mb);
|
||||
if(off == 0)
|
||||
syncmbox(f->mb, 1);
|
||||
else if(t == Qmbox)
|
||||
n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
|
||||
qunlock(f->mb);
|
||||
}else if(t == Qmboxctl)
|
||||
else if(t == Qmboxctl)
|
||||
n = 0;
|
||||
else
|
||||
n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
|
||||
|
@ -1318,7 +1300,6 @@ rwrite(Fid *f)
|
|||
|
||||
t = FILE(f->qid.path);
|
||||
rhdr.count = thdr.count;
|
||||
sanefid(f);
|
||||
if(thdr.count == 0)
|
||||
return Ebadctl;
|
||||
if(thdr.data[thdr.count - 1] == '\n')
|
||||
|
@ -1344,7 +1325,7 @@ rwrite(Fid *f)
|
|||
flags = 0;
|
||||
if(strcmp(argv[0], "create") == 0)
|
||||
flags |= DMcreate;
|
||||
return newmbox(file, argv[2], flags, 0);
|
||||
return newmbox(file, argv[2], flags, nil);
|
||||
}
|
||||
if(strcmp(argv[0], "close") == 0){
|
||||
if(argc < 2)
|
||||
|
@ -1383,10 +1364,8 @@ rwrite(Fid *f)
|
|||
return Ebadargs;
|
||||
for(; *argv; argv++){
|
||||
mboxpathbuf(file, sizeof file, getlog(), *argv);
|
||||
if(err = newmbox(file, nil, 0, 0))
|
||||
if(err = newmbox(file, nil, 0, nil))
|
||||
return err;
|
||||
// if(!mb->remove)
|
||||
// return "remove not implemented";
|
||||
if(err = removembox(file, flags))
|
||||
return err;
|
||||
}
|
||||
|
@ -1437,23 +1416,22 @@ rclunk(Fid *f)
|
|||
{
|
||||
Mailbox *mb;
|
||||
|
||||
sanefid(f);
|
||||
f->busy = 1;
|
||||
/* coherence(); */
|
||||
f->fid = -1;
|
||||
f->open = 0;
|
||||
mb = f->mb;
|
||||
if(mb != nil)
|
||||
if(mb){
|
||||
qlock(mb);
|
||||
}
|
||||
if(f->mtop)
|
||||
msgdecref(mb, f->mtop);
|
||||
if(f->m)
|
||||
msgdecref(mb, gettopmsg(mb, f->m));
|
||||
f->m = f->mtop = nil;
|
||||
if(mb != nil){
|
||||
if(mb){
|
||||
f->mb = nil;
|
||||
qunlock(mb);
|
||||
assert(mb->refs > 0);
|
||||
qlock(&mbllock);
|
||||
mboxdecref(mb);
|
||||
qunlock(&mbllock);
|
||||
|
@ -1465,11 +1443,12 @@ sanefid(f);
|
|||
char *
|
||||
rremove(Fid *f)
|
||||
{
|
||||
sanefid(f);
|
||||
if(f->m != nil){
|
||||
if(f->m->deleted == 0)
|
||||
qlock(f->mb);
|
||||
if(!f->m->deleted)
|
||||
mailplumb(f->mb, f->m, 1);
|
||||
f->m->deleted = Deleted;
|
||||
qunlock(f->mb);
|
||||
}
|
||||
return rclunk(f);
|
||||
}
|
||||
|
@ -1479,15 +1458,15 @@ rstat(Fid *f)
|
|||
{
|
||||
Dir d;
|
||||
|
||||
sanefid(f);
|
||||
if(FILE(f->qid.path) == Qmbox){
|
||||
if(f->mb)
|
||||
qlock(f->mb);
|
||||
if(FILE(f->qid.path) == Qmbox)
|
||||
syncmbox(f->mb, 1);
|
||||
qunlock(f->mb);
|
||||
}
|
||||
mkstat(&d, f->mb, f->m, FILE(f->qid.path));
|
||||
rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
|
||||
rhdr.stat = mbuf;
|
||||
if(f->mb)
|
||||
qunlock(f->mb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1521,19 +1500,6 @@ newfid(int fid)
|
|||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
fidmboxrefs(Mailbox *mb)
|
||||
{
|
||||
Fid *f;
|
||||
int refs = 0;
|
||||
|
||||
for(f = fids; f; f = f->next){
|
||||
if(f->mb == mb)
|
||||
refs++;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
void
|
||||
io(void)
|
||||
{
|
||||
|
@ -1554,19 +1520,8 @@ io(void)
|
|||
}
|
||||
|
||||
for(;;){
|
||||
/*
|
||||
* reading from a pipe or a network device
|
||||
* will give an error after a few eof reads
|
||||
* however, we cannot tell the difference
|
||||
* between a zero-length read and an interrupt
|
||||
* on the processes writing to us,
|
||||
* so we wait for the error
|
||||
*/
|
||||
checkmboxrefs();
|
||||
n = read9pmsg(mfd[0], mdata, messagesize);
|
||||
if(n == 0)
|
||||
continue;
|
||||
if(n < 0)
|
||||
if(n <= 0)
|
||||
return;
|
||||
if(convM2S(mdata, n, &thdr) == 0)
|
||||
continue;
|
||||
|
@ -1861,25 +1816,6 @@ hashmboxrefs(Mailbox *mb)
|
|||
return refs;
|
||||
}
|
||||
|
||||
void
|
||||
checkmboxrefs(void)
|
||||
{
|
||||
int refs;
|
||||
Mailbox *mb;
|
||||
|
||||
// qlock(&mbllock);
|
||||
for(mb = mbl; mb; mb = mb->next){
|
||||
qlock(mb);
|
||||
refs = fidmboxrefs(mb) + 1;
|
||||
if(refs != mb->refs){
|
||||
eprint("%s:%s ref mismatch got %d expected %d\n", mb->name, mb->path, refs, mb->refs);
|
||||
abort();
|
||||
}
|
||||
qunlock(mb);
|
||||
}
|
||||
// qunlock(&mbllock);
|
||||
}
|
||||
|
||||
void
|
||||
post(char *name, char *envname, int srvfd)
|
||||
{
|
||||
|
|
|
@ -52,7 +52,6 @@ static Mailboxinit *boxinit[] = {
|
|||
imap4mbox,
|
||||
pop3mbox,
|
||||
mdirmbox,
|
||||
// planbmbox,
|
||||
plan9mbox,
|
||||
};
|
||||
|
||||
|
@ -66,7 +65,7 @@ syncmbox(Mailbox *mb, int doplumb)
|
|||
int n, d, y, a;
|
||||
Message *m, *next;
|
||||
|
||||
assert(canqlock(mb) == 0);
|
||||
assert(!canqlock(mb));
|
||||
a = mb->root->subname;
|
||||
if(rdidxfile(mb, doplumb) == -2)
|
||||
wridxfile(mb);
|
||||
|
@ -116,7 +115,7 @@ mboxrename(char *a, char *b, int flags)
|
|||
snprint(f1, sizeof f1, "%s", b);
|
||||
err = newmbox(f0, nil, 0, &mb);
|
||||
dprint("mboxrename %s %s -> %s\n", f0, f1, err);
|
||||
if(!err && !mb->rename)
|
||||
if(err == nil && mb->rename == nil)
|
||||
err = "rename not supported";
|
||||
if(err)
|
||||
goto done;
|
||||
|
@ -147,11 +146,9 @@ mboxrename(char *a, char *b, int flags)
|
|||
henter(PATH(0, Qtop), mb->name,
|
||||
(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
|
||||
done:
|
||||
if(!mb)
|
||||
if(mb == nil)
|
||||
return err;
|
||||
qunlock(mb);
|
||||
// if(err)
|
||||
// mboxdecref(mb);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -175,6 +172,8 @@ newmbox(char *path, char *name, int flags, Mailbox **r)
|
|||
int i;
|
||||
Mailbox *mb, **l;
|
||||
|
||||
if(r)
|
||||
*r = nil;
|
||||
initheaders();
|
||||
mb = emalloc(sizeof *mb);
|
||||
mb->idxsem = 1;
|
||||
|
@ -1146,6 +1145,7 @@ msgincref(Message *m)
|
|||
void
|
||||
msgdecref(Mailbox *mb, Message *m)
|
||||
{
|
||||
assert(!canqlock(mb));
|
||||
assert(m->refs > 0);
|
||||
m->refs--;
|
||||
if(m->refs == 0){
|
||||
|
@ -1202,6 +1202,7 @@ mboxdecref(Mailbox *mb)
|
|||
qunlock(mb);
|
||||
}
|
||||
|
||||
|
||||
/* just space over \r. sleezy but necessary for ms email. */
|
||||
int
|
||||
deccr(char *x, int len)
|
||||
|
|
|
@ -14,7 +14,6 @@ OFILES=\
|
|||
mdir.$O\
|
||||
mtree.$O\
|
||||
plan9.$O\
|
||||
planb.$O\
|
||||
pop3.$O\
|
||||
ref.$O\
|
||||
remove.$O\
|
||||
|
|
|
@ -1,484 +0,0 @@
|
|||
/*
|
||||
* Plan B (mail2fs) mail box format.
|
||||
*
|
||||
* BUG: this does not reconstruct the
|
||||
* raw text for attachments. So imap and others
|
||||
* will be unable to access any attachment using upas/fs.
|
||||
* As an aid, we add the path to the message directory
|
||||
* to the message body, so the user could build the path
|
||||
* for any attachment and open it.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <ctype.h>
|
||||
#include <plumb.h>
|
||||
#include <libsec.h>
|
||||
#include "dat.h"
|
||||
|
||||
static char*
|
||||
parseunix(Message *m)
|
||||
{
|
||||
char *s, *p, *q;
|
||||
int l;
|
||||
Tm tm;
|
||||
|
||||
l = m->header - m->start;
|
||||
m->unixheader = smprint("%.*s", l, m->start);
|
||||
s = m->start + 5;
|
||||
if((p = strchr(s, ' ')) == nil)
|
||||
return s;
|
||||
*p = 0;
|
||||
m->unixfrom = strdup(s);
|
||||
*p++ = ' ';
|
||||
if(q = strchr(p, '\n'))
|
||||
*q = 0;
|
||||
if(strtotm(p, &tm) < 0)
|
||||
return p;
|
||||
if(q)
|
||||
*q = '\n';
|
||||
m->fileid = (uvlong)tm2sec(&tm) << 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
readmessage(Message *m, char *msg)
|
||||
{
|
||||
int fd, n;
|
||||
char *buf, *name, *p;
|
||||
char hdr[128];
|
||||
Dir *d;
|
||||
|
||||
buf = nil;
|
||||
d = nil;
|
||||
name = smprint("%s/raw", msg);
|
||||
if(name == nil)
|
||||
return -1;
|
||||
if(m->filename != nil)
|
||||
free(m->filename);
|
||||
m->filename = strdup(name);
|
||||
if(m->filename == nil)
|
||||
sysfatal("malloc: %r");
|
||||
fd = open(name, OREAD);
|
||||
if(fd < 0)
|
||||
goto Fail;
|
||||
n = read(fd, hdr, sizeof(hdr)-1);
|
||||
if(n <= 0)
|
||||
goto Fail;
|
||||
hdr[n] = 0;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
p = strchr(hdr, '\n');
|
||||
if(p != nil)
|
||||
*++p = 0;
|
||||
if(strncmp(hdr, "From ", 5) != 0)
|
||||
goto Fail;
|
||||
free(name);
|
||||
name = smprint("%s/text", msg);
|
||||
if(name == nil)
|
||||
goto Fail;
|
||||
fd = open(name, OREAD);
|
||||
if(fd < 0)
|
||||
goto Fail;
|
||||
d = dirfstat(fd);
|
||||
if(d == nil)
|
||||
goto Fail;
|
||||
buf = malloc(strlen(hdr) + d->length + strlen(msg) + 10); /* few extra chars */
|
||||
if(buf == nil)
|
||||
goto Fail;
|
||||
strcpy(buf, hdr);
|
||||
p = buf+strlen(hdr);
|
||||
n = readn(fd, p, d->length);
|
||||
if(n < 0)
|
||||
goto Fail;
|
||||
sprint(p+n, "\n[%s]\n", msg);
|
||||
n += 2 + strlen(msg) + 2;
|
||||
close(fd);
|
||||
free(name);
|
||||
free(d);
|
||||
free(m->start);
|
||||
m->start = buf;
|
||||
m->lim = m->end = p+n;
|
||||
if(*(m->end-1) == '\n')
|
||||
m->end--;
|
||||
*m->end = 0;
|
||||
m->bend = m->rbend = m->end;
|
||||
|
||||
return 0;
|
||||
Fail:
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
free(name);
|
||||
free(buf);
|
||||
free(d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deleted messages are kept as spam instead.
|
||||
*/
|
||||
static void
|
||||
archive(Message *m)
|
||||
{
|
||||
char *dir, *p, *nname;
|
||||
Dir d;
|
||||
|
||||
dir = strdup(m->filename);
|
||||
nname = nil;
|
||||
if(dir == nil)
|
||||
return;
|
||||
p = strrchr(dir, '/');
|
||||
if(p == nil)
|
||||
goto Fail;
|
||||
*p = 0;
|
||||
p = strrchr(dir, '/');
|
||||
if(p == nil)
|
||||
goto Fail;
|
||||
p++;
|
||||
if(*p < '0' || *p > '9')
|
||||
goto Fail;
|
||||
nname = smprint("s.%s", p);
|
||||
if(nname == nil)
|
||||
goto Fail;
|
||||
nulldir(&d);
|
||||
d.name = nname;
|
||||
dirwstat(dir, &d);
|
||||
Fail:
|
||||
free(dir);
|
||||
free(nname);
|
||||
}
|
||||
|
||||
int
|
||||
purgembox(Mailbox *mb, int virtual)
|
||||
{
|
||||
Message *m, *next;
|
||||
int newdels;
|
||||
|
||||
/* forget about what's no longer in the mailbox */
|
||||
newdels = 0;
|
||||
for(m = mb->root->part; m != nil; m = next){
|
||||
next = m->next;
|
||||
if(m->deleted > 0 && m->refs == 0){
|
||||
if(m->inmbox){
|
||||
newdels++;
|
||||
/*
|
||||
* virtual folders are virtual,
|
||||
* we do not archive
|
||||
*/
|
||||
if(virtual == 0)
|
||||
archive(m);
|
||||
}
|
||||
delmessage(mb, m);
|
||||
}
|
||||
}
|
||||
return newdels;
|
||||
}
|
||||
|
||||
static int
|
||||
mustshow(char* name)
|
||||
{
|
||||
if(isdigit(name[0]))
|
||||
return 1;
|
||||
if(0 && name[0] == 'a' && name[1] == '.')
|
||||
return 1;
|
||||
if(0 && name[0] == 's' && name[1] == '.')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
readpbmessage(Mailbox *mb, char *msg, int doplumb, int *nnew)
|
||||
{
|
||||
Message *m, **l;
|
||||
char *x, *p;
|
||||
|
||||
m = newmessage(mb->root);
|
||||
m->mallocd = 1;
|
||||
m->inmbox = 1;
|
||||
if(readmessage(m, msg) < 0){
|
||||
unnewmessage(mb, mb->root, m);
|
||||
return -1;
|
||||
}
|
||||
for(l = &mb->root->part; *l != nil; l = &(*l)->next)
|
||||
if(strcmp((*l)->filename, m->filename) == 0 &&
|
||||
*l != m){
|
||||
if((*l)->deleted < 0)
|
||||
(*l)->deleted = 0;
|
||||
delmessage(mb, m);
|
||||
mb->root->subname--;
|
||||
return -1;
|
||||
}
|
||||
m->header = m->end;
|
||||
if(x = strchr(m->start, '\n'))
|
||||
m->header = x + 1;
|
||||
if(p = parseunix(m))
|
||||
sysfatal("%s:%s naked From in body? [%s]", mb->path, (*l)->filename, p);
|
||||
m->mheader = m->mhend = m->header;
|
||||
parse(mb, m, 0, 0);
|
||||
if(m != *l && m->deleted != Dup){
|
||||
logmsg(m, "new");
|
||||
newcachehash(mb, m, doplumb);
|
||||
putcache(mb, m);
|
||||
nnew[0]++;
|
||||
}
|
||||
|
||||
/* chain in */
|
||||
*l = m;
|
||||
if(doplumb)
|
||||
mailplumb(mb, m, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dcmp(Dir *a, Dir *b)
|
||||
{
|
||||
char *an, *bn;
|
||||
|
||||
an = a->name;
|
||||
bn = b->name;
|
||||
if(an[0] != 0 && an[1] == '.')
|
||||
an += 2;
|
||||
if(bn[0] != 0 && bn[1] == '.')
|
||||
bn += 2;
|
||||
return strcmp(an, bn);
|
||||
}
|
||||
|
||||
static char*
|
||||
readpbmbox(Mailbox *mb, int doplumb, int *new)
|
||||
{
|
||||
char *month, *msg;
|
||||
int fd, i, j, nd, nmd;
|
||||
Dir *d, *md;
|
||||
static char err[ERRMAX];
|
||||
|
||||
fd = open(mb->path, OREAD);
|
||||
if(fd < 0){
|
||||
errstr(err, sizeof err);
|
||||
return err;
|
||||
}
|
||||
nd = dirreadall(fd, &d);
|
||||
close(fd);
|
||||
if(nd > 0)
|
||||
qsort(d, nd, sizeof d[0], (int (*)(void*, void*))dcmp);
|
||||
for(i = 0; i < nd; i++){
|
||||
month = smprint("%s/%s", mb->path, d[i].name);
|
||||
if(month == nil)
|
||||
break;
|
||||
fd = open(month, OREAD);
|
||||
if(fd < 0){
|
||||
fprint(2, "%s: %s: %r\n", argv0, month);
|
||||
free(month);
|
||||
continue;
|
||||
}
|
||||
md = dirfstat(fd);
|
||||
if(md != nil && (md->qid.type & QTDIR) != 0){
|
||||
free(md);
|
||||
md = nil;
|
||||
nmd = dirreadall(fd, &md);
|
||||
for(j = 0; j < nmd; j++)
|
||||
if(mustshow(md[j].name)){
|
||||
msg = smprint("%s/%s", month, md[j].name);
|
||||
readpbmessage(mb, msg, doplumb, new);
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
free(month);
|
||||
free(md);
|
||||
md = nil;
|
||||
}
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char*
|
||||
readpbvmbox(Mailbox *mb, int doplumb, int *new)
|
||||
{
|
||||
char *data, *ln, *p, *nln, *msg;
|
||||
int fd, nr;
|
||||
long sz;
|
||||
Dir *d;
|
||||
static char err[ERRMAX];
|
||||
|
||||
fd = open(mb->path, OREAD);
|
||||
if(fd < 0){
|
||||
errstr(err, sizeof err);
|
||||
return err;
|
||||
}
|
||||
d = dirfstat(fd);
|
||||
if(d == nil){
|
||||
errstr(err, sizeof err);
|
||||
return err;
|
||||
}
|
||||
sz = d->length;
|
||||
free(d);
|
||||
if(sz > 2 * 1024 * 1024){
|
||||
sz = 2 * 1024 * 1024;
|
||||
fprint(2, "upas/fs: %s: bug: folder too big\n", mb->path);
|
||||
}
|
||||
data = malloc(sz+1);
|
||||
if(data == nil){
|
||||
errstr(err, sizeof err);
|
||||
return err;
|
||||
}
|
||||
nr = readn(fd, data, sz);
|
||||
close(fd);
|
||||
if(nr < 0){
|
||||
errstr(err, sizeof err);
|
||||
free(data);
|
||||
return err;
|
||||
}
|
||||
data[nr] = 0;
|
||||
|
||||
for(ln = data; *ln != 0; ln = nln){
|
||||
nln = strchr(ln, '\n');
|
||||
if(nln != nil)
|
||||
*nln++ = 0;
|
||||
else
|
||||
nln = ln + strlen(ln);
|
||||
p = strchr(ln , ' ');
|
||||
if(p != nil)
|
||||
*p = 0;
|
||||
p = strchr(ln, '\t');
|
||||
if(p != nil)
|
||||
*p = 0;
|
||||
p = strstr(ln, "/text");
|
||||
if(p != nil)
|
||||
*p = 0;
|
||||
msg = smprint("/mail/box/%s/msgs/%s", user, ln);
|
||||
if(msg == nil){
|
||||
fprint(2, "upas/fs: malloc: %r\n");
|
||||
continue;
|
||||
}
|
||||
readpbmessage(mb, msg, doplumb, new);
|
||||
free(msg);
|
||||
}
|
||||
free(data);
|
||||
return nil;
|
||||
}
|
||||
|
||||
static char*
|
||||
readmbox(Mailbox *mb, int doplumb, int virt, int *new)
|
||||
{
|
||||
char *mberr;
|
||||
int fd;
|
||||
Dir *d;
|
||||
Message *m;
|
||||
static char err[128];
|
||||
|
||||
if(debug)
|
||||
fprint(2, "read mbox %s\n", mb->path);
|
||||
fd = open(mb->path, OREAD);
|
||||
if(fd < 0){
|
||||
errstr(err, sizeof(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
d = dirfstat(fd);
|
||||
if(d == nil){
|
||||
close(fd);
|
||||
errstr(err, sizeof(err));
|
||||
return err;
|
||||
}
|
||||
if(mb->d != nil){
|
||||
if(d->qid.path == mb->d->qid.path &&
|
||||
d->qid.vers == mb->d->qid.vers){
|
||||
close(fd);
|
||||
free(d);
|
||||
return nil;
|
||||
}
|
||||
free(mb->d);
|
||||
}
|
||||
close(fd);
|
||||
mb->d = d;
|
||||
mb->vers++;
|
||||
henter(PATH(0, Qtop), mb->name,
|
||||
(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
|
||||
snprint(err, sizeof err, "reading '%s'", mb->path);
|
||||
logmsg(nil, err, nil);
|
||||
|
||||
for(m = mb->root->part; m != nil; m = m->next)
|
||||
if(m->deleted == 0)
|
||||
m->deleted = -1;
|
||||
if(virt == 0)
|
||||
mberr = readpbmbox(mb, doplumb, new);
|
||||
else
|
||||
mberr = readpbvmbox(mb, doplumb, new);
|
||||
|
||||
/*
|
||||
* messages removed from the mbox; flag them to go.
|
||||
*/
|
||||
for(m = mb->root->part; m != nil; m = m->next)
|
||||
if(m->deleted < 0 && doplumb){
|
||||
delmessage(mb, m);
|
||||
if(doplumb)
|
||||
mailplumb(mb, m, 1);
|
||||
}
|
||||
logmsg(nil, "mbox read");
|
||||
return mberr;
|
||||
}
|
||||
|
||||
static char*
|
||||
mbsync(Mailbox *mb, int doplumb, int *new)
|
||||
{
|
||||
char *rv;
|
||||
|
||||
rv = readmbox(mb, doplumb, 0, new);
|
||||
purgembox(mb, 0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static char*
|
||||
mbvsync(Mailbox *mb, int doplumb, int *new)
|
||||
{
|
||||
char *rv;
|
||||
|
||||
rv = readmbox(mb, doplumb, 1, new);
|
||||
purgembox(mb, 1);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char*
|
||||
planbmbox(Mailbox *mb, char *path)
|
||||
{
|
||||
char *list;
|
||||
static char err[64];
|
||||
|
||||
if(access(path, AEXIST) < 0)
|
||||
return Enotme;
|
||||
list = smprint("%s/list", path);
|
||||
if(access(list, AEXIST) < 0){
|
||||
free(list);
|
||||
return Enotme;
|
||||
}
|
||||
free(list);
|
||||
mb->sync = mbsync;
|
||||
if(debug)
|
||||
fprint(2, "planb mbox %s\n", path);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
planbvmbox(Mailbox *mb, char *path)
|
||||
{
|
||||
int fd, nr, i;
|
||||
char buf[64];
|
||||
static char err[64];
|
||||
|
||||
fd = open(path, OREAD);
|
||||
if(fd < 0)
|
||||
return Enotme;
|
||||
nr = read(fd, buf, sizeof(buf)-1);
|
||||
close(fd);
|
||||
if(nr < 7)
|
||||
return Enotme;
|
||||
buf[nr] = 0;
|
||||
for(i = 0; i < 6; i++)
|
||||
if(buf[i] < '0' || buf[i] > '9')
|
||||
return Enotme;
|
||||
if(buf[6] != '/')
|
||||
return Enotme;
|
||||
mb->sync = mbvsync;
|
||||
if(debug)
|
||||
fprint(2, "planb virtual mbox %s\n", path);
|
||||
return nil;
|
||||
}
|
Loading…
Reference in a new issue