#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);
}
|