ref: b314c7b701080d882249e0f793708f216564e79d
dir: /main.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> enum { Qroot, Qnickname, Qspeak, Qcurrentchan, Qchannels, Qmax, }; typedef struct NeinFile NeinFile; typedef struct NeinAux NeinAux; struct NeinFile { char *name; Qid qid; ulong mode; }; struct NeinAux { char *nickname; int currentChan; }; void fsattach(Req*); void fsstat(Req*); void fsread(Req*); void fswrite(Req*); char *fsclone(Fid*, Fid*); char *fswalk1(Fid*, char*, Qid*); int rootgen(int, Dir*, void*); int channelsgen(int, Dir*, void*); NeinFile *findfile(uvlong); int findchannel(char*); void fillstat(Dir*, NeinFile); void readchanlog(Req*, uvlong); NeinFile qroot[] = { "nickname", {Qnickname, 0, QTFILE}, 0666, "speak", {Qspeak, 0, QTFILE}, 0222, "currentchan", {Qcurrentchan, 0, QTFILE}, 0666, "channels", {Qchannels, 0, QTDIR}, 0555 | DMDIR, }; int nchannels; NeinFile *channels; NeinFile root = {"/", {Qroot, 0, QTDIR}, 555 | DMDIR}; void main(void) { Srv fs = { .attach = fsattach, .walk1 = fswalk1, .clone = fsclone, .stat = fsstat, .read = fsread, .write = fswrite, }; char *postname = "neinchat"; char *addr = "tcp!*!12345"; nchannels = 0; channels = nil; print("Starting neinchat server on %s and posting to /srv/%s\n", addr, postname); listensrv(&fs, addr); postmountsrv(&fs, "neinchat", nil, MREPL|MCREATE); exits(nil); } void fsattach(Req *r) { static int nicknamecount; NeinAux *aux; r->fid->qid = root.qid; r->ofcall.qid = r->fid->qid; aux = emalloc9p(sizeof(NeinAux)); aux->nickname = smprint("RandomUser%d", nicknamecount++); aux->currentChan = -1; r->fid->aux = aux; respond(r, nil); } void fsstat(Req *r) { NeinFile *f = findfile(r->fid->qid.path); if(f == nil){ respond(r, "not found"); return; } fillstat(&r->d, *f); respond(r, nil); } void fsread(Req *r) { char *str; NeinAux *aux = r->fid->aux; uvlong path = r->fid->qid.path; if(path >= Qmax && path < (Qmax + nchannels)){ readchanlog(r, path); return; } switch(path){ case Qroot: dirread9p(r, rootgen, nil); respond(r, nil); break; case Qchannels: dirread9p(r, channelsgen, nil); respond(r, nil); break; case Qnickname: str = smprint("%s\n", aux->nickname); readstr(r, str); free(str); respond(r, nil); break; case Qcurrentchan: if(aux->currentChan == -1){ respond(r, "no channel selected"); return; }else{ str = smprint("%s\n", channels[aux->currentChan].name); readstr(r, str); free(str); respond(r, nil); } break; default: respond(r, "wut no"); } } void fswrite(Req *r) { NeinAux *aux = r->fid->aux; char *buf; if(r->ifcall.offset != 0){ respond(r, "Can't write at offset"); return; } switch(r->fid->qid.path){ case Qnickname: if(r->ifcall.count > 64){ respond(r, "nickname too long"); return; } r->ofcall.count = r->ifcall.count; buf = emalloc9p(r->ifcall.count + 1); memcpy(buf, r->ifcall.data, r->ifcall.count); buf[r->ifcall.count] = 0; free(aux->nickname); aux->nickname = buf; respond(r, nil); break; case Qcurrentchan: if(r->ifcall.count > 64){ respond(r, "Channel name too long"); return; } r->ofcall.count = r->ifcall.count; buf = emalloc9p(r->ifcall.count + 1); memcpy(buf, r->ifcall.data, r->ifcall.count); buf[r->ifcall.count] = 0; aux->currentChan = findchannel(buf); respond(r, nil); break; case Qspeak: respond(r, "Speaking not implemented yet ☺"); break; default: respond(r, "write prohibited"); } } char * fsclone(Fid *old, Fid *new) { new->aux = old->aux; return nil; } char * fswalk1(Fid *fid, char *name, Qid *qid) { int i; if(strcmp(name, "..") == 0){ *qid = root.qid; fid->qid = *qid; return nil; } switch(fid->qid.path){ case Qroot: for(i = 0; i < nelem(qroot); i++){ if(strcmp(qroot[i].name, name) == 0){ *qid = qroot[i].qid; fid->qid = *qid; return nil; } } break; case Qchannels: for(i = 0; i < nchannels; i++){ if(strcmp(channels[i].name, name) == 0){ *qid = channels[i].qid; fid->qid = *qid; return nil; } } break; } return "not found"; } int rootgen(int n, Dir *d, void *) { if(n >= nelem(qroot)) return -1; NeinFile f = qroot[n]; fillstat(d, f); return 0; } int channelsgen(int n, Dir *d, void *) { if(n >= nchannels) return -1; NeinFile f = channels[n]; fillstat(d, f); return 0; } NeinFile * findfile(uvlong path) { int i; if(path == Qroot) return &root; for(i = 0; i < nelem(qroot); i++){ if(qroot[i].qid.path == path) return &qroot[i]; } return nil; } int findchannel(char *name) { int i; int path; for(i = 0; i < nchannels; i++){ if(strcmp(channels[i].name, name) == 0) return i; } nchannels++; path = Qmax + i; channels = erealloc9p(channels, sizeof(NeinFile) * nchannels); channels[i] = (NeinFile){name, (Qid){path, 0, QTFILE}, 0444}; return i; } void fillstat(Dir *d, NeinFile f) { char *username = getuser(); d->qid = f.qid; d->mode = f.mode; d->length = 0; d->name = estrdup9p(f.name); d->uid = estrdup9p(username); d->gid = estrdup9p(username); d->muid = estrdup9p(username); d->atime = time(0); d->mtime = time(0); } void readchanlog(Req *r, uvlong path) { USED(path); readstr(r, "Nothing to see here yet\n"); respond(r, nil); }