ref: bb10512127f96aeb40f9f1e8f32768032c6425fe
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 *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; 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); }