ref: 0f18bf0aaf945b20b24f3ec8f3ae37f42c9e08b7
dir: /vcffs.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include "libvcard/vcard.h"
/* rough structure
/john-doe/
/fn/
/data (line value)
/group (line group)
/param (param value)
/tel/
/data (line value)
/group (line group)
/param (param value)
/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,
Qline,
Qdata,
Qgroup,
Qparams,
Qparamdata,
};
typedef struct Vfile Vfile;
struct Vfile {
int level;
Vcard *card;
Vline *line;
Vparam *param;
};
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
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 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;
// TODO: fill with Vfile structure, which points to card data
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");
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);
// closefile(f);
if (l->group) {
vf = emkvfile(Qgroup, c, l, nil);
f = createfile(fl, "group", user, 0666, vf);
// closefile(f);
}
vf = emkvfile(Qparams, c, l, nil);
f = createfile(fl, "params", user, DMDIR|0555, vf);
// closefile(f);
for (p = l->params; p; p = p->next) {
vf = emkvfile(Qparamdata, c, l, p);
fp = createfile(f, p->name, user, 0666, vf);
// closefile(fp);
}
// closefile(fl);
}
// closefile(fc);
}
}
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);
if (argc != 1)
usage();
file = argv[0];
cards = vcparsefile(file);
if (!cards)
sysfatal("%r");
user = getuser();
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);
}