xref: /plan9/sys/src/cmd/upas/fs/fs.c (revision 901d8e213ab012b55016953db878424fee53d285)
17dd7cddfSDavid du Colombier #include "common.h"
27dd7cddfSDavid du Colombier #include <auth.h>
37dd7cddfSDavid du Colombier #include <fcall.h>
47dd7cddfSDavid du Colombier #include <libsec.h>
5816336a7SDavid du Colombier #include <ctype.h>
67dd7cddfSDavid du Colombier #include "dat.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier enum
97dd7cddfSDavid du Colombier {
107dd7cddfSDavid du Colombier 	OPERM	= 0x3,		// mask of all permission types in open mode
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct Fid Fid;
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier struct Fid
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	Qid	qid;
187dd7cddfSDavid du Colombier 	short	busy;
197dd7cddfSDavid du Colombier 	short	open;
207dd7cddfSDavid du Colombier 	int	fid;
217dd7cddfSDavid du Colombier 	Fid	*next;
227dd7cddfSDavid du Colombier 	Mailbox	*mb;
237dd7cddfSDavid du Colombier 	Message	*m;
247dd7cddfSDavid du Colombier 	Message *mtop;		// top level message
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier 	//finger pointers to speed up reads of large directories
277dd7cddfSDavid du Colombier 	long	foff;	// offset/DIRLEN of finger
287dd7cddfSDavid du Colombier 	Message	*fptr;	// pointer to message at off
297dd7cddfSDavid du Colombier 	int	fvers;	// mailbox version when finger was saved
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier ulong	path;		// incremented for each new file
337dd7cddfSDavid du Colombier Fid	*fids;
347dd7cddfSDavid du Colombier int	mfd[2];
359a747e4fSDavid du Colombier char	user[Elemlen];
36*901d8e21SDavid du Colombier int	messagesize = 4*1024+IOHDRSZ;
37*901d8e21SDavid du Colombier uchar	mdata[8*1024+IOHDRSZ];
38*901d8e21SDavid du Colombier uchar	mbuf[8*1024+IOHDRSZ];
397dd7cddfSDavid du Colombier Fcall	thdr;
409a747e4fSDavid du Colombier Fcall	rhdr;
417dd7cddfSDavid du Colombier int	fflg;
427dd7cddfSDavid du Colombier char	*mntpt;
437dd7cddfSDavid du Colombier int	biffing;
447dd7cddfSDavid du Colombier int	plumbing = 1;
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier QLock	mbllock;
477dd7cddfSDavid du Colombier Mailbox	*mbl;
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier Fid		*newfid(int);
507dd7cddfSDavid du Colombier void		error(char*);
517dd7cddfSDavid du Colombier void		io(void);
527dd7cddfSDavid du Colombier void		*erealloc(void*, ulong);
537dd7cddfSDavid du Colombier void		*emalloc(ulong);
547dd7cddfSDavid du Colombier void		usage(void);
557dd7cddfSDavid du Colombier void		reader(void);
567dd7cddfSDavid du Colombier int		readheader(Message*, char*, int, int);
577dd7cddfSDavid du Colombier int		cistrncmp(char*, char*, int);
587dd7cddfSDavid du Colombier int		tokenconvert(String*, char*, int);
595d459b5aSDavid du Colombier String*		stringconvert(String*, char*, int);
6080ee5cbfSDavid du Colombier void		post(char*, char*, int);
617dd7cddfSDavid du Colombier 
629a747e4fSDavid du Colombier char	*rflush(Fid*), *rauth(Fid*),
639a747e4fSDavid du Colombier 	*rattach(Fid*), *rwalk(Fid*),
649a747e4fSDavid du Colombier 	*ropen(Fid*), *rcreate(Fid*),
657dd7cddfSDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
669a747e4fSDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
679a747e4fSDavid du Colombier 	*rversion(Fid*);
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier char 	*(*fcalls[])(Fid*) = {
707dd7cddfSDavid du Colombier 	[Tflush]	rflush,
719a747e4fSDavid du Colombier 	[Tversion]	rversion,
729a747e4fSDavid du Colombier 	[Tauth]	rauth,
737dd7cddfSDavid du Colombier 	[Tattach]	rattach,
747dd7cddfSDavid du Colombier 	[Twalk]		rwalk,
757dd7cddfSDavid du Colombier 	[Topen]		ropen,
767dd7cddfSDavid du Colombier 	[Tcreate]	rcreate,
777dd7cddfSDavid du Colombier 	[Tread]		rread,
787dd7cddfSDavid du Colombier 	[Twrite]	rwrite,
797dd7cddfSDavid du Colombier 	[Tclunk]	rclunk,
807dd7cddfSDavid du Colombier 	[Tremove]	rremove,
817dd7cddfSDavid du Colombier 	[Tstat]		rstat,
827dd7cddfSDavid du Colombier 	[Twstat]	rwstat,
837dd7cddfSDavid du Colombier };
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier char	Eperm[] =	"permission denied";
867dd7cddfSDavid du Colombier char	Enotdir[] =	"not a directory";
873ff48bf5SDavid du Colombier char	Enoauth[] =	"upas/fs: authentication not required";
887dd7cddfSDavid du Colombier char	Enotexist[] =	"file does not exist";
897dd7cddfSDavid du Colombier char	Einuse[] =	"file in use";
907dd7cddfSDavid du Colombier char	Eexist[] =	"file exists";
917dd7cddfSDavid du Colombier char	Enotowner[] =	"not owner";
927dd7cddfSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
937dd7cddfSDavid du Colombier char	Excl[] = 	"exclusive use file already open";
947dd7cddfSDavid du Colombier char	Ename[] = 	"illegal name";
957dd7cddfSDavid du Colombier char	Ebadctl[] =	"unknown control message";
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier char *dirtab[] =
987dd7cddfSDavid du Colombier {
997dd7cddfSDavid du Colombier [Qdir]		".",
1007dd7cddfSDavid du Colombier [Qbody]		"body",
1017dd7cddfSDavid du Colombier [Qbcc]		"bcc",
1027dd7cddfSDavid du Colombier [Qcc]		"cc",
1037dd7cddfSDavid du Colombier [Qdate]		"date",
1047dd7cddfSDavid du Colombier [Qdigest]	"digest",
1057dd7cddfSDavid du Colombier [Qdisposition]	"disposition",
1067dd7cddfSDavid du Colombier [Qfilename]	"filename",
1077dd7cddfSDavid du Colombier [Qfrom]		"from",
1087dd7cddfSDavid du Colombier [Qheader]	"header",
1097dd7cddfSDavid du Colombier [Qinfo]		"info",
1107dd7cddfSDavid du Colombier [Qinreplyto]	"inreplyto",
1117dd7cddfSDavid du Colombier [Qlines]	"lines",
1127dd7cddfSDavid du Colombier [Qmimeheader]	"mimeheader",
1137dd7cddfSDavid du Colombier [Qmessageid]	"messageid",
1147dd7cddfSDavid du Colombier [Qraw]		"raw",
1156b6b9ac8SDavid du Colombier [Qrawunix]	"rawunix",
1167dd7cddfSDavid du Colombier [Qrawbody]	"rawbody",
1177dd7cddfSDavid du Colombier [Qrawheader]	"rawheader",
1187dd7cddfSDavid du Colombier [Qreplyto]	"replyto",
1197dd7cddfSDavid du Colombier [Qsender]	"sender",
1207dd7cddfSDavid du Colombier [Qsubject]	"subject",
1217dd7cddfSDavid du Colombier [Qto]		"to",
1227dd7cddfSDavid du Colombier [Qtype]		"type",
1239a747e4fSDavid du Colombier [Qunixdate]	"unixdate",
1247dd7cddfSDavid du Colombier [Qunixheader]	"unixheader",
1257dd7cddfSDavid du Colombier [Qctl]		"ctl",
12680ee5cbfSDavid du Colombier [Qmboxctl]	"ctl",
1277dd7cddfSDavid du Colombier };
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier enum
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier 	Hsize=	1277,
1327dd7cddfSDavid du Colombier };
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier Hash	*htab[Hsize];
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier int	debug;
1377dd7cddfSDavid du Colombier int	fflag;
13859cc4ca5SDavid du Colombier int	logging;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier void
usage(void)1417dd7cddfSDavid du Colombier usage(void)
1427dd7cddfSDavid du Colombier {
143816336a7SDavid du Colombier 	fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n");
1447dd7cddfSDavid du Colombier 	exits("usage");
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier void
notifyf(void * a,char * s)1487dd7cddfSDavid du Colombier notifyf(void *a, char *s)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	USED(a);
1517dd7cddfSDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
1527dd7cddfSDavid du Colombier 		noted(NCONT);
1537dd7cddfSDavid du Colombier 	noted(NDFLT);
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier void
main(int argc,char * argv[])1577dd7cddfSDavid du Colombier main(int argc, char *argv[])
1587dd7cddfSDavid du Colombier {
15959cc4ca5SDavid du Colombier 	int p[2], std, nodflt;
1607dd7cddfSDavid du Colombier 	char maildir[128];
1617dd7cddfSDavid du Colombier 	char mbox[128];
1627dd7cddfSDavid du Colombier 	char *mboxfile, *err;
16380ee5cbfSDavid du Colombier 	char srvfile[64];
16480ee5cbfSDavid du Colombier 	int srvpost;
1657dd7cddfSDavid du Colombier 
1665d459b5aSDavid du Colombier 	rfork(RFNOTEG);
1677dd7cddfSDavid du Colombier 	mntpt = nil;
1687dd7cddfSDavid du Colombier 	fflag = 0;
1697dd7cddfSDavid du Colombier 	mboxfile = nil;
1707dd7cddfSDavid du Colombier 	std = 0;
17159cc4ca5SDavid du Colombier 	nodflt = 0;
17280ee5cbfSDavid du Colombier 	srvpost = 0;
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier 	ARGBEGIN{
1757dd7cddfSDavid du Colombier 	case 'b':
1767dd7cddfSDavid du Colombier 		biffing = 1;
1777dd7cddfSDavid du Colombier 		break;
1787dd7cddfSDavid du Colombier 	case 'f':
1797dd7cddfSDavid du Colombier 		fflag = 1;
180816336a7SDavid du Colombier 		mboxfile = EARGF(usage());
1817dd7cddfSDavid du Colombier 		break;
1827dd7cddfSDavid du Colombier 	case 'm':
183816336a7SDavid du Colombier 		mntpt = EARGF(usage());
1847dd7cddfSDavid du Colombier 		break;
1857dd7cddfSDavid du Colombier 	case 'd':
1867dd7cddfSDavid du Colombier 		debug = 1;
1877dd7cddfSDavid du Colombier 		break;
1887dd7cddfSDavid du Colombier 	case 'p':
1897dd7cddfSDavid du Colombier 		plumbing = 0;
1907dd7cddfSDavid du Colombier 		break;
19180ee5cbfSDavid du Colombier 	case 's':
19280ee5cbfSDavid du Colombier 		srvpost = 1;
19380ee5cbfSDavid du Colombier 		break;
19459cc4ca5SDavid du Colombier 	case 'l':
19559cc4ca5SDavid du Colombier 		logging = 1;
19659cc4ca5SDavid du Colombier 		break;
19759cc4ca5SDavid du Colombier 	case 'n':
19859cc4ca5SDavid du Colombier 		nodflt = 1;
19959cc4ca5SDavid du Colombier 		break;
2007dd7cddfSDavid du Colombier 	default:
2017dd7cddfSDavid du Colombier 		usage();
2027dd7cddfSDavid du Colombier 	}ARGEND
2037dd7cddfSDavid du Colombier 
204816336a7SDavid du Colombier 	if(argc)
205816336a7SDavid du Colombier 		usage();
2067dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
2077dd7cddfSDavid du Colombier 		error("pipe failed");
2087dd7cddfSDavid du Colombier 	mfd[0] = p[0];
2097dd7cddfSDavid du Colombier 	mfd[1] = p[0];
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	notify(notifyf);
2127dd7cddfSDavid du Colombier 	strcpy(user, getuser());
2137dd7cddfSDavid du Colombier 	if(mntpt == nil){
2147dd7cddfSDavid du Colombier 		snprint(maildir, sizeof(maildir), "/mail/fs");
2157dd7cddfSDavid du Colombier 		mntpt = maildir;
2167dd7cddfSDavid du Colombier 	}
21759cc4ca5SDavid du Colombier 	if(mboxfile == nil && !nodflt){
2187dd7cddfSDavid du Colombier 		snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);
2197dd7cddfSDavid du Colombier 		mboxfile = mbox;
2207dd7cddfSDavid du Colombier 		std = 1;
2217dd7cddfSDavid du Colombier 	}
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 	if(debug)
2249a747e4fSDavid du Colombier 		fmtinstall('F', fcallfmt);
2257dd7cddfSDavid du Colombier 
22659cc4ca5SDavid du Colombier 	if(mboxfile != nil){
2277dd7cddfSDavid du Colombier 		err = newmbox(mboxfile, "mbox", std);
2287dd7cddfSDavid du Colombier 		if(err != nil)
2293e748dfcSDavid du Colombier 			sysfatal("opening %s: %s", mboxfile, err);
23059cc4ca5SDavid du Colombier 	}
2317dd7cddfSDavid du Colombier 
23259cc4ca5SDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
2337dd7cddfSDavid du Colombier 	case -1:
2347dd7cddfSDavid du Colombier 		error("fork");
2357dd7cddfSDavid du Colombier 	case 0:
2369a747e4fSDavid du Colombier 		henter(PATH(0, Qtop), dirtab[Qctl],
2379a747e4fSDavid du Colombier 			(Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);
2387dd7cddfSDavid du Colombier 		close(p[1]);
2397dd7cddfSDavid du Colombier 		io();
2407dd7cddfSDavid du Colombier 		postnote(PNGROUP, getpid(), "die yankee pig dog");
2417dd7cddfSDavid du Colombier 		break;
2427dd7cddfSDavid du Colombier 	default:
2437dd7cddfSDavid du Colombier 		close(p[0]);	/* don't deadlock if child fails */
24480ee5cbfSDavid du Colombier 		if(srvpost){
24580ee5cbfSDavid du Colombier 			sprint(srvfile, "/srv/upasfs.%s", user);
24680ee5cbfSDavid du Colombier 			post(srvfile, "upasfs", p[1]);
24780ee5cbfSDavid du Colombier 		} else {
2489a747e4fSDavid du Colombier 			if(mount(p[1], -1, mntpt, MREPL, "") < 0)
2497dd7cddfSDavid du Colombier 				error("mount failed");
2507dd7cddfSDavid du Colombier 		}
25180ee5cbfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier 	exits(0);
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier static int
fileinfo(Message * m,int t,char ** pp)2567dd7cddfSDavid du Colombier fileinfo(Message *m, int t, char **pp)
2577dd7cddfSDavid du Colombier {
2587dd7cddfSDavid du Colombier 	char *p;
2597dd7cddfSDavid du Colombier 	int len;
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier 	p = "";
2627dd7cddfSDavid du Colombier 	len = 0;
2637dd7cddfSDavid du Colombier 	switch(t){
2647dd7cddfSDavid du Colombier 	case Qbody:
2657dd7cddfSDavid du Colombier 		p = m->body;
2667dd7cddfSDavid du Colombier 		len = m->bend - m->body;
2677dd7cddfSDavid du Colombier 		break;
2687dd7cddfSDavid du Colombier 	case Qbcc:
2697dd7cddfSDavid du Colombier 		if(m->bcc822){
2707dd7cddfSDavid du Colombier 			p = s_to_c(m->bcc822);
2717dd7cddfSDavid du Colombier 			len = strlen(p);
2727dd7cddfSDavid du Colombier 		}
2737dd7cddfSDavid du Colombier 		break;
2747dd7cddfSDavid du Colombier 	case Qcc:
2757dd7cddfSDavid du Colombier 		if(m->cc822){
2767dd7cddfSDavid du Colombier 			p = s_to_c(m->cc822);
2777dd7cddfSDavid du Colombier 			len = strlen(p);
2787dd7cddfSDavid du Colombier 		}
2797dd7cddfSDavid du Colombier 		break;
2807dd7cddfSDavid du Colombier 	case Qdisposition:
2817dd7cddfSDavid du Colombier 		switch(m->disposition){
2827dd7cddfSDavid du Colombier 		case Dinline:
2837dd7cddfSDavid du Colombier 			p = "inline";
2847dd7cddfSDavid du Colombier 			break;
2857dd7cddfSDavid du Colombier 		case Dfile:
2867dd7cddfSDavid du Colombier 			p = "file";
2877dd7cddfSDavid du Colombier 			break;
2887dd7cddfSDavid du Colombier 		}
2897dd7cddfSDavid du Colombier 		len = strlen(p);
2907dd7cddfSDavid du Colombier 		break;
2917dd7cddfSDavid du Colombier 	case Qdate:
2927dd7cddfSDavid du Colombier 		if(m->date822){
2937dd7cddfSDavid du Colombier 			p = s_to_c(m->date822);
2947dd7cddfSDavid du Colombier 			len = strlen(p);
2957dd7cddfSDavid du Colombier 		} else if(m->unixdate != nil){
2967dd7cddfSDavid du Colombier 			p = s_to_c(m->unixdate);
2977dd7cddfSDavid du Colombier 			len = strlen(p);
2987dd7cddfSDavid du Colombier 		}
2997dd7cddfSDavid du Colombier 		break;
3007dd7cddfSDavid du Colombier 	case Qfilename:
3017dd7cddfSDavid du Colombier 		if(m->filename){
3027dd7cddfSDavid du Colombier 			p = s_to_c(m->filename);
3037dd7cddfSDavid du Colombier 			len = strlen(p);
3047dd7cddfSDavid du Colombier 		}
3057dd7cddfSDavid du Colombier 		break;
3067dd7cddfSDavid du Colombier 	case Qinreplyto:
3077dd7cddfSDavid du Colombier 		if(m->inreplyto822){
3087dd7cddfSDavid du Colombier 			p = s_to_c(m->inreplyto822);
3097dd7cddfSDavid du Colombier 			len = strlen(p);
3107dd7cddfSDavid du Colombier 		}
3117dd7cddfSDavid du Colombier 		break;
3127dd7cddfSDavid du Colombier 	case Qmessageid:
3137dd7cddfSDavid du Colombier 		if(m->messageid822){
3147dd7cddfSDavid du Colombier 			p = s_to_c(m->messageid822);
3157dd7cddfSDavid du Colombier 			len = strlen(p);
3167dd7cddfSDavid du Colombier 		}
3177dd7cddfSDavid du Colombier 		break;
3187dd7cddfSDavid du Colombier 	case Qfrom:
3197dd7cddfSDavid du Colombier 		if(m->from822){
3207dd7cddfSDavid du Colombier 			p = s_to_c(m->from822);
3217dd7cddfSDavid du Colombier 			len = strlen(p);
3227dd7cddfSDavid du Colombier 		} else if(m->unixfrom != nil){
3237dd7cddfSDavid du Colombier 			p = s_to_c(m->unixfrom);
3247dd7cddfSDavid du Colombier 			len = strlen(p);
3257dd7cddfSDavid du Colombier 		}
3267dd7cddfSDavid du Colombier 		break;
3277dd7cddfSDavid du Colombier 	case Qheader:
3287dd7cddfSDavid du Colombier 		p = m->header;
3297dd7cddfSDavid du Colombier 		len = headerlen(m);
3307dd7cddfSDavid du Colombier 		break;
3317dd7cddfSDavid du Colombier 	case Qlines:
3327dd7cddfSDavid du Colombier 		p = m->lines;
3337dd7cddfSDavid du Colombier 		if(*p == 0)
3347dd7cddfSDavid du Colombier 			countlines(m);
3357dd7cddfSDavid du Colombier 		len = strlen(m->lines);
3367dd7cddfSDavid du Colombier 		break;
3377dd7cddfSDavid du Colombier 	case Qraw:
3387dd7cddfSDavid du Colombier 		p = m->start;
3397dd7cddfSDavid du Colombier 		if(strncmp(m->start, "From ", 5) == 0){
3407dd7cddfSDavid du Colombier 			p = strchr(p, '\n');
3417dd7cddfSDavid du Colombier 			if(p == nil)
3427dd7cddfSDavid du Colombier 				p = m->start;
3437dd7cddfSDavid du Colombier 			else
3447dd7cddfSDavid du Colombier 				p++;
3457dd7cddfSDavid du Colombier 		}
3467dd7cddfSDavid du Colombier 		len = m->end - p;
3477dd7cddfSDavid du Colombier 		break;
3486b6b9ac8SDavid du Colombier 	case Qrawunix:
3496b6b9ac8SDavid du Colombier 		p = m->start;
3506b6b9ac8SDavid du Colombier 		len = m->end - p;
3516b6b9ac8SDavid du Colombier 		break;
3527dd7cddfSDavid du Colombier 	case Qrawbody:
3537dd7cddfSDavid du Colombier 		p = m->rbody;
3547dd7cddfSDavid du Colombier 		len = m->rbend - p;
3557dd7cddfSDavid du Colombier 		break;
3567dd7cddfSDavid du Colombier 	case Qrawheader:
3577dd7cddfSDavid du Colombier 		p = m->header;
3587dd7cddfSDavid du Colombier 		len = m->hend - p;
3597dd7cddfSDavid du Colombier 		break;
3607dd7cddfSDavid du Colombier 	case Qmimeheader:
3617dd7cddfSDavid du Colombier 		p = m->mheader;
3627dd7cddfSDavid du Colombier 		len = m->mhend - p;
3637dd7cddfSDavid du Colombier 		break;
3647dd7cddfSDavid du Colombier 	case Qreplyto:
3657dd7cddfSDavid du Colombier 		p = nil;
3667dd7cddfSDavid du Colombier 		if(m->replyto822 != nil){
3677dd7cddfSDavid du Colombier 			p = s_to_c(m->replyto822);
3687dd7cddfSDavid du Colombier 			len = strlen(p);
3697dd7cddfSDavid du Colombier 		} else if(m->from822 != nil){
3707dd7cddfSDavid du Colombier 			p = s_to_c(m->from822);
3717dd7cddfSDavid du Colombier 			len = strlen(p);
3727dd7cddfSDavid du Colombier 		} else if(m->sender822 != nil){
3737dd7cddfSDavid du Colombier 			p = s_to_c(m->sender822);
3747dd7cddfSDavid du Colombier 			len = strlen(p);
3757dd7cddfSDavid du Colombier 		} else if(m->unixfrom != nil){
3767dd7cddfSDavid du Colombier 			p = s_to_c(m->unixfrom);
3777dd7cddfSDavid du Colombier 			len = strlen(p);
3787dd7cddfSDavid du Colombier 		}
3797dd7cddfSDavid du Colombier 		break;
3807dd7cddfSDavid du Colombier 	case Qsender:
3817dd7cddfSDavid du Colombier 		if(m->sender822){
3827dd7cddfSDavid du Colombier 			p = s_to_c(m->sender822);
3837dd7cddfSDavid du Colombier 			len = strlen(p);
3847dd7cddfSDavid du Colombier 		}
3857dd7cddfSDavid du Colombier 		break;
3867dd7cddfSDavid du Colombier 	case Qsubject:
3877dd7cddfSDavid du Colombier 		p = nil;
3887dd7cddfSDavid du Colombier 		if(m->subject822){
3897dd7cddfSDavid du Colombier 			p = s_to_c(m->subject822);
3907dd7cddfSDavid du Colombier 			len = strlen(p);
3917dd7cddfSDavid du Colombier 		}
3927dd7cddfSDavid du Colombier 		break;
3937dd7cddfSDavid du Colombier 	case Qto:
3947dd7cddfSDavid du Colombier 		if(m->to822){
3957dd7cddfSDavid du Colombier 			p = s_to_c(m->to822);
3967dd7cddfSDavid du Colombier 			len = strlen(p);
3977dd7cddfSDavid du Colombier 		}
3987dd7cddfSDavid du Colombier 		break;
3997dd7cddfSDavid du Colombier 	case Qtype:
4007dd7cddfSDavid du Colombier 		if(m->type){
4017dd7cddfSDavid du Colombier 			p = s_to_c(m->type);
4027dd7cddfSDavid du Colombier 			len = strlen(p);
4037dd7cddfSDavid du Colombier 		}
4047dd7cddfSDavid du Colombier 		break;
4057dd7cddfSDavid du Colombier 	case Qunixdate:
4067dd7cddfSDavid du Colombier 		if(m->unixdate){
4077dd7cddfSDavid du Colombier 			p = s_to_c(m->unixdate);
4087dd7cddfSDavid du Colombier 			len = strlen(p);
4097dd7cddfSDavid du Colombier 		}
4107dd7cddfSDavid du Colombier 		break;
4117dd7cddfSDavid du Colombier 	case Qunixheader:
41280ee5cbfSDavid du Colombier 		if(m->unixheader){
41380ee5cbfSDavid du Colombier 			p = s_to_c(m->unixheader);
41480ee5cbfSDavid du Colombier 			len = s_len(m->unixheader);
41580ee5cbfSDavid du Colombier 		}
4167dd7cddfSDavid du Colombier 		break;
4177dd7cddfSDavid du Colombier 	case Qdigest:
4187dd7cddfSDavid du Colombier 		if(m->sdigest){
4197dd7cddfSDavid du Colombier 			p = s_to_c(m->sdigest);
4207dd7cddfSDavid du Colombier 			len = strlen(p);
4217dd7cddfSDavid du Colombier 		}
4227dd7cddfSDavid du Colombier 		break;
4237dd7cddfSDavid du Colombier 	}
4247dd7cddfSDavid du Colombier 	*pp = p;
4257dd7cddfSDavid du Colombier 	return len;
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier int infofields[] = {
4297dd7cddfSDavid du Colombier 	Qfrom,
4307dd7cddfSDavid du Colombier 	Qto,
4317dd7cddfSDavid du Colombier 	Qcc,
4327dd7cddfSDavid du Colombier 	Qreplyto,
4337dd7cddfSDavid du Colombier 	Qunixdate,
4347dd7cddfSDavid du Colombier 	Qsubject,
4357dd7cddfSDavid du Colombier 	Qtype,
4367dd7cddfSDavid du Colombier 	Qdisposition,
4377dd7cddfSDavid du Colombier 	Qfilename,
4387dd7cddfSDavid du Colombier 	Qdigest,
4397dd7cddfSDavid du Colombier 	Qbcc,
4407dd7cddfSDavid du Colombier 	Qinreplyto,
4417dd7cddfSDavid du Colombier 	Qdate,
4427dd7cddfSDavid du Colombier 	Qsender,
4437dd7cddfSDavid du Colombier 	Qmessageid,
4447dd7cddfSDavid du Colombier 	Qlines,
4457dd7cddfSDavid du Colombier 	-1,
4467dd7cddfSDavid du Colombier };
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier static int
readinfo(Message * m,char * buf,long off,int count)4497dd7cddfSDavid du Colombier readinfo(Message *m, char *buf, long off, int count)
4507dd7cddfSDavid du Colombier {
4517dd7cddfSDavid du Colombier 	char *p;
4527dd7cddfSDavid du Colombier 	int len, i, n;
4537dd7cddfSDavid du Colombier 	String *s;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	s = s_new();
4567dd7cddfSDavid du Colombier 	len = 0;
4577dd7cddfSDavid du Colombier 	for(i = 0; len < count && infofields[i] >= 0; i++){
4587dd7cddfSDavid du Colombier 		n = fileinfo(m, infofields[i], &p);
4595d459b5aSDavid du Colombier 		s = stringconvert(s, p, n);
4609a747e4fSDavid du Colombier 		s_append(s, "\n");
4617dd7cddfSDavid du Colombier 		p = s_to_c(s);
4627dd7cddfSDavid du Colombier 		n = strlen(p);
4637dd7cddfSDavid du Colombier 		if(off > 0){
4649a747e4fSDavid du Colombier 			if(off >= n){
4659a747e4fSDavid du Colombier 				off -= n;
4667dd7cddfSDavid du Colombier 				continue;
4677dd7cddfSDavid du Colombier 			}
4687dd7cddfSDavid du Colombier 			p += off;
4697dd7cddfSDavid du Colombier 			n -= off;
4707dd7cddfSDavid du Colombier 			off = 0;
4717dd7cddfSDavid du Colombier 		}
4727dd7cddfSDavid du Colombier 		if(n > count - len)
4737dd7cddfSDavid du Colombier 			n = count - len;
4747dd7cddfSDavid du Colombier 		if(buf)
4757dd7cddfSDavid du Colombier 			memmove(buf+len, p, n);
4767dd7cddfSDavid du Colombier 		len += n;
4777dd7cddfSDavid du Colombier 	}
4787dd7cddfSDavid du Colombier 	s_free(s);
4797dd7cddfSDavid du Colombier 	return len;
4807dd7cddfSDavid du Colombier }
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier static void
mkstat(Dir * d,Mailbox * mb,Message * m,int t)4837dd7cddfSDavid du Colombier mkstat(Dir *d, Mailbox *mb, Message *m, int t)
4847dd7cddfSDavid du Colombier {
4857dd7cddfSDavid du Colombier 	char *p;
4867dd7cddfSDavid du Colombier 
4879a747e4fSDavid du Colombier 	d->uid = user;
4889a747e4fSDavid du Colombier 	d->gid = user;
4899a747e4fSDavid du Colombier 	d->muid = user;
4907dd7cddfSDavid du Colombier 	d->mode = 0444;
4917dd7cddfSDavid du Colombier 	d->qid.vers = 0;
4929a747e4fSDavid du Colombier 	d->qid.type = QTFILE;
4937dd7cddfSDavid du Colombier 	d->type = 0;
4947dd7cddfSDavid du Colombier 	d->dev = 0;
4959a747e4fSDavid du Colombier 	if(mb != nil && mb->d != nil){
4969a747e4fSDavid du Colombier 		d->atime = mb->d->atime;
4979a747e4fSDavid du Colombier 		d->mtime = mb->d->mtime;
4989a747e4fSDavid du Colombier 	} else {
4999a747e4fSDavid du Colombier 		d->atime = time(0);
5009a747e4fSDavid du Colombier 		d->mtime = d->atime;
5019a747e4fSDavid du Colombier 	}
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 	switch(t){
5047dd7cddfSDavid du Colombier 	case Qtop:
5059a747e4fSDavid du Colombier 		d->name = ".";
5069a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
5077dd7cddfSDavid du Colombier 		d->atime = d->mtime = time(0);
5087dd7cddfSDavid du Colombier 		d->length = 0;
5099a747e4fSDavid du Colombier 		d->qid.path = PATH(0, Qtop);
5109a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
5117dd7cddfSDavid du Colombier 		break;
5127dd7cddfSDavid du Colombier 	case Qmbox:
5139a747e4fSDavid du Colombier 		d->name = mb->name;
5149a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
5157dd7cddfSDavid du Colombier 		d->length = 0;
5169a747e4fSDavid du Colombier 		d->qid.path = PATH(mb->id, Qmbox);
5179a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
5187dd7cddfSDavid du Colombier 		d->qid.vers = mb->vers;
5197dd7cddfSDavid du Colombier 		break;
5207dd7cddfSDavid du Colombier 	case Qdir:
5219a747e4fSDavid du Colombier 		d->name = m->name;
5229a747e4fSDavid du Colombier 		d->mode = DMDIR|0555;
5237dd7cddfSDavid du Colombier 		d->length = 0;
5249a747e4fSDavid du Colombier 		d->qid.path = PATH(m->id, Qdir);
5259a747e4fSDavid du Colombier 		d->qid.type = QTDIR;
5267dd7cddfSDavid du Colombier 		break;
5277dd7cddfSDavid du Colombier 	case Qctl:
5289a747e4fSDavid du Colombier 		d->name = dirtab[t];
5297dd7cddfSDavid du Colombier 		d->mode = 0666;
5307dd7cddfSDavid du Colombier 		d->atime = d->mtime = time(0);
5317dd7cddfSDavid du Colombier 		d->length = 0;
5327dd7cddfSDavid du Colombier 		d->qid.path = PATH(0, Qctl);
5337dd7cddfSDavid du Colombier 		break;
53480ee5cbfSDavid du Colombier 	case Qmboxctl:
5359a747e4fSDavid du Colombier 		d->name = dirtab[t];
53680ee5cbfSDavid du Colombier 		d->mode = 0222;
53780ee5cbfSDavid du Colombier 		d->atime = d->mtime = time(0);
53880ee5cbfSDavid du Colombier 		d->length = 0;
53980ee5cbfSDavid du Colombier 		d->qid.path = PATH(mb->id, Qmboxctl);
54080ee5cbfSDavid du Colombier 		break;
5417dd7cddfSDavid du Colombier 	case Qinfo:
5429a747e4fSDavid du Colombier 		d->name = dirtab[t];
5437dd7cddfSDavid du Colombier 		d->length = readinfo(m, nil, 0, 1<<30);
5447dd7cddfSDavid du Colombier 		d->qid.path = PATH(m->id, t);
5457dd7cddfSDavid du Colombier 		break;
5467dd7cddfSDavid du Colombier 	default:
5479a747e4fSDavid du Colombier 		d->name = dirtab[t];
5487dd7cddfSDavid du Colombier 		d->length = fileinfo(m, t, &p);
5497dd7cddfSDavid du Colombier 		d->qid.path = PATH(m->id, t);
5507dd7cddfSDavid du Colombier 		break;
5517dd7cddfSDavid du Colombier 	}
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier 
5547dd7cddfSDavid du Colombier char*
rversion(Fid *)5559a747e4fSDavid du Colombier rversion(Fid*)
5567dd7cddfSDavid du Colombier {
5577dd7cddfSDavid du Colombier 	Fid *f;
5587dd7cddfSDavid du Colombier 
5599a747e4fSDavid du Colombier 	if(thdr.msize < 256)
5609a747e4fSDavid du Colombier 		return "max messagesize too small";
5619a747e4fSDavid du Colombier 	if(thdr.msize < messagesize)
5629a747e4fSDavid du Colombier 		messagesize = thdr.msize;
5639a747e4fSDavid du Colombier 	rhdr.msize = messagesize;
5649a747e4fSDavid du Colombier 	if(strncmp(thdr.version, "9P2000", 6) != 0)
5659a747e4fSDavid du Colombier 		return "unknown 9P version";
5669a747e4fSDavid du Colombier 	else
5679a747e4fSDavid du Colombier 		rhdr.version = "9P2000";
5687dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next)
5697dd7cddfSDavid du Colombier 		if(f->busy)
5707dd7cddfSDavid du Colombier 			rclunk(f);
5719a747e4fSDavid du Colombier 	return nil;
5729a747e4fSDavid du Colombier }
5739a747e4fSDavid du Colombier 
5749a747e4fSDavid du Colombier char*
rauth(Fid *)5759a747e4fSDavid du Colombier rauth(Fid*)
5769a747e4fSDavid du Colombier {
5773ff48bf5SDavid du Colombier 	return Enoauth;
5787dd7cddfSDavid du Colombier }
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier char*
rflush(Fid * f)5817dd7cddfSDavid du Colombier rflush(Fid *f)
5827dd7cddfSDavid du Colombier {
5837dd7cddfSDavid du Colombier 	USED(f);
5847dd7cddfSDavid du Colombier 	return 0;
5857dd7cddfSDavid du Colombier }
5867dd7cddfSDavid du Colombier 
5877dd7cddfSDavid du Colombier char*
rattach(Fid * f)5887dd7cddfSDavid du Colombier rattach(Fid *f)
5897dd7cddfSDavid du Colombier {
5907dd7cddfSDavid du Colombier 	f->busy = 1;
5917dd7cddfSDavid du Colombier 	f->m = nil;
5927dd7cddfSDavid du Colombier 	f->mb = nil;
5939a747e4fSDavid du Colombier 	f->qid.path = PATH(0, Qtop);
5949a747e4fSDavid du Colombier 	f->qid.type = QTDIR;
5957dd7cddfSDavid du Colombier 	f->qid.vers = 0;
5969a747e4fSDavid du Colombier 	rhdr.qid = f->qid;
5979a747e4fSDavid du Colombier 	if(strcmp(thdr.uname, user) != 0)
5987dd7cddfSDavid du Colombier 		return Eperm;
5997dd7cddfSDavid du Colombier 	return 0;
6007dd7cddfSDavid du Colombier }
6017dd7cddfSDavid du Colombier 
6029a747e4fSDavid du Colombier static Fid*
doclone(Fid * f,int nfid)6039a747e4fSDavid du Colombier doclone(Fid *f, int nfid)
6047dd7cddfSDavid du Colombier {
6057dd7cddfSDavid du Colombier 	Fid *nf;
6067dd7cddfSDavid du Colombier 
6079a747e4fSDavid du Colombier 	nf = newfid(nfid);
6089a747e4fSDavid du Colombier 	if(nf->busy)
6099a747e4fSDavid du Colombier 		return nil;
6107dd7cddfSDavid du Colombier 	nf->busy = 1;
6117dd7cddfSDavid du Colombier 	nf->open = 0;
6127dd7cddfSDavid du Colombier 	nf->m = f->m;
6137dd7cddfSDavid du Colombier 	nf->mtop = f->mtop;
6147dd7cddfSDavid du Colombier 	nf->mb = f->mb;
6157dd7cddfSDavid du Colombier 	if(f->mb != nil)
6167dd7cddfSDavid du Colombier 		mboxincref(f->mb);
6177dd7cddfSDavid du Colombier 	if(f->mtop != nil){
6187dd7cddfSDavid du Colombier 		qlock(f->mb);
6197dd7cddfSDavid du Colombier 		msgincref(f->mtop);
6207dd7cddfSDavid du Colombier 		qunlock(f->mb);
6217dd7cddfSDavid du Colombier 	}
6227dd7cddfSDavid du Colombier 	nf->qid = f->qid;
6239a747e4fSDavid du Colombier 	return nf;
6247dd7cddfSDavid du Colombier }
6257dd7cddfSDavid du Colombier 
6267dd7cddfSDavid du Colombier char*
dowalk(Fid * f,char * name)6279a747e4fSDavid du Colombier dowalk(Fid *f, char *name)
6287dd7cddfSDavid du Colombier {
6297dd7cddfSDavid du Colombier 	int t;
6307dd7cddfSDavid du Colombier 	Mailbox *omb, *mb;
6317dd7cddfSDavid du Colombier 	char *rv, *p;
6327dd7cddfSDavid du Colombier 	Hash *h;
6337dd7cddfSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier 	rv = Enotexist;
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier 	omb = f->mb;
6397dd7cddfSDavid du Colombier 	if(omb)
6407dd7cddfSDavid du Colombier 		qlock(omb);
6417dd7cddfSDavid du Colombier 	else
6427dd7cddfSDavid du Colombier 		qlock(&mbllock);
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	// this must catch everything except . and ..
6457dd7cddfSDavid du Colombier retry:
6467dd7cddfSDavid du Colombier 	h = hlook(f->qid.path, name);
6477dd7cddfSDavid du Colombier 	if(h != nil){
6487dd7cddfSDavid du Colombier 		f->mb = h->mb;
6497dd7cddfSDavid du Colombier 		f->m = h->m;
6507dd7cddfSDavid du Colombier 		switch(t){
6517dd7cddfSDavid du Colombier 		case Qtop:
6527dd7cddfSDavid du Colombier 			if(f->mb != nil)
6537dd7cddfSDavid du Colombier 				mboxincref(f->mb);
6547dd7cddfSDavid du Colombier 			break;
6557dd7cddfSDavid du Colombier 		case Qmbox:
65680ee5cbfSDavid du Colombier 			if(f->m){
6577dd7cddfSDavid du Colombier 				msgincref(f->m);
6587dd7cddfSDavid du Colombier 				f->mtop = f->m;
65980ee5cbfSDavid du Colombier 			}
6607dd7cddfSDavid du Colombier 			break;
6617dd7cddfSDavid du Colombier 		}
6627dd7cddfSDavid du Colombier 		f->qid = h->qid;
6637dd7cddfSDavid du Colombier 		rv = nil;
6647dd7cddfSDavid du Colombier 	} else if((p = strchr(name, '.')) != nil && *name != '.'){
6657dd7cddfSDavid du Colombier 		*p = 0;
6667dd7cddfSDavid du Colombier 		goto retry;
6677dd7cddfSDavid du Colombier 	}
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier 	if(omb)
6707dd7cddfSDavid du Colombier 		qunlock(omb);
6717dd7cddfSDavid du Colombier 	else
6727dd7cddfSDavid du Colombier 		qunlock(&mbllock);
6737dd7cddfSDavid du Colombier 	if(rv == nil)
6747dd7cddfSDavid du Colombier 		return rv;
6757dd7cddfSDavid du Colombier 
6769a747e4fSDavid du Colombier 	if(strcmp(name, ".") == 0)
6777dd7cddfSDavid du Colombier 		return nil;
6787dd7cddfSDavid du Colombier 
6799a747e4fSDavid du Colombier 	if(f->qid.type != QTDIR)
6807dd7cddfSDavid du Colombier 		return Enotdir;
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier 	if(strcmp(name, "..") == 0){
6837dd7cddfSDavid du Colombier 		switch(t){
6847dd7cddfSDavid du Colombier 		case Qtop:
6859a747e4fSDavid du Colombier 			f->qid.path = PATH(0, Qtop);
6869a747e4fSDavid du Colombier 			f->qid.type = QTDIR;
6877dd7cddfSDavid du Colombier 			f->qid.vers = 0;
6887dd7cddfSDavid du Colombier 			break;
6897dd7cddfSDavid du Colombier 		case Qmbox:
6909a747e4fSDavid du Colombier 			f->qid.path = PATH(0, Qtop);
6919a747e4fSDavid du Colombier 			f->qid.type = QTDIR;
6927dd7cddfSDavid du Colombier 			f->qid.vers = 0;
6937dd7cddfSDavid du Colombier 			qlock(&mbllock);
6947dd7cddfSDavid du Colombier 			mb = f->mb;
6957dd7cddfSDavid du Colombier 			f->mb = nil;
6967dd7cddfSDavid du Colombier 			mboxdecref(mb);
6977dd7cddfSDavid du Colombier 			qunlock(&mbllock);
6987dd7cddfSDavid du Colombier 			break;
6997dd7cddfSDavid du Colombier 		case Qdir:
7007dd7cddfSDavid du Colombier 			qlock(f->mb);
7017dd7cddfSDavid du Colombier 			if(f->m->whole == f->mb->root){
7029a747e4fSDavid du Colombier 				f->qid.path = PATH(f->mb->id, Qmbox);
7039a747e4fSDavid du Colombier 				f->qid.type = QTDIR;
7049a747e4fSDavid du Colombier 				f->qid.vers = f->mb->d->qid.vers;
7057dd7cddfSDavid du Colombier 				msgdecref(f->mb, f->mtop);
7067dd7cddfSDavid du Colombier 				f->m = f->mtop = nil;
7077dd7cddfSDavid du Colombier 			} else {
7087dd7cddfSDavid du Colombier 				f->m = f->m->whole;
7099a747e4fSDavid du Colombier 				f->qid.path = PATH(f->m->id, Qdir);
7109a747e4fSDavid du Colombier 				f->qid.type = QTDIR;
7117dd7cddfSDavid du Colombier 			}
7127dd7cddfSDavid du Colombier 			qunlock(f->mb);
7137dd7cddfSDavid du Colombier 			break;
7147dd7cddfSDavid du Colombier 		}
7157dd7cddfSDavid du Colombier 		rv = nil;
7167dd7cddfSDavid du Colombier 	}
7177dd7cddfSDavid du Colombier 	return rv;
7187dd7cddfSDavid du Colombier }
7197dd7cddfSDavid du Colombier 
7207dd7cddfSDavid du Colombier char*
rwalk(Fid * f)7219a747e4fSDavid du Colombier rwalk(Fid *f)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier 	Fid *nf;
7249a747e4fSDavid du Colombier 	char *rv;
7259a747e4fSDavid du Colombier 	int i;
7267dd7cddfSDavid du Colombier 
7279a747e4fSDavid du Colombier 	if(f->open)
7289a747e4fSDavid du Colombier 		return Eisopen;
7299a747e4fSDavid du Colombier 
7309a747e4fSDavid du Colombier 	rhdr.nwqid = 0;
7319a747e4fSDavid du Colombier 	nf = nil;
7329a747e4fSDavid du Colombier 
7339a747e4fSDavid du Colombier 	/* clone if requested */
7349a747e4fSDavid du Colombier 	if(thdr.newfid != thdr.fid){
7359a747e4fSDavid du Colombier 		nf = doclone(f, thdr.newfid);
7369a747e4fSDavid du Colombier 		if(nf == nil)
7379a747e4fSDavid du Colombier 			return "new fid in use";
7389a747e4fSDavid du Colombier 		f = nf;
7397dd7cddfSDavid du Colombier 	}
7409a747e4fSDavid du Colombier 
7419a747e4fSDavid du Colombier 	/* if it's just a clone, return */
7429a747e4fSDavid du Colombier 	if(thdr.nwname == 0 && nf != nil)
7439a747e4fSDavid du Colombier 		return nil;
7449a747e4fSDavid du Colombier 
7459a747e4fSDavid du Colombier 	/* walk each element */
7469a747e4fSDavid du Colombier 	rv = nil;
7479a747e4fSDavid du Colombier 	for(i = 0; i < thdr.nwname; i++){
7489a747e4fSDavid du Colombier 		rv = dowalk(f, thdr.wname[i]);
7499a747e4fSDavid du Colombier 		if(rv != nil){
7509a747e4fSDavid du Colombier 			if(nf != nil)
7517dd7cddfSDavid du Colombier 				rclunk(nf);
7529a747e4fSDavid du Colombier 			break;
7539a747e4fSDavid du Colombier 		}
7549a747e4fSDavid du Colombier 		rhdr.wqid[i] = f->qid;
7559a747e4fSDavid du Colombier 	}
7569a747e4fSDavid du Colombier 	rhdr.nwqid = i;
7579a747e4fSDavid du Colombier 
7589a747e4fSDavid du Colombier 	/* we only error out if no walk  */
7599a747e4fSDavid du Colombier 	if(i > 0)
7609a747e4fSDavid du Colombier 		rv = nil;
7619a747e4fSDavid du Colombier 
7629a747e4fSDavid du Colombier 	return rv;
7637dd7cddfSDavid du Colombier }
7647dd7cddfSDavid du Colombier 
7657dd7cddfSDavid du Colombier char *
ropen(Fid * f)7667dd7cddfSDavid du Colombier ropen(Fid *f)
7677dd7cddfSDavid du Colombier {
76880ee5cbfSDavid du Colombier 	int file;
76980ee5cbfSDavid du Colombier 
7707dd7cddfSDavid du Colombier 	if(f->open)
7717dd7cddfSDavid du Colombier 		return Eisopen;
7727dd7cddfSDavid du Colombier 
77380ee5cbfSDavid du Colombier 	file = FILE(f->qid.path);
7749a747e4fSDavid du Colombier 	if(thdr.mode != OREAD)
77580ee5cbfSDavid du Colombier 		if(file != Qctl && file != Qmboxctl)
7767dd7cddfSDavid du Colombier 			return Eperm;
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier 	// make sure we've decoded
77980ee5cbfSDavid du Colombier 	if(file == Qbody){
7807dd7cddfSDavid du Colombier 		if(f->m->decoded == 0)
7817dd7cddfSDavid du Colombier 			decode(f->m);
7827dd7cddfSDavid du Colombier 		if(f->m->converted == 0)
7837dd7cddfSDavid du Colombier 			convert(f->m);
7847dd7cddfSDavid du Colombier 	}
7857dd7cddfSDavid du Colombier 
7869a747e4fSDavid du Colombier 	rhdr.iounit = 0;
7879a747e4fSDavid du Colombier 	rhdr.qid = f->qid;
7887dd7cddfSDavid du Colombier 	f->open = 1;
7897dd7cddfSDavid du Colombier 	return 0;
7907dd7cddfSDavid du Colombier }
7917dd7cddfSDavid du Colombier 
7927dd7cddfSDavid du Colombier char *
rcreate(Fid *)7937dd7cddfSDavid du Colombier rcreate(Fid*)
7947dd7cddfSDavid du Colombier {
7957dd7cddfSDavid du Colombier 	return Eperm;
7967dd7cddfSDavid du Colombier }
7977dd7cddfSDavid du Colombier 
7987dd7cddfSDavid du Colombier int
readtopdir(Fid *,uchar * buf,long off,int cnt,int blen)7999a747e4fSDavid du Colombier readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
8007dd7cddfSDavid du Colombier {
8017dd7cddfSDavid du Colombier 	Dir d;
8029a747e4fSDavid du Colombier 	int m, n;
8039a747e4fSDavid du Colombier 	long pos;
8047dd7cddfSDavid du Colombier 	Mailbox *mb;
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier 	n = 0;
8079a747e4fSDavid du Colombier 	pos = 0;
8087dd7cddfSDavid du Colombier 	mkstat(&d, nil, nil, Qctl);
8099a747e4fSDavid du Colombier 	m = convD2M(&d, &buf[n], blen);
8109a747e4fSDavid du Colombier 	if(off <= pos){
8119a747e4fSDavid du Colombier 		if(m <= BIT16SZ || m > cnt)
8129a747e4fSDavid du Colombier 			return 0;
8139a747e4fSDavid du Colombier 		n += m;
8149a747e4fSDavid du Colombier 		cnt -= m;
8157dd7cddfSDavid du Colombier 	}
8169a747e4fSDavid du Colombier 	pos += m;
8179a747e4fSDavid du Colombier 
8189a747e4fSDavid du Colombier 	for(mb = mbl; mb != nil; mb = mb->next){
8197dd7cddfSDavid du Colombier 		mkstat(&d, mb, nil, Qmbox);
8209a747e4fSDavid du Colombier 		m = convD2M(&d, &buf[n], blen-n);
8219a747e4fSDavid du Colombier 		if(off <= pos){
8229a747e4fSDavid du Colombier 			if(m <= BIT16SZ || m > cnt)
8239a747e4fSDavid du Colombier 				break;
8249a747e4fSDavid du Colombier 			n += m;
8259a747e4fSDavid du Colombier 			cnt -= m;
8269a747e4fSDavid du Colombier 		}
8279a747e4fSDavid du Colombier 		pos += m;
8287dd7cddfSDavid du Colombier 	}
8297dd7cddfSDavid du Colombier 	return n;
8307dd7cddfSDavid du Colombier }
8317dd7cddfSDavid du Colombier 
8327dd7cddfSDavid du Colombier int
readmboxdir(Fid * f,uchar * buf,long off,int cnt,int blen)8339a747e4fSDavid du Colombier readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
8347dd7cddfSDavid du Colombier {
8357dd7cddfSDavid du Colombier 	Dir d;
8369a747e4fSDavid du Colombier 	int n, m;
8377dd7cddfSDavid du Colombier 	long pos;
8389a747e4fSDavid du Colombier 	Message *msg;
8397dd7cddfSDavid du Colombier 
84080ee5cbfSDavid du Colombier 	n = 0;
84180ee5cbfSDavid du Colombier 	if(f->mb->ctl){
84280ee5cbfSDavid du Colombier 		mkstat(&d, f->mb, nil, Qmboxctl);
8439a747e4fSDavid du Colombier 		m = convD2M(&d, &buf[n], blen);
8449a747e4fSDavid du Colombier 		if(off == 0){
8459a747e4fSDavid du Colombier 			if(m <= BIT16SZ || m > cnt){
8469a747e4fSDavid du Colombier 				f->fptr = nil;
8479a747e4fSDavid du Colombier 				return 0;
8489a747e4fSDavid du Colombier 			}
8499a747e4fSDavid du Colombier 			n += m;
8509a747e4fSDavid du Colombier 			cnt -= m;
85180ee5cbfSDavid du Colombier 		} else
8529a747e4fSDavid du Colombier 			off -= m;
85380ee5cbfSDavid du Colombier 	}
85480ee5cbfSDavid du Colombier 
8557dd7cddfSDavid du Colombier 	// to avoid n**2 reads of the directory, use a saved finger pointer
8569a747e4fSDavid du Colombier 	if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){
8579a747e4fSDavid du Colombier 		msg = f->fptr;
8587dd7cddfSDavid du Colombier 		pos = f->foff;
8597dd7cddfSDavid du Colombier 	} else {
8609a747e4fSDavid du Colombier 		msg = f->mb->root->part;
8617dd7cddfSDavid du Colombier 		pos = 0;
8627dd7cddfSDavid du Colombier 	}
8637dd7cddfSDavid du Colombier 
8649a747e4fSDavid du Colombier 	for(; cnt > 0 && msg != nil; msg = msg->next){
8657dd7cddfSDavid du Colombier 		// act like deleted files aren't there
8669a747e4fSDavid du Colombier 		if(msg->deleted)
8677dd7cddfSDavid du Colombier 			continue;
8687dd7cddfSDavid du Colombier 
8699a747e4fSDavid du Colombier 		mkstat(&d, f->mb, msg, Qdir);
8709a747e4fSDavid du Colombier 		m = convD2M(&d, &buf[n], blen-n);
8719a747e4fSDavid du Colombier 		if(off <= pos){
8729a747e4fSDavid du Colombier 			if(m <= BIT16SZ || m > cnt)
8739a747e4fSDavid du Colombier 				break;
8749a747e4fSDavid du Colombier 			n += m;
8759a747e4fSDavid du Colombier 			cnt -= m;
8767dd7cddfSDavid du Colombier 		}
8779a747e4fSDavid du Colombier 		pos += m;
8787dd7cddfSDavid du Colombier 	}
8797dd7cddfSDavid du Colombier 
8807dd7cddfSDavid du Colombier 	// save a finger pointer for next read of the mbox directory
8817dd7cddfSDavid du Colombier 	f->foff = pos;
8829a747e4fSDavid du Colombier 	f->fptr = msg;
8837dd7cddfSDavid du Colombier 	f->fvers = f->mb->vers;
8847dd7cddfSDavid du Colombier 
8857dd7cddfSDavid du Colombier 	return n;
8867dd7cddfSDavid du Colombier }
8877dd7cddfSDavid du Colombier 
8887dd7cddfSDavid du Colombier int
readmsgdir(Fid * f,uchar * buf,long off,int cnt,int blen)8899a747e4fSDavid du Colombier readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
8907dd7cddfSDavid du Colombier {
8917dd7cddfSDavid du Colombier 	Dir d;
8929a747e4fSDavid du Colombier 	int i, n, m;
8939a747e4fSDavid du Colombier 	long pos;
8949a747e4fSDavid du Colombier 	Message *msg;
8957dd7cddfSDavid du Colombier 
8967dd7cddfSDavid du Colombier 	n = 0;
8979a747e4fSDavid du Colombier 	pos = 0;
8989a747e4fSDavid du Colombier 	for(i = 0; i < Qmax; i++){
8997dd7cddfSDavid du Colombier 		mkstat(&d, f->mb, f->m, i);
9009a747e4fSDavid du Colombier 		m = convD2M(&d, &buf[n], blen-n);
9019a747e4fSDavid du Colombier 		if(off <= pos){
9029a747e4fSDavid du Colombier 			if(m <= BIT16SZ || m > cnt)
9039a747e4fSDavid du Colombier 				return n;
9049a747e4fSDavid du Colombier 			n += m;
9059a747e4fSDavid du Colombier 			cnt -= m;
9067dd7cddfSDavid du Colombier 		}
9079a747e4fSDavid du Colombier 		pos += m;
9087dd7cddfSDavid du Colombier 	}
9099a747e4fSDavid du Colombier 	for(msg = f->m->part; msg != nil; msg = msg->next){
9109a747e4fSDavid du Colombier 		mkstat(&d, f->mb, msg, Qdir);
9119a747e4fSDavid du Colombier 		m = convD2M(&d, &buf[n], blen-n);
9129a747e4fSDavid du Colombier 		if(off <= pos){
9139a747e4fSDavid du Colombier 			if(m <= BIT16SZ || m > cnt)
9149a747e4fSDavid du Colombier 				break;
9159a747e4fSDavid du Colombier 			n += m;
9169a747e4fSDavid du Colombier 			cnt -= m;
9179a747e4fSDavid du Colombier 		}
9189a747e4fSDavid du Colombier 		pos += m;
9197dd7cddfSDavid du Colombier 	}
9207dd7cddfSDavid du Colombier 
9217dd7cddfSDavid du Colombier 	return n;
9227dd7cddfSDavid du Colombier }
9237dd7cddfSDavid du Colombier 
9247dd7cddfSDavid du Colombier char*
rread(Fid * f)9257dd7cddfSDavid du Colombier rread(Fid *f)
9267dd7cddfSDavid du Colombier {
9277dd7cddfSDavid du Colombier 	long off;
9287dd7cddfSDavid du Colombier 	int t, i, n, cnt;
9297dd7cddfSDavid du Colombier 	char *p;
9307dd7cddfSDavid du Colombier 
9319a747e4fSDavid du Colombier 	rhdr.count = 0;
9329a747e4fSDavid du Colombier 	off = thdr.offset;
9339a747e4fSDavid du Colombier 	cnt = thdr.count;
9349a747e4fSDavid du Colombier 
9359a747e4fSDavid du Colombier 	if(cnt > messagesize - IOHDRSZ)
9369a747e4fSDavid du Colombier 		cnt = messagesize - IOHDRSZ;
9379a747e4fSDavid du Colombier 
9389a747e4fSDavid du Colombier 	rhdr.data = (char*)mbuf;
9397dd7cddfSDavid du Colombier 
9407dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
9419a747e4fSDavid du Colombier 	if(f->qid.type & QTDIR){
9427dd7cddfSDavid du Colombier 		if(t == Qtop) {
9437dd7cddfSDavid du Colombier 			qlock(&mbllock);
9449a747e4fSDavid du Colombier 			n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
9457dd7cddfSDavid du Colombier 			qunlock(&mbllock);
9467dd7cddfSDavid du Colombier 		} else if(t == Qmbox) {
9477dd7cddfSDavid du Colombier 			qlock(f->mb);
9487dd7cddfSDavid du Colombier 			if(off == 0)
9497dd7cddfSDavid du Colombier 				syncmbox(f->mb, 1);
9509a747e4fSDavid du Colombier 			n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
9517dd7cddfSDavid du Colombier 			qunlock(f->mb);
95280ee5cbfSDavid du Colombier 		} else if(t == Qmboxctl) {
95380ee5cbfSDavid du Colombier 			n = 0;
9547dd7cddfSDavid du Colombier 		} else {
9559a747e4fSDavid du Colombier 			n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
9567dd7cddfSDavid du Colombier 		}
9577dd7cddfSDavid du Colombier 
9589a747e4fSDavid du Colombier 		rhdr.count = n;
9597dd7cddfSDavid du Colombier 		return nil;
9607dd7cddfSDavid du Colombier 	}
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qheader){
9639a747e4fSDavid du Colombier 		rhdr.count = readheader(f->m, (char*)mbuf, off, cnt);
9647dd7cddfSDavid du Colombier 		return nil;
9657dd7cddfSDavid du Colombier 	}
9667dd7cddfSDavid du Colombier 
9677dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qinfo){
9689a747e4fSDavid du Colombier 		rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt);
9697dd7cddfSDavid du Colombier 		return nil;
9707dd7cddfSDavid du Colombier 	}
9717dd7cddfSDavid du Colombier 
9727dd7cddfSDavid du Colombier 	i = fileinfo(f->m, FILE(f->qid.path), &p);
9737dd7cddfSDavid du Colombier 	if(off < i){
9747dd7cddfSDavid du Colombier 		if((off + cnt) > i)
9757dd7cddfSDavid du Colombier 			cnt = i - off;
9769a747e4fSDavid du Colombier 		memmove(mbuf, p + off, cnt);
9779a747e4fSDavid du Colombier 		rhdr.count = cnt;
9787dd7cddfSDavid du Colombier 	}
9797dd7cddfSDavid du Colombier 	return nil;
9807dd7cddfSDavid du Colombier }
9817dd7cddfSDavid du Colombier 
9827dd7cddfSDavid du Colombier char*
rwrite(Fid * f)9837dd7cddfSDavid du Colombier rwrite(Fid *f)
9847dd7cddfSDavid du Colombier {
9857dd7cddfSDavid du Colombier 	char *err;
9867dd7cddfSDavid du Colombier 	char *token[1024];
9877dd7cddfSDavid du Colombier 	int t, n;
9887dd7cddfSDavid du Colombier 	String *file;
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
9919a747e4fSDavid du Colombier 	rhdr.count = thdr.count;
9927dd7cddfSDavid du Colombier 	switch(t){
9937dd7cddfSDavid du Colombier 	case Qctl:
9949a747e4fSDavid du Colombier 		if(thdr.count == 0)
9957dd7cddfSDavid du Colombier 			return Ebadctl;
9969a747e4fSDavid du Colombier 		if(thdr.data[thdr.count-1] == '\n')
9979a747e4fSDavid du Colombier 			thdr.data[thdr.count-1] = 0;
9987dd7cddfSDavid du Colombier 		else
9999a747e4fSDavid du Colombier 			thdr.data[thdr.count] = 0;
10009a747e4fSDavid du Colombier 		n = tokenize(thdr.data, token, nelem(token));
10017dd7cddfSDavid du Colombier 		if(n == 0)
10027dd7cddfSDavid du Colombier 			return Ebadctl;
10037dd7cddfSDavid du Colombier 		if(strcmp(token[0], "open") == 0){
10047dd7cddfSDavid du Colombier 			file = s_new();
10057dd7cddfSDavid du Colombier 			switch(n){
10067dd7cddfSDavid du Colombier 			case 1:
10077dd7cddfSDavid du Colombier 				err = Ebadctl;
10087dd7cddfSDavid du Colombier 				break;
10097dd7cddfSDavid du Colombier 			case 2:
10107dd7cddfSDavid du Colombier 				mboxpath(token[1], getlog(), file, 0);
10117dd7cddfSDavid du Colombier 				err = newmbox(s_to_c(file), nil, 0);
10127dd7cddfSDavid du Colombier 				break;
10137dd7cddfSDavid du Colombier 			default:
10147dd7cddfSDavid du Colombier 				mboxpath(token[1], getlog(), file, 0);
101580ee5cbfSDavid du Colombier 				if(strchr(token[2], '/') != nil)
101680ee5cbfSDavid du Colombier 					err = "/ not allowed in mailbox name";
101780ee5cbfSDavid du Colombier 				else
10187dd7cddfSDavid du Colombier 					err = newmbox(s_to_c(file), token[2], 0);
10197dd7cddfSDavid du Colombier 				break;
10207dd7cddfSDavid du Colombier 			}
10217dd7cddfSDavid du Colombier 			s_free(file);
10227dd7cddfSDavid du Colombier 			return err;
10237dd7cddfSDavid du Colombier 		}
10247dd7cddfSDavid du Colombier 		if(strcmp(token[0], "close") == 0){
10257dd7cddfSDavid du Colombier 			if(n < 2)
10267dd7cddfSDavid du Colombier 				return nil;
10277dd7cddfSDavid du Colombier 			freembox(token[1]);
10287dd7cddfSDavid du Colombier 			return nil;
10297dd7cddfSDavid du Colombier 		}
10307dd7cddfSDavid du Colombier 		if(strcmp(token[0], "delete") == 0){
10317dd7cddfSDavid du Colombier 			if(n < 3)
10327dd7cddfSDavid du Colombier 				return nil;
10337dd7cddfSDavid du Colombier 			delmessages(n-1, &token[1]);
10347dd7cddfSDavid du Colombier 			return nil;
10357dd7cddfSDavid du Colombier 		}
10367dd7cddfSDavid du Colombier 		return Ebadctl;
103780ee5cbfSDavid du Colombier 	case Qmboxctl:
103880ee5cbfSDavid du Colombier 		if(f->mb && f->mb->ctl){
10399a747e4fSDavid du Colombier 			if(thdr.count == 0)
104080ee5cbfSDavid du Colombier 				return Ebadctl;
10419a747e4fSDavid du Colombier 			if(thdr.data[thdr.count-1] == '\n')
10429a747e4fSDavid du Colombier 				thdr.data[thdr.count-1] = 0;
104380ee5cbfSDavid du Colombier 			else
10449a747e4fSDavid du Colombier 				thdr.data[thdr.count] = 0;
10459a747e4fSDavid du Colombier 			n = tokenize(thdr.data, token, nelem(token));
104680ee5cbfSDavid du Colombier 			if(n == 0)
104780ee5cbfSDavid du Colombier 				return Ebadctl;
104880ee5cbfSDavid du Colombier 			return (*f->mb->ctl)(f->mb, n, token);
104980ee5cbfSDavid du Colombier 		}
10507dd7cddfSDavid du Colombier 	}
10517dd7cddfSDavid du Colombier 	return Eperm;
10527dd7cddfSDavid du Colombier }
10537dd7cddfSDavid du Colombier 
10547dd7cddfSDavid du Colombier char *
rclunk(Fid * f)10557dd7cddfSDavid du Colombier rclunk(Fid *f)
10567dd7cddfSDavid du Colombier {
10577dd7cddfSDavid du Colombier 	Mailbox *mb;
10587dd7cddfSDavid du Colombier 
10597dd7cddfSDavid du Colombier 	f->busy = 0;
10607dd7cddfSDavid du Colombier 	f->open = 0;
10617dd7cddfSDavid du Colombier 	if(f->mtop != nil){
10627dd7cddfSDavid du Colombier 		qlock(f->mb);
10637dd7cddfSDavid du Colombier 		msgdecref(f->mb, f->mtop);
10647dd7cddfSDavid du Colombier 		qunlock(f->mb);
10657dd7cddfSDavid du Colombier 	}
10667dd7cddfSDavid du Colombier 	f->m = f->mtop = nil;
10677dd7cddfSDavid du Colombier 	mb = f->mb;
10687dd7cddfSDavid du Colombier 	if(mb != nil){
10697dd7cddfSDavid du Colombier 		f->mb = nil;
10709a747e4fSDavid du Colombier 		assert(mb->refs > 0);
10717dd7cddfSDavid du Colombier 		qlock(&mbllock);
10727dd7cddfSDavid du Colombier 		mboxdecref(mb);
10737dd7cddfSDavid du Colombier 		qunlock(&mbllock);
10747dd7cddfSDavid du Colombier 	}
10755d459b5aSDavid du Colombier 	f->fid = -1;
10767dd7cddfSDavid du Colombier 	return 0;
10777dd7cddfSDavid du Colombier }
10787dd7cddfSDavid du Colombier 
10797dd7cddfSDavid du Colombier char *
rremove(Fid * f)10807dd7cddfSDavid du Colombier rremove(Fid *f)
10817dd7cddfSDavid du Colombier {
10829a747e4fSDavid du Colombier 	if(f->m != nil){
10837dd7cddfSDavid du Colombier 		if(f->m->deleted == 0)
10847dd7cddfSDavid du Colombier 			mailplumb(f->mb, f->m, 1);
10857dd7cddfSDavid du Colombier 		f->m->deleted = 1;
10869a747e4fSDavid du Colombier 	}
10877dd7cddfSDavid du Colombier 	return rclunk(f);
10887dd7cddfSDavid du Colombier }
10897dd7cddfSDavid du Colombier 
10907dd7cddfSDavid du Colombier char *
rstat(Fid * f)10917dd7cddfSDavid du Colombier rstat(Fid *f)
10927dd7cddfSDavid du Colombier {
10937dd7cddfSDavid du Colombier 	Dir d;
10947dd7cddfSDavid du Colombier 
10957dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qmbox){
10967dd7cddfSDavid du Colombier 		qlock(f->mb);
10977dd7cddfSDavid du Colombier 		syncmbox(f->mb, 1);
10987dd7cddfSDavid du Colombier 		qunlock(f->mb);
10997dd7cddfSDavid du Colombier 	}
11007dd7cddfSDavid du Colombier 	mkstat(&d, f->mb, f->m, FILE(f->qid.path));
11019a747e4fSDavid du Colombier 	rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
11029a747e4fSDavid du Colombier 	rhdr.stat = mbuf;
11037dd7cddfSDavid du Colombier 	return 0;
11047dd7cddfSDavid du Colombier }
11057dd7cddfSDavid du Colombier 
11067dd7cddfSDavid du Colombier char *
rwstat(Fid *)11077dd7cddfSDavid du Colombier rwstat(Fid*)
11087dd7cddfSDavid du Colombier {
11097dd7cddfSDavid du Colombier 	return Eperm;
11107dd7cddfSDavid du Colombier }
11117dd7cddfSDavid du Colombier 
11127dd7cddfSDavid du Colombier Fid *
newfid(int fid)11137dd7cddfSDavid du Colombier newfid(int fid)
11147dd7cddfSDavid du Colombier {
11157dd7cddfSDavid du Colombier 	Fid *f, *ff;
11167dd7cddfSDavid du Colombier 
11177dd7cddfSDavid du Colombier 	ff = 0;
11187dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next)
11197dd7cddfSDavid du Colombier 		if(f->fid == fid)
11207dd7cddfSDavid du Colombier 			return f;
11217dd7cddfSDavid du Colombier 		else if(!ff && !f->busy)
11227dd7cddfSDavid du Colombier 			ff = f;
11237dd7cddfSDavid du Colombier 	if(ff){
11247dd7cddfSDavid du Colombier 		ff->fid = fid;
11259a747e4fSDavid du Colombier 		ff->fptr = nil;
11267dd7cddfSDavid du Colombier 		return ff;
11277dd7cddfSDavid du Colombier 	}
11287dd7cddfSDavid du Colombier 	f = emalloc(sizeof *f);
11297dd7cddfSDavid du Colombier 	f->fid = fid;
11309a747e4fSDavid du Colombier 	f->fptr = nil;
11317dd7cddfSDavid du Colombier 	f->next = fids;
11327dd7cddfSDavid du Colombier 	fids = f;
11337dd7cddfSDavid du Colombier 	return f;
11347dd7cddfSDavid du Colombier }
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier int
fidmboxrefs(Mailbox * mb)11377dd7cddfSDavid du Colombier fidmboxrefs(Mailbox *mb)
11387dd7cddfSDavid du Colombier {
11397dd7cddfSDavid du Colombier 	Fid *f;
11407dd7cddfSDavid du Colombier 	int refs = 0;
11417dd7cddfSDavid du Colombier 
11427dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next){
11437dd7cddfSDavid du Colombier 		if(f->mb == mb)
11447dd7cddfSDavid du Colombier 			refs++;
11457dd7cddfSDavid du Colombier 	}
11467dd7cddfSDavid du Colombier 	return refs;
11477dd7cddfSDavid du Colombier }
11487dd7cddfSDavid du Colombier 
11497dd7cddfSDavid du Colombier void
io(void)11507dd7cddfSDavid du Colombier io(void)
11517dd7cddfSDavid du Colombier {
11527dd7cddfSDavid du Colombier 	char *err;
11537dd7cddfSDavid du Colombier 	int n;
11547dd7cddfSDavid du Colombier 
11559a747e4fSDavid du Colombier 	/* start a process to watch the mailboxes*/
115659cc4ca5SDavid du Colombier 	if(plumbing){
11577dd7cddfSDavid du Colombier 		switch(rfork(RFPROC|RFMEM)){
11587dd7cddfSDavid du Colombier 		case -1:
11597dd7cddfSDavid du Colombier 			/* oh well */
11607dd7cddfSDavid du Colombier 			break;
11617dd7cddfSDavid du Colombier 		case 0:
11627dd7cddfSDavid du Colombier 			reader();
11637dd7cddfSDavid du Colombier 			exits(nil);
11647dd7cddfSDavid du Colombier 		default:
11657dd7cddfSDavid du Colombier 			break;
11667dd7cddfSDavid du Colombier 		}
116759cc4ca5SDavid du Colombier 	}
11687dd7cddfSDavid du Colombier 
11697dd7cddfSDavid du Colombier 	for(;;){
11707dd7cddfSDavid du Colombier 		/*
11717dd7cddfSDavid du Colombier 		 * reading from a pipe or a network device
11727dd7cddfSDavid du Colombier 		 * will give an error after a few eof reads
11737dd7cddfSDavid du Colombier 		 * however, we cannot tell the difference
11747dd7cddfSDavid du Colombier 		 * between a zero-length read and an interrupt
11757dd7cddfSDavid du Colombier 		 * on the processes writing to us,
11767dd7cddfSDavid du Colombier 		 * so we wait for the error
11777dd7cddfSDavid du Colombier 		 */
11785d459b5aSDavid du Colombier 		checkmboxrefs();
11799a747e4fSDavid du Colombier 		n = read9pmsg(mfd[0], mdata, messagesize);
11807dd7cddfSDavid du Colombier 		if(n == 0)
11817dd7cddfSDavid du Colombier 			continue;
11827dd7cddfSDavid du Colombier 		if(n < 0)
11837dd7cddfSDavid du Colombier 			return;
11849a747e4fSDavid du Colombier 		if(convM2S(mdata, n, &thdr) == 0)
11857dd7cddfSDavid du Colombier 			continue;
11867dd7cddfSDavid du Colombier 
11877dd7cddfSDavid du Colombier 		if(debug)
11889a747e4fSDavid du Colombier 			fprint(2, "%s:<-%F\n", argv0, &thdr);
11897dd7cddfSDavid du Colombier 
11909a747e4fSDavid du Colombier 		rhdr.data = (char*)mdata + messagesize;
11919a747e4fSDavid du Colombier 		if(!fcalls[thdr.type])
11927dd7cddfSDavid du Colombier 			err = "bad fcall type";
11937dd7cddfSDavid du Colombier 		else
11949a747e4fSDavid du Colombier 			err = (*fcalls[thdr.type])(newfid(thdr.fid));
11957dd7cddfSDavid du Colombier 		if(err){
11969a747e4fSDavid du Colombier 			rhdr.type = Rerror;
11979a747e4fSDavid du Colombier 			rhdr.ename = err;
11987dd7cddfSDavid du Colombier 		}else{
11999a747e4fSDavid du Colombier 			rhdr.type = thdr.type + 1;
12009a747e4fSDavid du Colombier 			rhdr.fid = thdr.fid;
12017dd7cddfSDavid du Colombier 		}
12029a747e4fSDavid du Colombier 		rhdr.tag = thdr.tag;
12037dd7cddfSDavid du Colombier 		if(debug)
12049a747e4fSDavid du Colombier 			fprint(2, "%s:->%F\n", argv0, &rhdr);/**/
12059a747e4fSDavid du Colombier 		n = convS2M(&rhdr, mdata, messagesize);
12067dd7cddfSDavid du Colombier 		if(write(mfd[1], mdata, n) != n)
12077dd7cddfSDavid du Colombier 			error("mount write");
12087dd7cddfSDavid du Colombier 	}
12097dd7cddfSDavid du Colombier }
12107dd7cddfSDavid du Colombier 
12117dd7cddfSDavid du Colombier void
reader(void)12127dd7cddfSDavid du Colombier reader(void)
12137dd7cddfSDavid du Colombier {
121480ee5cbfSDavid du Colombier 	ulong t;
12159a747e4fSDavid du Colombier 	Dir *d;
12167dd7cddfSDavid du Colombier 	Mailbox *mb;
12177dd7cddfSDavid du Colombier 
12187dd7cddfSDavid du Colombier 	sleep(15*1000);
12197dd7cddfSDavid du Colombier 	for(;;){
122080ee5cbfSDavid du Colombier 		t = time(0);
12217dd7cddfSDavid du Colombier 		qlock(&mbllock);
12227dd7cddfSDavid du Colombier 		for(mb = mbl; mb != nil; mb = mb->next){
12239a747e4fSDavid du Colombier 			assert(mb->refs > 0);
122480ee5cbfSDavid du Colombier 			if(mb->waketime != 0 && t > mb->waketime){
122580ee5cbfSDavid du Colombier 				qlock(mb);
122680ee5cbfSDavid du Colombier 				mb->waketime = 0;
122780ee5cbfSDavid du Colombier 				break;
122880ee5cbfSDavid du Colombier 			}
122980ee5cbfSDavid du Colombier 
12309a747e4fSDavid du Colombier 			d = dirstat(mb->path);
12319a747e4fSDavid du Colombier 			if(d == nil)
12327dd7cddfSDavid du Colombier 				continue;
12337dd7cddfSDavid du Colombier 
12343ff48bf5SDavid du Colombier 			qlock(mb);
12350fb3f58eSDavid du Colombier 			if(mb->d)
12369a747e4fSDavid du Colombier 			if(d->qid.path != mb->d->qid.path
12370fb3f58eSDavid du Colombier 			   || d->qid.vers != mb->d->qid.vers){
12389a747e4fSDavid du Colombier 				free(d);
12397dd7cddfSDavid du Colombier 				break;
12407dd7cddfSDavid du Colombier 			}
12413ff48bf5SDavid du Colombier 			qunlock(mb);
12429a747e4fSDavid du Colombier 			free(d);
12437dd7cddfSDavid du Colombier 		}
12447dd7cddfSDavid du Colombier 		qunlock(&mbllock);
12457dd7cddfSDavid du Colombier 		if(mb != nil){
12467dd7cddfSDavid du Colombier 			syncmbox(mb, 1);
12477dd7cddfSDavid du Colombier 			qunlock(mb);
12487dd7cddfSDavid du Colombier 		} else
12497dd7cddfSDavid du Colombier 			sleep(15*1000);
12507dd7cddfSDavid du Colombier 	}
12517dd7cddfSDavid du Colombier }
12527dd7cddfSDavid du Colombier 
12537dd7cddfSDavid du Colombier int
newid(void)12547dd7cddfSDavid du Colombier newid(void)
12557dd7cddfSDavid du Colombier {
12567dd7cddfSDavid du Colombier 	int rv;
12577dd7cddfSDavid du Colombier 	static int id;
12587dd7cddfSDavid du Colombier 	static Lock idlock;
12597dd7cddfSDavid du Colombier 
12607dd7cddfSDavid du Colombier 	lock(&idlock);
12617dd7cddfSDavid du Colombier 	rv = ++id;
12627dd7cddfSDavid du Colombier 	unlock(&idlock);
12637dd7cddfSDavid du Colombier 
12647dd7cddfSDavid du Colombier 	return rv;
12657dd7cddfSDavid du Colombier }
12667dd7cddfSDavid du Colombier 
12677dd7cddfSDavid du Colombier void
error(char * s)12687dd7cddfSDavid du Colombier error(char *s)
12697dd7cddfSDavid du Colombier {
12707dd7cddfSDavid du Colombier 	postnote(PNGROUP, getpid(), "die yankee pig dog");
12717dd7cddfSDavid du Colombier 	fprint(2, "%s: %s: %r\n", argv0, s);
12727dd7cddfSDavid du Colombier 	exits(s);
12737dd7cddfSDavid du Colombier }
12747dd7cddfSDavid du Colombier 
12757dd7cddfSDavid du Colombier 
12767dd7cddfSDavid du Colombier typedef struct Ignorance Ignorance;
12777dd7cddfSDavid du Colombier struct Ignorance
12787dd7cddfSDavid du Colombier {
12797dd7cddfSDavid du Colombier 	Ignorance *next;
12807dd7cddfSDavid du Colombier 	char	*str;		/* string */
12817dd7cddfSDavid du Colombier 	int	partial;	/* true if not exact match */
12827dd7cddfSDavid du Colombier };
12837dd7cddfSDavid du Colombier Ignorance *ignorance;
12847dd7cddfSDavid du Colombier 
12857dd7cddfSDavid du Colombier /*
12867dd7cddfSDavid du Colombier  *  read the file of headers to ignore
12877dd7cddfSDavid du Colombier  */
12887dd7cddfSDavid du Colombier void
readignore(void)12897dd7cddfSDavid du Colombier readignore(void)
12907dd7cddfSDavid du Colombier {
12917dd7cddfSDavid du Colombier 	char *p;
12927dd7cddfSDavid du Colombier 	Ignorance *i;
12937dd7cddfSDavid du Colombier 	Biobuf *b;
12947dd7cddfSDavid du Colombier 
12957dd7cddfSDavid du Colombier 	if(ignorance != nil)
12967dd7cddfSDavid du Colombier 		return;
12977dd7cddfSDavid du Colombier 
12987dd7cddfSDavid du Colombier 	b = Bopen("/mail/lib/ignore", OREAD);
12997dd7cddfSDavid du Colombier 	if(b == 0)
13007dd7cddfSDavid du Colombier 		return;
13017dd7cddfSDavid du Colombier 	while(p = Brdline(b, '\n')){
13027dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = 0;
13037dd7cddfSDavid du Colombier 		while(*p && (*p == ' ' || *p == '\t'))
13047dd7cddfSDavid du Colombier 			p++;
13057dd7cddfSDavid du Colombier 		if(*p == '#')
13067dd7cddfSDavid du Colombier 			continue;
13077dd7cddfSDavid du Colombier 		i = malloc(sizeof(Ignorance));
13087dd7cddfSDavid du Colombier 		if(i == 0)
13097dd7cddfSDavid du Colombier 			break;
13107dd7cddfSDavid du Colombier 		i->partial = strlen(p);
13117dd7cddfSDavid du Colombier 		i->str = strdup(p);
13127dd7cddfSDavid du Colombier 		if(i->str == 0){
13137dd7cddfSDavid du Colombier 			free(i);
13147dd7cddfSDavid du Colombier 			break;
13157dd7cddfSDavid du Colombier 		}
13167dd7cddfSDavid du Colombier 		i->next = ignorance;
13177dd7cddfSDavid du Colombier 		ignorance = i;
13187dd7cddfSDavid du Colombier 	}
13197dd7cddfSDavid du Colombier 	Bterm(b);
13207dd7cddfSDavid du Colombier }
13217dd7cddfSDavid du Colombier 
13227dd7cddfSDavid du Colombier int
ignore(char * p)13237dd7cddfSDavid du Colombier ignore(char *p)
13247dd7cddfSDavid du Colombier {
13257dd7cddfSDavid du Colombier 	Ignorance *i;
13267dd7cddfSDavid du Colombier 
13277dd7cddfSDavid du Colombier 	readignore();
13287dd7cddfSDavid du Colombier 	for(i = ignorance; i != nil; i = i->next)
13297dd7cddfSDavid du Colombier 		if(cistrncmp(i->str, p, i->partial) == 0)
13307dd7cddfSDavid du Colombier 			return 1;
13317dd7cddfSDavid du Colombier 	return 0;
13327dd7cddfSDavid du Colombier }
13337dd7cddfSDavid du Colombier 
13347dd7cddfSDavid du Colombier int
hdrlen(char * p,char * e)13357dd7cddfSDavid du Colombier hdrlen(char *p, char *e)
13367dd7cddfSDavid du Colombier {
13377dd7cddfSDavid du Colombier 	char *ep;
13387dd7cddfSDavid du Colombier 
13397dd7cddfSDavid du Colombier 	ep = p;
13407dd7cddfSDavid du Colombier 	do {
13417dd7cddfSDavid du Colombier 		ep = strchr(ep, '\n');
13427dd7cddfSDavid du Colombier 		if(ep == nil){
13437dd7cddfSDavid du Colombier 			ep = e;
13447dd7cddfSDavid du Colombier 			break;
13457dd7cddfSDavid du Colombier 		}
13467dd7cddfSDavid du Colombier 		ep++;
13477dd7cddfSDavid du Colombier 		if(ep >= e){
13487dd7cddfSDavid du Colombier 			ep = e;
13497dd7cddfSDavid du Colombier 			break;
13507dd7cddfSDavid du Colombier 		}
13517dd7cddfSDavid du Colombier 	} while(*ep == ' ' || *ep == '\t');
13527dd7cddfSDavid du Colombier 	return ep - p;
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier 
1355816336a7SDavid du Colombier // rfc2047 non-ascii: =?charset?q?encoded-text?=
13567dd7cddfSDavid du Colombier int
rfc2047convert(String * s,char * token,int len)13575d459b5aSDavid du Colombier rfc2047convert(String *s, char *token, int len)
13587dd7cddfSDavid du Colombier {
1359816336a7SDavid du Colombier 	char charset[100], decoded[1024], *e, *x;
1360816336a7SDavid du Colombier 	int l;
13617dd7cddfSDavid du Colombier 
13627dd7cddfSDavid du Colombier 	if(len == 0)
13637dd7cddfSDavid du Colombier 		return -1;
13647dd7cddfSDavid du Colombier 
13657dd7cddfSDavid du Colombier 	e = token+len-2;
13667dd7cddfSDavid du Colombier 	token += 2;
13677dd7cddfSDavid du Colombier 
1368816336a7SDavid du Colombier 	x = memchr(token, '?', e-token);
1369816336a7SDavid du Colombier 	if(x == nil || (l=x-token) >= sizeof charset)
13707dd7cddfSDavid du Colombier 		return -1;
1371816336a7SDavid du Colombier 	memmove(charset, token, l);
1372816336a7SDavid du Colombier 	charset[l] = 0;
1373816336a7SDavid du Colombier 
1374816336a7SDavid du Colombier 	token = x+1;
13757dd7cddfSDavid du Colombier 
13767dd7cddfSDavid du Colombier 	// bail if it doesn't fit
13773ff48bf5SDavid du Colombier 	if(e-token > sizeof(decoded)-1)
13787dd7cddfSDavid du Colombier 		return -1;
13797dd7cddfSDavid du Colombier 
13807dd7cddfSDavid du Colombier 	// bail if we don't understand the encoding
13817dd7cddfSDavid du Colombier 	if(cistrncmp(token, "b?", 2) == 0){
13827dd7cddfSDavid du Colombier 		token += 2;
13837dd7cddfSDavid du Colombier 		len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
13847dd7cddfSDavid du Colombier 		decoded[len] = 0;
13857dd7cddfSDavid du Colombier 	} else if(cistrncmp(token, "q?", 2) == 0){
13867dd7cddfSDavid du Colombier 		token += 2;
138717dd33a2SDavid du Colombier 		len = decquoted(decoded, token, e, 1);
13887dd7cddfSDavid du Colombier 		if(len > 0 && decoded[len-1] == '\n')
13897dd7cddfSDavid du Colombier 			len--;
13907dd7cddfSDavid du Colombier 		decoded[len] = 0;
13917dd7cddfSDavid du Colombier 	} else
13927dd7cddfSDavid du Colombier 		return -1;
13937dd7cddfSDavid du Colombier 
1394816336a7SDavid du Colombier 	if(xtoutf(charset, &x, decoded, decoded+len) <= 0)
13957dd7cddfSDavid du Colombier 		s_append(s, decoded);
1396816336a7SDavid du Colombier 	else {
13977dd7cddfSDavid du Colombier 		s_append(s, x);
13987dd7cddfSDavid du Colombier 		free(x);
13997dd7cddfSDavid du Colombier 	}
14007dd7cddfSDavid du Colombier 	return 0;
14017dd7cddfSDavid du Colombier }
14027dd7cddfSDavid du Colombier 
14035d459b5aSDavid du Colombier char*
rfc2047start(char * start,char * end)14045d459b5aSDavid du Colombier rfc2047start(char *start, char *end)
14057dd7cddfSDavid du Colombier {
14065d459b5aSDavid du Colombier 	int quests;
14077dd7cddfSDavid du Colombier 
14085d459b5aSDavid du Colombier 	if(*--end != '=')
14095d459b5aSDavid du Colombier 		return nil;
14105d459b5aSDavid du Colombier 	if(*--end != '?')
14115d459b5aSDavid du Colombier 		return nil;
14125d459b5aSDavid du Colombier 
14135d459b5aSDavid du Colombier 	quests = 0;
14145d459b5aSDavid du Colombier 	for(end--; end >= start; end--){
14155d459b5aSDavid du Colombier 		switch(*end){
14165d459b5aSDavid du Colombier 		case '=':
14175d459b5aSDavid du Colombier 			if(quests == 3 && *(end+1) == '?')
14185d459b5aSDavid du Colombier 				return end;
14195d459b5aSDavid du Colombier 			break;
14205d459b5aSDavid du Colombier 		case '?':
14215d459b5aSDavid du Colombier 			++quests;
14225d459b5aSDavid du Colombier 			break;
14237dd7cddfSDavid du Colombier 		case ' ':
14247dd7cddfSDavid du Colombier 		case '\t':
14257dd7cddfSDavid du Colombier 		case '\n':
14265d459b5aSDavid du Colombier 		case '\r':
14275d459b5aSDavid du Colombier 			/* can't have white space in a token */
14285d459b5aSDavid du Colombier 			return nil;
14297dd7cddfSDavid du Colombier 		}
14305d459b5aSDavid du Colombier 	}
14315d459b5aSDavid du Colombier 	return nil;
14325d459b5aSDavid du Colombier }
14337dd7cddfSDavid du Colombier 
14345d459b5aSDavid du Colombier // convert a header line
14355d459b5aSDavid du Colombier String*
stringconvert(String * s,char * uneaten,int len)14365d459b5aSDavid du Colombier stringconvert(String *s, char *uneaten, int len)
14375d459b5aSDavid du Colombier {
1438816336a7SDavid du Colombier 	char *token, *p, *e;
14395d459b5aSDavid du Colombier 
14405d459b5aSDavid du Colombier 	s = s_reset(s);
14415d459b5aSDavid du Colombier 	p = uneaten;
1442816336a7SDavid du Colombier 	for(e = p+len; p < e; ){
1443816336a7SDavid du Colombier 		while(*p++ == '=' && (token = rfc2047start(uneaten, p))){
14445d459b5aSDavid du Colombier 			s_nappend(s, uneaten, token-uneaten);
14455d459b5aSDavid du Colombier 			if(rfc2047convert(s, token, p - token) < 0)
14465d459b5aSDavid du Colombier 				s_nappend(s, token, p - token);
14475d459b5aSDavid du Colombier 			uneaten = p;
1448816336a7SDavid du Colombier 			for(; p<e && isspace(*p);)
1449816336a7SDavid du Colombier 				p++;
1450816336a7SDavid du Colombier 			if(p+2 < e && p[0] == '=' && p[1] == '?')
1451816336a7SDavid du Colombier 				uneaten = p;	// paste
14527dd7cddfSDavid du Colombier 		}
14535d459b5aSDavid du Colombier 	}
14545d459b5aSDavid du Colombier 	if(p > uneaten)
14555d459b5aSDavid du Colombier 		s_nappend(s, uneaten, p-uneaten);
14567dd7cddfSDavid du Colombier 	return s;
14577dd7cddfSDavid du Colombier }
14587dd7cddfSDavid du Colombier 
14597dd7cddfSDavid du Colombier int
readheader(Message * m,char * buf,int off,int cnt)14607dd7cddfSDavid du Colombier readheader(Message *m, char *buf, int off, int cnt)
14617dd7cddfSDavid du Colombier {
14627dd7cddfSDavid du Colombier 	char *p, *e;
14637dd7cddfSDavid du Colombier 	int n, ns;
14647dd7cddfSDavid du Colombier 	char *to = buf;
14657dd7cddfSDavid du Colombier 	String *s;
14667dd7cddfSDavid du Colombier 
14677dd7cddfSDavid du Colombier 	p = m->header;
14687dd7cddfSDavid du Colombier 	e = m->hend;
14697dd7cddfSDavid du Colombier 	s = nil;
14707dd7cddfSDavid du Colombier 
14717dd7cddfSDavid du Colombier 	// copy in good headers
14727dd7cddfSDavid du Colombier 	while(cnt > 0 && p < e){
14737dd7cddfSDavid du Colombier 		n = hdrlen(p, e);
14747dd7cddfSDavid du Colombier 		if(ignore(p)){
14757dd7cddfSDavid du Colombier 			p += n;
14767dd7cddfSDavid du Colombier 			continue;
14777dd7cddfSDavid du Colombier 		}
14787dd7cddfSDavid du Colombier 
14797dd7cddfSDavid du Colombier 		// rfc2047 processing
14805d459b5aSDavid du Colombier 		s = stringconvert(s, p, n);
14817dd7cddfSDavid du Colombier 		ns = s_len(s);
14827dd7cddfSDavid du Colombier 		if(off > 0){
14837dd7cddfSDavid du Colombier 			if(ns <= off){
14847dd7cddfSDavid du Colombier 				off -= ns;
14857dd7cddfSDavid du Colombier 				p += n;
14867dd7cddfSDavid du Colombier 				continue;
14877dd7cddfSDavid du Colombier 			}
14887dd7cddfSDavid du Colombier 			ns -= off;
14897dd7cddfSDavid du Colombier 		}
14907dd7cddfSDavid du Colombier 		if(ns > cnt)
14917dd7cddfSDavid du Colombier 			ns = cnt;
14927dd7cddfSDavid du Colombier 		memmove(to, s_to_c(s)+off, ns);
14937dd7cddfSDavid du Colombier 		to += ns;
14947dd7cddfSDavid du Colombier 		p += n;
14957dd7cddfSDavid du Colombier 		cnt -= ns;
14967dd7cddfSDavid du Colombier 		off = 0;
14977dd7cddfSDavid du Colombier 	}
14987dd7cddfSDavid du Colombier 
14997dd7cddfSDavid du Colombier 	s_free(s);
15007dd7cddfSDavid du Colombier 	return to - buf;
15017dd7cddfSDavid du Colombier }
15027dd7cddfSDavid du Colombier 
15037dd7cddfSDavid du Colombier int
headerlen(Message * m)15047dd7cddfSDavid du Colombier headerlen(Message *m)
15057dd7cddfSDavid du Colombier {
15067dd7cddfSDavid du Colombier 	char buf[1024];
15077dd7cddfSDavid du Colombier 	int i, n;
15087dd7cddfSDavid du Colombier 
15097dd7cddfSDavid du Colombier 	if(m->hlen >= 0)
15107dd7cddfSDavid du Colombier 		return m->hlen;
15117dd7cddfSDavid du Colombier 	for(n = 0; ; n += i){
15127dd7cddfSDavid du Colombier 		i = readheader(m, buf, n, sizeof(buf));
15137dd7cddfSDavid du Colombier 		if(i <= 0)
15147dd7cddfSDavid du Colombier 			break;
15157dd7cddfSDavid du Colombier 	}
15167dd7cddfSDavid du Colombier 	m->hlen = n;
15177dd7cddfSDavid du Colombier 	return n;
15187dd7cddfSDavid du Colombier }
15197dd7cddfSDavid du Colombier 
15207dd7cddfSDavid du Colombier QLock hashlock;
15217dd7cddfSDavid du Colombier 
15227dd7cddfSDavid du Colombier uint
hash(ulong ppath,char * name)15237dd7cddfSDavid du Colombier hash(ulong ppath, char *name)
15247dd7cddfSDavid du Colombier {
15257dd7cddfSDavid du Colombier 	uchar *p;
15267dd7cddfSDavid du Colombier 	uint h;
15277dd7cddfSDavid du Colombier 
15287dd7cddfSDavid du Colombier 	h = 0;
15297dd7cddfSDavid du Colombier 	for(p = (uchar*)name; *p; p++)
15307dd7cddfSDavid du Colombier 		h = h*7 + *p;
15317dd7cddfSDavid du Colombier 	h += ppath;
15327dd7cddfSDavid du Colombier 
15337dd7cddfSDavid du Colombier 	return h % Hsize;
15347dd7cddfSDavid du Colombier }
15357dd7cddfSDavid du Colombier 
15367dd7cddfSDavid du Colombier Hash*
hlook(ulong ppath,char * name)15377dd7cddfSDavid du Colombier hlook(ulong ppath, char *name)
15387dd7cddfSDavid du Colombier {
15397dd7cddfSDavid du Colombier 	int h;
15407dd7cddfSDavid du Colombier 	Hash *hp;
15417dd7cddfSDavid du Colombier 
15427dd7cddfSDavid du Colombier 	qlock(&hashlock);
15437dd7cddfSDavid du Colombier 	h = hash(ppath, name);
15447dd7cddfSDavid du Colombier 	for(hp = htab[h]; hp != nil; hp = hp->next)
15457dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
15467dd7cddfSDavid du Colombier 			qunlock(&hashlock);
15477dd7cddfSDavid du Colombier 			return hp;
15487dd7cddfSDavid du Colombier 		}
15497dd7cddfSDavid du Colombier 	qunlock(&hashlock);
15507dd7cddfSDavid du Colombier 	return nil;
15517dd7cddfSDavid du Colombier }
15527dd7cddfSDavid du Colombier 
15537dd7cddfSDavid du Colombier void
henter(ulong ppath,char * name,Qid qid,Message * m,Mailbox * mb)15547dd7cddfSDavid du Colombier henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
15557dd7cddfSDavid du Colombier {
15567dd7cddfSDavid du Colombier 	int h;
15577dd7cddfSDavid du Colombier 	Hash *hp, **l;
15587dd7cddfSDavid du Colombier 
15597dd7cddfSDavid du Colombier 	qlock(&hashlock);
15607dd7cddfSDavid du Colombier 	h = hash(ppath, name);
15617dd7cddfSDavid du Colombier 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
15627dd7cddfSDavid du Colombier 		hp = *l;
15637dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
15647dd7cddfSDavid du Colombier 			hp->m = m;
15657dd7cddfSDavid du Colombier 			hp->mb = mb;
15667dd7cddfSDavid du Colombier 			hp->qid = qid;
15677dd7cddfSDavid du Colombier 			qunlock(&hashlock);
15687dd7cddfSDavid du Colombier 			return;
15697dd7cddfSDavid du Colombier 		}
15707dd7cddfSDavid du Colombier 	}
15717dd7cddfSDavid du Colombier 
15727dd7cddfSDavid du Colombier 	*l = hp = emalloc(sizeof(*hp));
15737dd7cddfSDavid du Colombier 	hp->m = m;
15747dd7cddfSDavid du Colombier 	hp->mb = mb;
15757dd7cddfSDavid du Colombier 	hp->qid = qid;
15767dd7cddfSDavid du Colombier 	hp->name = name;
15777dd7cddfSDavid du Colombier 	hp->ppath = ppath;
15787dd7cddfSDavid du Colombier 	qunlock(&hashlock);
15797dd7cddfSDavid du Colombier }
15807dd7cddfSDavid du Colombier 
15817dd7cddfSDavid du Colombier void
hfree(ulong ppath,char * name)15827dd7cddfSDavid du Colombier hfree(ulong ppath, char *name)
15837dd7cddfSDavid du Colombier {
15847dd7cddfSDavid du Colombier 	int h;
15857dd7cddfSDavid du Colombier 	Hash *hp, **l;
15867dd7cddfSDavid du Colombier 
15877dd7cddfSDavid du Colombier 	qlock(&hashlock);
15887dd7cddfSDavid du Colombier 	h = hash(ppath, name);
15897dd7cddfSDavid du Colombier 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
15907dd7cddfSDavid du Colombier 		hp = *l;
15917dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
15925d459b5aSDavid du Colombier 			hp->mb = nil;
15937dd7cddfSDavid du Colombier 			*l = hp->next;
15947dd7cddfSDavid du Colombier 			free(hp);
15957dd7cddfSDavid du Colombier 			break;
15967dd7cddfSDavid du Colombier 		}
15977dd7cddfSDavid du Colombier 	}
15987dd7cddfSDavid du Colombier 	qunlock(&hashlock);
15997dd7cddfSDavid du Colombier }
16007dd7cddfSDavid du Colombier 
16017dd7cddfSDavid du Colombier int
hashmboxrefs(Mailbox * mb)16027dd7cddfSDavid du Colombier hashmboxrefs(Mailbox *mb)
16037dd7cddfSDavid du Colombier {
16047dd7cddfSDavid du Colombier 	int h;
16057dd7cddfSDavid du Colombier 	Hash *hp;
16067dd7cddfSDavid du Colombier 	int refs = 0;
16077dd7cddfSDavid du Colombier 
16087dd7cddfSDavid du Colombier 	qlock(&hashlock);
16097dd7cddfSDavid du Colombier 	for(h = 0; h < Hsize; h++){
16107dd7cddfSDavid du Colombier 		for(hp = htab[h]; hp != nil; hp = hp->next)
16117dd7cddfSDavid du Colombier 			if(hp->mb == mb)
16127dd7cddfSDavid du Colombier 				refs++;
16137dd7cddfSDavid du Colombier 	}
16147dd7cddfSDavid du Colombier 	qunlock(&hashlock);
16157dd7cddfSDavid du Colombier 	return refs;
16167dd7cddfSDavid du Colombier }
161780ee5cbfSDavid du Colombier 
161880ee5cbfSDavid du Colombier void
checkmboxrefs(void)16195d459b5aSDavid du Colombier checkmboxrefs(void)
16205d459b5aSDavid du Colombier {
16215d459b5aSDavid du Colombier 	int f, refs;
16225d459b5aSDavid du Colombier 	Mailbox *mb;
16235d459b5aSDavid du Colombier 
16245d459b5aSDavid du Colombier 	qlock(&mbllock);
16255d459b5aSDavid du Colombier 	for(mb=mbl; mb; mb=mb->next){
16265d459b5aSDavid du Colombier 		qlock(mb);
16275d459b5aSDavid du Colombier 		refs = (f=fidmboxrefs(mb))+1;
16285d459b5aSDavid du Colombier 		if(refs != mb->refs){
16295d459b5aSDavid du Colombier 			fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);
16305d459b5aSDavid du Colombier 			abort();
16315d459b5aSDavid du Colombier 		}
16325d459b5aSDavid du Colombier 		qunlock(mb);
16335d459b5aSDavid du Colombier 	}
16345d459b5aSDavid du Colombier 	qunlock(&mbllock);
16355d459b5aSDavid du Colombier }
16365d459b5aSDavid du Colombier 
16375d459b5aSDavid du Colombier void
post(char * name,char * envname,int srvfd)163880ee5cbfSDavid du Colombier post(char *name, char *envname, int srvfd)
163980ee5cbfSDavid du Colombier {
164080ee5cbfSDavid du Colombier 	int fd;
164180ee5cbfSDavid du Colombier 	char buf[32];
164280ee5cbfSDavid du Colombier 
164380ee5cbfSDavid du Colombier 	fd = create(name, OWRITE, 0600);
164480ee5cbfSDavid du Colombier 	if(fd < 0)
164567031067SDavid du Colombier 		error("post failed");
164680ee5cbfSDavid du Colombier 	sprint(buf, "%d",srvfd);
164780ee5cbfSDavid du Colombier 	if(write(fd, buf, strlen(buf)) != strlen(buf))
164880ee5cbfSDavid du Colombier 		error("srv write");
164980ee5cbfSDavid du Colombier 	close(fd);
165080ee5cbfSDavid du Colombier 	putenv(envname, name);
165180ee5cbfSDavid du Colombier }
1652