shithub: riscv

Download patch

ref: a1c1e00973b8799860db594e64a9dee231e325d1
parent: c3d372c3dae46dbf4657ded30dc3b2bf6c369f59
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jun 18 14:52:54 EDT 2017

upas/fs: work in progress...

get plumbing logic out of mailbox drivers, all handled from
syncmbox() now. avoid reentrancy in syncmbox().

store attachment filename in index, so that we can return it
in mail info without fetching headers. (used to return blank
filename when read out of the index messing up attachments in
nedmail).

maintain Message.size for attachments.

get rid of string "refs" and just have a simple string intern
table (only used for Message.type and Message.charset).

Message.replyto and Message.filename are owned by the index,
so don't free in delmessage().

--- a/sys/src/cmd/upas/fs/cache.c
+++ b/sys/src/cmd/upas/fs/cache.c
@@ -371,18 +371,6 @@
 		(Qid){PATH(m->id, Qmax), 0, QTFILE}, m, mb);	/* sleezy speedup */
 }
 
-void
-newcachehash(Mailbox *mb, Message *m, int doplumb)
-{
-	if(doplumb)
-		mailplumb(mb, m, 0);
-	else
-		if(insurecache(mb, m) == 0)
-			msgdecref(mb, m);
-	/* avoid cachehash on error? */
-	cachehash(mb, m);
-}
-
 static char *itab[] = {
 	"idx",
 	"stale",
@@ -424,7 +412,7 @@
 	}
 	if(y == 0)
 		return 0;
-	dprint("middlecache %d [%D] %lud %lud\n", m->id, m->fileid, m->end - m->start, m->size);
+	dprint("middlecache %d [%D] %lud %lud\n", m->id, m->fileid, (ulong)(m->end - m->start), m->size);
 	return cachebody(mb, m);
 }
 
@@ -487,7 +475,7 @@
 	if(!mb->fetch || m->cstate&Cbody)
 		return 0;
 	o = m->end - m->start;
-	dprint("cachebody %d [%D] %lud %lud %s\n", m->id, m->fileid, o, m->size, cstate(m));
+	dprint("cachebody %d [%D] %lud %lud %s", m->id, m->fileid, o, m->size, cstate(m));
 	if(o < m->size)
 	if(fetch(mb, m, o, m->size - o) < 0)
 		return -1;
--- a/sys/src/cmd/upas/fs/chkidx.c
+++ /dev/null
@@ -1,416 +1,0 @@
-#include "common.h"
-#include <auth.h>
-#include <libsec.h>
-#include <bin.h>
-#include "dat.h"
-
-#define idprint(...)	if(1) fprint(2, __VA_ARGS__); else {}
-enum{
-	Maxver	= 10,
-};
-static char *magictab[Maxver] = {
-[4]	"idx magic v4\n",
-[7]	"idx magic v7\n",
-};
-static int fieldstab[Maxver] = {
-[4]	19,
-[7]	21,
-};
-
-static	char	*magic;
-static	int	Idxfields;
-static	int	lineno;
-static	int	idxver;
-
-int
-newid(void)
-{
-	static int id;
-
-	return ++id;
-}
-
-void*
-emalloc(ulong n)
-{
-	void *p;
-
-	p = mallocz(n, 1);
-	if(!p)
-		sysfatal("malloc %lud: %r", n);
-	setmalloctag(p, getcallerpc(&n));
-	return p;
-}
-	
-static int
-Afmt(Fmt *f)
-{
-	char buf[SHA1dlen*2 + 1];
-	uchar *u, i;
-
-	u = va_arg(f->args, uchar*);
-	if(u == 0 && f->flags & FmtSharp)
-		return fmtstrcpy(f, "-");
-	if(u == 0)
-		return fmtstrcpy(f, "<nildigest>");
-	for(i = 0; i < SHA1dlen; i++)
-		sprint(buf + 2*i, "%2.2ux", u[i]);
-	return fmtstrcpy(f, buf);
-}
-
-static int
-Dfmt(Fmt *f)
-{
-	char buf[32];
-	int seq;
-	uvlong v;
-
-	v = va_arg(f->args, uvlong);
-	seq = v & 0xff;
-	if(seq > 99)
-		seq = 99;
-	snprint(buf, sizeof buf, "%llud.%.2d", v>>8, seq);
-	return fmtstrcpy(f, buf);
-}
-
-static Mailbox*
-shellmailbox(char *path)
-{
-	Mailbox *mb;
-
-	mb = malloc(sizeof *mb);
-	if(mb == 0)
-		sysfatal("malloc");
-	memset(mb, 0, sizeof *mb);
-	snprint(mb->path, sizeof mb->path, "%s", path);
-	mb->id = newid();
-	mb->root = newmessage(nil);
-	mb->mtree = mkavltree(mtreecmp);
-	return mb;
-}
-
-void
-shellmailboxfree(Mailbox*)
-{
-}
-
-Message*
-newmessage(Message *parent)
-{
-	static int id;
-	Message *m;
-
-//	msgallocd++;
-
-	m = mallocz(sizeof *m, 1);
-	if(m == 0)
-		sysfatal("malloc");
-	m->disposition = Dnone;
-//	m->type = newrefs("text/plain");
-//	m->charset = newrefs("iso-8859-1");
-	m->cstate = Cidxstale;
-	m->flags = Frecent;
-	m->id = newid();
-	if(parent)
-		snprint(m->name, sizeof m->name, "%d", ++(parent->subname));
-	if(parent == nil)
-		parent = m;
-	m->whole = parent;
-	m->hlen = -1;
-	return m;
-}
-
-void
-unnewmessage(Mailbox *mb, Message *parent, Message *m)
-{
-	assert(parent->subname > 0);
-//	delmessage(mb, m);
-	USED(mb, m);
-	parent->subname -= 1;
-}
-
-
-static int
-validmessage(Mailbox *mb, Message *m, int level)
-{
-	if(level){
-		if(m->digest != 0)
-			goto lose;
-		if(m->fileid <= 1000000ull<<8)
-		if(m->fileid != 0)
-			goto lose;
-	}else{
-		if(m->digest == 0)
-			goto lose;
-		if(m->size == 0)
-			goto lose;
-		if(m->fileid <= 1000000ull<<8)
-			goto lose;
-		if(mtreefind(mb, m->digest))
-			goto lose;
-	}
-	return 1;
-lose:
-	fprint(2, "invalid cache[%d] %#A size %ld %D\n", level, m->digest, m->size, m->fileid);
-	return 0;
-}
-
-static char*
-∫(char *x)
-{
-	if(x && *x)
-		return x;
-	return nil;
-}
-
-static char*
-brdstr(Biobuf *b, int c, int eat)
-{
-	char *s;
-
-	s = Brdstr(b, c, eat);
-	if(s)
-		lineno++;
-	return s;
-}
-
-static int
-nibble(int c)
-{
-	if(c >= '0' && c <= '9')
-		return c - '0';
-	if(c < 0x20)
-		c += 0x20;
-	if(c >= 'a' && c <= 'f')
-		return c - 'a'+10;
-	return 0xff;
-}
-
-static uchar*
-hackdigest(char *s)
-{
-	uchar t[SHA1dlen];
-	int i;
-
-	if(strcmp(s, "-") == 0)
-		return 0;
-	if(strlen(s) != 2*SHA1dlen){
-		fprint(2, "bad digest %s\n", s);
-		return 0;
-	}
-	for(i = 0; i < SHA1dlen; i++)
-		t[i] = nibble(s[2*i])<<4 | nibble(s[2*i + 1]);
-	memmove(s, t, SHA1dlen);
-	return (uchar*)s;
-}
-
-static Message*
-findmessage(Mailbox *, Message *parent, int n)
-{
-	Message *m;
-
-	for(m = parent->part; m; m = m->next)
-		if(!m->digest && n-- == 0)
-			return m;
-	return 0;
-}
-
-static uvlong
-rdfileid(char *s, int level)
-{
-	char *p;
-	uvlong uv;
-
-	uv = strtoul(s, &p, 0);
-	if((level == 0 && uv < 1000000) || *p != '.')
-		return 0;
-	return uv<<8 | strtoul(p + 1, 0, 10);
-}
-
-static int
-rdidx(Biobuf *b, Mailbox *mb, Message *parent, int npart, int level)
-{
-	char *f[50 + 1], *s;
-	uchar *digest;
-	int n, nparts, good, bad, redux;
-	Message *m, **ll, *l;
-
-	bad = good = redux = 0;
-	ll = &parent->part;
-	nparts = npart;
-	for(; npart != 0 && (s = brdstr(b, '\n', 1)); npart--){
-//if(lineno>18&&lineno<25)idprint("%d: %d [%s]\n", lineno, level, s);
-		n = tokenize(s, f, nelem(f));
-		if(n != Idxfields){
-			print("%d: bad line\n", lineno);
-			bad++;
-			free(s);
-			continue;
-		}
-		digest = hackdigest(f[0]);
-		if(level == 0){
-			if(digest == 0)
-				idprint("%d: no digest\n", lineno);
-			m = mtreefind(mb, digest);
-		}else{
-			m = findmessage(mb, parent, nparts - npart);
-			if(m == 0){
-			//	idprint("can't find message\n");
-			}
-		}
-		if(m){
-			/*
-			 * read in mutable information.
-			 * currently this is only flags
-			 */
-			idprint("%d seen before %d... %.2ux", level, m->id, m->cstate);
-			redux++;
-			m->flags |= strtoul(f[1], 0, 16);
-			m->cstate &= ~Cidxstale;
-			m->cstate |= Cidx;
-			idprint("→%.2ux\n", m->cstate);
-			free(s);
-
-			if(m->nparts)
-				rdidx(b, mb, m, m->nparts, level + 1);
-			ll = &m->next;
-			continue;
-		}
-		m = newmessage(parent);
-//if(lineno>18&&lineno<25)idprint("%d: %d %d %A\n", lineno, level, m->id, digest);
-//		idprint("%d new %d %#A \n", level, m->id, digest);
-		m->digest = digest;
-		m->flags = strtoul(f[1], 0, 16);
-		m->fileid = rdfileid(f[2], level);
-		m->lines = atoi(f[3]);
-		m->ffrom = ∫(f[4]);
-		m->from = ∫(f[5]);
-		m->to = ∫(f[6]);
-		m->cc = ∫(f[7]);
-		m->bcc = ∫(f[8]);
-		m->replyto = ∫(f[9]);
-		m->messageid = ∫(f[10]);
-		m->subject = ∫(f[11]);
-		m->sender = ∫(f[12]);
-		m->inreplyto = ∫(f[13]);
-//		m->type = newrefs(f[14]);
-		m->disposition = atoi(f[15]);
-		m->size = strtoul(f[16], 0, 0);
-		m->rawbsize = strtoul(f[17], 0, 0);
-		switch(idxver){
-		case 4:
-			m->nparts = strtoul(f[18], 0, 0);
-		case 7:
-			m->ibadchars = strtoul(f[18], 0, 0);
-			m->idxaux = ∫(f[19]);
-			m->nparts = strtoul(f[20], 0, 0);
-		}
-		m->cstate &= ~Cidxstale;
-		m->cstate |= Cidx;
-		m->str = s;
-//		free(s);
-		if(!validmessage(mb, m, level)){
-			/*
-			 *  if this was an okay message, and somebody
-			 * wrote garbage to the index file, we lose the msg.
-			 */
-			print("%d: !validmessage\n", lineno);
-			bad++;
-			unnewmessage(mb, parent, m);
-			continue;
-		}
-		if(level == 0)
-			m->inmbox = 1;
-//		cachehash(mb, m);		/* hokey */
-		l = *ll;
-		*ll = m;
-		ll = &m->next;
-		*ll = l;
-		good++;
-
-		if(m->nparts){
-//			fprint(2, "%d: %d parts [%s]\n", lineno, m->nparts, f[18]);
-			rdidx(b, mb, m, m->nparts, level + 1);
-		}
-	}
-	if(level == 0)
-		print("idx: %d %d %d\n", good, bad, redux);
-	return 0;
-}
-
-static int
-verscmp(Biobuf *b)
-{
-	char *s;
-	int i;
-
-	if((s = brdstr(b, '\n', 0)) == 0)
-		return -1;
-	for(i = 0; i < Maxver; i++)
-		if(magictab[i])
-		if(strcmp(s, magictab[i]) == 0)
-			break;
-	free(s);
-	if(i == Maxver)
-		return -1;
-	idxver = i;
-	magic = magictab[i];
-	Idxfields = fieldstab[i];
-	fprint(2, "version %d\n", i);
-	return 0;
-}
-
-int
-mbvers(Biobuf *b)
-{
-	char *s;
-
-	if(s = brdstr(b, '\n', 1)){
-		free(s);
-		return 0;
-	}
-	return -1;
-}
-
-int
-ckidxfile(Mailbox *mb)
-{
-	char buf[Pathlen + 4];
-	int r;
-	Biobuf *b;
-
-	snprint(buf, sizeof buf, "%s", mb->path);
-	b = Bopen(buf, OREAD);
-	if(b == nil)
-		return -1;
-	if(verscmp(b) == -1)
-		return -1;
-	if(idxver >= 7)
-		mbvers(b);
-	r = rdidx(b, mb, mb->root, -1, 0);
-	Bterm(b);
-	return r;
-}
-
-static char *bargv[] = {"/fd/0", 0};
-
-void
-main(int argc, char **argv)
-{
-	Mailbox *mb;
-
-	fmtinstall('A', Afmt);
-	fmtinstall('D', Dfmt);
-	ARGBEGIN{
-	}ARGEND
-	if(*argv == 0)
-		argv = bargv;
-	for(; *argv; argv++){
-		mb = shellmailbox(*argv);
-		lineno = 0;
-		if(ckidxfile(mb) == -1)
-			fprint(2, "%s: %r\n", *argv);
-		shellmailboxfree(mb);
-	}
-	exits("");
-}
--- a/sys/src/cmd/upas/fs/dat.h
+++ b/sys/src/cmd/upas/fs/dat.h
@@ -62,10 +62,12 @@
 	char	*subject;
 	char	*sender;
 	char	*inreplyto;
-	char	*idxaux;			/* mailbox specific */
+	char	*idxaux;		/* mailbox specific */
 
-	int	type;			/* very few types: refstring */
-	int	disposition;		/* very few types: refstring */
+	char	*type;			/* mime info */
+	char	disposition;
+	char	*filename;
+
 	int	nparts;
 };
 
@@ -114,10 +116,9 @@
 	char	*references[Nref];
 
 	/* mime info */
-	char	*boundary;
-	int	charset;
-	char	*filename;
+	char	*charset;		
 	char	encoding;
+	char	*boundary;
 	char	converted;
 	char	decoded;
 	char	mimeflag;
@@ -175,12 +176,14 @@
 	char	*(*ctl)(Mailbox*, int, char**);
 	char	*(*remove)(Mailbox *, int);
 	char	*(*rename)(Mailbox*, char*, int);
-	char	*(*sync)(Mailbox*, int, int*);
+	char	*(*sync)(Mailbox*);
 	void	(*modflags)(Mailbox*, Message*, int);
 	void	(*idxwrite)(Biobuf*, Mailbox*);
 	int	(*idxread)(char*, Mailbox*);
 	void	(*idxinvalid)(Mailbox*);
 	void	*aux;		/* private to Mailbox implementation */
+
+	int	syncing;	/* currently syncing? */
 };
 
 typedef char *Mailboxinit(Mailbox*, char*);
@@ -195,7 +198,6 @@
 void		genericidxinvalid(Mailbox*);
 
 void		cachehash(Mailbox*, Message*);
-void		newcachehash(Mailbox*, Message*, int);
 int		cacheheaders(Mailbox*, Message*);		/* "getcache" */
 int		cachebody(Mailbox*, Message*);
 int		cacheidx(Mailbox*, Message*);
@@ -206,12 +208,11 @@
 long		cachefree(Mailbox*, Message*, int);
 
 Message*	gettopmsg(Mailbox*, Message*);
-char*		syncmbox(Mailbox*, int);
+char*		syncmbox(Mailbox*);
 void*		emalloc(ulong);
 void*		erealloc(void*, ulong);
 Message*	newmessage(Message*);
 void		unnewmessage(Mailbox*, Message*, Message*);
-void		delmessage(Mailbox*, Message*);
 char*		delmessages(int, char**);
 char		*flagmessages(int, char**);
 void		digestmessage(Mailbox*, Message*);
@@ -221,7 +222,6 @@
 void		eprint(char*, ...);
 void		iprint(char *, ...);
 int		newid(void);
-void		mailplumb(Mailbox*, Message*, int);
 char*		newmbox(char*, char*, int, Mailbox**);
 void		freembox(char*);
 char*		removembox(char*, int);
@@ -318,24 +318,14 @@
 	Message	*m;
 };
 
+uint	hash(char*);
 Hash	*hlook(ulong, char*);
 void	henter(ulong, char*, Qid, Message*, Mailbox*);
 void	hfree(ulong, char*);
 
-typedef struct {
-	char	*s;
-	int	l;
-	ulong	ref;
-} Refs;
-
-int	newrefs(char*);
-void	delrefs(int);
-void	refsinit(void);
-int	prrefs(Biobuf*);
-int	rdrefs(Biobuf*);
-
+char	*intern(char*);
 void	idxfree(Idx*);
-int	rdidxfile(Mailbox*, int);
+int	rdidxfile(Mailbox*);
 int	wridxfile(Mailbox*);
 
 char	*modflags(Mailbox*, Message*, char*);
@@ -356,7 +346,6 @@
 extern ulong	msgfreed;
 extern Mailbox	*mbl;
 extern Message	*root;
-extern Refs	*rtab;
 
 #define	dprint(...)	if(debug) fprint(2, __VA_ARGS__); else {}
 #define	Topmsg(mb, m)	(m->whole == mb->root)
--- a/sys/src/cmd/upas/fs/fs.c
+++ b/sys/src/cmd/upas/fs/fs.c
@@ -104,11 +104,6 @@
 [Qmboxctl]	"ctl",
 };
 
-enum
-{
-	Hsize=	1999,
-};
-
 char	*mntpt;
 char	user[Elemlen];
 int	Dflag;
@@ -127,7 +122,7 @@
 static	uchar	mbuf[16*1024 + IOHDRSZ];
 static	uchar	mdata[16*1024 + IOHDRSZ];
 static	ulong	path;		/* incremented for each new file */
-static	Hash	*htab[Hsize];
+static	Hash	*htab[1024];
 static	Fcall	rhdr;
 static	Fcall	thdr;
 static	Fid	*fids;
@@ -136,8 +131,6 @@
 void
 sanemsg(Message *m)
 {
-	if(debug)
-		poolcheck(mainmem);
 	assert(m->refs < 100);
 	assert(m->next != m);
 	if(m->end < m->start)
@@ -294,8 +287,8 @@
 		cachetarg = ntoi(EARGF(usage()));
 		break;
 	case 'd':
-		debug = 1;
-		mainmem->flags |= POOL_PARANOIA;
+		if(++debug > 1)
+			mainmem->flags |= POOL_PARANOIA;
 		break;
 	case 'f':
 		mboxfile = EARGF(usage());
@@ -527,8 +520,8 @@
 		p = m->to;
 		break;
 	case Qtype:
-		p = rtab[m->type].s;
-		len = rtab[m->type].l;
+		p = m->type;
+		len = strlen(m->type);
 		break;
 	case Qunixdate:
 		p = buf;
@@ -1015,7 +1008,7 @@
 	Message *msg;
 
 	if(off == 0)
-		syncmbox(f->mb, 1);
+		syncmbox(f->mb);
 
 	n = 0;
 	if(f->mb->ctl){
@@ -1339,11 +1332,8 @@
 char *
 rremove(Fid *f)
 {
-	if(f->m != nil){
-		if(!f->m->deleted)
-			mailplumb(f->mb, f->m, 1);
+	if(f->m != nil && f->m->deleted == 0)
 		f->m->deleted = Deleted;
-	}
 	return rclunk(f);
 }
 
@@ -1353,7 +1343,7 @@
 	Dir d;
 
 	if(FILE(f->qid.path) == Qmbox)
-		syncmbox(f->mb, 1);
+		syncmbox(f->mb);
 	mkstat(&d, f->mb, f->m, FILE(f->qid.path));
 	rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
 	rhdr.stat = mbuf;
@@ -1475,7 +1465,7 @@
 			}
 		}
 		if(mb != nil) {
-			syncmbox(mb, 1);
+			syncmbox(mb);
 			qunlock(&synclock);
 		} else {
 			qunlock(&synclock);
@@ -1610,17 +1600,15 @@
 }
 
 uint
-hash(ulong ppath, char *name)
+hash(char *s)
 {
-	uchar *p;
-	uint h;
+	uint c, h;
 
 	h = 0;
-	for(p = (uchar*)name; *p; p++)
-		h = h*7 + *p;
-	h += ppath;
+	while(c = *s++)
+		h = h*131 + c;
 
-	return h % Hsize;
+	return h;
 }
 
 Hash*
@@ -1629,7 +1617,7 @@
 	int h;
 	Hash *hp;
 
-	h = hash(ppath, name);
+	h = (hash(name)+ppath) % nelem(htab);
 	for(hp = htab[h]; hp != nil; hp = hp->next)
 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0)
 			return hp;
@@ -1642,7 +1630,7 @@
 	int h;
 	Hash *hp, **l;
 
-	h = hash(ppath, name);
+	h = (hash(name)+ppath) % nelem(htab);
 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
 		hp = *l;
 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
@@ -1666,7 +1654,7 @@
 	int h;
 	Hash *hp, **l;
 
-	h = hash(ppath, name);
+	h = (hash(name)+ppath) % nelem(htab);
 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
 		hp = *l;
 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
--- a/sys/src/cmd/upas/fs/idx.c
+++ b/sys/src/cmd/upas/fs/idx.c
@@ -5,15 +5,42 @@
 #define idprint(...)	if(iflag > 1) fprint(2, __VA_ARGS__); else {}
 #define iprint(...)		if(iflag) fprint(2, __VA_ARGS__); else {}
 
-static char *magic		= "idx magic v7\n";
+static char *magic	= "idx magic v8\n";
 static char *mbmagic	= "genericv1";
 enum {
-	Idxfields		= 21,
+	Idxfields		= 22,
 
 	Idxto		= 30000,		/* index timeout in ms */
 	Idxstep		= 300,		/* sleep between tries */
 };
 
+typedef struct Intern Intern;
+struct Intern
+{
+	Intern	*next;
+	char	str[];
+};
+
+static Intern *itab[64];
+
+char*
+intern(char *s)
+{
+	Intern *i, **h;
+	int n;
+
+	h = &itab[hash(s) % nelem(itab)];
+	for(i = *h; i != nil; i = i->next)
+		if(strcmp(s, i->str) == 0)
+			return i->str;
+	n = strlen(s)+1;
+	i = emalloc(sizeof(*i) + n);
+	memmove(i->str, s, n);
+	i->next = *h;
+	*h = i;
+	return i->str;
+}
+
 void
 idxfree(Idx *i)
 {
@@ -32,6 +59,7 @@
 		free(i->sender);
 		free(i->inreplyto);
 		free(i->idxaux);
+		free(i->filename);
 	}
 	memset(i, 0, sizeof *i);
 }
@@ -50,7 +78,7 @@
 	Bprint(b, "%#A %ux %D %lud ", x->digest, x->flags&~Frecent, x->fileid, x->lines);
 	Bprint(b, "%q %q %q %q %q ", ∂(x->ffrom), ∂(x->from), ∂(x->to), ∂(x->cc), ∂(x->bcc));
 	Bprint(b, "%q %q %q %q %q ", ∂(x->replyto), ∂(x->messageid), ∂(x->subject), ∂(x->sender), ∂(x->inreplyto));
-	Bprint(b, "%s %d %lud %lud ", rtab[x->type].s, x->disposition, x->size, x->rawbsize);
+	Bprint(b, "%s %d %q %lud %lud ", x->type, x->disposition, ∂(x->filename), x->size, x->rawbsize);
 	Bprint(b, "%lud %q %d\n", x->ibadchars, ∂(x->idxaux), x->nparts);
 	return 0;
 }
@@ -87,7 +115,6 @@
 
 	Bprint(b, magic);
 	mb->idxwrite(b, mb);
-//	prrefs(b);
 	i = pridx0(b, mb, mb->root->part, 0);
 	return i;
 }
@@ -304,7 +331,7 @@
  */
 
 static int
-rdidx(Biobuf *b, Mailbox *mb, Message *parent, int npart, int level, int doplumb)
+rdidx(Biobuf *b, Mailbox *mb, Message *parent, int npart, int level)
 {
 	char *f[Idxfields + 1], *s;
 	uchar *digest;
@@ -345,7 +372,7 @@
 			if(level == 0)
 				m->deleted &= ~Dmark;
 			if(m->nparts)
-			if(rdidx(b, mb, m, m->nparts, level + 1, 0) == -1)
+			if(rdidx(b, mb, m, m->nparts, level + 1) == -1)
 				goto dead;
 			ll = &m->next;
 			idprint("%d seen before %d... %.2ux", level, m->id, m->cstate);
@@ -375,17 +402,20 @@
 		m->subject = ∫(f[11]);
 		m->sender = ∫(f[12]);
 		m->inreplyto = ∫(f[13]);
-		m->type = newrefs(f[14]);
+		m->type = intern(f[14]);
 		m->disposition = atoi(f[15]);
-		m->size = strtoul(f[16], 0, 0);
-		m->rawbsize = strtoul(f[17], 0, 0);
-		m->ibadchars = strtoul(f[18], 0, 0);
-		m->idxaux = ∫(f[19]);
-		m->nparts = strtoul(f[20], 0, 0);
+		m->filename = ∫(f[16]);
+		m->size = strtoul(f[17], 0, 0);
+		m->rawbsize = strtoul(f[18], 0, 0);
+		m->ibadchars = strtoul(f[19], 0, 0);
+		m->idxaux = ∫(f[20]);
+		m->nparts = strtoul(f[21], 0, 0);
+
 		m->cstate &= ~Cidxstale;
 		m->cstate |= Cidx;
 		m->str = s;
 		s = 0;
+
 		if(!validmessage(mb, m, level))
 			goto dead;
 		if(level == 0){
@@ -400,10 +430,8 @@
 		good++;
 
 		if(m->nparts)
-		if(rdidx(b, mb, m, m->nparts, level + 1, 0) == -1)
+		if(rdidx(b, mb, m, m->nparts, level + 1) == -1)
 			goto dead;
-		if(doplumb && level == 0)
-			mailplumb(mb, m, 0);
 	}
 	if(level == 0 && bad + redux > 0)
 		iprint("idx: %d %d %d\n", good, bad, redux);
@@ -493,7 +521,7 @@
 }
 
 int
-rdidxfile0(Mailbox *mb, int doplumb)
+rdidxfile0(Mailbox *mb)
 {
 	char buf[Pathlen + 4];
 	int r, v;
@@ -509,7 +537,7 @@
 		r = -1;
 	else{
 		mark(mb);
-		r = rdidx(b, mb, mb->root, -1, 0, doplumb);
+		r = rdidx(b, mb, mb->root, -1, 0);
 		v = unmark(mb);
 		if(r == 0 && v > 0)
 			r = -1;
@@ -519,11 +547,11 @@
 }
 
 int
-rdidxfile(Mailbox *mb, int doplumb)
+rdidxfile(Mailbox *mb)
 {
 	int r;
 
-	r = rdidxfile0(mb, doplumb);
+	r = rdidxfile0(mb);
 	if(r == -1 && mb->idxinvalid)
 		mb->idxinvalid(mb);
 	return r;
--- a/sys/src/cmd/upas/fs/imap.c
+++ b/sys/src/cmd/upas/fs/imap.c
@@ -876,15 +876,6 @@
 	return v;
 }
 
-static void
-markdel(Mailbox *mb, Message *m, int doplumb)
-{
-	if(doplumb)
-		mailplumb(mb, m, 1);
-	m->inmbox = 0;
-	m->deleted = Disappear;
-}
-
 static int
 vcmp(vlong a, vlong b)
 {
@@ -903,14 +894,13 @@
 }
 
 static char*
-imap4read(Imap *imap, Mailbox *mb, int doplumb, int *new)
+imap4read(Imap *imap, Mailbox *mb)
 {
 	char *s;
-	int i, n, c, nnew, ndel;
+	int i, n, c;
 	Fetchi *f;
 	Message *m, **ll;
 
-	*new = 0;
 	imap4cmd(imap, "status %Z (messages uidvalidity)", imap->mbox);
 	if(!isokay(s = imap4resp(imap)))
 		return s;
@@ -928,7 +918,6 @@
 	n = imap->nuid;
 	if(n < imap->nmsg) idprint(imap, "partial sync %d < %d\n", n, imap->nmsg);
 	qsort(f, n, sizeof f[0], (int(*)(void*, void*))fetchicmp);
-	nnew = ndel = 0;
 	ll = &mb->root->part;
 	for(i = 0; (m = *ll) != nil || i < n; ){
 		c = -1;
@@ -948,7 +937,6 @@
 				i++;
 				continue;
 			}
-			nnew++;
 			m = newmessage(mb->root);
 			m->inmbox = 1;
 			m->idxaux = smprint("%llud", f[i].uid);
@@ -958,14 +946,12 @@
 			m->next = *ll;
 			*ll = m;
 			ll = &m->next;
-			newcachehash(mb, m, doplumb);
-			putcache(mb, m);
 			i++;
 		}else if(c > 0){
 			/* deleted message; */
 			idprint(imap, "deleted: %U (%U)\n", i<n? f[i].uid: 0, m? m->imapuid: 0);
-			ndel++;
-			markdel(mb, m, doplumb);
+			m->inmbox = 0;
+			m->deleted = Disappear;
 			ll = &m->next;
 		}else{
 			ll = &m->next;
@@ -972,8 +958,6 @@
 			i++;
 		}
 	}
-
-	*new = nnew;
 	return nil;
 }
 
@@ -995,7 +979,7 @@
 }
 
 static char*
-imap4sync(Mailbox *mb, int doplumb, int *new)
+imap4sync(Mailbox *mb)
 {
 	char *err;
 	Imap *imap;
@@ -1003,7 +987,7 @@
 	imap = mb->aux;
 	if(err = imap4dial(imap))
 		goto out;
-	err = imap4read(imap, mb, doplumb, new);
+	err = imap4read(imap, mb);
 out:
 	mb->waketime = (ulong)time(0) + imap->refreshtime;
 	return err;
--- a/sys/src/cmd/upas/fs/mbox.c
+++ b/sys/src/cmd/upas/fs/mbox.c
@@ -55,25 +55,42 @@
 	plan9mbox,
 };
 
+static void delmessage(Mailbox*, Message*);
+static void mailplumb(Mailbox*, Message*);
+
 /*
  * do we want to plumb flag changes?
  */
 char*
-syncmbox(Mailbox *mb, int doplumb)
+syncmbox(Mailbox *mb)
 {
 	char *s;
 	int n, d, y, a;
 	Message *m, *next;
 
+	if(mb->syncing)
+		return nil;
+
+	mb->syncing = 1;
+
 	a = mb->root->subname;
-	if(rdidxfile(mb, doplumb) == -2)
+	if(rdidxfile(mb) == -2)
 		wridxfile(mb);
-	if(s = mb->sync(mb, doplumb, &n))
+	if(s = mb->sync(mb))
 		return s;
+	n = 0;
 	d = 0;
 	y = 0;
 	for(m = mb->root->part; m; m = next){
 		next = m->next;
+		if((m->cstate & Cidx) == 0 && m->deleted == 0){
+			cachehash(mb, m);
+			if(insurecache(mb, m) == 0){
+				mailplumb(mb, m);
+				msgdecref(mb, m);
+			}
+			n++;
+		}
 		if(m->cstate & Cidxstale)
 			y++;
 		if(m->deleted == 0 || m->refs > 0)
@@ -81,6 +98,7 @@
 		if(mb->delete && m->inmbox && m->deleted & Deleted)
 			mb->delete(mb, m);
 		if(!m->inmbox){
+			mailplumb(mb, m);
 			delmessage(mb, m);
 			d++;
 		}
@@ -97,6 +115,9 @@
 		henter(PATH(0, Qtop), mb->name,
 			(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
 	}
+
+	mb->syncing = 0;
+
 	return nil;
 }
 
@@ -229,11 +250,10 @@
 	if(mb->ctl)
 		henter(PATH(mb->id, Qmbox), "ctl",
 			(Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb);
-	rv = syncmbox(mb, 0);
 	if(r)
 		*r = mb;
 
-	return rv;
+	return syncmbox(mb);
 }
 
 /* close the named mailbox */
@@ -259,7 +279,7 @@
 	Mailbox *m;
 
 	for(m = mbl; m != nil; m = m->next)
-		if(err = syncmbox(m, 1))
+		if(err = syncmbox(m))
 			eprint("syncmbox: %s\n", err);
 }
 
@@ -329,7 +349,6 @@
 void
 datesec(Mailbox *mb, Message *m)
 {
-	char *s;
 	vlong v;
 	Tm tm;
 
@@ -342,11 +361,10 @@
 	else if(rxtotm(m, &tm) >= 0)
 		v = tm2sec(&tm);
 	else{
-		s = rtab[m->type].s;
 		logmsg(gettopmsg(mb, m), "%s:%s: datasec %s %s\n", mb->path,
 			m->whole? m->whole->name: "?",
-			m->name, s);
-		if(Topmsg(mb, m) || strcmp(s, "message/rfc822") == 0)
+			m->name, m->type);
+		if(Topmsg(mb, m) || strcmp(m->type, "message/rfc822") == 0)
 			abort();
 		v = 0;
 	}
@@ -377,14 +395,12 @@
 	Message *nm, **l;
 
 	/* if there's a boundary, recurse... */
-sanemsg(m);
-//	dprint("parseattachments %p %ld\n", m->start, m->end - m->start);
+	dprint("parseattachments %p %ld bonudary %s\n", m->start, (ulong)(m->end - m->start), m->boundary);
 	if(m->boundary != nil){
 		p = m->body;
 		nm = nil;
 		l = &m->part;
 		for(i = 0;;){
-sanemsg(m);
 			x = strstr(p, m->boundary);
 			/* two sequential boundaries; ignore nil message */
 			if(nm && x == p){
@@ -401,7 +417,6 @@
 			if(x == nil){
 				if(nm != nil){
 					nm->rbend = nm->bend = nm->end = m->bend;
-sanemsg(nm);
 					if(nm->end == nm->start)
 						nm->mimeflag |= Mtrunc;
 				}
@@ -414,9 +429,7 @@
 			}
 
 			if(nm != nil)
-{
 				nm->rbend = nm->bend = nm->end = x;
-sanemsg(nm);}
 			x += strlen(m->boundary);
 
 			/* is this the last part? ignore anything after it */
@@ -435,6 +448,7 @@
 			nm->mheader = nm->header = nm->body = nm->rbody = nm->start;
 		}
 		for(nm = m->part; nm != nil; nm = nm->next){
+			nm->size = nm->end - nm->start;
 			parse(mb, nm, 0, 1);
 			cachehash(mb, nm);		/* botchy place for this */
 		}
@@ -442,7 +456,7 @@
 	}
 
 	/* if we've got an rfc822 message, recurse... */
-	if(strcmp(rtab[m->type].s, "message/rfc822") == 0){
+	if(strcmp(m->type, "message/rfc822") == 0){
 		if((nm = haschild(m, 0)) == nil){
 			nm = newmessage(m);
 			m->part = nm;
@@ -452,6 +466,7 @@
 		nm->end = nm->bend = nm->rbend = m->bend;
 		if(nm->end == nm->start)
 			nm->mimeflag |= Mtrunc;
+		nm->size = nm->end - nm->start;
 		parse(mb, nm, 0, 0);
 		cachehash(mb, nm);			/* botchy place for this */
 	}
@@ -543,16 +558,12 @@
 void
 parsebody(Message *m, Mailbox *mb)
 {
-	char *s;
-	int l;
 	Message *nm;
 
 	/* recurse */
-	s = rtab[m->type].s;
-	l = rtab[m->type].l;
-	if(l >= 10 && strncmp(s, "multipart/", 10) == 0)
+	if(strncmp(m->type, "multipart/", 10) == 0)
 		parseattachments(m, mb);
-	else if(l == 14 && strcmp(s, "message/rfc822") == 0){
+	else if(strcmp(m->type, "message/rfc822") == 0){
 		decode(m);
 		parseattachments(m, mb);
 		nm = m->part;
@@ -566,7 +577,7 @@
 			m->replyto = promote(nm->replyto);
 			m->subject = promote(nm->subject);
 		}
-	}else if(strncmp(rtab[m->type].s, "text/", 5) == 0)
+	}else if(strncmp(m->type, "text/", 5) == 0)
 		sanemsg(m);
 	m->rawbsize = m->rbend - m->rbody;
 	m->cstate |= Cbody;
@@ -651,7 +662,9 @@
 {
 	char buf[Pathlen];
 
-	free(m->filename);
+	dprint("setfilename %p %s -> %s\n", m, m->filename, p);
+	if(m->filename != nil)
+		return;
 	getstring(p, buf, buf + sizeof buf - 1, 0);
 	m->filename = smprint("%s", buf);
 	for(p = m->filename; *p; p++)
@@ -909,7 +922,7 @@
 
 	e = buf + sizeof buf - 1;
 	p = getstring(skipwhite(p + h->len), buf, e, 1);
-	m->type = newrefs(buf);
+	m->type = intern(buf);
 
 	for(; *p; p = skiptosemi(p))
 		if(isattribute(&p, "boundary")){
@@ -922,12 +935,10 @@
 			 *  the preamble, is not displayed or saved
 			 */
 		} else if(isattribute(&p, "name")){
-			if(m->filename == nil)
-				setfilename(m, p);
+			setfilename(m, p);
 		} else if(isattribute(&p, "charset")){
-			p = getstring(p, buf, e, 0);
-			lowercase(buf);
-			m->charset = newrefs(buf);
+			p = getstring(p, buf, e, 1);
+			m->charset = intern(buf);
 		}
 	return (char*)~0;
 }
@@ -971,9 +982,8 @@
 
 	m = emalloc(sizeof *m);
 	dprint("newmessage %ld	%p	%p\n", msgallocd, parent, m);
-	m->disposition = Dnone;
-	m->type = newrefs("text/plain");
-	m->charset = newrefs("iso-8859-1");
+	m->type = intern("text/plain");
+	m->charset = intern("iso-8859-1");
 	m->cstate = Cidxstale;
 	m->flags = Frecent;
 	m->id = newid();
@@ -987,7 +997,7 @@
 }
 
 /* delete a message from a mailbox */
-void
+static void
 delmessage(Mailbox *mb, Message *m)
 {
 	Message **l;
@@ -1014,8 +1024,6 @@
 			mtreedelete(mb, m);
 		cachefree(mb, m, 1);
 	}
-	delrefs(m->type);
-	delrefs(m->charset);
 	idxfree(m);
 	while(m->part)
 		delmessage(mb, m->part);
@@ -1022,9 +1030,7 @@
 	free(m->unixfrom);
 	free(m->unixheader);
 	free(m->date822);
-	free(m->inreplyto);
 	free(m->boundary);
-	free(m->filename);
 
 	free(m);
 }
@@ -1057,7 +1063,6 @@
 		for(m = mb->root->part; m != nil; m = m->next)
 			if(strcmp(m->name, av[i]) == 0){
 				if(!m->deleted){
-					mailplumb(mb, m, 1);
 					needwrite = 1;
 					m->deleted = Deleted;
 					logmsg(m, "deleting");
@@ -1065,7 +1070,7 @@
 				break;
 			}
 	if(needwrite)
-		syncmbox(mb, 1);
+		syncmbox(mb);
 	return 0;
 }
 
@@ -1095,7 +1100,7 @@
 					needwrite = 1;
 			}
 	if(needwrite)
-		syncmbox(mb, 1);
+		syncmbox(mb);
 	return rerr;
 }
 
@@ -1112,7 +1117,7 @@
 	m->refs--;
 	if(m->refs == 0){
 		if(m->deleted)
-			syncmbox(mb, 1);
+			syncmbox(mb);
 		else
 			putcache(mb, m);
 	}
@@ -1144,7 +1149,7 @@
 	assert(mb->refs > 0);
 	mb->refs--;
 	if(mb->refs == 0){
-		syncmbox(mb, 1);
+		syncmbox(mb);
 		delmessage(mb, mb->root);
 		if(mb->ctl)
 			hfree(PATH(mb->id, Qmbox), "ctl");
@@ -1187,6 +1192,7 @@
 
 	if(m->decoded)
 		return;
+	dprint("decode %d %p\n", m->encoding, m);
 	switch(m->encoding){
 	case Ebase64:
 		len = m->bend - m->body;
@@ -1197,7 +1203,7 @@
 			free(x);
 			break;
 		}
-		if(strncmp(rtab[m->type].s, "text/", 5) == 0)
+		if(strncmp(m->type, "text/", 5) == 0)
 			len = deccr(x, len);
 		if(m->ballocd)
 			free(m->body);
@@ -1231,10 +1237,11 @@
 	/* don't convert if we're not a leaf, not text, or already converted */
 	if(m->converted)
 		return;
+	dprint("convert type=%q charset=%q %p\n", m->type, m->charset, m);
 	m->converted = 1;
-	if(m->part != nil || cistrncmp(rtab[m->type].s, "text", 4) != 0)
+	if(m->part != nil || strncmp(m->type, "text", 4) != 0 || *m->charset == 0)
 		return;
-	len = xtoutf(rtab[m->charset].s, &x, m->body, m->bend);
+	len = xtoutf(m->charset, &x, m->body, m->bend);
 	if(len > 0){
 		if(m->ballocd)
 			free(m->body);
@@ -1376,9 +1383,9 @@
 	int totcs[2], fromtcs[2], n, len, sofar;
 
 	/* might not need to convert */
-	if(cistrcmp(charset, "us-ascii") == 0 || cistrcmp(charset, "utf-8") == 0)
+	if(strcmp(charset, "us-ascii") == 0 || strcmp(charset, "utf-8") == 0)
 		return 0;
-	if(cistrcmp(charset, "iso-8859-1") == 0)
+	if(strcmp(charset, "iso-8859-1") == 0)
 		return latin1toutf(out, in, e);
 
 	len = e - in + 1;
@@ -1495,16 +1502,15 @@
 	return n;
 }
 
-void
-mailplumb(Mailbox *mb, Message *m, int delete)
+static void
+mailplumb(Mailbox *mb, Message *m)
 {
 	char buf[256], dbuf[SHA1dlen*2 + 1], len[10], date[30], *from, *subject;
-	int ai, cache;
+	int ai;
 	Plumbmsg p;
 	Plumbattr a[7];
 	static int fd = -1;
 
-	cache = insurecache(mb, m) == 0;	/* living dangerously if deleted */
 	subject = m->subject;
 	if(subject == nil)
 		subject = "";
@@ -1517,15 +1523,15 @@
 		from = "";
 
 	sprint(len, "%lud", m->size);
-	if(biffing && !delete)
+	if(biffing && m->inmbox)
 		fprint(2, "[ %s / %s / %s ]\n", from, subject, len);
 	if(!plumbing)
-		goto out;
+		return;
 
 	if(fd < 0)
 		fd = plumbopen("send", OWRITE);
 	if(fd < 0)
-		goto out;
+		return;
 
 	p.src = "mailfs";
 	p.dst = "seemail";
@@ -1545,7 +1551,7 @@
 	a[ai-1].next = &a[ai];
 
 	a[++ai].name = "mailtype";
-	a[ai].value = delete? "delete": "new";
+	a[ai].value = !m->inmbox ? "delete": "new";
 	a[ai-1].next = &a[ai];
 
 	snprint(date, sizeof date, "%Δ", m->fileid);
@@ -1567,9 +1573,6 @@
 	p.data = buf;
 
 	myplumbsend(fd, &p);
-out:
-	if(cache)
-		msgdecref(mb, m);
 }
 
 /*
--- a/sys/src/cmd/upas/fs/mdir.c
+++ b/sys/src/cmd/upas/fs/mdir.c
@@ -109,9 +109,9 @@
 }
 
 static char*
-mdirread(Mdir* mdir, Mailbox* mb, int doplumb, int *new)
+mdirread(Mdir* mdir, Mailbox* mb)
 {
-	int i, nnew, ndel, fd, n, c;
+	int i, fd, n, c;
 	uvlong uv;
 	Dir *d;
 	Message *m, **ll;
@@ -127,7 +127,6 @@
 		close(fd);
 		return err;
 	}
-	*new = nnew = 0;
 	if(mb->d){
 		if(d->qid.path == mb->d->qid.path)
 		if(d->qid.vers == mb->d->qid.vers){
@@ -149,7 +148,6 @@
 	}
 
 	qsort(d, n, sizeof *d, (int(*)(void*, void*))dircmp);
-	ndel = 0;
 	ll = &mb->root->part;
 	for(i = 0; (m = *ll) != nil || i < n; ){
 		if(i < n && dirskip(d + i, &uv)){
@@ -170,7 +168,6 @@
 				i++;
 				continue;
 			}
-			nnew++;
 			m = newmessage(mb->root);
 			m->fileid = uv;
 			m->size = d[i].length;
@@ -178,15 +175,10 @@
 			m->next = *ll;
 			*ll = m;
 			ll = &m->next;
-			newcachehash(mb, m, doplumb);
-			putcache(mb, m);
 			i++;
 		}else if(c > 0){
 			/* deleted message; */
 			mdprint(mdir, "deleted: %s (%D)\n", i<n? d[i].name: 0, m? m->fileid: 0);
-			ndel++;
-			if(doplumb)
-				mailplumb(mb, m, 1);
 			m->inmbox = 0;
 			m->deleted = Disappear;
 			ll = &m->next;
@@ -196,11 +188,8 @@
 			i++;
 		}
 	}
-
 	free(d);
-	logmsg(nil, "mbox read: %d new %d deleted", nnew, ndel);
 finished:
-	*new = nnew;
 	return nil;
 }
 
@@ -220,13 +209,13 @@
 }
 
 static char*
-mdirsync(Mailbox* mb, int doplumb, int *new)
+mdirsync(Mailbox* mb)
 {
 	Mdir *mdir;
 
 	mdir = mb->aux;
 	mdprint(mdir, "mdirsync()\n");
-	return mdirread(mdir, mb, doplumb, new);
+	return mdirread(mdir, mb);
 }
 
 static char*
--- a/sys/src/cmd/upas/fs/mkfile
+++ b/sys/src/cmd/upas/fs/mkfile
@@ -14,7 +14,6 @@
 	mtree.$O\
 	plan9.$O\
 	pop3.$O\
-	ref.$O\
 	remove.$O\
 	rename.$O\
 	strtotm.$O\
@@ -36,6 +35,3 @@
 
 acid:V:
 	$CC -a $CFLAGS fs.c>a$O
-
-chkidx: mtree.$O chkidx.$O
-	$LD $LDFLAGS -o $target $prereq
--- a/sys/src/cmd/upas/fs/plan9.c
+++ b/sys/src/cmd/upas/fs/plan9.c
@@ -179,17 +179,15 @@
 int
 purgedeleted(Mailbox *mb)
 {
-	Message *m, *next;
+	Message *m;
 	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 && m->refs == 0){
-			if(m->inmbox)
-				newdels++;
-			delmessage(mb, m);
+	for(m = mb->root->part; m != nil; m = m->next){
+		if(m->deleted && m->inmbox){
+			newdels++;
+			m->inmbox = 0;
 		}
 	}
 	return newdels;
@@ -217,10 +215,9 @@
  *   read in the mailbox and parse into messages.
  */
 static char*
-readmbox(Mailbox *mb, int doplumb, int *new, Mlock *lk)
+readmbox(Mailbox *mb, Mlock *lk)
 {
 	char *p, *x, buf[Pathlen];
-	int nnew;
 	Biobuf *in;
 	Dir *d;
 	Inbuf b;
@@ -256,7 +253,6 @@
 	}
 	if(mb->d != nil){
 		if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){
-			*new = 0;
 			Bterm(in);
 			free(d);
 			return nil;
@@ -276,7 +272,6 @@
 
 	/*  read new messages */
 	logmsg(nil, "reading %s", mb->path);
-	nnew = 0;
 	for(;;){
 		if(lk != nil)
 			syslockrefresh(lk);
@@ -306,8 +301,6 @@
 			} else {
 				/* old mail no longer in box, mark deleted */
 				logmsg(*l, "disappeared");
-				if(doplumb)
-					mailplumb(mb, *l, 1);
 				(*l)->inmbox = 0;
 				(*l)->deleted = Disappear;
 				l = &(*l)->next;
@@ -324,9 +317,6 @@
 		parse(mb, m, 0, 0);
 		if(m != *l && m->deleted != Dup){
 			logmsg(m, "new");
-			newcachehash(mb, m, doplumb);
-			putcache(mb, m);
-			nnew++;
 		}
 		/* chain in */
 		*l = m;
@@ -336,8 +326,6 @@
 
 	/* whatever is left has been removed from the mbox, mark deleted */
 	while(*l != nil){
-		if(doplumb)
-			mailplumb(mb, *l, 1);
 		(*l)->inmbox = 0;
 		(*l)->deleted = Deleted;
 		l = &(*l)->next;
@@ -344,7 +332,6 @@
 	}
 
 	Bterm(in);
-	*new = nnew;
 	return nil;
 }
 
@@ -408,7 +395,7 @@
 }
 
 char*
-plan9syncmbox(Mailbox *mb, int doplumb, int *new)
+plan9syncmbox(Mailbox *mb)
 {
 	char *rv;
 	Mlock *lk;
@@ -420,7 +407,7 @@
 			return "can't lock mailbox";
 	}
 
-	rv = readmbox(mb, doplumb, new, lk);		/* interpolate */
+	rv = readmbox(mb, lk);		/* interpolate */
 	if(purgedeleted(mb) > 0)
 		writembox(mb, lk);
 
--- a/sys/src/cmd/upas/fs/pop3.c
+++ b/sys/src/cmd/upas/fs/pop3.c
@@ -359,14 +359,13 @@
  *  we'll use it to make our lives easier.
  */
 static char*
-pop3read(Pop *pop, Mailbox *mb, int doplumb, int *new)
+pop3read(Pop *pop, Mailbox *mb)
 {
 	char *s, *p, *uidl, *f[2];
-	int mno, ignore, nnew;
+	int mno, ignore;
 	Message *m, *next, **l;
 	Popm *a;
 
-	*new = 0;
 	/* Some POP servers disallow UIDL if the maildrop is empty. */
 	pop3cmd(pop, "STAT");
 	if(!isokay(s = pop3resp(pop)))
@@ -409,8 +408,6 @@
 					break;
 				}else{
 					/* old mail no longer in box mark deleted */
-					if(doplumb)
-						mailplumb(mb, *l, 1);
 					(*l)->inmbox = 0;
 					(*l)->deleted = Deleted;
 					l = &(*l)->next;
@@ -434,8 +431,6 @@
 
 	/* whatever is left has been removed from the mbox, mark as deleted */
 	while(*l != nil) {
-		if(doplumb)
-			mailplumb(mb, *l, 1);
 		(*l)->inmbox = 0;
 		(*l)->deleted = Disappear;
 		l = &(*l)->next;
@@ -442,7 +437,6 @@
 	}
 
 	/* download new messages */
-	nnew = 0;
 	if(pop->pipeline){
 		switch(rfork(RFPROC|RFMEM)){
 		case -1:
@@ -469,20 +463,14 @@
 		if(m->start != nil || m->deleted)
 			continue;
 		if(s = pop3download(mb, pop, m)) {
-			/* message disappeared? unchain */
 			eprint("pop3: download %d: %s\n", mesgno(m), s);
-			delmessage(mb, m);
-			mb->root->subname--;
+			unnewmessage(mb, mb->root, m);
 			continue;
 		}
-		nnew++;
 		parse(mb, m, 1, 0);
-		newcachehash(mb, m, doplumb);
-		putcache(mb, m);
 	}
 	if(pop->pipeline)
 		waitpid();
-	*new = nnew;
 	return nil;	
 }
 
@@ -492,7 +480,7 @@
 static void
 pop3purge(Pop *pop, Mailbox *mb)
 {
-	Message *m, *next;
+	Message *m;
 
 	if(pop->pipeline){
 		switch(rfork(RFPROC|RFMEM)){
@@ -504,27 +492,21 @@
 			break;
 
 		case 0:
-			for(m = mb->root->part; m != nil; m = next){
-				next = m->next;
-				if(m->deleted && m->refs == 0){
-					if(m->inmbox)
-						Bprint(&pop->bout, "DELE %d\r\n", mesgno(m));
-				}
+			for(m = mb->root->part; m != nil; m = m->next){
+				if(m->deleted && m->inmbox)
+					Bprint(&pop->bout, "DELE %d\r\n", mesgno(m));
 			}
 			Bflush(&pop->bout);
 			_exits("");
 		}
 	}
-	for(m = mb->root->part; m != nil; m = next) {
-		next = m->next;
-		if(m->deleted && m->refs == 0) {
-			if(m->inmbox) {
-				if(!pop->pipeline)
-					pop3cmd(pop, "DELE %d", mesgno(m));
-				if(isokay(pop3resp(pop)))
-					delmessage(mb, m);
-			} else
-				delmessage(mb, m);
+	for(m = mb->root->part; m != nil; m = m->next) {
+		if(m->deleted && m->inmbox) {
+			if(!pop->pipeline)
+				pop3cmd(pop, "DELE %d", mesgno(m));
+			if(!isokay(pop3resp(pop)))
+				continue;
+			m->inmbox = 0;
 		}
 	}
 }
@@ -532,16 +514,15 @@
 
 /* connect to pop3 server, sync mailbox */
 static char*
-pop3sync(Mailbox *mb, int doplumb, int *new)
+pop3sync(Mailbox *mb)
 {
 	char *err;
 	Pop *pop;
 
 	pop = mb->aux;
-
 	if(err = pop3dial(pop))
 		goto out;
-	if((err = pop3read(pop, mb, doplumb, new)) == nil)
+	if((err = pop3read(pop, mb)) == nil)
 		pop3purge(pop, mb);
 	pop3hangup(pop);
 out:
--- a/sys/src/cmd/upas/fs/ref.c
+++ /dev/null
@@ -1,100 +1,0 @@
-#include "common.h"
-#include <libsec.h>
-#include "dat.h"
-
-/* all the data that's fit to cache */
-
-typedef struct{
-	char	*s;
-	int	l;
-	ulong	ref;
-}Refs;
-
-Refs	*rtab;
-int	nrtab;
-int	nralloc;
-
-int
-newrefs(char *s)
-{
-	int l, i;
-	Refs *r;
-
-	l = strlen(s);
-	for(i = 0; i < nrtab; i++){
-		r = rtab + i;
-		if(r->ref == 0)
-			goto enter;
-		if(l == r->l && strcmp(r->s, s) == 0){
-			r->ref++;
-			return i;
-		}
-	}
-	if(nrtab == nralloc)
-		rtab = erealloc(rtab, sizeof *rtab*(nralloc += 50));
-	nrtab = i + 1;
-enter:
-	r = rtab + i;
-	r->s = strdup(s);
-	r->l = l;
-	r->ref = 1;
-	return i;
-}
-
-void
-delrefs(int i)
-{
-	Refs *r;
-
-	r = rtab + i;
-	if(--r->ref > 0)
-		return;
-	free(r->s);
-	memset(r, 0, sizeof *r);
-}
-
-void
-refsinit(void)
-{
-	newrefs("");
-}
-
-static char *sep = "--------\n";
-
-int
-prrefs(Biobuf *b)
-{
-	int i, n;
-
-	n = 0;
-	for(i = 1; i < nrtab; i++){
-		if(rtab[i].ref == 0)
-			continue;
-		Bprint(b, "%s ", rtab[i].s);
-		if(n++%8 == 7)
-			Bprint(b, "\n");
-	}
-	if(n%8 != 7)
-		Bprint(b, "\n");
-	Bprint(b, sep);
-	return 0;
-}
-
-int
-rdrefs(Biobuf *b)
-{
-	char *f[10], *s;
-	int i, n;
-
-	while(s = Brdstr(b, '\n', 1)){
-		if(strcmp(s, sep) == 0){
-			free(s);
-			return 0;
-		}
-		n = tokenize(s, f, nelem(f));
-		for(i = 0; i < n; i++)
-			newrefs(f[i]);
-		free(s);
-	}
-	return -1;
-}