shithub: neinchat

ref: 62f992b9b69dc0d2d4c95364def709eb5ad15ac7
dir: /main.c/

View raw version
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>

enum {
	Qroot,
		Qnickname,
		Qchannels,
};

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);
void	fillstat(Dir*, Neinfile);

char *username;

Neinfile qroot[] = {
	"nickname", {Qnickname, 0, QTFILE}, 0666,
	"channels", {Qchannels, 0, QTDIR}, 0555 | DMDIR,
};

Neinfile root = {"/", {Qroot, 0, QTDIR}, 555 | DMDIR};

void
main(void)
{
	Srv fs = {
		.attach = fsattach,
		.walk1 = fswalk1,
		.clone = fsclone,
		.stat = fsstat,
		.read = fsread,
		.write = fswrite,
	};

	chatty9p = 1;
	char *mountpoint = "/mnt/neinchat";
	username = getuser();
	print("Starting neinchat server on %s\n", mountpoint);
	postmountsrv(&fs, "neinchat", mountpoint, 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;

	switch(r->fid->qid.path){
	case Qroot:
		dirread9p(r, rootgen, nil);
		respond(r, nil);
		break;
	case Qchannels:
		dirread9p(r, channelsgen, nil);
		respond(r, nil);
		break;
	case Qnickname:
		aux = r->fid->aux;
		str = smprint("%s\n", aux->nickname);
		readstr(r, str);
		free(str);
		respond(r, nil);
		break;
	default:
		respond(r, "wut no");
	}
}

void
fswrite(Req *r)
{
	NeinAux *aux = r->fid->aux;

	if(r->fid->qid.path == Qnickname){
		if(r->ifcall.count > 64){
			respond(r, "nickname too long (max is 64 chars)");
			return;
		}
		if(r->ifcall.offset != 0){
			respond(r, "Can't write at offset");
			return;
		}

		char *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;
		r->ofcall.count = r->ifcall.count;
		respond(r, nil);
		return;
	}
	
	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;
			}
		}
		if(strcmp("..", name) == 0){
			*qid = root.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 *)
{
	USED(n);
	USED(d);
	return -1;
}

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

void
fillstat(Dir *d, Neinfile f)
{
	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);
}