ref: a5b091764d98d99ac86694bb11e4f674fd681506
dir: /vcardfs.c/
#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);
}