shithub: vcardfs

ref: a5b091764d98d99ac86694bb11e4f674fd681506
dir: /vcardfs.c/

View raw version
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "libvcard/vcard.h"

/* rough structure

/john-doe/
	export (export single contact as vcard file)
	/fn/
		/data (line value)
		/group (line group)
		/params/
			p1 (param value)
			...
	/tel/
		/data (line value)
		/group (line group)
		/params/
			...
/ctl
	- "write" (save file)
/import
	- write new vcf file to import

*/

void
usage(void)
{
	fprint(2, "usage: %s [-s srv] [-m mtpt] [file]\n", argv0);
	exits("usage");
}

static void*
emalloc(long n)
{
	void *p;
	p = mallocz(n, 1);
	if (!p)
		sysfatal("emalloc: %r");
	return p;
}

static char*
estrdup(char *s)
{
	void *t;
	t = strdup(s);
	if (!t)
		sysfatal("estrdup: %r");
	return t;
}

enum {
	Qroot,
		Qctl,
		Qimport,
		Qcard,
			Qexport,
			Qline,
				Qdata,
				Qgroup,
				Qparams,
					Qparamdata,
};

typedef struct Vfile Vfile;
struct Vfile {
	int level;
	Vcard *card;
	Vline *line;
	Vparam *param;
	char *serialized;
};

char *user = nil;
char *mtpt = "/mnt/vcf";
char *service = nil;

char *file = nil;
Vcard *cards = nil;

static Vfile*
emkvfile(int level, Vcard *c, Vline *l, Vparam *p)
{
	Vfile *f;
	f = mallocz(sizeof(Vfile), 1);
	if (!f)
		sysfatal("%r");
	f->level = level;
	f->card = c;
	f->line = l;
	f->param = p;
	return f;
}

static void
readserialized(Req *r, Vfile *f)
{
	int n;
	char *s;
	Vcard *tmp;
	
	if (f->serialized)
		goto Readin;
	
	tmp = f->card->next;
	f->card->next = nil;
	f->serialized = vcmserialize(f->card);
	f->card->next = tmp;
	
	if (!f->serialized) {
		respond(r, "unable to serialize");
		return;
	}

Readin:
	s = f->serialized + r->ifcall.offset;
	n = strlen(s);
	n = n < r->ifcall.count ? n : r->ifcall.count;
	readbuf(r, s, n);
	respond(r, nil);
}

static void
fsread(Req *r)
{
	Vfile *f;
	f = r->fid->file->aux;
	switch (f->level) {
	case Qctl:
		respond(r, nil);
		return;
	case Qimport:
		respond(r, nil);
		return;
	case Qexport:
		readserialized(r, f);
		return;
	case Qdata:
		readstr(r, f->line->value);
		respond(r, nil);
		return;
	case Qgroup:
		if (!f->line->group) {
			respond(r, "file not found");
			return;
		}
		readstr(r, f->line->group);
		respond(r, nil);
		return;
	case Qparamdata:
		readstr(r, f->param->value);
		respond(r, nil);
		return;
	}
	respond(r, "not implemented");
}

static void
fswrite(Req *r)
{
	Vfile *f;
	f = r->fid->file->aux;
	switch (f->level) {
	case Qctl:
		break;
	}
	respond(r, "not implemented");
}

Srv fs = {
	.read = fsread,
	.write = fswrite,
};

/* TODO: LOOKAT:
	/sys/src/cmd/webcookies.c:/createfile
	/sys/src/cmd/aux/gps/gpsfs.c:/createfile
*/
static char*
safename(char *n)
{
	char *s;
	
	s = estrdup(n);
	n = s;
	while (*n) {
		switch (*n) {
		case ' ':
			*n = '_';
			break;
		case '\t':
			*n = '_';
			break;
		}
		n++;
	}
	return s;
}

static char*
getcardname(Vcard *c)
{
	Vline *l;
	Vline *fn = nil, *n = nil;
	
	for (l = c->content; l; l = l->next) {
		if (cistrcmp(l->name, "fn") == 0)
			fn = l;
		else if (cistrcmp(l->name, "n") == 0)
			n = l;
		if (fn && n)
			break;
	}
	
	if (fn)
		return safename(fn->value);
	if (n)
		return safename(n->value);
	return nil;
}

static void
initcardfiles(Vcard *chain)
{
	File *fc, *fl, *fp, *f;
	Vcard *c;
	Vline *l;
	Vparam *p;
	Vfile *vf;
	char *s;
	
	for (c = chain; c; c = c->next) {
		s = getcardname(c);
		if (!s)
			continue;
		vf = emkvfile(Qcard, c, nil, nil);
		fc = createfile(fs.tree->root, s, user, DMDIR|0555, vf);
		free(s);
		if (!fc)
			sysfatal("%r");
		vf = emkvfile(Qexport, c, nil, nil);
		f = createfile(fc, "export", user, 0444, vf);
		
		for (l = c->content; l; l = l->next) {
			vf = emkvfile(Qline, c, l, nil);
			fl = createfile(fc, l->name, user, DMDIR|0555, vf);
			vf = emkvfile(Qdata, c, l, nil);
			f = createfile(fl, "data", user, 0666, vf);
			if (l->group) {
				vf = emkvfile(Qgroup, c, l, nil);
				f = createfile(fl, "group", user, 0666, vf);
			}
			vf = emkvfile(Qparams, c, l, nil);
			f = createfile(fl, "params", user, DMDIR|0555, vf);
			
			for (p = l->params; p; p = p->next) {
				vf = emkvfile(Qparamdata, c, l, p);
				fp = createfile(f, p->name, user, 0666, vf);
			}
		}
	}
}

void
main(int argc, char **argv)
{
	ARGBEGIN{
	case 'D':
		chatty9p++;
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	case 's':
		service = EARGF(usage());
		break;
	default:
		usage();
		break;
	}ARGEND;
	
	rfork(RFNOTEG);
	
	user = getuser();
	
	if (argc == 1)
		file = argv[0];
	else {
		file = smprint("/usr/%s/lib/vcarddb.vcf", user);
		if (!file)
			sysfatal("%r");
	}
	
	cards = vcparsefile(file);
	
	if (!cards)
		sysfatal("%r");
	
	fs.tree = alloctree("vcf", "vcf", DMDIR|0555, nil);
	createfile(fs.tree->root, "ctl", user, 0666,
		emkvfile(Qctl, nil, nil, nil));
	createfile(fs.tree->root, "import", user, 0666,
		emkvfile(Qimport, nil, nil, nil));
	initcardfiles(cards);
	
	postmountsrv(&fs, service, mtpt, MREPL);
	exits(nil);
}