xref: /plan9/sys/src/cmd/upas/fs/plan9.c (revision 21887c0b3fa083db468c32f3247dbe932cf708df)
180ee5cbfSDavid du Colombier #include "common.h"
280ee5cbfSDavid du Colombier #include <ctype.h>
380ee5cbfSDavid du Colombier #include <plumb.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier #include "dat.h"
680ee5cbfSDavid du Colombier 
780ee5cbfSDavid du Colombier enum {
880ee5cbfSDavid du Colombier 	Buffersize = 64*1024,
980ee5cbfSDavid du Colombier };
1080ee5cbfSDavid du Colombier 
1180ee5cbfSDavid du Colombier typedef struct Inbuf Inbuf;
1280ee5cbfSDavid du Colombier struct Inbuf
1380ee5cbfSDavid du Colombier {
1480ee5cbfSDavid du Colombier 	int	fd;
1580ee5cbfSDavid du Colombier 	uchar	*lim;
1680ee5cbfSDavid du Colombier 	uchar	*rptr;
1780ee5cbfSDavid du Colombier 	uchar	*wptr;
1880ee5cbfSDavid du Colombier 	uchar	data[Buffersize+7];
1980ee5cbfSDavid du Colombier };
2080ee5cbfSDavid du Colombier 
2180ee5cbfSDavid du Colombier static void
2280ee5cbfSDavid du Colombier addtomessage(Message *m, uchar *p, int n, int done)
2380ee5cbfSDavid du Colombier {
2480ee5cbfSDavid du Colombier 	int i, len;
2580ee5cbfSDavid du Colombier 
263e748dfcSDavid du Colombier 	// add to message (+1 in malloc is for a trailing NUL)
2780ee5cbfSDavid du Colombier 	if(m->lim - m->end < n){
2880ee5cbfSDavid du Colombier 		if(m->start != nil){
2980ee5cbfSDavid du Colombier 			i = m->end-m->start;
3080ee5cbfSDavid du Colombier 			if(done)
3180ee5cbfSDavid du Colombier 				len = i + n;
3280ee5cbfSDavid du Colombier 			else
3380ee5cbfSDavid du Colombier 				len = (4*(i+n))/3;
3480ee5cbfSDavid du Colombier 			m->start = erealloc(m->start, len + 1);
3580ee5cbfSDavid du Colombier 			m->end = m->start + i;
3680ee5cbfSDavid du Colombier 		} else {
3780ee5cbfSDavid du Colombier 			if(done)
3880ee5cbfSDavid du Colombier 				len = n;
3980ee5cbfSDavid du Colombier 			else
4080ee5cbfSDavid du Colombier 				len = 2*n;
4180ee5cbfSDavid du Colombier 			m->start = emalloc(len + 1);
4280ee5cbfSDavid du Colombier 			m->end = m->start;
4380ee5cbfSDavid du Colombier 		}
4480ee5cbfSDavid du Colombier 		m->lim = m->start + len;
45901d8e21SDavid du Colombier 		*m->lim = '\0';
4680ee5cbfSDavid du Colombier 	}
4780ee5cbfSDavid du Colombier 
4880ee5cbfSDavid du Colombier 	memmove(m->end, p, n);
4980ee5cbfSDavid du Colombier 	m->end += n;
50901d8e21SDavid du Colombier 	*m->end = '\0';
5180ee5cbfSDavid du Colombier }
5280ee5cbfSDavid du Colombier 
5380ee5cbfSDavid du Colombier //
5480ee5cbfSDavid du Colombier //  read in a single message
5580ee5cbfSDavid du Colombier //
5680ee5cbfSDavid du Colombier static int
5780ee5cbfSDavid du Colombier readmessage(Message *m, Inbuf *inb)
5880ee5cbfSDavid du Colombier {
5980ee5cbfSDavid du Colombier 	int i, n, done;
6080ee5cbfSDavid du Colombier 	uchar *p, *np;
6180ee5cbfSDavid du Colombier 	char sdigest[SHA1dlen*2+1];
629a747e4fSDavid du Colombier 	char tmp[64];
6380ee5cbfSDavid du Colombier 
6480ee5cbfSDavid du Colombier 	for(done = 0; !done;){
6580ee5cbfSDavid du Colombier 		n = inb->wptr - inb->rptr;
6680ee5cbfSDavid du Colombier 		if(n < 6){
6780ee5cbfSDavid du Colombier 			if(n)
6880ee5cbfSDavid du Colombier 				memmove(inb->data, inb->rptr, n);
6980ee5cbfSDavid du Colombier 			inb->rptr = inb->data;
7080ee5cbfSDavid du Colombier 			inb->wptr = inb->rptr + n;
7180ee5cbfSDavid du Colombier 			i = read(inb->fd, inb->wptr, Buffersize);
7280ee5cbfSDavid du Colombier 			if(i < 0){
739a747e4fSDavid du Colombier 				if(fd2path(inb->fd, tmp, sizeof tmp) < 0)
749a747e4fSDavid du Colombier 					strcpy(tmp, "unknown mailbox");
759a747e4fSDavid du Colombier 				fprint(2, "error reading '%s': %r\n", tmp);
7680ee5cbfSDavid du Colombier 				return -1;
7780ee5cbfSDavid du Colombier 			}
7880ee5cbfSDavid du Colombier 			if(i == 0){
7980ee5cbfSDavid du Colombier 				if(n != 0)
8080ee5cbfSDavid du Colombier 					addtomessage(m, inb->rptr, n, 1);
8180ee5cbfSDavid du Colombier 				if(m->end == m->start)
8280ee5cbfSDavid du Colombier 					return -1;
8380ee5cbfSDavid du Colombier 				break;
8480ee5cbfSDavid du Colombier 			}
8580ee5cbfSDavid du Colombier 			inb->wptr += i;
8680ee5cbfSDavid du Colombier 		}
8780ee5cbfSDavid du Colombier 
8880ee5cbfSDavid du Colombier 		// look for end of message
8980ee5cbfSDavid du Colombier 		for(p = inb->rptr; p < inb->wptr; p = np+1){
9080ee5cbfSDavid du Colombier 			// first part of search for '\nFrom '
9180ee5cbfSDavid du Colombier 			np = memchr(p, '\n', inb->wptr - p);
9280ee5cbfSDavid du Colombier 			if(np == nil){
9380ee5cbfSDavid du Colombier 				p = inb->wptr;
9480ee5cbfSDavid du Colombier 				break;
9580ee5cbfSDavid du Colombier 			}
9680ee5cbfSDavid du Colombier 
9780ee5cbfSDavid du Colombier 			/*
9880ee5cbfSDavid du Colombier 			 *  if we've found a \n but there's
9980ee5cbfSDavid du Colombier 			 *  not enough room for '\nFrom ', don't do
10080ee5cbfSDavid du Colombier 			 *  the comparison till we've read in more.
10180ee5cbfSDavid du Colombier 			 */
10280ee5cbfSDavid du Colombier 			if(inb->wptr - np < 6){
10380ee5cbfSDavid du Colombier 				p = np;
10480ee5cbfSDavid du Colombier 				break;
10580ee5cbfSDavid du Colombier 			}
10680ee5cbfSDavid du Colombier 
10780ee5cbfSDavid du Colombier 			if(strncmp((char*)np, "\nFrom ", 6) == 0){
10880ee5cbfSDavid du Colombier 				done = 1;
10980ee5cbfSDavid du Colombier 				p = np+1;
11080ee5cbfSDavid du Colombier 				break;
11180ee5cbfSDavid du Colombier 			}
11280ee5cbfSDavid du Colombier 		}
11380ee5cbfSDavid du Colombier 
11480ee5cbfSDavid du Colombier 		// add to message (+ 1 in malloc is for a trailing null)
11580ee5cbfSDavid du Colombier 		n = p - inb->rptr;
11680ee5cbfSDavid du Colombier 		addtomessage(m, inb->rptr, n, done);
11780ee5cbfSDavid du Colombier 		inb->rptr += n;
11880ee5cbfSDavid du Colombier 	}
11980ee5cbfSDavid du Colombier 
12080ee5cbfSDavid du Colombier 	// if it doesn't start with a 'From ', this ain't a mailbox
12180ee5cbfSDavid du Colombier 	if(strncmp(m->start, "From ", 5) != 0)
12280ee5cbfSDavid du Colombier 		return -1;
12380ee5cbfSDavid du Colombier 
12480ee5cbfSDavid du Colombier 	// dump trailing newline, make sure there's a trailing null
12580ee5cbfSDavid du Colombier 	// (helps in body searches)
12680ee5cbfSDavid du Colombier 	if(*(m->end-1) == '\n')
12780ee5cbfSDavid du Colombier 		m->end--;
12880ee5cbfSDavid du Colombier 	*m->end = 0;
12980ee5cbfSDavid du Colombier 	m->bend = m->rbend = m->end;
13080ee5cbfSDavid du Colombier 
13180ee5cbfSDavid du Colombier 	// digest message
13280ee5cbfSDavid du Colombier 	sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
13380ee5cbfSDavid du Colombier 	for(i = 0; i < SHA1dlen; i++)
13480ee5cbfSDavid du Colombier 		sprint(sdigest+2*i, "%2.2ux", m->digest[i]);
13580ee5cbfSDavid du Colombier 	m->sdigest = s_copy(sdigest);
13680ee5cbfSDavid du Colombier 
13780ee5cbfSDavid du Colombier 	return 0;
13880ee5cbfSDavid du Colombier }
13980ee5cbfSDavid du Colombier 
14080ee5cbfSDavid du Colombier 
14180ee5cbfSDavid du Colombier // throw out deleted messages.  return number of freshly deleted messages
14280ee5cbfSDavid du Colombier int
14380ee5cbfSDavid du Colombier purgedeleted(Mailbox *mb)
14480ee5cbfSDavid du Colombier {
14580ee5cbfSDavid du Colombier 	Message *m, *next;
14680ee5cbfSDavid du Colombier 	int newdels;
14780ee5cbfSDavid du Colombier 
14880ee5cbfSDavid du Colombier 	// forget about what's no longer in the mailbox
14980ee5cbfSDavid du Colombier 	newdels = 0;
15080ee5cbfSDavid du Colombier 	for(m = mb->root->part; m != nil; m = next){
15180ee5cbfSDavid du Colombier 		next = m->next;
15280ee5cbfSDavid du Colombier 		if(m->deleted && m->refs == 0){
15380ee5cbfSDavid du Colombier 			if(m->inmbox)
15480ee5cbfSDavid du Colombier 				newdels++;
15580ee5cbfSDavid du Colombier 			delmessage(mb, m);
15680ee5cbfSDavid du Colombier 		}
15780ee5cbfSDavid du Colombier 	}
15880ee5cbfSDavid du Colombier 	return newdels;
15980ee5cbfSDavid du Colombier }
16080ee5cbfSDavid du Colombier 
16180ee5cbfSDavid du Colombier //
16280ee5cbfSDavid du Colombier //  read in the mailbox and parse into messages.
16380ee5cbfSDavid du Colombier //
16480ee5cbfSDavid du Colombier static char*
16580ee5cbfSDavid du Colombier _readmbox(Mailbox *mb, int doplumb, Mlock *lk)
16680ee5cbfSDavid du Colombier {
1673b86f2f8SDavid du Colombier 	int fd, n;
16880ee5cbfSDavid du Colombier 	String *tmp;
1699a747e4fSDavid du Colombier 	Dir *d;
170*21887c0bSDavid du Colombier 	static char err[Errlen];
17180ee5cbfSDavid du Colombier 	Message *m, **l;
17280ee5cbfSDavid du Colombier 	Inbuf *inb;
17380ee5cbfSDavid du Colombier 	char *x;
17480ee5cbfSDavid du Colombier 
17580ee5cbfSDavid du Colombier 	l = &mb->root->part;
17680ee5cbfSDavid du Colombier 
17780ee5cbfSDavid du Colombier 	/*
17880ee5cbfSDavid du Colombier 	 *  open the mailbox.  If it doesn't exist, try the temporary one.
17980ee5cbfSDavid du Colombier 	 */
1803b86f2f8SDavid du Colombier 	n = 0;
18180ee5cbfSDavid du Colombier retry:
18280ee5cbfSDavid du Colombier 	fd = open(mb->path, OREAD);
18380ee5cbfSDavid du Colombier 	if(fd < 0){
1843b86f2f8SDavid du Colombier 		rerrstr(err, sizeof(err));
1853b86f2f8SDavid du Colombier 		if(strstr(err, "exclusive lock") != 0 && n++ < 20){
1863b86f2f8SDavid du Colombier 			sleep(500);	/* wait for lock to go away */
1873b86f2f8SDavid du Colombier 			goto retry;
1883b86f2f8SDavid du Colombier 		}
18980ee5cbfSDavid du Colombier 		if(strstr(err, "exist") != 0){
19080ee5cbfSDavid du Colombier 			tmp = s_copy(mb->path);
19180ee5cbfSDavid du Colombier 			s_append(tmp, ".tmp");
19280ee5cbfSDavid du Colombier 			if(sysrename(s_to_c(tmp), mb->path) == 0){
19380ee5cbfSDavid du Colombier 				s_free(tmp);
19480ee5cbfSDavid du Colombier 				goto retry;
19580ee5cbfSDavid du Colombier 			}
19680ee5cbfSDavid du Colombier 			s_free(tmp);
19780ee5cbfSDavid du Colombier 		}
19880ee5cbfSDavid du Colombier 		return err;
19980ee5cbfSDavid du Colombier 	}
20080ee5cbfSDavid du Colombier 
20180ee5cbfSDavid du Colombier 	/*
20280ee5cbfSDavid du Colombier 	 *  a new qid.path means reread the mailbox, while
20380ee5cbfSDavid du Colombier 	 *  a new qid.vers means read any new messages
20480ee5cbfSDavid du Colombier 	 */
2059a747e4fSDavid du Colombier 	d = dirfstat(fd);
2069a747e4fSDavid du Colombier 	if(d == nil){
20780ee5cbfSDavid du Colombier 		close(fd);
2089a747e4fSDavid du Colombier 		errstr(err, sizeof(err));
20980ee5cbfSDavid du Colombier 		return err;
21080ee5cbfSDavid du Colombier 	}
2119a747e4fSDavid du Colombier 	if(mb->d != nil){
2129a747e4fSDavid du Colombier 		if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){
21380ee5cbfSDavid du Colombier 			close(fd);
2149a747e4fSDavid du Colombier 			free(d);
21580ee5cbfSDavid du Colombier 			return nil;
21680ee5cbfSDavid du Colombier 		}
2179a747e4fSDavid du Colombier 		if(d->qid.path == mb->d->qid.path){
21880ee5cbfSDavid du Colombier 			while(*l != nil)
21980ee5cbfSDavid du Colombier 				l = &(*l)->next;
2209a747e4fSDavid du Colombier 			seek(fd, mb->d->length, 0);
22180ee5cbfSDavid du Colombier 		}
2229a747e4fSDavid du Colombier 		free(mb->d);
2239a747e4fSDavid du Colombier 	}
2249a747e4fSDavid du Colombier 	mb->d = d;
22580ee5cbfSDavid du Colombier 	mb->vers++;
2269a747e4fSDavid du Colombier 	henter(PATH(0, Qtop), mb->name,
2279a747e4fSDavid du Colombier 		(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
22880ee5cbfSDavid du Colombier 
22980ee5cbfSDavid du Colombier 	inb = emalloc(sizeof(Inbuf));
23080ee5cbfSDavid du Colombier 	inb->rptr = inb->wptr = inb->data;
23180ee5cbfSDavid du Colombier 	inb->fd = fd;
23280ee5cbfSDavid du Colombier 
23380ee5cbfSDavid du Colombier 	//  read new messages
2349a747e4fSDavid du Colombier 	snprint(err, sizeof err, "reading '%s'", mb->path);
2359a747e4fSDavid du Colombier 	logmsg(err, nil);
23680ee5cbfSDavid du Colombier 	for(;;){
23780ee5cbfSDavid du Colombier 		if(lk != nil)
23880ee5cbfSDavid du Colombier 			syslockrefresh(lk);
23980ee5cbfSDavid du Colombier 		m = newmessage(mb->root);
24080ee5cbfSDavid du Colombier 		m->mallocd = 1;
24180ee5cbfSDavid du Colombier 		m->inmbox = 1;
24280ee5cbfSDavid du Colombier 		if(readmessage(m, inb) < 0){
24380ee5cbfSDavid du Colombier 			delmessage(mb, m);
24480ee5cbfSDavid du Colombier 			mb->root->subname--;
24580ee5cbfSDavid du Colombier 			break;
24680ee5cbfSDavid du Colombier 		}
24780ee5cbfSDavid du Colombier 
24880ee5cbfSDavid du Colombier 		// merge mailbox versions
24980ee5cbfSDavid du Colombier 		while(*l != nil){
25080ee5cbfSDavid du Colombier 			if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){
25180ee5cbfSDavid du Colombier 				// matches mail we already read, discard
25280ee5cbfSDavid du Colombier 				logmsg("duplicate", *l);
25380ee5cbfSDavid du Colombier 				delmessage(mb, m);
25480ee5cbfSDavid du Colombier 				mb->root->subname--;
25580ee5cbfSDavid du Colombier 				m = nil;
25680ee5cbfSDavid du Colombier 				l = &(*l)->next;
25780ee5cbfSDavid du Colombier 				break;
25880ee5cbfSDavid du Colombier 			} else {
25980ee5cbfSDavid du Colombier 				// old mail no longer in box, mark deleted
26080ee5cbfSDavid du Colombier 				logmsg("disappeared", *l);
26180ee5cbfSDavid du Colombier 				if(doplumb)
26280ee5cbfSDavid du Colombier 					mailplumb(mb, *l, 1);
26380ee5cbfSDavid du Colombier 				(*l)->inmbox = 0;
26480ee5cbfSDavid du Colombier 				(*l)->deleted = 1;
26580ee5cbfSDavid du Colombier 				l = &(*l)->next;
26680ee5cbfSDavid du Colombier 			}
26780ee5cbfSDavid du Colombier 		}
26880ee5cbfSDavid du Colombier 		if(m == nil)
26980ee5cbfSDavid du Colombier 			continue;
27080ee5cbfSDavid du Colombier 
27180ee5cbfSDavid du Colombier 		x = strchr(m->start, '\n');
27280ee5cbfSDavid du Colombier 		if(x == nil)
27380ee5cbfSDavid du Colombier 			m->header = m->end;
27480ee5cbfSDavid du Colombier 		else
27580ee5cbfSDavid du Colombier 			m->header = x + 1;
27680ee5cbfSDavid du Colombier 		m->mheader = m->mhend = m->header;
27780ee5cbfSDavid du Colombier 		parseunix(m);
2787a02f3c0SDavid du Colombier 		parse(m, 0, mb, 0);
27980ee5cbfSDavid du Colombier 		logmsg("new", m);
28080ee5cbfSDavid du Colombier 
28180ee5cbfSDavid du Colombier 		/* chain in */
28280ee5cbfSDavid du Colombier 		*l = m;
28380ee5cbfSDavid du Colombier 		l = &m->next;
28480ee5cbfSDavid du Colombier 		if(doplumb)
28580ee5cbfSDavid du Colombier 			mailplumb(mb, m, 0);
28680ee5cbfSDavid du Colombier 
28780ee5cbfSDavid du Colombier 	}
28880ee5cbfSDavid du Colombier 	logmsg("mbox read", nil);
28980ee5cbfSDavid du Colombier 
29080ee5cbfSDavid du Colombier 	// whatever is left has been removed from the mbox, mark deleted
29180ee5cbfSDavid du Colombier 	while(*l != nil){
29280ee5cbfSDavid du Colombier 		if(doplumb)
29380ee5cbfSDavid du Colombier 			mailplumb(mb, *l, 1);
29480ee5cbfSDavid du Colombier 		(*l)->inmbox = 0;
29580ee5cbfSDavid du Colombier 		(*l)->deleted = 1;
29680ee5cbfSDavid du Colombier 		l = &(*l)->next;
29780ee5cbfSDavid du Colombier 	}
29880ee5cbfSDavid du Colombier 
29980ee5cbfSDavid du Colombier 	close(fd);
30080ee5cbfSDavid du Colombier 	free(inb);
30180ee5cbfSDavid du Colombier 	return nil;
30280ee5cbfSDavid du Colombier }
30380ee5cbfSDavid du Colombier 
30480ee5cbfSDavid du Colombier static void
30580ee5cbfSDavid du Colombier _writembox(Mailbox *mb, Mlock *lk)
30680ee5cbfSDavid du Colombier {
3079a747e4fSDavid du Colombier 	Dir *d;
30880ee5cbfSDavid du Colombier 	Message *m;
30980ee5cbfSDavid du Colombier 	String *tmp;
31080ee5cbfSDavid du Colombier 	int mode, errs;
31180ee5cbfSDavid du Colombier 	Biobuf *b;
31280ee5cbfSDavid du Colombier 
31380ee5cbfSDavid du Colombier 	tmp = s_copy(mb->path);
31480ee5cbfSDavid du Colombier 	s_append(tmp, ".tmp");
31580ee5cbfSDavid du Colombier 
31680ee5cbfSDavid du Colombier 	/*
31780ee5cbfSDavid du Colombier 	 * preserve old files permissions, if possible
31880ee5cbfSDavid du Colombier 	 */
3199a747e4fSDavid du Colombier 	d = dirstat(mb->path);
3209a747e4fSDavid du Colombier 	if(d != nil){
3219a747e4fSDavid du Colombier 		mode = d->mode&0777;
3229a747e4fSDavid du Colombier 		free(d);
3239a747e4fSDavid du Colombier 	} else
32480ee5cbfSDavid du Colombier 		mode = MBOXMODE;
32580ee5cbfSDavid du Colombier 
32680ee5cbfSDavid du Colombier 	sysremove(s_to_c(tmp));
32780ee5cbfSDavid du Colombier 	b = sysopen(s_to_c(tmp), "alc", mode);
32880ee5cbfSDavid du Colombier 	if(b == 0){
32980ee5cbfSDavid du Colombier 		fprint(2, "can't write temporary mailbox %s: %r\n", s_to_c(tmp));
33080ee5cbfSDavid du Colombier 		return;
33180ee5cbfSDavid du Colombier 	}
33280ee5cbfSDavid du Colombier 
33380ee5cbfSDavid du Colombier 	logmsg("writing new mbox", nil);
33480ee5cbfSDavid du Colombier 	errs = 0;
33580ee5cbfSDavid du Colombier 	for(m = mb->root->part; m != nil; m = m->next){
33680ee5cbfSDavid du Colombier 		if(lk != nil)
33780ee5cbfSDavid du Colombier 			syslockrefresh(lk);
33880ee5cbfSDavid du Colombier 		if(m->deleted)
33980ee5cbfSDavid du Colombier 			continue;
34080ee5cbfSDavid du Colombier 		logmsg("writing", m);
34180ee5cbfSDavid du Colombier 		if(Bwrite(b, m->start, m->end - m->start) < 0)
34280ee5cbfSDavid du Colombier 			errs = 1;
34380ee5cbfSDavid du Colombier 		if(Bwrite(b, "\n", 1) < 0)
34480ee5cbfSDavid du Colombier 			errs = 1;
34580ee5cbfSDavid du Colombier 	}
34680ee5cbfSDavid du Colombier 	logmsg("wrote new mbox", nil);
34780ee5cbfSDavid du Colombier 
34880ee5cbfSDavid du Colombier 	if(sysclose(b) < 0)
34980ee5cbfSDavid du Colombier 		errs = 1;
35080ee5cbfSDavid du Colombier 
35180ee5cbfSDavid du Colombier 	if(errs){
35280ee5cbfSDavid du Colombier 		fprint(2, "error writing temporary mail file\n");
35380ee5cbfSDavid du Colombier 		s_free(tmp);
35480ee5cbfSDavid du Colombier 		return;
35580ee5cbfSDavid du Colombier 	}
35680ee5cbfSDavid du Colombier 
35780ee5cbfSDavid du Colombier 	sysremove(mb->path);
35880ee5cbfSDavid du Colombier 	if(sysrename(s_to_c(tmp), mb->path) < 0)
35980ee5cbfSDavid du Colombier 		fprint(2, "%s: can't rename %s to %s: %r\n", argv0,
36080ee5cbfSDavid du Colombier 			s_to_c(tmp), mb->path);
36180ee5cbfSDavid du Colombier 	s_free(tmp);
3629a747e4fSDavid du Colombier 	if(mb->d != nil)
3639a747e4fSDavid du Colombier 		free(mb->d);
3649a747e4fSDavid du Colombier 	mb->d = dirstat(mb->path);
36580ee5cbfSDavid du Colombier }
36680ee5cbfSDavid du Colombier 
36780ee5cbfSDavid du Colombier char*
36880ee5cbfSDavid du Colombier plan9syncmbox(Mailbox *mb, int doplumb)
36980ee5cbfSDavid du Colombier {
37080ee5cbfSDavid du Colombier 	Mlock *lk;
37180ee5cbfSDavid du Colombier 	char *rv;
37280ee5cbfSDavid du Colombier 
37380ee5cbfSDavid du Colombier 	lk = nil;
37480ee5cbfSDavid du Colombier 	if(mb->dolock){
375ed250ae1SDavid du Colombier 		lk = syslock(mb->path);
37680ee5cbfSDavid du Colombier 		if(lk == nil)
37780ee5cbfSDavid du Colombier 			return "can't lock mailbox";
37880ee5cbfSDavid du Colombier 	}
37980ee5cbfSDavid du Colombier 
38080ee5cbfSDavid du Colombier 	rv = _readmbox(mb, doplumb, lk);		/* interpolate */
38180ee5cbfSDavid du Colombier 	if(purgedeleted(mb) > 0)
38280ee5cbfSDavid du Colombier 		_writembox(mb, lk);
38380ee5cbfSDavid du Colombier 
38480ee5cbfSDavid du Colombier 	if(lk != nil)
38580ee5cbfSDavid du Colombier 		sysunlock(lk);
38680ee5cbfSDavid du Colombier 
38780ee5cbfSDavid du Colombier 	return rv;
38880ee5cbfSDavid du Colombier }
38980ee5cbfSDavid du Colombier 
39080ee5cbfSDavid du Colombier //
39180ee5cbfSDavid du Colombier //  look to see if we can open this mail box
39280ee5cbfSDavid du Colombier //
39380ee5cbfSDavid du Colombier char*
39480ee5cbfSDavid du Colombier plan9mbox(Mailbox *mb, char *path)
39580ee5cbfSDavid du Colombier {
396*21887c0bSDavid du Colombier 	static char err[Errlen];
39780ee5cbfSDavid du Colombier 	String *tmp;
39880ee5cbfSDavid du Colombier 
39980ee5cbfSDavid du Colombier 	if(access(path, AEXIST) < 0){
4009a747e4fSDavid du Colombier 		errstr(err, sizeof(err));
40180ee5cbfSDavid du Colombier 		tmp = s_copy(path);
40280ee5cbfSDavid du Colombier 		s_append(tmp, ".tmp");
40380ee5cbfSDavid du Colombier 		if(access(s_to_c(tmp), AEXIST) < 0){
40480ee5cbfSDavid du Colombier 			s_free(tmp);
40580ee5cbfSDavid du Colombier 			return err;
40680ee5cbfSDavid du Colombier 		}
40780ee5cbfSDavid du Colombier 		s_free(tmp);
40880ee5cbfSDavid du Colombier 	}
40980ee5cbfSDavid du Colombier 
41080ee5cbfSDavid du Colombier 	mb->sync = plan9syncmbox;
41180ee5cbfSDavid du Colombier 	return nil;
41280ee5cbfSDavid du Colombier }
413