12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679 |
- #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(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", },
- };
- 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);
- 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);
- }
|