Plan 9 from Bell Labs’s /usr/web/sources/contrib/gabidiaz/wip/mboxfs/fs.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "a.h"

char	Eperm[] =	"permission denied";
char	Enotdir[] =	"not a directory";
char	Enoauth[] =	"upas/fs: authentication not required";
char	Enotexist[] =	"file does not exist";
char	Einuse[] =	"file in use";
char	Eexist[] =	"file exists";
char	Enotowner[] =	"not owner";
char	Eisopen[] = 	"file already open for I/O";
char	Excl[] = 	"exclusive use file already open";
char	Ename[] = 	"illegal name";
char	Ebadctl[] =	"unknown control message";
char Eioerror[] = "error reading or writting file";
char Enomess[] = "message do not exist";
char Enomailbox[]= "mailbox do not exist";
char Eunknown[]= "unknown error";
enum
{
	Qbody,
	Qbcc,
	Qcc,
	Qdate,
	Qdigest,
	Qdisposition,
	Qfilename,
	Qfrom,
	Qheader,
	Qinreplyto,
	Qlines,
	Qmimeheader,
	Qmessageid,
	Qraw,
	Qrawbody,
	Qrawheader,
	Qrawunix,
	Qreplyto,
	Qsender,
	Qsubject,
	Qto,
	Qtype,
	Qunixheader,
	Qinfo,
	Qunixdate,
	Qctl,
	Qmboxctl
};

char *dirtab[] =
{
[Qbody]		"body",
[Qbcc]		"bcc",
[Qcc]		"cc",
[Qdate]		"date",
[Qdigest]	"digest",
[Qdisposition]	"disposition",
[Qfilename]	"filename",
[Qfrom]		"from",
[Qheader]	"header",
[Qinfo]		"info",
[Qinreplyto]	"inreplyto",
[Qlines]	"lines",
[Qmimeheader]	"mimeheader",
[Qmessageid]	"message-id",
[Qraw]		"raw",
[Qrawunix]	"rawunix",
[Qrawbody]	"rawbody",
[Qrawheader]	"rawheader",
[Qreplyto]	"replyto",
[Qsender]	"sender",
[Qsubject]	"subject",
[Qto]		"to",
[Qtype]		"type",
[Qunixdate]	"unixdate",
[Qunixheader]	"unixheader",
[Qctl]		"ctl",
[Qmboxctl]	"ctl",
};

/* no auth, just mount the selected box */
void 
fsattach(Req *r)
{
	File *f;

	f = fstree->root;

	r->fid->file = f;
	incref(r->fid->file);
 	r->ofcall.qid = f->qid;
	r->fid->qid = r->ofcall.qid;

	respond(r,nil);
	return;

}

void
strrespond(Req *r,char *s,vlong n)
{
	r->ofcall.count = r->ifcall.count;
	if(r->ifcall.offset >= n){
		r->ofcall.count = 0;
		respond(r,nil);
		return;
	}
	if(r->ifcall.offset+r->ofcall.count > n)
		r->ofcall.count = n - r->ifcall.offset;
	memmove(r->ofcall.data, (char*)s+r->ifcall.offset, r->ofcall.count);

	respond(r,nil);

}
void
buffrespond(Req *r,char *s,vlong n)
{
	if(n <= 0){
		r->ofcall.count = 0;
		respond(r,nil);
		return;
	}

	r->ofcall.count = n;
	memmove(r->ofcall.data, s, n);

	respond(r,nil);

}

void
fsread(Req *r)
{
	File *pf;
	Fileinfo info;

	Message *m;

	char *resp;


	vlong len;
	
	pf = r->fid->file;
	if ( pf->aux == nil) {
		respond(nil,Eunknown);
		return;
	}

	memcpy(&info,pf->aux,sizeof info);

	m=info.m;
	if (m == nil) {
		respond(nil,Eunknown);
		return;
	} 
	resp=nil;

	switch(info.Q) {
		case Qto:
			len=m->to(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qfrom:
			len=m->from(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qbcc:
			len=m->bcc(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qcc:
			len=m->cc(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qbody:
			len=m->body(m,&resp,r->ifcall.offset, r->ifcall.count);
			buffrespond(r,resp,len);
			break;
		case Qsubject:
			len=m->subject(m,&resp);
			strrespond(r,resp,len);	
			break;
		case Qdate:
			len=m->date(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qdigest:
			len=m->digest(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qdisposition:
			len=m->disposition(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qfilename:
			len=m->filename(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qheader:
			len=m->header(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qinreplyto:
			len=m->inreplyto(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qlines:
			len=m->lines(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qmimeheader:
			len=m->mimeheader(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qmessageid:
			len=m->messageid(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qraw:
			len=m->raw(m,&resp,r->ifcall.offset, r->ifcall.count);
			buffrespond(r,resp,len);
			break;
		case Qrawbody:
			len=m->rawbody(m,&resp,r->ifcall.offset, r->ifcall.count);
			buffrespond(r,resp,len);
			break;
		case Qrawheader:
			len=m->rawheader(m,&resp,r->ifcall.offset, r->ifcall.count);
			buffrespond(r,resp,len);
			break;
		case Qrawunix:
			len=m->rawunix(m,&resp,r->ifcall.offset, r->ifcall.count);
			buffrespond(r,resp,len);
			break;
		case Qreplyto:
			len=m->replyto(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qsender:
			len=m->sender(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qtype:
			len=m->type(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qunixheader:
			len=m->unixheader(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qinfo:
			len=m->info(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qunixdate:
			len=m->unixdate(m,&resp);
			strrespond(r,resp,len);
			break;
		case Qctl:
		case Qmboxctl:
			strrespond(r,nil,0);
			break;
		default:
			respond(r,Enotexist);
			break;
	}

	free(resp);

	return;

}

void
fswrite(Req *r)
{
	File *pf;
	Fileinfo info;
	Message *m;
	char *cmd;
	vlong len;
	char *token[1024];
	int t, n;
	Mailbox *b;


	pf = r->fid->file;
	if ( pf->aux == nil) {
		respond(nil,Eunknown);
		return;
	}

	memcpy(&info,pf->aux,sizeof info);

	m=info.m;
	if (m == nil) {
		respond(nil,Eunknown);
		return;
	} 


	switch(info.Q) {
		case Qctl:
			len=r->ifcall.count;
			if ( r->ifcall.offset > 0 ||  len == 0) {
				respond(nil,Ebadctl);
				return;
			}
			cmd=emalloc(len);
			memmove(cmd,r->ifcall.data,len);
		
			if(cmd[len-1] == '\n')
				cmd[len-1] = 0;
			else
				cmd[len] = 0;

			n = tokenize(cmd, token, nelem(token));
			if(n == 0) {
				respond(nil,Ebadctl);
				return;
			}
			if(strcmp(token[0], "open") == 0){
				switch(n){
					case 1:
						respond(nil,Ebadctl);
						break;
					case 2:
						respond(nil,Ebadctl);
						break;
				}
			}
	}
	respond(nil,Ebadctl);
	return;
}


void
fscreate(Req *r)
{

	respond(r, Eperm);
	return;

}

Srv fs = {
	.attach=	fsattach,
	.read=	fsread,
	.write=	fswrite,
	.create=	fscreate,
};

/* initial parse of  mailbox */

void
fsinittab(Message *m, File *mess, char *user)
{
	File *f;
	Fileinfo info;
	char *aux;

	for(int fi=Qbody; fi<=Qctl;fi++) {

		f = createfile(mess,dirtab[fi],user,0400,nil);
		info.Q=fi;
		info.m=m;
		f->aux=emalloc(sizeof info);
		memcpy(f->aux,&info,sizeof info);

		aux=nil;
		/* file info, required to be compatible with acme mail and others */
		switch(fi) {
		case Qto:
			f->length=m->to(m,&aux);
			break;
		case Qfrom:
			f->length=m->from(m,&aux);
			break;
		case Qbcc:
			f->length=m->bcc(m,&aux);
			break;
		case Qcc:
			f->length=m->cc(m,&aux);
			break;
		case Qsubject:
			f->length=m->subject(m,&aux);
			break;
		case Qdate:
			f->length=m->date(m,&aux);
			break;
		case Qdigest:
			f->length=m->digest(m,&aux);
			break;
		case Qdisposition:
			f->length=m->disposition(m,&aux);
			break;
		case Qfilename:
			f->length=m->filename(m,&aux);
			break;
		case Qheader:
			f->length=m->header(m,&aux);
			break;
		case Qinreplyto:
			f->length=m->inreplyto(m,&aux);
			break;
		case Qlines:
			f->length=m->lines(m,&aux);
			break;
		case Qmimeheader:
			f->length=m->mimeheader(m,&aux);
			break;
		case Qmessageid:
			f->length=m->messageid(m,&aux);
			break;
		case Qreplyto:
			f->length=m->replyto(m,&aux);
			break;
		case Qsender:
			f->length=m->sender(m,&aux);
			break;
		case Qtype:
			f->length=m->type(m,&aux);
			break;
		case Qunixheader:
			f->length=m->unixheader(m,&aux);
			break;
		case Qinfo:
			f->length=m->info(m,&aux);
			break;
		case Qunixdate:
			f->length=m->unixdate(m,&aux);
			break;
		case Qbody:
		case Qrawbody:
			f->length=m->bend-m->bstart;
			break;
		case Qraw:
		case Qrawunix:
			f->length=m->end-m->start;
			break;
		case Qrawheader:
			f->length=m->hend-m->hstart;
			break;
		case Qctl:
		case Qmboxctl:
			f->length=0;
			break;
		}
		free(aux);
	}

}

int
fsinitmsg(Message *m, File *parent, char *user) 
{
	Message *p;
	File *fm;
	File *fp;
	char *mname;

	for(;m!=nil;m=m->next) {
		mname=smprint("%d",m->id);
		fm = createfile(parent,mname,user,DMDIR|0700,nil);
		if ( fm == nil ) {
			error(DEBUG,"fs M 0x%luX cannot create dir %s\n",m,mname);
			free(mname);
			return 0;
		}
		free(mname);
		fsinittab(m,fm,user);
		for(p=m->part;p!=nil;p=p->next) {
			mname=smprint("%d",p->id);
			fp = createfile(fm,mname,user,DMDIR|0700,nil);
			if ( fm == nil ) {
				error(DEBUG,"fs P 0x%luX cannot create dir %s\n",p,mname);
				free(mname);
				return 0;
			}
			free(mname);
			fsinittab(p,fp,user);
			if ( p->part != nil )
				fsinitmsg(p->part,fp,user);
		}
	}
	return 1;
}

int
fsinit(Mailbox *b, char *user)
{
	Message *m;
	File *box;
	Qid q;

	fs.tree = alloctree(nil, nil, DMDIR|0777, nil);
	fstree = fs.tree;
	q = fs.tree->root->qid;

	box=createfile(fs.tree->root,b->name,user,DMDIR|0700,nil);
	createfile(fs.tree->root,dirtab[Qmboxctl],user,0600,nil);
	m=b->msgs;
	
	fsinitmsg(m,box,user);

	return 1;

}

void
usage(void)
{
	fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n");
	exits("usage");
}

void
threadmain(int argc, char **argv)
{
	int nodflt;
	char maildir[128];
	char mbox[128];
	char *mboxfile, *user, *mntpt;
	char *srvfile, *pr;

	fmtinstall('D',dirfmt);
	fmtinstall('M',dirmodefmt);
	fmtinstall('F',fcallfmt);

	rfork(RFNOTEG);
	mntpt = nil;
	fflag = 0;
	mboxfile = nil;
	nodflt = 0;
	srvfile=nil;


	ARGBEGIN{
	case 'f':
		fflag = 1;
		mboxfile = EARGF(usage());
		break;
	case 'm':
		mntpt = EARGF(usage());
		break;
	case 'd':
		debug = 1;
		chatty9p++;
		break;
	case 's':
		srvfile=EARGF(usage());
		break;
	case 'l':
		logging = 1;
		break;
	case 'n':
		nodflt = 1;
		break;
	default:
		usage();
	}ARGEND

	if(argc)
		usage();

	user=getuser();

	if(mntpt == nil){
		snprint(maildir, sizeof(maildir), "/mail/fs");
		mntpt = maildir;
	}

	if(mboxfile == nil && !nodflt){
		snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);
		mboxfile = mbox;
	}

	if(mboxfile != nil)
		Box = newbox(mboxfile);
	else
		usage();

	initbox(Box);

	Box->open(Box);
	Box->fetch(Box);

	fsinit(Box,user);

	if ( debug == 1 )
		printbox(Box);
	
	if(srvfile || mntpt)
		threadpostmountsrv(&fs, srvfile, mntpt, MREPL|MCREATE);

	exits(0);

}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].