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