xref: /plan9/sys/src/cmd/upas/fs/fs.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include "common.h"
2*7dd7cddfSDavid du Colombier #include <auth.h>
3*7dd7cddfSDavid du Colombier #include <fcall.h>
4*7dd7cddfSDavid du Colombier #include <libsec.h>
5*7dd7cddfSDavid du Colombier #include "dat.h"
6*7dd7cddfSDavid du Colombier 
7*7dd7cddfSDavid du Colombier enum
8*7dd7cddfSDavid du Colombier {
9*7dd7cddfSDavid du Colombier 	OPERM	= 0x3,		// mask of all permission types in open mode
10*7dd7cddfSDavid du Colombier };
11*7dd7cddfSDavid du Colombier 
12*7dd7cddfSDavid du Colombier typedef struct Fid Fid;
13*7dd7cddfSDavid du Colombier 
14*7dd7cddfSDavid du Colombier struct Fid
15*7dd7cddfSDavid du Colombier {
16*7dd7cddfSDavid du Colombier 	Qid	qid;
17*7dd7cddfSDavid du Colombier 	short	busy;
18*7dd7cddfSDavid du Colombier 	short	open;
19*7dd7cddfSDavid du Colombier 	int	fid;
20*7dd7cddfSDavid du Colombier 	Fid	*next;
21*7dd7cddfSDavid du Colombier 	Mailbox	*mb;
22*7dd7cddfSDavid du Colombier 	Message	*m;
23*7dd7cddfSDavid du Colombier 	Message *mtop;		// top level message
24*7dd7cddfSDavid du Colombier 
25*7dd7cddfSDavid du Colombier 	//finger pointers to speed up reads of large directories
26*7dd7cddfSDavid du Colombier 	long	foff;	// offset/DIRLEN of finger
27*7dd7cddfSDavid du Colombier 	Message	*fptr;	// pointer to message at off
28*7dd7cddfSDavid du Colombier 	int	fvers;	// mailbox version when finger was saved
29*7dd7cddfSDavid du Colombier };
30*7dd7cddfSDavid du Colombier 
31*7dd7cddfSDavid du Colombier ulong	path;		// incremented for each new file
32*7dd7cddfSDavid du Colombier Fid	*fids;
33*7dd7cddfSDavid du Colombier int	mfd[2];
34*7dd7cddfSDavid du Colombier char	user[NAMELEN];
35*7dd7cddfSDavid du Colombier char	mdata[MAXMSG+MAXFDATA];
36*7dd7cddfSDavid du Colombier Fcall	rhdr;
37*7dd7cddfSDavid du Colombier Fcall	thdr;
38*7dd7cddfSDavid du Colombier int	fflg;
39*7dd7cddfSDavid du Colombier char	*mntpt;
40*7dd7cddfSDavid du Colombier int	biffing;
41*7dd7cddfSDavid du Colombier int	plumbing = 1;
42*7dd7cddfSDavid du Colombier 
43*7dd7cddfSDavid du Colombier QLock	mbllock;
44*7dd7cddfSDavid du Colombier Mailbox	*mbl;
45*7dd7cddfSDavid du Colombier 
46*7dd7cddfSDavid du Colombier Fid		*newfid(int);
47*7dd7cddfSDavid du Colombier void		error(char*);
48*7dd7cddfSDavid du Colombier void		io(void);
49*7dd7cddfSDavid du Colombier void		*erealloc(void*, ulong);
50*7dd7cddfSDavid du Colombier void		*emalloc(ulong);
51*7dd7cddfSDavid du Colombier void		usage(void);
52*7dd7cddfSDavid du Colombier void		reader(void);
53*7dd7cddfSDavid du Colombier int		readheader(Message*, char*, int, int);
54*7dd7cddfSDavid du Colombier int		cistrncmp(char*, char*, int);
55*7dd7cddfSDavid du Colombier int		tokenconvert(String*, char*, int);
56*7dd7cddfSDavid du Colombier 
57*7dd7cddfSDavid du Colombier char	*rflush(Fid*), *rnop(Fid*), *rsession(Fid*),
58*7dd7cddfSDavid du Colombier 	*rattach(Fid*), *rclone(Fid*), *rwalk(Fid*),
59*7dd7cddfSDavid du Colombier 	*rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*),
60*7dd7cddfSDavid du Colombier 	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
61*7dd7cddfSDavid du Colombier 	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
62*7dd7cddfSDavid du Colombier 
63*7dd7cddfSDavid du Colombier char 	*(*fcalls[])(Fid*) = {
64*7dd7cddfSDavid du Colombier 	[Tflush]	rflush,
65*7dd7cddfSDavid du Colombier 	[Tsession]	rsession,
66*7dd7cddfSDavid du Colombier 	[Tnop]		rnop,
67*7dd7cddfSDavid du Colombier 	[Tattach]	rattach,
68*7dd7cddfSDavid du Colombier 	[Tclone]	rclone,
69*7dd7cddfSDavid du Colombier 	[Twalk]		rwalk,
70*7dd7cddfSDavid du Colombier 	[Tclwalk]	rclwalk,
71*7dd7cddfSDavid du Colombier 	[Topen]		ropen,
72*7dd7cddfSDavid du Colombier 	[Tcreate]	rcreate,
73*7dd7cddfSDavid du Colombier 	[Tread]		rread,
74*7dd7cddfSDavid du Colombier 	[Twrite]	rwrite,
75*7dd7cddfSDavid du Colombier 	[Tclunk]	rclunk,
76*7dd7cddfSDavid du Colombier 	[Tremove]	rremove,
77*7dd7cddfSDavid du Colombier 	[Tstat]		rstat,
78*7dd7cddfSDavid du Colombier 	[Twstat]	rwstat,
79*7dd7cddfSDavid du Colombier };
80*7dd7cddfSDavid du Colombier 
81*7dd7cddfSDavid du Colombier char	Eperm[] =	"permission denied";
82*7dd7cddfSDavid du Colombier char	Enotdir[] =	"not a directory";
83*7dd7cddfSDavid du Colombier char	Enoauth[] =	"no authentication in ramfs";
84*7dd7cddfSDavid du Colombier char	Enotexist[] =	"file does not exist";
85*7dd7cddfSDavid du Colombier char	Einuse[] =	"file in use";
86*7dd7cddfSDavid du Colombier char	Eexist[] =	"file exists";
87*7dd7cddfSDavid du Colombier char	Enotowner[] =	"not owner";
88*7dd7cddfSDavid du Colombier char	Eisopen[] = 	"file already open for I/O";
89*7dd7cddfSDavid du Colombier char	Excl[] = 	"exclusive use file already open";
90*7dd7cddfSDavid du Colombier char	Ename[] = 	"illegal name";
91*7dd7cddfSDavid du Colombier char	Ebadctl[] =	"unknown control message";
92*7dd7cddfSDavid du Colombier 
93*7dd7cddfSDavid du Colombier char *dirtab[] =
94*7dd7cddfSDavid du Colombier {
95*7dd7cddfSDavid du Colombier [Qdir]		".",
96*7dd7cddfSDavid du Colombier [Qbody]		"body",
97*7dd7cddfSDavid du Colombier [Qbcc]		"bcc",
98*7dd7cddfSDavid du Colombier [Qcc]		"cc",
99*7dd7cddfSDavid du Colombier [Qdate]		"date",
100*7dd7cddfSDavid du Colombier [Qdigest]	"digest",
101*7dd7cddfSDavid du Colombier [Qdisposition]	"disposition",
102*7dd7cddfSDavid du Colombier [Qfilename]	"filename",
103*7dd7cddfSDavid du Colombier [Qfrom]		"from",
104*7dd7cddfSDavid du Colombier [Qheader]	"header",
105*7dd7cddfSDavid du Colombier [Qinfo]		"info",
106*7dd7cddfSDavid du Colombier [Qinreplyto]	"inreplyto",
107*7dd7cddfSDavid du Colombier [Qlines]	"lines",
108*7dd7cddfSDavid du Colombier [Qmimeheader]	"mimeheader",
109*7dd7cddfSDavid du Colombier [Qmessageid]	"messageid",
110*7dd7cddfSDavid du Colombier [Qraw]		"raw",
111*7dd7cddfSDavid du Colombier [Qrawbody]	"rawbody",
112*7dd7cddfSDavid du Colombier [Qrawheader]	"rawheader",
113*7dd7cddfSDavid du Colombier [Qreplyto]	"replyto",
114*7dd7cddfSDavid du Colombier [Qsender]	"sender",
115*7dd7cddfSDavid du Colombier [Qsubject]	"subject",
116*7dd7cddfSDavid du Colombier [Qto]		"to",
117*7dd7cddfSDavid du Colombier [Qtype]		"type",
118*7dd7cddfSDavid du Colombier [Qunixheader]	"unixheader",
119*7dd7cddfSDavid du Colombier [Qctl]		"ctl",
120*7dd7cddfSDavid du Colombier };
121*7dd7cddfSDavid du Colombier 
122*7dd7cddfSDavid du Colombier enum
123*7dd7cddfSDavid du Colombier {
124*7dd7cddfSDavid du Colombier 	Hsize=	1277,
125*7dd7cddfSDavid du Colombier };
126*7dd7cddfSDavid du Colombier 
127*7dd7cddfSDavid du Colombier Hash	*htab[Hsize];
128*7dd7cddfSDavid du Colombier 
129*7dd7cddfSDavid du Colombier int	debug;
130*7dd7cddfSDavid du Colombier int	fflag;
131*7dd7cddfSDavid du Colombier 
132*7dd7cddfSDavid du Colombier void
133*7dd7cddfSDavid du Colombier usage(void)
134*7dd7cddfSDavid du Colombier {
135*7dd7cddfSDavid du Colombier 	fprint(2, "usage: %s [-b -m mountpoint]\n", argv0);
136*7dd7cddfSDavid du Colombier 	exits("usage");
137*7dd7cddfSDavid du Colombier }
138*7dd7cddfSDavid du Colombier 
139*7dd7cddfSDavid du Colombier void
140*7dd7cddfSDavid du Colombier notifyf(void *a, char *s)
141*7dd7cddfSDavid du Colombier {
142*7dd7cddfSDavid du Colombier 	USED(a);
143*7dd7cddfSDavid du Colombier 	if(strncmp(s, "interrupt", 9) == 0)
144*7dd7cddfSDavid du Colombier 		noted(NCONT);
145*7dd7cddfSDavid du Colombier 	noted(NDFLT);
146*7dd7cddfSDavid du Colombier }
147*7dd7cddfSDavid du Colombier 
148*7dd7cddfSDavid du Colombier void
149*7dd7cddfSDavid du Colombier main(int argc, char *argv[])
150*7dd7cddfSDavid du Colombier {
151*7dd7cddfSDavid du Colombier 	int p[2], std;
152*7dd7cddfSDavid du Colombier 	char maildir[128];
153*7dd7cddfSDavid du Colombier 	char mbox[128];
154*7dd7cddfSDavid du Colombier 	char *mboxfile, *err;
155*7dd7cddfSDavid du Colombier 
156*7dd7cddfSDavid du Colombier 	mntpt = nil;
157*7dd7cddfSDavid du Colombier 	fflag = 0;
158*7dd7cddfSDavid du Colombier 	mboxfile = nil;
159*7dd7cddfSDavid du Colombier 	std = 0;
160*7dd7cddfSDavid du Colombier 
161*7dd7cddfSDavid du Colombier 	ARGBEGIN{
162*7dd7cddfSDavid du Colombier 	case 'b':
163*7dd7cddfSDavid du Colombier 		biffing = 1;
164*7dd7cddfSDavid du Colombier 		break;
165*7dd7cddfSDavid du Colombier 	case 'f':
166*7dd7cddfSDavid du Colombier 		fflag = 1;
167*7dd7cddfSDavid du Colombier 		mboxfile = ARGF();
168*7dd7cddfSDavid du Colombier 		break;
169*7dd7cddfSDavid du Colombier 	case 'm':
170*7dd7cddfSDavid du Colombier 		mntpt = ARGF();
171*7dd7cddfSDavid du Colombier 		break;
172*7dd7cddfSDavid du Colombier 	case 'd':
173*7dd7cddfSDavid du Colombier 		debug = 1;
174*7dd7cddfSDavid du Colombier 		break;
175*7dd7cddfSDavid du Colombier 	case 'p':
176*7dd7cddfSDavid du Colombier 		plumbing = 0;
177*7dd7cddfSDavid du Colombier 		break;
178*7dd7cddfSDavid du Colombier 	default:
179*7dd7cddfSDavid du Colombier 		usage();
180*7dd7cddfSDavid du Colombier 	}ARGEND
181*7dd7cddfSDavid du Colombier 
182*7dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
183*7dd7cddfSDavid du Colombier 		error("pipe failed");
184*7dd7cddfSDavid du Colombier 	mfd[0] = p[0];
185*7dd7cddfSDavid du Colombier 	mfd[1] = p[0];
186*7dd7cddfSDavid du Colombier 
187*7dd7cddfSDavid du Colombier 	notify(notifyf);
188*7dd7cddfSDavid du Colombier 	strcpy(user, getuser());
189*7dd7cddfSDavid du Colombier 	if(mntpt == nil){
190*7dd7cddfSDavid du Colombier 		snprint(maildir, sizeof(maildir), "/mail/fs");
191*7dd7cddfSDavid du Colombier 		mntpt = maildir;
192*7dd7cddfSDavid du Colombier 	}
193*7dd7cddfSDavid du Colombier 	if(mboxfile == nil){
194*7dd7cddfSDavid du Colombier 		snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);
195*7dd7cddfSDavid du Colombier 		mboxfile = mbox;
196*7dd7cddfSDavid du Colombier 		std = 1;
197*7dd7cddfSDavid du Colombier 	}
198*7dd7cddfSDavid du Colombier 
199*7dd7cddfSDavid du Colombier 	if(debug)
200*7dd7cddfSDavid du Colombier 		fmtinstall('F', fcallconv);
201*7dd7cddfSDavid du Colombier 
202*7dd7cddfSDavid du Colombier 	err = newmbox(mboxfile, "mbox", std);
203*7dd7cddfSDavid du Colombier 	if(err != nil)
204*7dd7cddfSDavid du Colombier 		sysfatal("opening mailbox: %s", err);
205*7dd7cddfSDavid du Colombier 
206*7dd7cddfSDavid du Colombier 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
207*7dd7cddfSDavid du Colombier 	case -1:
208*7dd7cddfSDavid du Colombier 		error("fork");
209*7dd7cddfSDavid du Colombier 	case 0:
210*7dd7cddfSDavid du Colombier 		henter(CHDIR|PATH(0, Qtop), dirtab[Qctl],
211*7dd7cddfSDavid du Colombier 			(Qid){PATH(0, Qctl), 0}, nil, nil);
212*7dd7cddfSDavid du Colombier 		close(p[1]);
213*7dd7cddfSDavid du Colombier 		io();
214*7dd7cddfSDavid du Colombier 		postnote(PNGROUP, getpid(), "die yankee pig dog");
215*7dd7cddfSDavid du Colombier 		break;
216*7dd7cddfSDavid du Colombier 	default:
217*7dd7cddfSDavid du Colombier 		close(p[0]);	/* don't deadlock if child fails */
218*7dd7cddfSDavid du Colombier 		if(mount(p[1], mntpt, MREPL, "") < 0)
219*7dd7cddfSDavid du Colombier 			error("mount failed");
220*7dd7cddfSDavid du Colombier 	}
221*7dd7cddfSDavid du Colombier 	exits(0);
222*7dd7cddfSDavid du Colombier }
223*7dd7cddfSDavid du Colombier 
224*7dd7cddfSDavid du Colombier static int
225*7dd7cddfSDavid du Colombier fileinfo(Message *m, int t, char **pp)
226*7dd7cddfSDavid du Colombier {
227*7dd7cddfSDavid du Colombier 	char *p;
228*7dd7cddfSDavid du Colombier 	int len;
229*7dd7cddfSDavid du Colombier 
230*7dd7cddfSDavid du Colombier 	p = "";
231*7dd7cddfSDavid du Colombier 	len = 0;
232*7dd7cddfSDavid du Colombier 	switch(t){
233*7dd7cddfSDavid du Colombier 	case Qbody:
234*7dd7cddfSDavid du Colombier 		p = m->body;
235*7dd7cddfSDavid du Colombier 		len = m->bend - m->body;
236*7dd7cddfSDavid du Colombier 		break;
237*7dd7cddfSDavid du Colombier 	case Qbcc:
238*7dd7cddfSDavid du Colombier 		if(m->bcc822){
239*7dd7cddfSDavid du Colombier 			p = s_to_c(m->bcc822);
240*7dd7cddfSDavid du Colombier 			len = strlen(p);
241*7dd7cddfSDavid du Colombier 		}
242*7dd7cddfSDavid du Colombier 		break;
243*7dd7cddfSDavid du Colombier 	case Qcc:
244*7dd7cddfSDavid du Colombier 		if(m->cc822){
245*7dd7cddfSDavid du Colombier 			p = s_to_c(m->cc822);
246*7dd7cddfSDavid du Colombier 			len = strlen(p);
247*7dd7cddfSDavid du Colombier 		}
248*7dd7cddfSDavid du Colombier 		break;
249*7dd7cddfSDavid du Colombier 	case Qdisposition:
250*7dd7cddfSDavid du Colombier 		switch(m->disposition){
251*7dd7cddfSDavid du Colombier 		case Dinline:
252*7dd7cddfSDavid du Colombier 			p = "inline";
253*7dd7cddfSDavid du Colombier 			break;
254*7dd7cddfSDavid du Colombier 		case Dfile:
255*7dd7cddfSDavid du Colombier 			p = "file";
256*7dd7cddfSDavid du Colombier 			break;
257*7dd7cddfSDavid du Colombier 		}
258*7dd7cddfSDavid du Colombier 		len = strlen(p);
259*7dd7cddfSDavid du Colombier 		break;
260*7dd7cddfSDavid du Colombier 	case Qdate:
261*7dd7cddfSDavid du Colombier 		if(m->date822){
262*7dd7cddfSDavid du Colombier 			p = s_to_c(m->date822);
263*7dd7cddfSDavid du Colombier 			len = strlen(p);
264*7dd7cddfSDavid du Colombier 		} else if(m->unixdate != nil){
265*7dd7cddfSDavid du Colombier 			p = s_to_c(m->unixdate);
266*7dd7cddfSDavid du Colombier 			len = strlen(p);
267*7dd7cddfSDavid du Colombier 		}
268*7dd7cddfSDavid du Colombier 		break;
269*7dd7cddfSDavid du Colombier 	case Qfilename:
270*7dd7cddfSDavid du Colombier 		if(m->filename){
271*7dd7cddfSDavid du Colombier 			p = s_to_c(m->filename);
272*7dd7cddfSDavid du Colombier 			len = strlen(p);
273*7dd7cddfSDavid du Colombier 		}
274*7dd7cddfSDavid du Colombier 		break;
275*7dd7cddfSDavid du Colombier 	case Qinreplyto:
276*7dd7cddfSDavid du Colombier 		if(m->inreplyto822){
277*7dd7cddfSDavid du Colombier 			p = s_to_c(m->inreplyto822);
278*7dd7cddfSDavid du Colombier 			len = strlen(p);
279*7dd7cddfSDavid du Colombier 		}
280*7dd7cddfSDavid du Colombier 		break;
281*7dd7cddfSDavid du Colombier 	case Qmessageid:
282*7dd7cddfSDavid du Colombier 		if(m->messageid822){
283*7dd7cddfSDavid du Colombier 			p = s_to_c(m->messageid822);
284*7dd7cddfSDavid du Colombier 			len = strlen(p);
285*7dd7cddfSDavid du Colombier 		}
286*7dd7cddfSDavid du Colombier 		break;
287*7dd7cddfSDavid du Colombier 	case Qfrom:
288*7dd7cddfSDavid du Colombier 		if(m->from822){
289*7dd7cddfSDavid du Colombier 			p = s_to_c(m->from822);
290*7dd7cddfSDavid du Colombier 			len = strlen(p);
291*7dd7cddfSDavid du Colombier 		} else if(m->unixfrom != nil){
292*7dd7cddfSDavid du Colombier 			p = s_to_c(m->unixfrom);
293*7dd7cddfSDavid du Colombier 			len = strlen(p);
294*7dd7cddfSDavid du Colombier 		}
295*7dd7cddfSDavid du Colombier 		break;
296*7dd7cddfSDavid du Colombier 	case Qheader:
297*7dd7cddfSDavid du Colombier 		p = m->header;
298*7dd7cddfSDavid du Colombier 		len = headerlen(m);
299*7dd7cddfSDavid du Colombier 		break;
300*7dd7cddfSDavid du Colombier 	case Qlines:
301*7dd7cddfSDavid du Colombier 		p = m->lines;
302*7dd7cddfSDavid du Colombier 		if(*p == 0)
303*7dd7cddfSDavid du Colombier 			countlines(m);
304*7dd7cddfSDavid du Colombier 		len = strlen(m->lines);
305*7dd7cddfSDavid du Colombier 		break;
306*7dd7cddfSDavid du Colombier 	case Qraw:
307*7dd7cddfSDavid du Colombier 		p = m->start;
308*7dd7cddfSDavid du Colombier 		if(strncmp(m->start, "From ", 5) == 0){
309*7dd7cddfSDavid du Colombier 			p = strchr(p, '\n');
310*7dd7cddfSDavid du Colombier 			if(p == nil)
311*7dd7cddfSDavid du Colombier 				p = m->start;
312*7dd7cddfSDavid du Colombier 			else
313*7dd7cddfSDavid du Colombier 				p++;
314*7dd7cddfSDavid du Colombier 		}
315*7dd7cddfSDavid du Colombier 		len = m->end - p;
316*7dd7cddfSDavid du Colombier 		break;
317*7dd7cddfSDavid du Colombier 	case Qrawbody:
318*7dd7cddfSDavid du Colombier 		p = m->rbody;
319*7dd7cddfSDavid du Colombier 		len = m->rbend - p;
320*7dd7cddfSDavid du Colombier 		break;
321*7dd7cddfSDavid du Colombier 	case Qrawheader:
322*7dd7cddfSDavid du Colombier 		p = m->header;
323*7dd7cddfSDavid du Colombier 		len = m->hend - p;
324*7dd7cddfSDavid du Colombier 		break;
325*7dd7cddfSDavid du Colombier 	case Qmimeheader:
326*7dd7cddfSDavid du Colombier 		p = m->mheader;
327*7dd7cddfSDavid du Colombier 		len = m->mhend - p;
328*7dd7cddfSDavid du Colombier 		break;
329*7dd7cddfSDavid du Colombier 	case Qreplyto:
330*7dd7cddfSDavid du Colombier 		p = nil;
331*7dd7cddfSDavid du Colombier 		if(m->replyto822 != nil){
332*7dd7cddfSDavid du Colombier 			p = s_to_c(m->replyto822);
333*7dd7cddfSDavid du Colombier 			len = strlen(p);
334*7dd7cddfSDavid du Colombier 		} else if(m->from822 != nil){
335*7dd7cddfSDavid du Colombier 			p = s_to_c(m->from822);
336*7dd7cddfSDavid du Colombier 			len = strlen(p);
337*7dd7cddfSDavid du Colombier 		} else if(m->sender822 != nil){
338*7dd7cddfSDavid du Colombier 			p = s_to_c(m->sender822);
339*7dd7cddfSDavid du Colombier 			len = strlen(p);
340*7dd7cddfSDavid du Colombier 		} else if(m->unixfrom != nil){
341*7dd7cddfSDavid du Colombier 			p = s_to_c(m->unixfrom);
342*7dd7cddfSDavid du Colombier 			len = strlen(p);
343*7dd7cddfSDavid du Colombier 		}
344*7dd7cddfSDavid du Colombier 		break;
345*7dd7cddfSDavid du Colombier 	case Qsender:
346*7dd7cddfSDavid du Colombier 		if(m->sender822){
347*7dd7cddfSDavid du Colombier 			p = s_to_c(m->sender822);
348*7dd7cddfSDavid du Colombier 			len = strlen(p);
349*7dd7cddfSDavid du Colombier 		}
350*7dd7cddfSDavid du Colombier 		break;
351*7dd7cddfSDavid du Colombier 	case Qsubject:
352*7dd7cddfSDavid du Colombier 		p = nil;
353*7dd7cddfSDavid du Colombier 		if(m->subject822){
354*7dd7cddfSDavid du Colombier 			p = s_to_c(m->subject822);
355*7dd7cddfSDavid du Colombier 			len = strlen(p);
356*7dd7cddfSDavid du Colombier 		}
357*7dd7cddfSDavid du Colombier 		break;
358*7dd7cddfSDavid du Colombier 	case Qto:
359*7dd7cddfSDavid du Colombier 		if(m->to822){
360*7dd7cddfSDavid du Colombier 			p = s_to_c(m->to822);
361*7dd7cddfSDavid du Colombier 			len = strlen(p);
362*7dd7cddfSDavid du Colombier 		}
363*7dd7cddfSDavid du Colombier 		break;
364*7dd7cddfSDavid du Colombier 	case Qtype:
365*7dd7cddfSDavid du Colombier 		if(m->type){
366*7dd7cddfSDavid du Colombier 			p = s_to_c(m->type);
367*7dd7cddfSDavid du Colombier 			len = strlen(p);
368*7dd7cddfSDavid du Colombier 		}
369*7dd7cddfSDavid du Colombier 		break;
370*7dd7cddfSDavid du Colombier 	case Qunixdate:
371*7dd7cddfSDavid du Colombier 		if(m->unixdate){
372*7dd7cddfSDavid du Colombier 			p = s_to_c(m->unixdate);
373*7dd7cddfSDavid du Colombier 			len = strlen(p);
374*7dd7cddfSDavid du Colombier 		}
375*7dd7cddfSDavid du Colombier 		break;
376*7dd7cddfSDavid du Colombier 	case Qunixheader:
377*7dd7cddfSDavid du Colombier 		p = m->start;
378*7dd7cddfSDavid du Colombier 		len = m->header - m->start;
379*7dd7cddfSDavid du Colombier 		break;
380*7dd7cddfSDavid du Colombier 	case Qdigest:
381*7dd7cddfSDavid du Colombier 		if(m->sdigest){
382*7dd7cddfSDavid du Colombier 			p = s_to_c(m->sdigest);
383*7dd7cddfSDavid du Colombier 			len = strlen(p);
384*7dd7cddfSDavid du Colombier 		}
385*7dd7cddfSDavid du Colombier 		break;
386*7dd7cddfSDavid du Colombier 	}
387*7dd7cddfSDavid du Colombier 	*pp = p;
388*7dd7cddfSDavid du Colombier 	return len;
389*7dd7cddfSDavid du Colombier }
390*7dd7cddfSDavid du Colombier 
391*7dd7cddfSDavid du Colombier int infofields[] = {
392*7dd7cddfSDavid du Colombier 	Qfrom,
393*7dd7cddfSDavid du Colombier 	Qto,
394*7dd7cddfSDavid du Colombier 	Qcc,
395*7dd7cddfSDavid du Colombier 	Qreplyto,
396*7dd7cddfSDavid du Colombier 	Qunixdate,
397*7dd7cddfSDavid du Colombier 	Qsubject,
398*7dd7cddfSDavid du Colombier 	Qtype,
399*7dd7cddfSDavid du Colombier 	Qdisposition,
400*7dd7cddfSDavid du Colombier 	Qfilename,
401*7dd7cddfSDavid du Colombier 	Qdigest,
402*7dd7cddfSDavid du Colombier 	Qbcc,
403*7dd7cddfSDavid du Colombier 	Qinreplyto,
404*7dd7cddfSDavid du Colombier 	Qdate,
405*7dd7cddfSDavid du Colombier 	Qsender,
406*7dd7cddfSDavid du Colombier 	Qmessageid,
407*7dd7cddfSDavid du Colombier 	Qlines,
408*7dd7cddfSDavid du Colombier 	-1,
409*7dd7cddfSDavid du Colombier };
410*7dd7cddfSDavid du Colombier 
411*7dd7cddfSDavid du Colombier static int
412*7dd7cddfSDavid du Colombier readinfo(Message *m, char *buf, long off, int count)
413*7dd7cddfSDavid du Colombier {
414*7dd7cddfSDavid du Colombier 	char *p;
415*7dd7cddfSDavid du Colombier 	int len, i, n;
416*7dd7cddfSDavid du Colombier 	String *s;
417*7dd7cddfSDavid du Colombier 
418*7dd7cddfSDavid du Colombier 	s = s_new();
419*7dd7cddfSDavid du Colombier 	len = 0;
420*7dd7cddfSDavid du Colombier 	for(i = 0; len < count && infofields[i] >= 0; i++){
421*7dd7cddfSDavid du Colombier 		n = fileinfo(m, infofields[i], &p);
422*7dd7cddfSDavid du Colombier 		s_reset(s);
423*7dd7cddfSDavid du Colombier 		if(tokenconvert(s, p, n) == 0){
424*7dd7cddfSDavid du Colombier 			p = s_to_c(s);
425*7dd7cddfSDavid du Colombier 			n = strlen(p);
426*7dd7cddfSDavid du Colombier 		}
427*7dd7cddfSDavid du Colombier 		if(off > 0){
428*7dd7cddfSDavid du Colombier 			if(off >= n+1){
429*7dd7cddfSDavid du Colombier 				off -= n+1;
430*7dd7cddfSDavid du Colombier 				continue;
431*7dd7cddfSDavid du Colombier 			}
432*7dd7cddfSDavid du Colombier 			p += off;
433*7dd7cddfSDavid du Colombier 			n -= off;
434*7dd7cddfSDavid du Colombier 			off = 0;
435*7dd7cddfSDavid du Colombier 		}
436*7dd7cddfSDavid du Colombier 		if(n > count - len)
437*7dd7cddfSDavid du Colombier 			n = count - len;
438*7dd7cddfSDavid du Colombier 		if(buf)
439*7dd7cddfSDavid du Colombier 			memmove(buf+len, p, n);
440*7dd7cddfSDavid du Colombier 		len += n;
441*7dd7cddfSDavid du Colombier 		if(buf)
442*7dd7cddfSDavid du Colombier 			buf[len] = '\n';
443*7dd7cddfSDavid du Colombier 		len++;
444*7dd7cddfSDavid du Colombier 	}
445*7dd7cddfSDavid du Colombier 	s_free(s);
446*7dd7cddfSDavid du Colombier 	return len;
447*7dd7cddfSDavid du Colombier }
448*7dd7cddfSDavid du Colombier 
449*7dd7cddfSDavid du Colombier static void
450*7dd7cddfSDavid du Colombier mkstat(Dir *d, Mailbox *mb, Message *m, int t)
451*7dd7cddfSDavid du Colombier {
452*7dd7cddfSDavid du Colombier 	char *p;
453*7dd7cddfSDavid du Colombier 
454*7dd7cddfSDavid du Colombier 	strncpy(d->uid, user, NAMELEN);
455*7dd7cddfSDavid du Colombier 	strncpy(d->gid, user, NAMELEN);
456*7dd7cddfSDavid du Colombier 	d->mode = 0444;
457*7dd7cddfSDavid du Colombier 	d->qid.vers = 0;
458*7dd7cddfSDavid du Colombier 	d->type = 0;
459*7dd7cddfSDavid du Colombier 	d->dev = 0;
460*7dd7cddfSDavid du Colombier 
461*7dd7cddfSDavid du Colombier 	switch(t){
462*7dd7cddfSDavid du Colombier 	case Qtop:
463*7dd7cddfSDavid du Colombier 		strcpy(d->name, ".");
464*7dd7cddfSDavid du Colombier 		d->mode = CHDIR|0555;
465*7dd7cddfSDavid du Colombier 		d->atime = d->mtime = time(0);
466*7dd7cddfSDavid du Colombier 		d->length = 0;
467*7dd7cddfSDavid du Colombier 		d->qid.path = CHDIR|PATH(0, Qtop);
468*7dd7cddfSDavid du Colombier 		break;
469*7dd7cddfSDavid du Colombier 	case Qmbox:
470*7dd7cddfSDavid du Colombier 		strcpy(d->name, mb->name);
471*7dd7cddfSDavid du Colombier 		d->mode = CHDIR|0555;
472*7dd7cddfSDavid du Colombier 		d->atime = mb->d.atime;
473*7dd7cddfSDavid du Colombier 		d->mtime = mb->d.mtime;
474*7dd7cddfSDavid du Colombier 		d->length = 0;
475*7dd7cddfSDavid du Colombier 		d->qid.path = CHDIR|PATH(mb->id, Qmbox);
476*7dd7cddfSDavid du Colombier 		d->qid.vers = mb->vers;
477*7dd7cddfSDavid du Colombier 		break;
478*7dd7cddfSDavid du Colombier 	case Qdir:
479*7dd7cddfSDavid du Colombier 		strcpy(d->name, m->name);
480*7dd7cddfSDavid du Colombier 		d->mode = CHDIR|0555;
481*7dd7cddfSDavid du Colombier 		d->atime = mb->d.atime;
482*7dd7cddfSDavid du Colombier 		d->mtime = mb->d.mtime;
483*7dd7cddfSDavid du Colombier 		d->length = 0;
484*7dd7cddfSDavid du Colombier 		d->qid.path = CHDIR|PATH(m->id, Qdir);
485*7dd7cddfSDavid du Colombier 		break;
486*7dd7cddfSDavid du Colombier 	case Qctl:
487*7dd7cddfSDavid du Colombier 		strncpy(d->name, dirtab[t], NAMELEN);
488*7dd7cddfSDavid du Colombier 		d->mode = 0666;
489*7dd7cddfSDavid du Colombier 		d->atime = d->mtime = time(0);
490*7dd7cddfSDavid du Colombier 		d->length = 0;
491*7dd7cddfSDavid du Colombier 		d->qid.path = PATH(0, Qctl);
492*7dd7cddfSDavid du Colombier 		break;
493*7dd7cddfSDavid du Colombier 	case Qinfo:
494*7dd7cddfSDavid du Colombier 		strncpy(d->name, dirtab[t], NAMELEN);
495*7dd7cddfSDavid du Colombier 		d->atime = mb->d.atime;
496*7dd7cddfSDavid du Colombier 		d->mtime = mb->d.mtime;
497*7dd7cddfSDavid du Colombier 		d->length = readinfo(m, nil, 0, 1<<30);
498*7dd7cddfSDavid du Colombier 		d->qid.path = PATH(m->id, t);
499*7dd7cddfSDavid du Colombier 		break;
500*7dd7cddfSDavid du Colombier 	default:
501*7dd7cddfSDavid du Colombier 		strncpy(d->name, dirtab[t], NAMELEN);
502*7dd7cddfSDavid du Colombier 		d->atime = mb->d.atime;
503*7dd7cddfSDavid du Colombier 		d->mtime = mb->d.mtime;
504*7dd7cddfSDavid du Colombier 		d->length = fileinfo(m, t, &p);
505*7dd7cddfSDavid du Colombier 		d->qid.path = PATH(m->id, t);
506*7dd7cddfSDavid du Colombier 		break;
507*7dd7cddfSDavid du Colombier 	}
508*7dd7cddfSDavid du Colombier }
509*7dd7cddfSDavid du Colombier 
510*7dd7cddfSDavid du Colombier char*
511*7dd7cddfSDavid du Colombier rnop(Fid *f)
512*7dd7cddfSDavid du Colombier {
513*7dd7cddfSDavid du Colombier 	USED(f);
514*7dd7cddfSDavid du Colombier 	return 0;
515*7dd7cddfSDavid du Colombier }
516*7dd7cddfSDavid du Colombier 
517*7dd7cddfSDavid du Colombier char*
518*7dd7cddfSDavid du Colombier rsession(Fid *unused)
519*7dd7cddfSDavid du Colombier {
520*7dd7cddfSDavid du Colombier 	Fid *f;
521*7dd7cddfSDavid du Colombier 
522*7dd7cddfSDavid du Colombier 	USED(unused);
523*7dd7cddfSDavid du Colombier 
524*7dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next)
525*7dd7cddfSDavid du Colombier 		if(f->busy)
526*7dd7cddfSDavid du Colombier 			rclunk(f);
527*7dd7cddfSDavid du Colombier 	memset(thdr.authid, 0, sizeof(thdr.authid));
528*7dd7cddfSDavid du Colombier 	memset(thdr.authdom, 0, sizeof(thdr.authdom));
529*7dd7cddfSDavid du Colombier 	memset(thdr.chal, 0, sizeof(thdr.chal));
530*7dd7cddfSDavid du Colombier 	return 0;
531*7dd7cddfSDavid du Colombier }
532*7dd7cddfSDavid du Colombier 
533*7dd7cddfSDavid du Colombier char*
534*7dd7cddfSDavid du Colombier rflush(Fid *f)
535*7dd7cddfSDavid du Colombier {
536*7dd7cddfSDavid du Colombier 	USED(f);
537*7dd7cddfSDavid du Colombier 	return 0;
538*7dd7cddfSDavid du Colombier }
539*7dd7cddfSDavid du Colombier 
540*7dd7cddfSDavid du Colombier char*
541*7dd7cddfSDavid du Colombier rattach(Fid *f)
542*7dd7cddfSDavid du Colombier {
543*7dd7cddfSDavid du Colombier 	f->busy = 1;
544*7dd7cddfSDavid du Colombier 	f->m = nil;
545*7dd7cddfSDavid du Colombier 	f->mb = nil;
546*7dd7cddfSDavid du Colombier 	thdr.qid.path = f->qid.path = CHDIR|PATH(0, Qtop);
547*7dd7cddfSDavid du Colombier 	f->qid.vers = 0;
548*7dd7cddfSDavid du Colombier 	thdr.qid.vers = 0;
549*7dd7cddfSDavid du Colombier 	if(strcmp(rhdr.uname, user) != 0)
550*7dd7cddfSDavid du Colombier 		return Eperm;
551*7dd7cddfSDavid du Colombier 	return 0;
552*7dd7cddfSDavid du Colombier }
553*7dd7cddfSDavid du Colombier 
554*7dd7cddfSDavid du Colombier char*
555*7dd7cddfSDavid du Colombier rclone(Fid *f)
556*7dd7cddfSDavid du Colombier {
557*7dd7cddfSDavid du Colombier 	Fid *nf;
558*7dd7cddfSDavid du Colombier 
559*7dd7cddfSDavid du Colombier 	if(f->open)
560*7dd7cddfSDavid du Colombier 		return Eisopen;
561*7dd7cddfSDavid du Colombier 	nf = newfid(rhdr.newfid);
562*7dd7cddfSDavid du Colombier 	nf->busy = 1;
563*7dd7cddfSDavid du Colombier 	nf->open = 0;
564*7dd7cddfSDavid du Colombier 	nf->m = f->m;
565*7dd7cddfSDavid du Colombier 	nf->mtop = f->mtop;
566*7dd7cddfSDavid du Colombier 	nf->mb = f->mb;
567*7dd7cddfSDavid du Colombier 	if(f->mb != nil)
568*7dd7cddfSDavid du Colombier 		mboxincref(f->mb);
569*7dd7cddfSDavid du Colombier 	if(f->mtop != nil){
570*7dd7cddfSDavid du Colombier 		qlock(f->mb);
571*7dd7cddfSDavid du Colombier 		msgincref(f->mtop);
572*7dd7cddfSDavid du Colombier 		qunlock(f->mb);
573*7dd7cddfSDavid du Colombier 	}
574*7dd7cddfSDavid du Colombier 	nf->qid = f->qid;
575*7dd7cddfSDavid du Colombier 	return 0;
576*7dd7cddfSDavid du Colombier }
577*7dd7cddfSDavid du Colombier 
578*7dd7cddfSDavid du Colombier char*
579*7dd7cddfSDavid du Colombier rwalk(Fid *f)
580*7dd7cddfSDavid du Colombier {
581*7dd7cddfSDavid du Colombier 	char *name;
582*7dd7cddfSDavid du Colombier 	int t;
583*7dd7cddfSDavid du Colombier 	Mailbox *omb, *mb;
584*7dd7cddfSDavid du Colombier 	char *rv, *p;
585*7dd7cddfSDavid du Colombier 	Hash *h;
586*7dd7cddfSDavid du Colombier 
587*7dd7cddfSDavid du Colombier 	name = rhdr.name;
588*7dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
589*7dd7cddfSDavid du Colombier 
590*7dd7cddfSDavid du Colombier 	rv = Enotexist;
591*7dd7cddfSDavid du Colombier 
592*7dd7cddfSDavid du Colombier 	omb = f->mb;
593*7dd7cddfSDavid du Colombier 	if(omb)
594*7dd7cddfSDavid du Colombier 		qlock(omb);
595*7dd7cddfSDavid du Colombier 	else
596*7dd7cddfSDavid du Colombier 		qlock(&mbllock);
597*7dd7cddfSDavid du Colombier 
598*7dd7cddfSDavid du Colombier 	// this must catch everything except . and ..
599*7dd7cddfSDavid du Colombier retry:
600*7dd7cddfSDavid du Colombier 	h = hlook(f->qid.path, name);
601*7dd7cddfSDavid du Colombier 	if(h != nil){
602*7dd7cddfSDavid du Colombier 		f->mb = h->mb;
603*7dd7cddfSDavid du Colombier 		f->m = h->m;
604*7dd7cddfSDavid du Colombier 		switch(t){
605*7dd7cddfSDavid du Colombier 		case Qtop:
606*7dd7cddfSDavid du Colombier 			if(f->mb != nil)
607*7dd7cddfSDavid du Colombier 				mboxincref(f->mb);
608*7dd7cddfSDavid du Colombier 			break;
609*7dd7cddfSDavid du Colombier 		case Qmbox:
610*7dd7cddfSDavid du Colombier 			msgincref(f->m);
611*7dd7cddfSDavid du Colombier 			f->mtop = f->m;
612*7dd7cddfSDavid du Colombier 			break;
613*7dd7cddfSDavid du Colombier 		}
614*7dd7cddfSDavid du Colombier 		f->qid = h->qid;
615*7dd7cddfSDavid du Colombier 		thdr.qid = f->qid;
616*7dd7cddfSDavid du Colombier 		rv = nil;
617*7dd7cddfSDavid du Colombier 	} else if((p = strchr(name, '.')) != nil && *name != '.'){
618*7dd7cddfSDavid du Colombier 		*p = 0;
619*7dd7cddfSDavid du Colombier 		goto retry;
620*7dd7cddfSDavid du Colombier 	}
621*7dd7cddfSDavid du Colombier 
622*7dd7cddfSDavid du Colombier 	if(omb)
623*7dd7cddfSDavid du Colombier 		qunlock(omb);
624*7dd7cddfSDavid du Colombier 	else
625*7dd7cddfSDavid du Colombier 		qunlock(&mbllock);
626*7dd7cddfSDavid du Colombier 	if(rv == nil)
627*7dd7cddfSDavid du Colombier 		return rv;
628*7dd7cddfSDavid du Colombier 
629*7dd7cddfSDavid du Colombier 
630*7dd7cddfSDavid du Colombier 	if(strcmp(name, ".") == 0){
631*7dd7cddfSDavid du Colombier 		thdr.qid = f->qid;
632*7dd7cddfSDavid du Colombier 		return nil;
633*7dd7cddfSDavid du Colombier 	}
634*7dd7cddfSDavid du Colombier 
635*7dd7cddfSDavid du Colombier 	if((f->qid.path&CHDIR) != CHDIR)
636*7dd7cddfSDavid du Colombier 		return Enotdir;
637*7dd7cddfSDavid du Colombier 
638*7dd7cddfSDavid du Colombier 	if(strcmp(name, "..") == 0){
639*7dd7cddfSDavid du Colombier 		switch(t){
640*7dd7cddfSDavid du Colombier 		case Qtop:
641*7dd7cddfSDavid du Colombier 			f->qid.path = CHDIR|PATH(0, Qtop);
642*7dd7cddfSDavid du Colombier 			f->qid.vers = 0;
643*7dd7cddfSDavid du Colombier 			break;
644*7dd7cddfSDavid du Colombier 		case Qmbox:
645*7dd7cddfSDavid du Colombier 			f->qid.path = CHDIR|PATH(0, Qtop);
646*7dd7cddfSDavid du Colombier 			f->qid.vers = 0;
647*7dd7cddfSDavid du Colombier 			qlock(&mbllock);
648*7dd7cddfSDavid du Colombier 			mb = f->mb;
649*7dd7cddfSDavid du Colombier 			f->mb = nil;
650*7dd7cddfSDavid du Colombier 			mboxdecref(mb);
651*7dd7cddfSDavid du Colombier 			qunlock(&mbllock);
652*7dd7cddfSDavid du Colombier 			break;
653*7dd7cddfSDavid du Colombier 		case Qdir:
654*7dd7cddfSDavid du Colombier 			qlock(f->mb);
655*7dd7cddfSDavid du Colombier 			if(f->m->whole == f->mb->root){
656*7dd7cddfSDavid du Colombier 				f->qid.path = CHDIR|PATH(f->mb->id, Qmbox);
657*7dd7cddfSDavid du Colombier 				f->qid.vers = f->mb->d.qid.vers;
658*7dd7cddfSDavid du Colombier 				msgdecref(f->mb, f->mtop);
659*7dd7cddfSDavid du Colombier 				f->m = f->mtop = nil;
660*7dd7cddfSDavid du Colombier 			} else {
661*7dd7cddfSDavid du Colombier 				f->m = f->m->whole;
662*7dd7cddfSDavid du Colombier 				f->qid.path = CHDIR|PATH(f->m->id, Qdir);
663*7dd7cddfSDavid du Colombier 			}
664*7dd7cddfSDavid du Colombier 			qunlock(f->mb);
665*7dd7cddfSDavid du Colombier 			break;
666*7dd7cddfSDavid du Colombier 		}
667*7dd7cddfSDavid du Colombier 		thdr.qid = f->qid;
668*7dd7cddfSDavid du Colombier 		rv = nil;
669*7dd7cddfSDavid du Colombier 	}
670*7dd7cddfSDavid du Colombier 
671*7dd7cddfSDavid du Colombier 	return rv;
672*7dd7cddfSDavid du Colombier }
673*7dd7cddfSDavid du Colombier 
674*7dd7cddfSDavid du Colombier char *
675*7dd7cddfSDavid du Colombier rclwalk(Fid *f)
676*7dd7cddfSDavid du Colombier {
677*7dd7cddfSDavid du Colombier 	Fid *nf;
678*7dd7cddfSDavid du Colombier 	char *err;
679*7dd7cddfSDavid du Colombier 
680*7dd7cddfSDavid du Colombier 	nf = newfid(rhdr.newfid);
681*7dd7cddfSDavid du Colombier 	nf->busy = 1;
682*7dd7cddfSDavid du Colombier 	nf->open = 0;
683*7dd7cddfSDavid du Colombier 	if(f->mb != nil)
684*7dd7cddfSDavid du Colombier 		mboxincref(f->mb);
685*7dd7cddfSDavid du Colombier 	if(f->mtop != nil){
686*7dd7cddfSDavid du Colombier 		qlock(f->mb);
687*7dd7cddfSDavid du Colombier 		msgincref(f->m);
688*7dd7cddfSDavid du Colombier 		qunlock(f->mb);
689*7dd7cddfSDavid du Colombier 	}
690*7dd7cddfSDavid du Colombier 	nf->mtop = f->mtop;
691*7dd7cddfSDavid du Colombier 	nf->m = f->m;
692*7dd7cddfSDavid du Colombier 	nf->mb = f->mb;
693*7dd7cddfSDavid du Colombier 	if(err = rwalk(nf))
694*7dd7cddfSDavid du Colombier 		rclunk(nf);
695*7dd7cddfSDavid du Colombier 	return err;
696*7dd7cddfSDavid du Colombier }
697*7dd7cddfSDavid du Colombier 
698*7dd7cddfSDavid du Colombier char *
699*7dd7cddfSDavid du Colombier ropen(Fid *f)
700*7dd7cddfSDavid du Colombier {
701*7dd7cddfSDavid du Colombier 	if(f->open)
702*7dd7cddfSDavid du Colombier 		return Eisopen;
703*7dd7cddfSDavid du Colombier 
704*7dd7cddfSDavid du Colombier 	if(rhdr.mode != OREAD)
705*7dd7cddfSDavid du Colombier 		if(FILE(f->qid.path) != Qctl)
706*7dd7cddfSDavid du Colombier 			return Eperm;
707*7dd7cddfSDavid du Colombier 
708*7dd7cddfSDavid du Colombier 	// make sure we've decoded
709*7dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qbody){
710*7dd7cddfSDavid du Colombier 		if(f->m->decoded == 0)
711*7dd7cddfSDavid du Colombier 			decode(f->m);
712*7dd7cddfSDavid du Colombier 		if(f->m->converted == 0)
713*7dd7cddfSDavid du Colombier 			convert(f->m);
714*7dd7cddfSDavid du Colombier 	}
715*7dd7cddfSDavid du Colombier 
716*7dd7cddfSDavid du Colombier 	thdr.qid = f->qid;
717*7dd7cddfSDavid du Colombier 	f->open = 1;
718*7dd7cddfSDavid du Colombier 	return 0;
719*7dd7cddfSDavid du Colombier }
720*7dd7cddfSDavid du Colombier 
721*7dd7cddfSDavid du Colombier char *
722*7dd7cddfSDavid du Colombier rcreate(Fid*)
723*7dd7cddfSDavid du Colombier {
724*7dd7cddfSDavid du Colombier 	return Eperm;
725*7dd7cddfSDavid du Colombier }
726*7dd7cddfSDavid du Colombier 
727*7dd7cddfSDavid du Colombier int
728*7dd7cddfSDavid du Colombier readtopdir(Fid*, char *buf, long off, int cnt)
729*7dd7cddfSDavid du Colombier {
730*7dd7cddfSDavid du Colombier 	Dir d;
731*7dd7cddfSDavid du Colombier 	int n;
732*7dd7cddfSDavid du Colombier 	Mailbox *mb;
733*7dd7cddfSDavid du Colombier 
734*7dd7cddfSDavid du Colombier 	n = 0;
735*7dd7cddfSDavid du Colombier 	if(cnt == 0)
736*7dd7cddfSDavid du Colombier 		return 0;
737*7dd7cddfSDavid du Colombier 	if(off == 0){
738*7dd7cddfSDavid du Colombier 		mkstat(&d, nil, nil, Qctl);
739*7dd7cddfSDavid du Colombier 		convD2M(&d, &buf[n]);
740*7dd7cddfSDavid du Colombier 		n += DIRLEN;
741*7dd7cddfSDavid du Colombier 		cnt--;
742*7dd7cddfSDavid du Colombier 	} else
743*7dd7cddfSDavid du Colombier 		off--;
744*7dd7cddfSDavid du Colombier 
745*7dd7cddfSDavid du Colombier 	for(mb = mbl; cnt > 0 && mb != nil; mb = mb->next){
746*7dd7cddfSDavid du Colombier 		if(off > 0){
747*7dd7cddfSDavid du Colombier 			off--;
748*7dd7cddfSDavid du Colombier 			continue;
749*7dd7cddfSDavid du Colombier 		}
750*7dd7cddfSDavid du Colombier 		mkstat(&d, mb, nil, Qmbox);
751*7dd7cddfSDavid du Colombier 		convD2M(&d, &buf[n]);
752*7dd7cddfSDavid du Colombier 		n += DIRLEN;
753*7dd7cddfSDavid du Colombier 		cnt--;
754*7dd7cddfSDavid du Colombier 	}
755*7dd7cddfSDavid du Colombier 	return n;
756*7dd7cddfSDavid du Colombier }
757*7dd7cddfSDavid du Colombier 
758*7dd7cddfSDavid du Colombier int
759*7dd7cddfSDavid du Colombier readmboxdir(Fid *f, char *buf, long off, int cnt)
760*7dd7cddfSDavid du Colombier {
761*7dd7cddfSDavid du Colombier 	Dir d;
762*7dd7cddfSDavid du Colombier 	int n;
763*7dd7cddfSDavid du Colombier 	Message *m;
764*7dd7cddfSDavid du Colombier 	long pos;
765*7dd7cddfSDavid du Colombier 
766*7dd7cddfSDavid du Colombier 	// to avoid n**2 reads of the directory, use a saved finger pointer
767*7dd7cddfSDavid du Colombier 	if(f->mb->vers == f->fvers && off >= f->foff && f->foff > 0){
768*7dd7cddfSDavid du Colombier 		m = f->fptr;
769*7dd7cddfSDavid du Colombier 		pos = f->foff;
770*7dd7cddfSDavid du Colombier 	} else {
771*7dd7cddfSDavid du Colombier 		m = f->mb->root->part;
772*7dd7cddfSDavid du Colombier 		pos = 0;
773*7dd7cddfSDavid du Colombier 	}
774*7dd7cddfSDavid du Colombier 
775*7dd7cddfSDavid du Colombier 	n = 0;
776*7dd7cddfSDavid du Colombier 	for(; cnt > 0 && m != nil; m = m->next){
777*7dd7cddfSDavid du Colombier 		// act like deleted files aren't there
778*7dd7cddfSDavid du Colombier 		if(m->deleted)
779*7dd7cddfSDavid du Colombier 			continue;
780*7dd7cddfSDavid du Colombier 
781*7dd7cddfSDavid du Colombier 		// skip till we've passed the offset
782*7dd7cddfSDavid du Colombier 		if(off > pos){
783*7dd7cddfSDavid du Colombier 			pos++;
784*7dd7cddfSDavid du Colombier  			continue;
785*7dd7cddfSDavid du Colombier 		}
786*7dd7cddfSDavid du Colombier 
787*7dd7cddfSDavid du Colombier 		mkstat(&d, f->mb, m, Qdir);
788*7dd7cddfSDavid du Colombier 		convD2M(&d, &buf[n]);
789*7dd7cddfSDavid du Colombier 		n += DIRLEN;
790*7dd7cddfSDavid du Colombier 		cnt--;
791*7dd7cddfSDavid du Colombier 		pos++;
792*7dd7cddfSDavid du Colombier 	}
793*7dd7cddfSDavid du Colombier 
794*7dd7cddfSDavid du Colombier 	// save a finger pointer for next read of the mbox directory
795*7dd7cddfSDavid du Colombier 	f->foff = pos;
796*7dd7cddfSDavid du Colombier 	f->fptr = m;
797*7dd7cddfSDavid du Colombier 	f->fvers = f->mb->vers;
798*7dd7cddfSDavid du Colombier 
799*7dd7cddfSDavid du Colombier 	return n;
800*7dd7cddfSDavid du Colombier }
801*7dd7cddfSDavid du Colombier 
802*7dd7cddfSDavid du Colombier int
803*7dd7cddfSDavid du Colombier readmsgdir(Fid *f, char *buf, long off, int cnt)
804*7dd7cddfSDavid du Colombier {
805*7dd7cddfSDavid du Colombier 	Dir d;
806*7dd7cddfSDavid du Colombier 	int i, n;
807*7dd7cddfSDavid du Colombier 	Message *m;
808*7dd7cddfSDavid du Colombier 
809*7dd7cddfSDavid du Colombier 	n = 0;
810*7dd7cddfSDavid du Colombier 	for(i = 0; cnt > 0 && i < Qmax; i++){
811*7dd7cddfSDavid du Colombier 		if(off > 0){
812*7dd7cddfSDavid du Colombier 			off--;
813*7dd7cddfSDavid du Colombier 			continue;
814*7dd7cddfSDavid du Colombier 		}
815*7dd7cddfSDavid du Colombier 		mkstat(&d, f->mb, f->m, i);
816*7dd7cddfSDavid du Colombier 		convD2M(&d, &buf[n]);
817*7dd7cddfSDavid du Colombier 		n += DIRLEN;
818*7dd7cddfSDavid du Colombier 		cnt--;
819*7dd7cddfSDavid du Colombier 	}
820*7dd7cddfSDavid du Colombier 	for(m = f->m->part; cnt > 0 && m != nil; m = m->next){
821*7dd7cddfSDavid du Colombier 		if(off > 0){
822*7dd7cddfSDavid du Colombier 			off--;
823*7dd7cddfSDavid du Colombier 			continue;
824*7dd7cddfSDavid du Colombier 		}
825*7dd7cddfSDavid du Colombier 		mkstat(&d, f->mb, m, Qdir);
826*7dd7cddfSDavid du Colombier 		convD2M(&d, &buf[n]);
827*7dd7cddfSDavid du Colombier 		n += DIRLEN;
828*7dd7cddfSDavid du Colombier 		cnt--;
829*7dd7cddfSDavid du Colombier 	}
830*7dd7cddfSDavid du Colombier 
831*7dd7cddfSDavid du Colombier 	return n;
832*7dd7cddfSDavid du Colombier }
833*7dd7cddfSDavid du Colombier 
834*7dd7cddfSDavid du Colombier char*
835*7dd7cddfSDavid du Colombier rread(Fid *f)
836*7dd7cddfSDavid du Colombier {
837*7dd7cddfSDavid du Colombier 	char *buf;
838*7dd7cddfSDavid du Colombier 	long off;
839*7dd7cddfSDavid du Colombier 	int t, i, n, cnt;
840*7dd7cddfSDavid du Colombier 	char *p;
841*7dd7cddfSDavid du Colombier 
842*7dd7cddfSDavid du Colombier 	thdr.count = 0;
843*7dd7cddfSDavid du Colombier 	off = rhdr.offset;
844*7dd7cddfSDavid du Colombier 	buf = thdr.data;
845*7dd7cddfSDavid du Colombier 	cnt = rhdr.count;
846*7dd7cddfSDavid du Colombier 
847*7dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
848*7dd7cddfSDavid du Colombier 	if(f->qid.path & CHDIR){
849*7dd7cddfSDavid du Colombier 		cnt /= DIRLEN;
850*7dd7cddfSDavid du Colombier 		if(off%DIRLEN)
851*7dd7cddfSDavid du Colombier 			return "i/o error";
852*7dd7cddfSDavid du Colombier 		off /= DIRLEN;
853*7dd7cddfSDavid du Colombier 
854*7dd7cddfSDavid du Colombier 		if(t == Qtop) {
855*7dd7cddfSDavid du Colombier 			qlock(&mbllock);
856*7dd7cddfSDavid du Colombier 			n = readtopdir(f, buf, off, cnt);
857*7dd7cddfSDavid du Colombier 			qunlock(&mbllock);
858*7dd7cddfSDavid du Colombier 		} else if(t == Qmbox) {
859*7dd7cddfSDavid du Colombier 			qlock(f->mb);
860*7dd7cddfSDavid du Colombier 			if(off == 0)
861*7dd7cddfSDavid du Colombier 				syncmbox(f->mb, 1);
862*7dd7cddfSDavid du Colombier 			n = readmboxdir(f, buf, off, cnt);
863*7dd7cddfSDavid du Colombier 			qunlock(f->mb);
864*7dd7cddfSDavid du Colombier 		} else {
865*7dd7cddfSDavid du Colombier 			n = readmsgdir(f, buf, off, cnt);
866*7dd7cddfSDavid du Colombier 		}
867*7dd7cddfSDavid du Colombier 
868*7dd7cddfSDavid du Colombier 		thdr.count = n;
869*7dd7cddfSDavid du Colombier 		return nil;
870*7dd7cddfSDavid du Colombier 	}
871*7dd7cddfSDavid du Colombier 
872*7dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qheader){
873*7dd7cddfSDavid du Colombier 		thdr.count = readheader(f->m, buf, off, cnt);
874*7dd7cddfSDavid du Colombier 		return nil;
875*7dd7cddfSDavid du Colombier 	}
876*7dd7cddfSDavid du Colombier 
877*7dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qinfo){
878*7dd7cddfSDavid du Colombier 		thdr.count = readinfo(f->m, buf, off, cnt);
879*7dd7cddfSDavid du Colombier 		return nil;
880*7dd7cddfSDavid du Colombier 	}
881*7dd7cddfSDavid du Colombier 
882*7dd7cddfSDavid du Colombier 	i = fileinfo(f->m, FILE(f->qid.path), &p);
883*7dd7cddfSDavid du Colombier 	if(off < i){
884*7dd7cddfSDavid du Colombier 		if((off + cnt) > i)
885*7dd7cddfSDavid du Colombier 			cnt = i - off;
886*7dd7cddfSDavid du Colombier 		memmove(buf, p + off, cnt);
887*7dd7cddfSDavid du Colombier 		thdr.count = cnt;
888*7dd7cddfSDavid du Colombier 	}
889*7dd7cddfSDavid du Colombier 	return nil;
890*7dd7cddfSDavid du Colombier }
891*7dd7cddfSDavid du Colombier 
892*7dd7cddfSDavid du Colombier char*
893*7dd7cddfSDavid du Colombier rwrite(Fid *f)
894*7dd7cddfSDavid du Colombier {
895*7dd7cddfSDavid du Colombier 	char *err;
896*7dd7cddfSDavid du Colombier 	char *token[1024];
897*7dd7cddfSDavid du Colombier 	int t, n;
898*7dd7cddfSDavid du Colombier 	String *file;
899*7dd7cddfSDavid du Colombier 
900*7dd7cddfSDavid du Colombier 	t = FILE(f->qid.path);
901*7dd7cddfSDavid du Colombier 	switch(t){
902*7dd7cddfSDavid du Colombier 	case Qctl:
903*7dd7cddfSDavid du Colombier 		if(rhdr.count == 0)
904*7dd7cddfSDavid du Colombier 			return Ebadctl;
905*7dd7cddfSDavid du Colombier 		if(rhdr.data[rhdr.count-1] == '\n')
906*7dd7cddfSDavid du Colombier 			rhdr.data[rhdr.count-1] = 0;
907*7dd7cddfSDavid du Colombier 		else
908*7dd7cddfSDavid du Colombier 			rhdr.data[rhdr.count] = 0;
909*7dd7cddfSDavid du Colombier 		n = tokenize(rhdr.data, token, nelem(token));
910*7dd7cddfSDavid du Colombier 		if(n == 0)
911*7dd7cddfSDavid du Colombier 			return Ebadctl;
912*7dd7cddfSDavid du Colombier 		if(strcmp(token[0], "open") == 0){
913*7dd7cddfSDavid du Colombier 			file = s_new();
914*7dd7cddfSDavid du Colombier 			switch(n){
915*7dd7cddfSDavid du Colombier 			case 1:
916*7dd7cddfSDavid du Colombier 				err = Ebadctl;
917*7dd7cddfSDavid du Colombier 				break;
918*7dd7cddfSDavid du Colombier 			case 2:
919*7dd7cddfSDavid du Colombier 				mboxpath(token[1], getlog(), file, 0);
920*7dd7cddfSDavid du Colombier 				err = newmbox(s_to_c(file), nil, 0);
921*7dd7cddfSDavid du Colombier 				break;
922*7dd7cddfSDavid du Colombier 			default:
923*7dd7cddfSDavid du Colombier 				mboxpath(token[1], getlog(), file, 0);
924*7dd7cddfSDavid du Colombier 				err = newmbox(s_to_c(file), token[2], 0);
925*7dd7cddfSDavid du Colombier 				break;
926*7dd7cddfSDavid du Colombier 			}
927*7dd7cddfSDavid du Colombier 			s_free(file);
928*7dd7cddfSDavid du Colombier 			thdr.count = rhdr.count;
929*7dd7cddfSDavid du Colombier 			return err;
930*7dd7cddfSDavid du Colombier 		}
931*7dd7cddfSDavid du Colombier 		if(strcmp(token[0], "close") == 0){
932*7dd7cddfSDavid du Colombier 			if(n < 2)
933*7dd7cddfSDavid du Colombier 				return nil;
934*7dd7cddfSDavid du Colombier 			freembox(token[1]);
935*7dd7cddfSDavid du Colombier 			return nil;
936*7dd7cddfSDavid du Colombier 		}
937*7dd7cddfSDavid du Colombier 		if(strcmp(token[0], "delete") == 0){
938*7dd7cddfSDavid du Colombier 			if(n < 3)
939*7dd7cddfSDavid du Colombier 				return nil;
940*7dd7cddfSDavid du Colombier 			delmessages(n-1, &token[1]);
941*7dd7cddfSDavid du Colombier 			thdr.count = rhdr.count;
942*7dd7cddfSDavid du Colombier 			return nil;
943*7dd7cddfSDavid du Colombier 		}
944*7dd7cddfSDavid du Colombier //		if(strcmp(token[0], "pooldump") == 0){
945*7dd7cddfSDavid du Colombier //			print("msgallocd %d, msgfreed %d\n", msgallocd, msgfreed);
946*7dd7cddfSDavid du Colombier //			pooldump("Main");
947*7dd7cddfSDavid du Colombier //			return nil;
948*7dd7cddfSDavid du Colombier //		}
949*7dd7cddfSDavid du Colombier 		return Ebadctl;
950*7dd7cddfSDavid du Colombier 	}
951*7dd7cddfSDavid du Colombier 	return Eperm;
952*7dd7cddfSDavid du Colombier }
953*7dd7cddfSDavid du Colombier 
954*7dd7cddfSDavid du Colombier char *
955*7dd7cddfSDavid du Colombier rclunk(Fid *f)
956*7dd7cddfSDavid du Colombier {
957*7dd7cddfSDavid du Colombier 	Mailbox *mb;
958*7dd7cddfSDavid du Colombier 
959*7dd7cddfSDavid du Colombier 	f->busy = 0;
960*7dd7cddfSDavid du Colombier 	f->open = 0;
961*7dd7cddfSDavid du Colombier 	if(f->mtop != nil){
962*7dd7cddfSDavid du Colombier 		qlock(f->mb);
963*7dd7cddfSDavid du Colombier 		msgdecref(f->mb, f->mtop);
964*7dd7cddfSDavid du Colombier 		qunlock(f->mb);
965*7dd7cddfSDavid du Colombier 	}
966*7dd7cddfSDavid du Colombier 	f->m = f->mtop = nil;
967*7dd7cddfSDavid du Colombier 	mb = f->mb;
968*7dd7cddfSDavid du Colombier 	if(mb != nil){
969*7dd7cddfSDavid du Colombier 		f->mb = nil;
970*7dd7cddfSDavid du Colombier 		qlock(&mbllock);
971*7dd7cddfSDavid du Colombier 		mboxdecref(mb);
972*7dd7cddfSDavid du Colombier 		qunlock(&mbllock);
973*7dd7cddfSDavid du Colombier 	}
974*7dd7cddfSDavid du Colombier 	return 0;
975*7dd7cddfSDavid du Colombier }
976*7dd7cddfSDavid du Colombier 
977*7dd7cddfSDavid du Colombier char *
978*7dd7cddfSDavid du Colombier rremove(Fid *f)
979*7dd7cddfSDavid du Colombier {
980*7dd7cddfSDavid du Colombier 	if(f->m->deleted == 0)
981*7dd7cddfSDavid du Colombier 		mailplumb(f->mb, f->m, 1);
982*7dd7cddfSDavid du Colombier 	f->m->deleted = 1;
983*7dd7cddfSDavid du Colombier 	return rclunk(f);
984*7dd7cddfSDavid du Colombier }
985*7dd7cddfSDavid du Colombier 
986*7dd7cddfSDavid du Colombier char *
987*7dd7cddfSDavid du Colombier rstat(Fid *f)
988*7dd7cddfSDavid du Colombier {
989*7dd7cddfSDavid du Colombier 	Dir d;
990*7dd7cddfSDavid du Colombier 
991*7dd7cddfSDavid du Colombier 	if(FILE(f->qid.path) == Qmbox){
992*7dd7cddfSDavid du Colombier 		qlock(f->mb);
993*7dd7cddfSDavid du Colombier 		syncmbox(f->mb, 1);
994*7dd7cddfSDavid du Colombier 		qunlock(f->mb);
995*7dd7cddfSDavid du Colombier 	}
996*7dd7cddfSDavid du Colombier 	mkstat(&d, f->mb, f->m, FILE(f->qid.path));
997*7dd7cddfSDavid du Colombier 	convD2M(&d, thdr.stat);
998*7dd7cddfSDavid du Colombier 	return 0;
999*7dd7cddfSDavid du Colombier }
1000*7dd7cddfSDavid du Colombier 
1001*7dd7cddfSDavid du Colombier char *
1002*7dd7cddfSDavid du Colombier rwstat(Fid*)
1003*7dd7cddfSDavid du Colombier {
1004*7dd7cddfSDavid du Colombier 	return Eperm;
1005*7dd7cddfSDavid du Colombier }
1006*7dd7cddfSDavid du Colombier 
1007*7dd7cddfSDavid du Colombier Fid *
1008*7dd7cddfSDavid du Colombier newfid(int fid)
1009*7dd7cddfSDavid du Colombier {
1010*7dd7cddfSDavid du Colombier 	Fid *f, *ff;
1011*7dd7cddfSDavid du Colombier 
1012*7dd7cddfSDavid du Colombier 	ff = 0;
1013*7dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next)
1014*7dd7cddfSDavid du Colombier 		if(f->fid == fid)
1015*7dd7cddfSDavid du Colombier 			return f;
1016*7dd7cddfSDavid du Colombier 		else if(!ff && !f->busy)
1017*7dd7cddfSDavid du Colombier 			ff = f;
1018*7dd7cddfSDavid du Colombier 	if(ff){
1019*7dd7cddfSDavid du Colombier 		ff->fid = fid;
1020*7dd7cddfSDavid du Colombier 		return ff;
1021*7dd7cddfSDavid du Colombier 	}
1022*7dd7cddfSDavid du Colombier 	f = emalloc(sizeof *f);
1023*7dd7cddfSDavid du Colombier 	f->fid = fid;
1024*7dd7cddfSDavid du Colombier 	f->next = fids;
1025*7dd7cddfSDavid du Colombier 	fids = f;
1026*7dd7cddfSDavid du Colombier 	return f;
1027*7dd7cddfSDavid du Colombier }
1028*7dd7cddfSDavid du Colombier 
1029*7dd7cddfSDavid du Colombier int
1030*7dd7cddfSDavid du Colombier fidmboxrefs(Mailbox *mb)
1031*7dd7cddfSDavid du Colombier {
1032*7dd7cddfSDavid du Colombier 	Fid *f;
1033*7dd7cddfSDavid du Colombier 	int refs = 0;
1034*7dd7cddfSDavid du Colombier 
1035*7dd7cddfSDavid du Colombier 	for(f = fids; f; f = f->next){
1036*7dd7cddfSDavid du Colombier 		if(f->mb == mb)
1037*7dd7cddfSDavid du Colombier 			refs++;
1038*7dd7cddfSDavid du Colombier 	}
1039*7dd7cddfSDavid du Colombier 	return refs;
1040*7dd7cddfSDavid du Colombier }
1041*7dd7cddfSDavid du Colombier 
1042*7dd7cddfSDavid du Colombier void
1043*7dd7cddfSDavid du Colombier io(void)
1044*7dd7cddfSDavid du Colombier {
1045*7dd7cddfSDavid du Colombier 	char *err;
1046*7dd7cddfSDavid du Colombier 	int n;
1047*7dd7cddfSDavid du Colombier 
1048*7dd7cddfSDavid du Colombier 	// start a process to watch the mailboxes
1049*7dd7cddfSDavid du Colombier 	switch(rfork(RFPROC|RFMEM)){
1050*7dd7cddfSDavid du Colombier 	case -1:
1051*7dd7cddfSDavid du Colombier 		/* oh well */
1052*7dd7cddfSDavid du Colombier 		break;
1053*7dd7cddfSDavid du Colombier 	case 0:
1054*7dd7cddfSDavid du Colombier 		reader();
1055*7dd7cddfSDavid du Colombier 		exits(nil);
1056*7dd7cddfSDavid du Colombier 	default:
1057*7dd7cddfSDavid du Colombier 		break;
1058*7dd7cddfSDavid du Colombier 	}
1059*7dd7cddfSDavid du Colombier 
1060*7dd7cddfSDavid du Colombier 	for(;;){
1061*7dd7cddfSDavid du Colombier 		/*
1062*7dd7cddfSDavid du Colombier 		 * reading from a pipe or a network device
1063*7dd7cddfSDavid du Colombier 		 * will give an error after a few eof reads
1064*7dd7cddfSDavid du Colombier 		 * however, we cannot tell the difference
1065*7dd7cddfSDavid du Colombier 		 * between a zero-length read and an interrupt
1066*7dd7cddfSDavid du Colombier 		 * on the processes writing to us,
1067*7dd7cddfSDavid du Colombier 		 * so we wait for the error
1068*7dd7cddfSDavid du Colombier 		 */
1069*7dd7cddfSDavid du Colombier 		n = read(mfd[0], mdata, sizeof mdata);
1070*7dd7cddfSDavid du Colombier 		if(n == 0)
1071*7dd7cddfSDavid du Colombier 			continue;
1072*7dd7cddfSDavid du Colombier 		if(n < 0)
1073*7dd7cddfSDavid du Colombier 			return;
1074*7dd7cddfSDavid du Colombier 		if(convM2S(mdata, &rhdr, n) == 0)
1075*7dd7cddfSDavid du Colombier 			continue;
1076*7dd7cddfSDavid du Colombier 
1077*7dd7cddfSDavid du Colombier 		if(debug)
1078*7dd7cddfSDavid du Colombier 			fprint(2, "%s:<-%F\n", argv0, &rhdr);
1079*7dd7cddfSDavid du Colombier 
1080*7dd7cddfSDavid du Colombier 		thdr.data = mdata + MAXMSG;
1081*7dd7cddfSDavid du Colombier 		if(!fcalls[rhdr.type])
1082*7dd7cddfSDavid du Colombier 			err = "bad fcall type";
1083*7dd7cddfSDavid du Colombier 		else
1084*7dd7cddfSDavid du Colombier 			err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
1085*7dd7cddfSDavid du Colombier 		if(err){
1086*7dd7cddfSDavid du Colombier 			thdr.type = Rerror;
1087*7dd7cddfSDavid du Colombier 			strncpy(thdr.ename, err, ERRLEN);
1088*7dd7cddfSDavid du Colombier 		}else{
1089*7dd7cddfSDavid du Colombier 			thdr.type = rhdr.type + 1;
1090*7dd7cddfSDavid du Colombier 			thdr.fid = rhdr.fid;
1091*7dd7cddfSDavid du Colombier 		}
1092*7dd7cddfSDavid du Colombier 		thdr.tag = rhdr.tag;
1093*7dd7cddfSDavid du Colombier 		if(debug)
1094*7dd7cddfSDavid du Colombier 			fprint(2, "%s:->%F\n", argv0, &thdr);/**/
1095*7dd7cddfSDavid du Colombier 		n = convS2M(&thdr, mdata);
1096*7dd7cddfSDavid du Colombier 		if(write(mfd[1], mdata, n) != n)
1097*7dd7cddfSDavid du Colombier 			error("mount write");
1098*7dd7cddfSDavid du Colombier 	}
1099*7dd7cddfSDavid du Colombier }
1100*7dd7cddfSDavid du Colombier 
1101*7dd7cddfSDavid du Colombier void
1102*7dd7cddfSDavid du Colombier reader(void)
1103*7dd7cddfSDavid du Colombier {
1104*7dd7cddfSDavid du Colombier 	Dir d;
1105*7dd7cddfSDavid du Colombier 	Mailbox *mb;
1106*7dd7cddfSDavid du Colombier 
1107*7dd7cddfSDavid du Colombier 	sleep(15*1000);
1108*7dd7cddfSDavid du Colombier 	for(;;){
1109*7dd7cddfSDavid du Colombier 		qlock(&mbllock);
1110*7dd7cddfSDavid du Colombier 		for(mb = mbl; mb != nil; mb = mb->next){
1111*7dd7cddfSDavid du Colombier 			if(dirstat(mb->path, &d) < 0)
1112*7dd7cddfSDavid du Colombier 				continue;
1113*7dd7cddfSDavid du Colombier 
1114*7dd7cddfSDavid du Colombier 			if(d.qid.path != mb->d.qid.path
1115*7dd7cddfSDavid du Colombier 			   || d.qid.vers != mb->d.qid.vers){
1116*7dd7cddfSDavid du Colombier 				qlock(mb);
1117*7dd7cddfSDavid du Colombier 				break;
1118*7dd7cddfSDavid du Colombier 			}
1119*7dd7cddfSDavid du Colombier 		}
1120*7dd7cddfSDavid du Colombier 		qunlock(&mbllock);
1121*7dd7cddfSDavid du Colombier 		if(mb != nil){
1122*7dd7cddfSDavid du Colombier 			syncmbox(mb, 1);
1123*7dd7cddfSDavid du Colombier 			qunlock(mb);
1124*7dd7cddfSDavid du Colombier 		} else
1125*7dd7cddfSDavid du Colombier 			sleep(15*1000);
1126*7dd7cddfSDavid du Colombier 	}
1127*7dd7cddfSDavid du Colombier }
1128*7dd7cddfSDavid du Colombier 
1129*7dd7cddfSDavid du Colombier int
1130*7dd7cddfSDavid du Colombier newid(void)
1131*7dd7cddfSDavid du Colombier {
1132*7dd7cddfSDavid du Colombier 	int rv;
1133*7dd7cddfSDavid du Colombier 	static int id;
1134*7dd7cddfSDavid du Colombier 	static Lock idlock;
1135*7dd7cddfSDavid du Colombier 
1136*7dd7cddfSDavid du Colombier 	lock(&idlock);
1137*7dd7cddfSDavid du Colombier 	rv = ++id;
1138*7dd7cddfSDavid du Colombier 	unlock(&idlock);
1139*7dd7cddfSDavid du Colombier 
1140*7dd7cddfSDavid du Colombier 	return rv;
1141*7dd7cddfSDavid du Colombier }
1142*7dd7cddfSDavid du Colombier 
1143*7dd7cddfSDavid du Colombier void
1144*7dd7cddfSDavid du Colombier error(char *s)
1145*7dd7cddfSDavid du Colombier {
1146*7dd7cddfSDavid du Colombier 	postnote(PNGROUP, getpid(), "die yankee pig dog");
1147*7dd7cddfSDavid du Colombier 	fprint(2, "%s: %s: %r\n", argv0, s);
1148*7dd7cddfSDavid du Colombier 	exits(s);
1149*7dd7cddfSDavid du Colombier }
1150*7dd7cddfSDavid du Colombier 
1151*7dd7cddfSDavid du Colombier 
1152*7dd7cddfSDavid du Colombier typedef struct Ignorance Ignorance;
1153*7dd7cddfSDavid du Colombier struct Ignorance
1154*7dd7cddfSDavid du Colombier {
1155*7dd7cddfSDavid du Colombier 	Ignorance *next;
1156*7dd7cddfSDavid du Colombier 	char	*str;		/* string */
1157*7dd7cddfSDavid du Colombier 	int	partial;	/* true if not exact match */
1158*7dd7cddfSDavid du Colombier };
1159*7dd7cddfSDavid du Colombier Ignorance *ignorance;
1160*7dd7cddfSDavid du Colombier 
1161*7dd7cddfSDavid du Colombier /*
1162*7dd7cddfSDavid du Colombier  *  read the file of headers to ignore
1163*7dd7cddfSDavid du Colombier  */
1164*7dd7cddfSDavid du Colombier void
1165*7dd7cddfSDavid du Colombier readignore(void)
1166*7dd7cddfSDavid du Colombier {
1167*7dd7cddfSDavid du Colombier 	char *p;
1168*7dd7cddfSDavid du Colombier 	Ignorance *i;
1169*7dd7cddfSDavid du Colombier 	Biobuf *b;
1170*7dd7cddfSDavid du Colombier 
1171*7dd7cddfSDavid du Colombier 	if(ignorance != nil)
1172*7dd7cddfSDavid du Colombier 		return;
1173*7dd7cddfSDavid du Colombier 
1174*7dd7cddfSDavid du Colombier 	b = Bopen("/mail/lib/ignore", OREAD);
1175*7dd7cddfSDavid du Colombier 	if(b == 0)
1176*7dd7cddfSDavid du Colombier 		return;
1177*7dd7cddfSDavid du Colombier 	while(p = Brdline(b, '\n')){
1178*7dd7cddfSDavid du Colombier 		p[Blinelen(b)-1] = 0;
1179*7dd7cddfSDavid du Colombier 		while(*p && (*p == ' ' || *p == '\t'))
1180*7dd7cddfSDavid du Colombier 			p++;
1181*7dd7cddfSDavid du Colombier 		if(*p == '#')
1182*7dd7cddfSDavid du Colombier 			continue;
1183*7dd7cddfSDavid du Colombier 		i = malloc(sizeof(Ignorance));
1184*7dd7cddfSDavid du Colombier 		if(i == 0)
1185*7dd7cddfSDavid du Colombier 			break;
1186*7dd7cddfSDavid du Colombier 		i->partial = strlen(p);
1187*7dd7cddfSDavid du Colombier 		i->str = strdup(p);
1188*7dd7cddfSDavid du Colombier 		if(i->str == 0){
1189*7dd7cddfSDavid du Colombier 			free(i);
1190*7dd7cddfSDavid du Colombier 			break;
1191*7dd7cddfSDavid du Colombier 		}
1192*7dd7cddfSDavid du Colombier 		i->next = ignorance;
1193*7dd7cddfSDavid du Colombier 		ignorance = i;
1194*7dd7cddfSDavid du Colombier 	}
1195*7dd7cddfSDavid du Colombier 	Bterm(b);
1196*7dd7cddfSDavid du Colombier }
1197*7dd7cddfSDavid du Colombier 
1198*7dd7cddfSDavid du Colombier int
1199*7dd7cddfSDavid du Colombier ignore(char *p)
1200*7dd7cddfSDavid du Colombier {
1201*7dd7cddfSDavid du Colombier 	Ignorance *i;
1202*7dd7cddfSDavid du Colombier 
1203*7dd7cddfSDavid du Colombier 	readignore();
1204*7dd7cddfSDavid du Colombier 	for(i = ignorance; i != nil; i = i->next)
1205*7dd7cddfSDavid du Colombier 		if(cistrncmp(i->str, p, i->partial) == 0)
1206*7dd7cddfSDavid du Colombier 			return 1;
1207*7dd7cddfSDavid du Colombier 	return 0;
1208*7dd7cddfSDavid du Colombier }
1209*7dd7cddfSDavid du Colombier 
1210*7dd7cddfSDavid du Colombier int
1211*7dd7cddfSDavid du Colombier hdrlen(char *p, char *e)
1212*7dd7cddfSDavid du Colombier {
1213*7dd7cddfSDavid du Colombier 	char *ep;
1214*7dd7cddfSDavid du Colombier 
1215*7dd7cddfSDavid du Colombier 	ep = p;
1216*7dd7cddfSDavid du Colombier 	do {
1217*7dd7cddfSDavid du Colombier 		ep = strchr(ep, '\n');
1218*7dd7cddfSDavid du Colombier 		if(ep == nil){
1219*7dd7cddfSDavid du Colombier 			ep = e;
1220*7dd7cddfSDavid du Colombier 			break;
1221*7dd7cddfSDavid du Colombier 		}
1222*7dd7cddfSDavid du Colombier 		ep++;
1223*7dd7cddfSDavid du Colombier 		if(ep >= e){
1224*7dd7cddfSDavid du Colombier 			ep = e;
1225*7dd7cddfSDavid du Colombier 			break;
1226*7dd7cddfSDavid du Colombier 		}
1227*7dd7cddfSDavid du Colombier 	} while(*ep == ' ' || *ep == '\t');
1228*7dd7cddfSDavid du Colombier 	return ep - p;
1229*7dd7cddfSDavid du Colombier }
1230*7dd7cddfSDavid du Colombier 
1231*7dd7cddfSDavid du Colombier // rfc2047 non-ascii
1232*7dd7cddfSDavid du Colombier typedef struct Charset Charset;
1233*7dd7cddfSDavid du Colombier struct Charset {
1234*7dd7cddfSDavid du Colombier 	char *name;
1235*7dd7cddfSDavid du Colombier 	int len;
1236*7dd7cddfSDavid du Colombier 	int convert;
1237*7dd7cddfSDavid du Colombier } charsets[4] =
1238*7dd7cddfSDavid du Colombier {
1239*7dd7cddfSDavid du Colombier 	{ "us-ascii",		8,	1, },
1240*7dd7cddfSDavid du Colombier 	{ "utf-8",		5,	0, },
1241*7dd7cddfSDavid du Colombier 	{ "iso-8859-1",		10,	1, },
1242*7dd7cddfSDavid du Colombier 	{ "big5",		4,	2, },
1243*7dd7cddfSDavid du Colombier };
1244*7dd7cddfSDavid du Colombier 
1245*7dd7cddfSDavid du Colombier // convert a single token
1246*7dd7cddfSDavid du Colombier int
1247*7dd7cddfSDavid du Colombier tokenconvert(String *s, char *token, int len)
1248*7dd7cddfSDavid du Colombier {
1249*7dd7cddfSDavid du Colombier 	char decoded[1024];
1250*7dd7cddfSDavid du Colombier 	char utfbuf[2*1024];
1251*7dd7cddfSDavid du Colombier 	int i, havequote;
1252*7dd7cddfSDavid du Colombier 	char *e, *x;
1253*7dd7cddfSDavid du Colombier 
1254*7dd7cddfSDavid du Colombier 	if(len == 0)
1255*7dd7cddfSDavid du Colombier 		return -1;
1256*7dd7cddfSDavid du Colombier 
1257*7dd7cddfSDavid du Colombier 	havequote = 0;
1258*7dd7cddfSDavid du Colombier 	if(token[0] == '"' && token[len-1] == '"'){
1259*7dd7cddfSDavid du Colombier 		havequote = 1;
1260*7dd7cddfSDavid du Colombier 		token++;
1261*7dd7cddfSDavid du Colombier 		len -= 2;
1262*7dd7cddfSDavid du Colombier 	}
1263*7dd7cddfSDavid du Colombier 
1264*7dd7cddfSDavid du Colombier 	if(token[0] != '=' || token[1] != '?' ||
1265*7dd7cddfSDavid du Colombier 	   token[len-2] != '?' || token[len-1] != '=')
1266*7dd7cddfSDavid du Colombier 		return -1;
1267*7dd7cddfSDavid du Colombier 	e = token+len-2;
1268*7dd7cddfSDavid du Colombier 	token += 2;
1269*7dd7cddfSDavid du Colombier 
1270*7dd7cddfSDavid du Colombier 	// bail if we don't understand the character set
1271*7dd7cddfSDavid du Colombier 	for(i = 0; i < nelem(charsets); i++)
1272*7dd7cddfSDavid du Colombier 		if(cistrncmp(charsets[i].name, token, charsets[i].len) == 0)
1273*7dd7cddfSDavid du Colombier 		if(token[charsets[i].len] == '?'){
1274*7dd7cddfSDavid du Colombier 			token += charsets[i].len + 1;
1275*7dd7cddfSDavid du Colombier 			break;
1276*7dd7cddfSDavid du Colombier 		}
1277*7dd7cddfSDavid du Colombier 	if(i >= nelem(charsets))
1278*7dd7cddfSDavid du Colombier 		return -1;
1279*7dd7cddfSDavid du Colombier 
1280*7dd7cddfSDavid du Colombier 	// bail if it doesn't fit
1281*7dd7cddfSDavid du Colombier 	if(strlen(token) > sizeof(decoded)-1)
1282*7dd7cddfSDavid du Colombier 		return -1;
1283*7dd7cddfSDavid du Colombier 
1284*7dd7cddfSDavid du Colombier 	// bail if we don't understand the encoding
1285*7dd7cddfSDavid du Colombier 	if(cistrncmp(token, "b?", 2) == 0){
1286*7dd7cddfSDavid du Colombier 		token += 2;
1287*7dd7cddfSDavid du Colombier 		len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
1288*7dd7cddfSDavid du Colombier 		decoded[len] = 0;
1289*7dd7cddfSDavid du Colombier 	} else if(cistrncmp(token, "q?", 2) == 0){
1290*7dd7cddfSDavid du Colombier 		token += 2;
1291*7dd7cddfSDavid du Colombier 		len = decquoted(decoded, token, e);
1292*7dd7cddfSDavid du Colombier 		if(len > 0 && decoded[len-1] == '\n')
1293*7dd7cddfSDavid du Colombier 			len--;
1294*7dd7cddfSDavid du Colombier 		decoded[len] = 0;
1295*7dd7cddfSDavid du Colombier 	} else
1296*7dd7cddfSDavid du Colombier 		return -1;
1297*7dd7cddfSDavid du Colombier 
1298*7dd7cddfSDavid du Colombier 	if(havequote)
1299*7dd7cddfSDavid du Colombier 		s_append(s, "\"");
1300*7dd7cddfSDavid du Colombier 	switch(charsets[i].convert){
1301*7dd7cddfSDavid du Colombier 	case 0:
1302*7dd7cddfSDavid du Colombier 		s_append(s, decoded);
1303*7dd7cddfSDavid du Colombier 		break;
1304*7dd7cddfSDavid du Colombier 	case 1:
1305*7dd7cddfSDavid du Colombier 		latin1toutf(utfbuf, decoded, decoded+len);
1306*7dd7cddfSDavid du Colombier 		s_append(s, utfbuf);
1307*7dd7cddfSDavid du Colombier 		break;
1308*7dd7cddfSDavid du Colombier 	case 2:
1309*7dd7cddfSDavid du Colombier 		if(xtoutf(charsets[i].name, &x, decoded, decoded+len) <= 0){
1310*7dd7cddfSDavid du Colombier 			s_append(s, decoded);
1311*7dd7cddfSDavid du Colombier 		} else {
1312*7dd7cddfSDavid du Colombier 			s_append(s, x);
1313*7dd7cddfSDavid du Colombier 			free(x);
1314*7dd7cddfSDavid du Colombier 		}
1315*7dd7cddfSDavid du Colombier 		break;
1316*7dd7cddfSDavid du Colombier 	}
1317*7dd7cddfSDavid du Colombier 	if(havequote)
1318*7dd7cddfSDavid du Colombier 		s_append(s, "\"");
1319*7dd7cddfSDavid du Colombier 
1320*7dd7cddfSDavid du Colombier 	return 0;
1321*7dd7cddfSDavid du Colombier }
1322*7dd7cddfSDavid du Colombier 
1323*7dd7cddfSDavid du Colombier // convert a header line
1324*7dd7cddfSDavid du Colombier String*
1325*7dd7cddfSDavid du Colombier hdrconvert(String *s, char *line, int len)
1326*7dd7cddfSDavid du Colombier {
1327*7dd7cddfSDavid du Colombier 	char *end;
1328*7dd7cddfSDavid du Colombier 	char token[1024];
1329*7dd7cddfSDavid du Colombier 	int i;
1330*7dd7cddfSDavid du Colombier 
1331*7dd7cddfSDavid du Colombier 	end = line+len;
1332*7dd7cddfSDavid du Colombier 	s = s_reset(s);
1333*7dd7cddfSDavid du Colombier 	i = 0;
1334*7dd7cddfSDavid du Colombier 	if(memchr(line, '=', len) == 0){
1335*7dd7cddfSDavid du Colombier 		s_nappend(s, line, len);
1336*7dd7cddfSDavid du Colombier 		return s;
1337*7dd7cddfSDavid du Colombier 	}
1338*7dd7cddfSDavid du Colombier 	while(line < end){
1339*7dd7cddfSDavid du Colombier 		switch(*line){
1340*7dd7cddfSDavid du Colombier 		case ' ':
1341*7dd7cddfSDavid du Colombier 		case '\t':
1342*7dd7cddfSDavid du Colombier 		case '\n':
1343*7dd7cddfSDavid du Colombier 			token[i] = 0;
1344*7dd7cddfSDavid du Colombier 			if(tokenconvert(s, token, i) < 0){
1345*7dd7cddfSDavid du Colombier 				token[i++] = *line++;
1346*7dd7cddfSDavid du Colombier 				token[i] = 0;
1347*7dd7cddfSDavid du Colombier 				s_append(s, token);
1348*7dd7cddfSDavid du Colombier 				i = 0;
1349*7dd7cddfSDavid du Colombier 				continue;
1350*7dd7cddfSDavid du Colombier 			}
1351*7dd7cddfSDavid du Colombier 			s_putc(s, *line++);
1352*7dd7cddfSDavid du Colombier 			s_terminate(s);
1353*7dd7cddfSDavid du Colombier 			i = 0;
1354*7dd7cddfSDavid du Colombier 			break;
1355*7dd7cddfSDavid du Colombier 
1356*7dd7cddfSDavid du Colombier 		default:
1357*7dd7cddfSDavid du Colombier 			if(i >= sizeof(token)-3){
1358*7dd7cddfSDavid du Colombier 				token[i++] = *line++;
1359*7dd7cddfSDavid du Colombier 				token[i] = 0;
1360*7dd7cddfSDavid du Colombier 				s_append(s, token);
1361*7dd7cddfSDavid du Colombier 				i = 0;
1362*7dd7cddfSDavid du Colombier 				continue;
1363*7dd7cddfSDavid du Colombier 			}
1364*7dd7cddfSDavid du Colombier 			token[i++] = *line++;
1365*7dd7cddfSDavid du Colombier 			break;
1366*7dd7cddfSDavid du Colombier 		}
1367*7dd7cddfSDavid du Colombier 	}
1368*7dd7cddfSDavid du Colombier 	return s;
1369*7dd7cddfSDavid du Colombier }
1370*7dd7cddfSDavid du Colombier 
1371*7dd7cddfSDavid du Colombier int
1372*7dd7cddfSDavid du Colombier readheader(Message *m, char *buf, int off, int cnt)
1373*7dd7cddfSDavid du Colombier {
1374*7dd7cddfSDavid du Colombier 	char *p, *e;
1375*7dd7cddfSDavid du Colombier 	int n, ns;
1376*7dd7cddfSDavid du Colombier 	char *to = buf;
1377*7dd7cddfSDavid du Colombier 	String *s;
1378*7dd7cddfSDavid du Colombier 
1379*7dd7cddfSDavid du Colombier 	p = m->header;
1380*7dd7cddfSDavid du Colombier 	e = m->hend;
1381*7dd7cddfSDavid du Colombier 	s = nil;
1382*7dd7cddfSDavid du Colombier 
1383*7dd7cddfSDavid du Colombier 	// copy in good headers
1384*7dd7cddfSDavid du Colombier 	while(cnt > 0 && p < e){
1385*7dd7cddfSDavid du Colombier 		n = hdrlen(p, e);
1386*7dd7cddfSDavid du Colombier 		if(ignore(p)){
1387*7dd7cddfSDavid du Colombier 			p += n;
1388*7dd7cddfSDavid du Colombier 			continue;
1389*7dd7cddfSDavid du Colombier 		}
1390*7dd7cddfSDavid du Colombier 
1391*7dd7cddfSDavid du Colombier 		// rfc2047 processing
1392*7dd7cddfSDavid du Colombier 		s = hdrconvert(s, p, n);
1393*7dd7cddfSDavid du Colombier 		ns = s_len(s);
1394*7dd7cddfSDavid du Colombier 		if(off > 0){
1395*7dd7cddfSDavid du Colombier 			if(ns <= off){
1396*7dd7cddfSDavid du Colombier 				off -= ns;
1397*7dd7cddfSDavid du Colombier 				p += n;
1398*7dd7cddfSDavid du Colombier 				continue;
1399*7dd7cddfSDavid du Colombier 			}
1400*7dd7cddfSDavid du Colombier 			ns -= off;
1401*7dd7cddfSDavid du Colombier 		}
1402*7dd7cddfSDavid du Colombier 		if(ns > cnt)
1403*7dd7cddfSDavid du Colombier 			ns = cnt;
1404*7dd7cddfSDavid du Colombier 		memmove(to, s_to_c(s)+off, ns);
1405*7dd7cddfSDavid du Colombier 		to += ns;
1406*7dd7cddfSDavid du Colombier 		p += n;
1407*7dd7cddfSDavid du Colombier 		cnt -= ns;
1408*7dd7cddfSDavid du Colombier 		off = 0;
1409*7dd7cddfSDavid du Colombier 	}
1410*7dd7cddfSDavid du Colombier 
1411*7dd7cddfSDavid du Colombier 	s_free(s);
1412*7dd7cddfSDavid du Colombier 	return to - buf;
1413*7dd7cddfSDavid du Colombier }
1414*7dd7cddfSDavid du Colombier 
1415*7dd7cddfSDavid du Colombier int
1416*7dd7cddfSDavid du Colombier headerlen(Message *m)
1417*7dd7cddfSDavid du Colombier {
1418*7dd7cddfSDavid du Colombier 	char buf[1024];
1419*7dd7cddfSDavid du Colombier 	int i, n;
1420*7dd7cddfSDavid du Colombier 
1421*7dd7cddfSDavid du Colombier 	if(m->hlen >= 0)
1422*7dd7cddfSDavid du Colombier 		return m->hlen;
1423*7dd7cddfSDavid du Colombier 	for(n = 0; ; n += i){
1424*7dd7cddfSDavid du Colombier 		i = readheader(m, buf, n, sizeof(buf));
1425*7dd7cddfSDavid du Colombier 		if(i <= 0)
1426*7dd7cddfSDavid du Colombier 			break;
1427*7dd7cddfSDavid du Colombier 	}
1428*7dd7cddfSDavid du Colombier 	m->hlen = n;
1429*7dd7cddfSDavid du Colombier 	return n;
1430*7dd7cddfSDavid du Colombier }
1431*7dd7cddfSDavid du Colombier 
1432*7dd7cddfSDavid du Colombier QLock hashlock;
1433*7dd7cddfSDavid du Colombier 
1434*7dd7cddfSDavid du Colombier uint
1435*7dd7cddfSDavid du Colombier hash(ulong ppath, char *name)
1436*7dd7cddfSDavid du Colombier {
1437*7dd7cddfSDavid du Colombier 	uchar *p;
1438*7dd7cddfSDavid du Colombier 	uint h;
1439*7dd7cddfSDavid du Colombier 
1440*7dd7cddfSDavid du Colombier 	h = 0;
1441*7dd7cddfSDavid du Colombier 	for(p = (uchar*)name; *p; p++)
1442*7dd7cddfSDavid du Colombier 		h = h*7 + *p;
1443*7dd7cddfSDavid du Colombier 	h += ppath;
1444*7dd7cddfSDavid du Colombier 
1445*7dd7cddfSDavid du Colombier 	return h % Hsize;
1446*7dd7cddfSDavid du Colombier }
1447*7dd7cddfSDavid du Colombier 
1448*7dd7cddfSDavid du Colombier Hash*
1449*7dd7cddfSDavid du Colombier hlook(ulong ppath, char *name)
1450*7dd7cddfSDavid du Colombier {
1451*7dd7cddfSDavid du Colombier 	int h;
1452*7dd7cddfSDavid du Colombier 	Hash *hp;
1453*7dd7cddfSDavid du Colombier 
1454*7dd7cddfSDavid du Colombier 	qlock(&hashlock);
1455*7dd7cddfSDavid du Colombier 	h = hash(ppath, name);
1456*7dd7cddfSDavid du Colombier 	for(hp = htab[h]; hp != nil; hp = hp->next)
1457*7dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
1458*7dd7cddfSDavid du Colombier 			qunlock(&hashlock);
1459*7dd7cddfSDavid du Colombier 			return hp;
1460*7dd7cddfSDavid du Colombier 		}
1461*7dd7cddfSDavid du Colombier 	qunlock(&hashlock);
1462*7dd7cddfSDavid du Colombier 	return nil;
1463*7dd7cddfSDavid du Colombier }
1464*7dd7cddfSDavid du Colombier 
1465*7dd7cddfSDavid du Colombier void
1466*7dd7cddfSDavid du Colombier henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
1467*7dd7cddfSDavid du Colombier {
1468*7dd7cddfSDavid du Colombier 	int h;
1469*7dd7cddfSDavid du Colombier 	Hash *hp, **l;
1470*7dd7cddfSDavid du Colombier 
1471*7dd7cddfSDavid du Colombier 	qlock(&hashlock);
1472*7dd7cddfSDavid du Colombier 	h = hash(ppath, name);
1473*7dd7cddfSDavid du Colombier 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
1474*7dd7cddfSDavid du Colombier 		hp = *l;
1475*7dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
1476*7dd7cddfSDavid du Colombier 			hp->m = m;
1477*7dd7cddfSDavid du Colombier 			hp->mb = mb;
1478*7dd7cddfSDavid du Colombier 			hp->qid = qid;
1479*7dd7cddfSDavid du Colombier 			qunlock(&hashlock);
1480*7dd7cddfSDavid du Colombier 			return;
1481*7dd7cddfSDavid du Colombier 		}
1482*7dd7cddfSDavid du Colombier 	}
1483*7dd7cddfSDavid du Colombier 
1484*7dd7cddfSDavid du Colombier 	*l = hp = emalloc(sizeof(*hp));
1485*7dd7cddfSDavid du Colombier 	hp->m = m;
1486*7dd7cddfSDavid du Colombier 	hp->mb = mb;
1487*7dd7cddfSDavid du Colombier 	hp->qid = qid;
1488*7dd7cddfSDavid du Colombier 	hp->name = name;
1489*7dd7cddfSDavid du Colombier 	hp->ppath = ppath;
1490*7dd7cddfSDavid du Colombier 	qunlock(&hashlock);
1491*7dd7cddfSDavid du Colombier }
1492*7dd7cddfSDavid du Colombier 
1493*7dd7cddfSDavid du Colombier void
1494*7dd7cddfSDavid du Colombier hfree(ulong ppath, char *name)
1495*7dd7cddfSDavid du Colombier {
1496*7dd7cddfSDavid du Colombier 	int h;
1497*7dd7cddfSDavid du Colombier 	Hash *hp, **l;
1498*7dd7cddfSDavid du Colombier 
1499*7dd7cddfSDavid du Colombier 	qlock(&hashlock);
1500*7dd7cddfSDavid du Colombier 	h = hash(ppath, name);
1501*7dd7cddfSDavid du Colombier 	for(l = &htab[h]; *l != nil; l = &(*l)->next){
1502*7dd7cddfSDavid du Colombier 		hp = *l;
1503*7dd7cddfSDavid du Colombier 		if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
1504*7dd7cddfSDavid du Colombier 			*l = hp->next;
1505*7dd7cddfSDavid du Colombier 			free(hp);
1506*7dd7cddfSDavid du Colombier 			break;
1507*7dd7cddfSDavid du Colombier 		}
1508*7dd7cddfSDavid du Colombier 	}
1509*7dd7cddfSDavid du Colombier 	qunlock(&hashlock);
1510*7dd7cddfSDavid du Colombier }
1511*7dd7cddfSDavid du Colombier 
1512*7dd7cddfSDavid du Colombier int
1513*7dd7cddfSDavid du Colombier hashmboxrefs(Mailbox *mb)
1514*7dd7cddfSDavid du Colombier {
1515*7dd7cddfSDavid du Colombier 	int h;
1516*7dd7cddfSDavid du Colombier 	Hash *hp;
1517*7dd7cddfSDavid du Colombier 	int refs = 0;
1518*7dd7cddfSDavid du Colombier 
1519*7dd7cddfSDavid du Colombier 	qlock(&hashlock);
1520*7dd7cddfSDavid du Colombier 	for(h = 0; h < Hsize; h++){
1521*7dd7cddfSDavid du Colombier 		for(hp = htab[h]; hp != nil; hp = hp->next)
1522*7dd7cddfSDavid du Colombier 			if(hp->mb == mb)
1523*7dd7cddfSDavid du Colombier 				refs++;
1524*7dd7cddfSDavid du Colombier 	}
1525*7dd7cddfSDavid du Colombier 	qunlock(&hashlock);
1526*7dd7cddfSDavid du Colombier 	return refs;
1527*7dd7cddfSDavid du Colombier }
1528