123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683 |
- #include "common.h"
- #include <auth.h>
- #include <fcall.h>
- #include <libsec.h>
- #include "dat.h"
- enum
- {
- OPERM = 0x3, // mask of all permission types in open mode
- };
- typedef struct Fid Fid;
- struct Fid
- {
- Qid qid;
- short busy;
- short open;
- int fid;
- Fid *next;
- Mailbox *mb;
- Message *m;
- Message *mtop; // top level message
- //finger pointers to speed up reads of large directories
- long foff; // offset/DIRLEN of finger
- Message *fptr; // pointer to message at off
- int fvers; // mailbox version when finger was saved
- };
- ulong path; // incremented for each new file
- Fid *fids;
- int mfd[2];
- char user[Elemlen];
- int messagesize = 4*1024*IOHDRSZ;
- uchar mdata[8*1024*IOHDRSZ];
- uchar mbuf[8*1024*IOHDRSZ];
- Fcall thdr;
- Fcall rhdr;
- int fflg;
- char *mntpt;
- int biffing;
- int plumbing = 1;
- QLock mbllock;
- Mailbox *mbl;
- Fid *newfid(int);
- void error(char*);
- void io(void);
- void *erealloc(void*, ulong);
- void *emalloc(ulong);
- void usage(void);
- void reader(void);
- int readheader(Message*, char*, int, int);
- int cistrncmp(char*, char*, int);
- int tokenconvert(String*, char*, int);
- String* stringconvert(String*, char*, int);
- void post(char*, char*, int);
- char *rflush(Fid*), *rauth(Fid*),
- *rattach(Fid*), *rwalk(Fid*),
- *ropen(Fid*), *rcreate(Fid*),
- *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
- *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
- *rversion(Fid*);
- char *(*fcalls[])(Fid*) = {
- [Tflush] rflush,
- [Tversion] rversion,
- [Tauth] rauth,
- [Tattach] rattach,
- [Twalk] rwalk,
- [Topen] ropen,
- [Tcreate] rcreate,
- [Tread] rread,
- [Twrite] rwrite,
- [Tclunk] rclunk,
- [Tremove] rremove,
- [Tstat] rstat,
- [Twstat] rwstat,
- };
- 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 *dirtab[] =
- {
- [Qdir] ".",
- [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] "messageid",
- [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",
- };
- enum
- {
- Hsize= 1277,
- };
- Hash *htab[Hsize];
- int debug;
- int fflag;
- int logging;
- void
- usage(void)
- {
- fprint(2, "usage: %s [-b -m mountpoint]\n", argv0);
- exits("usage");
- }
- void
- notifyf(void *a, char *s)
- {
- USED(a);
- if(strncmp(s, "interrupt", 9) == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- void
- main(int argc, char *argv[])
- {
- int p[2], std, nodflt;
- char maildir[128];
- char mbox[128];
- char *mboxfile, *err;
- char srvfile[64];
- int srvpost;
- rfork(RFNOTEG);
- mntpt = nil;
- fflag = 0;
- mboxfile = nil;
- std = 0;
- nodflt = 0;
- srvpost = 0;
- ARGBEGIN{
- case 'b':
- biffing = 1;
- break;
- case 'f':
- fflag = 1;
- mboxfile = ARGF();
- break;
- case 'm':
- mntpt = ARGF();
- break;
- case 'd':
- debug = 1;
- break;
- case 'p':
- plumbing = 0;
- break;
- case 's':
- srvpost = 1;
- break;
- case 'l':
- logging = 1;
- break;
- case 'n':
- nodflt = 1;
- break;
- default:
- usage();
- }ARGEND
- if(pipe(p) < 0)
- error("pipe failed");
- mfd[0] = p[0];
- mfd[1] = p[0];
- notify(notifyf);
- strcpy(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;
- std = 1;
- }
- if(debug)
- fmtinstall('F', fcallfmt);
- if(mboxfile != nil){
- err = newmbox(mboxfile, "mbox", std);
- if(err != nil)
- sysfatal("opening mailbox: %s", err);
- }
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
- case -1:
- error("fork");
- case 0:
- henter(PATH(0, Qtop), dirtab[Qctl],
- (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);
- close(p[1]);
- io();
- postnote(PNGROUP, getpid(), "die yankee pig dog");
- break;
- default:
- close(p[0]); /* don't deadlock if child fails */
- if(srvpost){
- sprint(srvfile, "/srv/upasfs.%s", user);
- post(srvfile, "upasfs", p[1]);
- } else {
- if(mount(p[1], -1, mntpt, MREPL, "") < 0)
- error("mount failed");
- }
- }
- exits(0);
- }
- static int
- fileinfo(Message *m, int t, char **pp)
- {
- char *p;
- int len;
- p = "";
- len = 0;
- switch(t){
- case Qbody:
- p = m->body;
- len = m->bend - m->body;
- break;
- case Qbcc:
- if(m->bcc822){
- p = s_to_c(m->bcc822);
- len = strlen(p);
- }
- break;
- case Qcc:
- if(m->cc822){
- p = s_to_c(m->cc822);
- len = strlen(p);
- }
- break;
- case Qdisposition:
- switch(m->disposition){
- case Dinline:
- p = "inline";
- break;
- case Dfile:
- p = "file";
- break;
- }
- len = strlen(p);
- break;
- case Qdate:
- if(m->date822){
- p = s_to_c(m->date822);
- len = strlen(p);
- } else if(m->unixdate != nil){
- p = s_to_c(m->unixdate);
- len = strlen(p);
- }
- break;
- case Qfilename:
- if(m->filename){
- p = s_to_c(m->filename);
- len = strlen(p);
- }
- break;
- case Qinreplyto:
- if(m->inreplyto822){
- p = s_to_c(m->inreplyto822);
- len = strlen(p);
- }
- break;
- case Qmessageid:
- if(m->messageid822){
- p = s_to_c(m->messageid822);
- len = strlen(p);
- }
- break;
- case Qfrom:
- if(m->from822){
- p = s_to_c(m->from822);
- len = strlen(p);
- } else if(m->unixfrom != nil){
- p = s_to_c(m->unixfrom);
- len = strlen(p);
- }
- break;
- case Qheader:
- p = m->header;
- len = headerlen(m);
- break;
- case Qlines:
- p = m->lines;
- if(*p == 0)
- countlines(m);
- len = strlen(m->lines);
- break;
- case Qraw:
- p = m->start;
- if(strncmp(m->start, "From ", 5) == 0){
- p = strchr(p, '\n');
- if(p == nil)
- p = m->start;
- else
- p++;
- }
- len = m->end - p;
- break;
- case Qrawunix:
- p = m->start;
- len = m->end - p;
- break;
- case Qrawbody:
- p = m->rbody;
- len = m->rbend - p;
- break;
- case Qrawheader:
- p = m->header;
- len = m->hend - p;
- break;
- case Qmimeheader:
- p = m->mheader;
- len = m->mhend - p;
- break;
- case Qreplyto:
- p = nil;
- if(m->replyto822 != nil){
- p = s_to_c(m->replyto822);
- len = strlen(p);
- } else if(m->from822 != nil){
- p = s_to_c(m->from822);
- len = strlen(p);
- } else if(m->sender822 != nil){
- p = s_to_c(m->sender822);
- len = strlen(p);
- } else if(m->unixfrom != nil){
- p = s_to_c(m->unixfrom);
- len = strlen(p);
- }
- break;
- case Qsender:
- if(m->sender822){
- p = s_to_c(m->sender822);
- len = strlen(p);
- }
- break;
- case Qsubject:
- p = nil;
- if(m->subject822){
- p = s_to_c(m->subject822);
- len = strlen(p);
- }
- break;
- case Qto:
- if(m->to822){
- p = s_to_c(m->to822);
- len = strlen(p);
- }
- break;
- case Qtype:
- if(m->type){
- p = s_to_c(m->type);
- len = strlen(p);
- }
- break;
- case Qunixdate:
- if(m->unixdate){
- p = s_to_c(m->unixdate);
- len = strlen(p);
- }
- break;
- case Qunixheader:
- if(m->unixheader){
- p = s_to_c(m->unixheader);
- len = s_len(m->unixheader);
- }
- break;
- case Qdigest:
- if(m->sdigest){
- p = s_to_c(m->sdigest);
- len = strlen(p);
- }
- break;
- }
- *pp = p;
- return len;
- }
- int infofields[] = {
- Qfrom,
- Qto,
- Qcc,
- Qreplyto,
- Qunixdate,
- Qsubject,
- Qtype,
- Qdisposition,
- Qfilename,
- Qdigest,
- Qbcc,
- Qinreplyto,
- Qdate,
- Qsender,
- Qmessageid,
- Qlines,
- -1,
- };
- static int
- readinfo(Message *m, char *buf, long off, int count)
- {
- char *p;
- int len, i, n;
- String *s;
- s = s_new();
- len = 0;
- for(i = 0; len < count && infofields[i] >= 0; i++){
- n = fileinfo(m, infofields[i], &p);
- s = stringconvert(s, p, n);
- s_append(s, "\n");
- p = s_to_c(s);
- n = strlen(p);
- if(off > 0){
- if(off >= n){
- off -= n;
- continue;
- }
- p += off;
- n -= off;
- off = 0;
- }
- if(n > count - len)
- n = count - len;
- if(buf)
- memmove(buf+len, p, n);
- len += n;
- }
- s_free(s);
- return len;
- }
- static void
- mkstat(Dir *d, Mailbox *mb, Message *m, int t)
- {
- char *p;
- d->uid = user;
- d->gid = user;
- d->muid = user;
- d->mode = 0444;
- d->qid.vers = 0;
- d->qid.type = QTFILE;
- d->type = 0;
- d->dev = 0;
- if(mb != nil && mb->d != nil){
- d->atime = mb->d->atime;
- d->mtime = mb->d->mtime;
- } else {
- d->atime = time(0);
- d->mtime = d->atime;
- }
- switch(t){
- case Qtop:
- d->name = ".";
- d->mode = DMDIR|0555;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(0, Qtop);
- d->qid.type = QTDIR;
- break;
- case Qmbox:
- d->name = mb->name;
- d->mode = DMDIR|0555;
- d->length = 0;
- d->qid.path = PATH(mb->id, Qmbox);
- d->qid.type = QTDIR;
- d->qid.vers = mb->vers;
- break;
- case Qdir:
- d->name = m->name;
- d->mode = DMDIR|0555;
- d->length = 0;
- d->qid.path = PATH(m->id, Qdir);
- d->qid.type = QTDIR;
- break;
- case Qctl:
- d->name = dirtab[t];
- d->mode = 0666;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(0, Qctl);
- break;
- case Qmboxctl:
- d->name = dirtab[t];
- d->mode = 0222;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(mb->id, Qmboxctl);
- break;
- case Qinfo:
- d->name = dirtab[t];
- d->length = readinfo(m, nil, 0, 1<<30);
- d->qid.path = PATH(m->id, t);
- break;
- default:
- d->name = dirtab[t];
- d->length = fileinfo(m, t, &p);
- d->qid.path = PATH(m->id, t);
- break;
- }
- }
- char*
- rversion(Fid*)
- {
- Fid *f;
- if(thdr.msize < 256)
- return "max messagesize too small";
- if(thdr.msize < messagesize)
- messagesize = thdr.msize;
- rhdr.msize = messagesize;
- if(strncmp(thdr.version, "9P2000", 6) != 0)
- return "unknown 9P version";
- else
- rhdr.version = "9P2000";
- for(f = fids; f; f = f->next)
- if(f->busy)
- rclunk(f);
- return nil;
- }
- char*
- rauth(Fid*)
- {
- return Enoauth;
- }
- char*
- rflush(Fid *f)
- {
- USED(f);
- return 0;
- }
- char*
- rattach(Fid *f)
- {
- f->busy = 1;
- f->m = nil;
- f->mb = nil;
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- rhdr.qid = f->qid;
- if(strcmp(thdr.uname, user) != 0)
- return Eperm;
- return 0;
- }
- static Fid*
- doclone(Fid *f, int nfid)
- {
- Fid *nf;
- nf = newfid(nfid);
- if(nf->busy)
- return nil;
- nf->busy = 1;
- nf->open = 0;
- nf->m = f->m;
- nf->mtop = f->mtop;
- nf->mb = f->mb;
- if(f->mb != nil)
- mboxincref(f->mb);
- if(f->mtop != nil){
- qlock(f->mb);
- msgincref(f->mtop);
- qunlock(f->mb);
- }
- nf->qid = f->qid;
- return nf;
- }
- char*
- dowalk(Fid *f, char *name)
- {
- int t;
- Mailbox *omb, *mb;
- char *rv, *p;
- Hash *h;
- t = FILE(f->qid.path);
- rv = Enotexist;
- omb = f->mb;
- if(omb)
- qlock(omb);
- else
- qlock(&mbllock);
- // this must catch everything except . and ..
- retry:
- h = hlook(f->qid.path, name);
- if(h != nil){
- f->mb = h->mb;
- f->m = h->m;
- switch(t){
- case Qtop:
- if(f->mb != nil)
- mboxincref(f->mb);
- break;
- case Qmbox:
- if(f->m){
- msgincref(f->m);
- f->mtop = f->m;
- }
- break;
- }
- f->qid = h->qid;
- rv = nil;
- } else if((p = strchr(name, '.')) != nil && *name != '.'){
- *p = 0;
- goto retry;
- }
- if(omb)
- qunlock(omb);
- else
- qunlock(&mbllock);
- if(rv == nil)
- return rv;
- if(strcmp(name, ".") == 0)
- return nil;
- if(f->qid.type != QTDIR)
- return Enotdir;
- if(strcmp(name, "..") == 0){
- switch(t){
- case Qtop:
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- break;
- case Qmbox:
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- qlock(&mbllock);
- mb = f->mb;
- f->mb = nil;
- mboxdecref(mb);
- qunlock(&mbllock);
- break;
- case Qdir:
- qlock(f->mb);
- if(f->m->whole == f->mb->root){
- f->qid.path = PATH(f->mb->id, Qmbox);
- f->qid.type = QTDIR;
- f->qid.vers = f->mb->d->qid.vers;
- msgdecref(f->mb, f->mtop);
- f->m = f->mtop = nil;
- } else {
- f->m = f->m->whole;
- f->qid.path = PATH(f->m->id, Qdir);
- f->qid.type = QTDIR;
- }
- qunlock(f->mb);
- break;
- }
- rv = nil;
- }
- return rv;
- }
- char*
- rwalk(Fid *f)
- {
- Fid *nf;
- char *rv;
- int i;
- if(f->open)
- return Eisopen;
- rhdr.nwqid = 0;
- nf = nil;
- /* clone if requested */
- if(thdr.newfid != thdr.fid){
- nf = doclone(f, thdr.newfid);
- if(nf == nil)
- return "new fid in use";
- f = nf;
- }
- /* if it's just a clone, return */
- if(thdr.nwname == 0 && nf != nil)
- return nil;
- /* walk each element */
- rv = nil;
- for(i = 0; i < thdr.nwname; i++){
- rv = dowalk(f, thdr.wname[i]);
- if(rv != nil){
- if(nf != nil)
- rclunk(nf);
- break;
- }
- rhdr.wqid[i] = f->qid;
- }
- rhdr.nwqid = i;
- /* we only error out if no walk */
- if(i > 0)
- rv = nil;
- return rv;
- }
- char *
- ropen(Fid *f)
- {
- int file;
- if(f->open)
- return Eisopen;
- file = FILE(f->qid.path);
- if(thdr.mode != OREAD)
- if(file != Qctl && file != Qmboxctl)
- return Eperm;
- // make sure we've decoded
- if(file == Qbody){
- if(f->m->decoded == 0)
- decode(f->m);
- if(f->m->converted == 0)
- convert(f->m);
- }
- rhdr.iounit = 0;
- rhdr.qid = f->qid;
- f->open = 1;
- return 0;
- }
- char *
- rcreate(Fid*)
- {
- return Eperm;
- }
- int
- readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
- {
- Dir d;
- int m, n;
- long pos;
- Mailbox *mb;
- n = 0;
- pos = 0;
- mkstat(&d, nil, nil, Qctl);
- m = convD2M(&d, &buf[n], blen);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- return 0;
- n += m;
- cnt -= m;
- }
- pos += m;
-
- for(mb = mbl; mb != nil; mb = mb->next){
- mkstat(&d, mb, nil, Qmbox);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- return n;
- }
- int
- readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
- {
- Dir d;
- int n, m;
- long pos;
- Message *msg;
- n = 0;
- if(f->mb->ctl){
- mkstat(&d, f->mb, nil, Qmboxctl);
- m = convD2M(&d, &buf[n], blen);
- if(off == 0){
- if(m <= BIT16SZ || m > cnt){
- f->fptr = nil;
- return 0;
- }
- n += m;
- cnt -= m;
- } else
- off -= m;
- }
- // to avoid n**2 reads of the directory, use a saved finger pointer
- if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){
- msg = f->fptr;
- pos = f->foff;
- } else {
- msg = f->mb->root->part;
- pos = 0;
- }
- for(; cnt > 0 && msg != nil; msg = msg->next){
- // act like deleted files aren't there
- if(msg->deleted)
- continue;
- mkstat(&d, f->mb, msg, Qdir);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- // save a finger pointer for next read of the mbox directory
- f->foff = pos;
- f->fptr = msg;
- f->fvers = f->mb->vers;
- return n;
- }
- int
- readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
- {
- Dir d;
- int i, n, m;
- long pos;
- Message *msg;
- n = 0;
- pos = 0;
- for(i = 0; i < Qmax; i++){
- mkstat(&d, f->mb, f->m, i);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- return n;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- for(msg = f->m->part; msg != nil; msg = msg->next){
- mkstat(&d, f->mb, msg, Qdir);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- return n;
- }
- char*
- rread(Fid *f)
- {
- long off;
- int t, i, n, cnt;
- char *p;
- rhdr.count = 0;
- off = thdr.offset;
- cnt = thdr.count;
- if(cnt > messagesize - IOHDRSZ)
- cnt = messagesize - IOHDRSZ;
- rhdr.data = (char*)mbuf;
- t = FILE(f->qid.path);
- if(f->qid.type & QTDIR){
- if(t == Qtop) {
- qlock(&mbllock);
- n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
- qunlock(&mbllock);
- } else if(t == Qmbox) {
- qlock(f->mb);
- if(off == 0)
- syncmbox(f->mb, 1);
- n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
- qunlock(f->mb);
- } else if(t == Qmboxctl) {
- n = 0;
- } else {
- n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
- }
- rhdr.count = n;
- return nil;
- }
- if(FILE(f->qid.path) == Qheader){
- rhdr.count = readheader(f->m, (char*)mbuf, off, cnt);
- return nil;
- }
- if(FILE(f->qid.path) == Qinfo){
- rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt);
- return nil;
- }
- i = fileinfo(f->m, FILE(f->qid.path), &p);
- if(off < i){
- if((off + cnt) > i)
- cnt = i - off;
- memmove(mbuf, p + off, cnt);
- rhdr.count = cnt;
- }
- return nil;
- }
- char*
- rwrite(Fid *f)
- {
- char *err;
- char *token[1024];
- int t, n;
- String *file;
- t = FILE(f->qid.path);
- rhdr.count = thdr.count;
- switch(t){
- case Qctl:
- if(thdr.count == 0)
- return Ebadctl;
- if(thdr.data[thdr.count-1] == '\n')
- thdr.data[thdr.count-1] = 0;
- else
- thdr.data[thdr.count] = 0;
- n = tokenize(thdr.data, token, nelem(token));
- if(n == 0)
- return Ebadctl;
- if(strcmp(token[0], "open") == 0){
- file = s_new();
- switch(n){
- case 1:
- err = Ebadctl;
- break;
- case 2:
- mboxpath(token[1], getlog(), file, 0);
- err = newmbox(s_to_c(file), nil, 0);
- break;
- default:
- mboxpath(token[1], getlog(), file, 0);
- if(strchr(token[2], '/') != nil)
- err = "/ not allowed in mailbox name";
- else
- err = newmbox(s_to_c(file), token[2], 0);
- break;
- }
- s_free(file);
- return err;
- }
- if(strcmp(token[0], "close") == 0){
- if(n < 2)
- return nil;
- freembox(token[1]);
- return nil;
- }
- if(strcmp(token[0], "delete") == 0){
- if(n < 3)
- return nil;
- delmessages(n-1, &token[1]);
- return nil;
- }
- return Ebadctl;
- case Qmboxctl:
- if(f->mb && f->mb->ctl){
- if(thdr.count == 0)
- return Ebadctl;
- if(thdr.data[thdr.count-1] == '\n')
- thdr.data[thdr.count-1] = 0;
- else
- thdr.data[thdr.count] = 0;
- n = tokenize(thdr.data, token, nelem(token));
- if(n == 0)
- return Ebadctl;
- return (*f->mb->ctl)(f->mb, n, token);
- }
- }
- return Eperm;
- }
- char *
- rclunk(Fid *f)
- {
- Mailbox *mb;
- f->busy = 0;
- f->open = 0;
- if(f->mtop != nil){
- qlock(f->mb);
- msgdecref(f->mb, f->mtop);
- qunlock(f->mb);
- }
- f->m = f->mtop = nil;
- mb = f->mb;
- if(mb != nil){
- f->mb = nil;
- assert(mb->refs > 0);
- qlock(&mbllock);
- mboxdecref(mb);
- qunlock(&mbllock);
- }
- f->fid = -1;
- return 0;
- }
- char *
- rremove(Fid *f)
- {
- if(f->m != nil){
- if(f->m->deleted == 0)
- mailplumb(f->mb, f->m, 1);
- f->m->deleted = 1;
- }
- return rclunk(f);
- }
- char *
- rstat(Fid *f)
- {
- Dir d;
- if(FILE(f->qid.path) == Qmbox){
- qlock(f->mb);
- syncmbox(f->mb, 1);
- qunlock(f->mb);
- }
- mkstat(&d, f->mb, f->m, FILE(f->qid.path));
- rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
- rhdr.stat = mbuf;
- return 0;
- }
- char *
- rwstat(Fid*)
- {
- return Eperm;
- }
- Fid *
- newfid(int fid)
- {
- Fid *f, *ff;
- ff = 0;
- for(f = fids; f; f = f->next)
- if(f->fid == fid)
- return f;
- else if(!ff && !f->busy)
- ff = f;
- if(ff){
- ff->fid = fid;
- ff->fptr = nil;
- return ff;
- }
- f = emalloc(sizeof *f);
- f->fid = fid;
- f->fptr = nil;
- f->next = fids;
- fids = f;
- return f;
- }
- int
- fidmboxrefs(Mailbox *mb)
- {
- Fid *f;
- int refs = 0;
- for(f = fids; f; f = f->next){
- if(f->mb == mb)
- refs++;
- }
- return refs;
- }
- void
- io(void)
- {
- char *err;
- int n;
- /* start a process to watch the mailboxes*/
- if(plumbing){
- switch(rfork(RFPROC|RFMEM)){
- case -1:
- /* oh well */
- break;
- case 0:
- reader();
- exits(nil);
- default:
- break;
- }
- }
- for(;;){
- /*
- * reading from a pipe or a network device
- * will give an error after a few eof reads
- * however, we cannot tell the difference
- * between a zero-length read and an interrupt
- * on the processes writing to us,
- * so we wait for the error
- */
- checkmboxrefs();
- n = read9pmsg(mfd[0], mdata, messagesize);
- if(n == 0)
- continue;
- if(n < 0)
- return;
- if(convM2S(mdata, n, &thdr) == 0)
- continue;
- if(debug)
- fprint(2, "%s:<-%F\n", argv0, &thdr);
- rhdr.data = (char*)mdata + messagesize;
- if(!fcalls[thdr.type])
- err = "bad fcall type";
- else
- err = (*fcalls[thdr.type])(newfid(thdr.fid));
- if(err){
- rhdr.type = Rerror;
- rhdr.ename = err;
- }else{
- rhdr.type = thdr.type + 1;
- rhdr.fid = thdr.fid;
- }
- rhdr.tag = thdr.tag;
- if(debug)
- fprint(2, "%s:->%F\n", argv0, &rhdr);/**/
- n = convS2M(&rhdr, mdata, messagesize);
- if(write(mfd[1], mdata, n) != n)
- error("mount write");
- }
- }
- void
- reader(void)
- {
- ulong t;
- Dir *d;
- Mailbox *mb;
- sleep(15*1000);
- for(;;){
- t = time(0);
- qlock(&mbllock);
- for(mb = mbl; mb != nil; mb = mb->next){
- assert(mb->refs > 0);
- if(mb->waketime != 0 && t > mb->waketime){
- qlock(mb);
- mb->waketime = 0;
- break;
- }
- d = dirstat(mb->path);
- if(d == nil)
- continue;
- qlock(mb);
- if(mb->d)
- if(d->qid.path != mb->d->qid.path
- || d->qid.vers != mb->d->qid.vers){
- free(d);
- break;
- }
- qunlock(mb);
- free(d);
- }
- qunlock(&mbllock);
- if(mb != nil){
- syncmbox(mb, 1);
- qunlock(mb);
- } else
- sleep(15*1000);
- }
- }
- int
- newid(void)
- {
- int rv;
- static int id;
- static Lock idlock;
- lock(&idlock);
- rv = ++id;
- unlock(&idlock);
- return rv;
- }
- void
- error(char *s)
- {
- postnote(PNGROUP, getpid(), "die yankee pig dog");
- fprint(2, "%s: %s: %r\n", argv0, s);
- exits(s);
- }
- typedef struct Ignorance Ignorance;
- struct Ignorance
- {
- Ignorance *next;
- char *str; /* string */
- int partial; /* true if not exact match */
- };
- Ignorance *ignorance;
- /*
- * read the file of headers to ignore
- */
- void
- readignore(void)
- {
- char *p;
- Ignorance *i;
- Biobuf *b;
- if(ignorance != nil)
- return;
- b = Bopen("/mail/lib/ignore", OREAD);
- if(b == 0)
- return;
- while(p = Brdline(b, '\n')){
- p[Blinelen(b)-1] = 0;
- while(*p && (*p == ' ' || *p == '\t'))
- p++;
- if(*p == '#')
- continue;
- i = malloc(sizeof(Ignorance));
- if(i == 0)
- break;
- i->partial = strlen(p);
- i->str = strdup(p);
- if(i->str == 0){
- free(i);
- break;
- }
- i->next = ignorance;
- ignorance = i;
- }
- Bterm(b);
- }
- int
- ignore(char *p)
- {
- Ignorance *i;
- readignore();
- for(i = ignorance; i != nil; i = i->next)
- if(cistrncmp(i->str, p, i->partial) == 0)
- return 1;
- return 0;
- }
- int
- hdrlen(char *p, char *e)
- {
- char *ep;
- ep = p;
- do {
- ep = strchr(ep, '\n');
- if(ep == nil){
- ep = e;
- break;
- }
- ep++;
- if(ep >= e){
- ep = e;
- break;
- }
- } while(*ep == ' ' || *ep == '\t');
- return ep - p;
- }
- // rfc2047 non-ascii
- typedef struct Charset Charset;
- struct Charset {
- char *name;
- int len;
- int convert;
- char *tcsname;
- } charsets[] =
- {
- { "us-ascii", 8, 1, nil, },
- { "utf-8", 5, 0, nil, },
- { "iso-8859-1", 10, 1, nil, },
- { "iso-8859-2", 10, 2, "8859-2", },
- { "big5", 4, 2, "big5", },
- { "iso-2022-jp", 11, 2, "jis", },
- { "windows-1251", 12, 2, "cp1251"},
- { "koi8-r", 6, 2, "koi8"},
- };
- int
- rfc2047convert(String *s, char *token, int len)
- {
- char decoded[1024];
- char utfbuf[2*1024];
- int i;
- char *e, *x;
- if(len == 0)
- return -1;
- e = token+len-2;
- token += 2;
- // bail if we don't understand the character set
- for(i = 0; i < nelem(charsets); i++)
- if(cistrncmp(charsets[i].name, token, charsets[i].len) == 0)
- if(token[charsets[i].len] == '?'){
- token += charsets[i].len + 1;
- break;
- }
- if(i >= nelem(charsets))
- return -1;
- // bail if it doesn't fit
- if(e-token > sizeof(decoded)-1)
- return -1;
- // bail if we don't understand the encoding
- if(cistrncmp(token, "b?", 2) == 0){
- token += 2;
- len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
- decoded[len] = 0;
- } else if(cistrncmp(token, "q?", 2) == 0){
- token += 2;
- len = decquoted(decoded, token, e, 1);
- if(len > 0 && decoded[len-1] == '\n')
- len--;
- decoded[len] = 0;
- } else
- return -1;
- switch(charsets[i].convert){
- case 0:
- s_append(s, decoded);
- break;
- case 1:
- latin1toutf(utfbuf, decoded, decoded+len);
- s_append(s, utfbuf);
- break;
- case 2:
- if(xtoutf(charsets[i].tcsname, &x, decoded, decoded+len) <= 0){
- s_append(s, decoded);
- } else {
- s_append(s, x);
- free(x);
- }
- break;
- }
- return 0;
- }
- char*
- rfc2047start(char *start, char *end)
- {
- int quests;
- if(*--end != '=')
- return nil;
- if(*--end != '?')
- return nil;
- quests = 0;
- for(end--; end >= start; end--){
- switch(*end){
- case '=':
- if(quests == 3 && *(end+1) == '?')
- return end;
- break;
- case '?':
- ++quests;
- break;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- /* can't have white space in a token */
- return nil;
- }
- }
- return nil;
- }
- // convert a header line
- String*
- stringconvert(String *s, char *uneaten, int len)
- {
- char *token;
- char *p;
- int i;
- s = s_reset(s);
- p = uneaten;
- for(i = 0; i < len; i++){
- if(*p++ == '='){
- token = rfc2047start(uneaten, p);
- if(token != nil){
- s_nappend(s, uneaten, token-uneaten);
- if(rfc2047convert(s, token, p - token) < 0)
- s_nappend(s, token, p - token);
- uneaten = p;
- }
- }
- }
- if(p > uneaten)
- s_nappend(s, uneaten, p-uneaten);
- return s;
- }
- int
- readheader(Message *m, char *buf, int off, int cnt)
- {
- char *p, *e;
- int n, ns;
- char *to = buf;
- String *s;
- p = m->header;
- e = m->hend;
- s = nil;
- // copy in good headers
- while(cnt > 0 && p < e){
- n = hdrlen(p, e);
- if(ignore(p)){
- p += n;
- continue;
- }
- // rfc2047 processing
- s = stringconvert(s, p, n);
- ns = s_len(s);
- if(off > 0){
- if(ns <= off){
- off -= ns;
- p += n;
- continue;
- }
- ns -= off;
- }
- if(ns > cnt)
- ns = cnt;
- memmove(to, s_to_c(s)+off, ns);
- to += ns;
- p += n;
- cnt -= ns;
- off = 0;
- }
- s_free(s);
- return to - buf;
- }
- int
- headerlen(Message *m)
- {
- char buf[1024];
- int i, n;
- if(m->hlen >= 0)
- return m->hlen;
- for(n = 0; ; n += i){
- i = readheader(m, buf, n, sizeof(buf));
- if(i <= 0)
- break;
- }
- m->hlen = n;
- return n;
- }
- QLock hashlock;
- uint
- hash(ulong ppath, char *name)
- {
- uchar *p;
- uint h;
- h = 0;
- for(p = (uchar*)name; *p; p++)
- h = h*7 + *p;
- h += ppath;
- return h % Hsize;
- }
- Hash*
- hlook(ulong ppath, char *name)
- {
- int h;
- Hash *hp;
- qlock(&hashlock);
- h = hash(ppath, name);
- for(hp = htab[h]; hp != nil; hp = hp->next)
- if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
- qunlock(&hashlock);
- return hp;
- }
- qunlock(&hashlock);
- return nil;
- }
- void
- henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
- {
- int h;
- Hash *hp, **l;
- qlock(&hashlock);
- h = hash(ppath, name);
- for(l = &htab[h]; *l != nil; l = &(*l)->next){
- hp = *l;
- if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
- hp->m = m;
- hp->mb = mb;
- hp->qid = qid;
- qunlock(&hashlock);
- return;
- }
- }
- *l = hp = emalloc(sizeof(*hp));
- hp->m = m;
- hp->mb = mb;
- hp->qid = qid;
- hp->name = name;
- hp->ppath = ppath;
- qunlock(&hashlock);
- }
- void
- hfree(ulong ppath, char *name)
- {
- int h;
- Hash *hp, **l;
- qlock(&hashlock);
- h = hash(ppath, name);
- for(l = &htab[h]; *l != nil; l = &(*l)->next){
- hp = *l;
- if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
- hp->mb = nil;
- *l = hp->next;
- free(hp);
- break;
- }
- }
- qunlock(&hashlock);
- }
- int
- hashmboxrefs(Mailbox *mb)
- {
- int h;
- Hash *hp;
- int refs = 0;
- qlock(&hashlock);
- for(h = 0; h < Hsize; h++){
- for(hp = htab[h]; hp != nil; hp = hp->next)
- if(hp->mb == mb)
- refs++;
- }
- qunlock(&hashlock);
- return refs;
- }
- void
- checkmboxrefs(void)
- {
- int f, refs;
- Mailbox *mb;
- qlock(&mbllock);
- for(mb=mbl; mb; mb=mb->next){
- qlock(mb);
- refs = (f=fidmboxrefs(mb))+1;
- if(refs != mb->refs){
- fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);
- abort();
- }
- qunlock(mb);
- }
- qunlock(&mbllock);
- }
- void
- post(char *name, char *envname, int srvfd)
- {
- int fd;
- char buf[32];
- fd = create(name, OWRITE, 0600);
- if(fd < 0)
- error("post failed");
- sprint(buf, "%d",srvfd);
- if(write(fd, buf, strlen(buf)) != strlen(buf))
- error("srv write");
- close(fd);
- putenv(envname, name);
- }
|