ref: 29ecb5f41a832a68cad00ad9314fabeb30f16ad8
parent: a0054fa2fc711277c267fbd7d6b48bff6e0d4a82
author: sirjofri <sirjofri@sirjofri.de>
date: Thu Nov 7 12:03:34 EST 2024
adds support for duplicate fields using <N>:group.name syntax
--- a/john.vcf
+++ b/john.vcf
@@ -1,6 +1,7 @@
BEGIN:VCARD
VERSION:4.0
N;TYPE=ABC;value="A;B;C":Doe;John;;
+N;TYPE=Another:Do;Jon;;
FN:John
Doe
END:VCARD
--- a/vcardfs.c
+++ b/vcardfs.c
@@ -84,6 +84,14 @@
[Qparamdata] "paramdata",
};
+typedef struct Vlinenumber Vlinenumber;
+struct Vlinenumber
+{
+ char *name;
+ int value;
+ Vlinenumber *next;
+};
+
typedef struct Vfile Vfile;
struct Vfile {
int level;
@@ -93,8 +101,55 @@
Vfile *cardfile;
File *file;
char *serialized;
+ Vlinenumber *linenumbers;
};
+static Vlinenumber*
+findlinenumber(Vfile *f, char *line)
+{
+ Vlinenumber *l, *last;
+
+ if (!f->linenumbers) {
+ f->linenumbers = emalloc(sizeof(Vlinenumber));
+ last = f->linenumbers;
+ goto Out;
+ }
+
+ last = nil;
+ for (l = f->linenumbers; l; l = l->next) {
+ if (cistrcmp(l->name, line) == 0)
+ return l;
+ last = l;
+ }
+
+ if (!last)
+ return nil;
+ last->next = emalloc(sizeof(Vlinenumber));
+ last = last->next;
+ Out:
+ last->name = estrdup(line);
+ last->value = 0;
+ return last;
+}
+
+static int
+getcurrentlinenumber(Vfile *f, char *line)
+{
+ Vlinenumber *l;
+ l = findlinenumber(f, line);
+ return l ? l->value : -1;
+}
+
+static void
+inclinenumber(Vfile *f, char *line)
+{
+ Vlinenumber *l;
+ l = findlinenumber(f, line);
+ if (!l)
+ return;
+ l->value++;
+}
+
static char*
vfqn(Vfile *f)
{
@@ -121,6 +176,20 @@
static char* getcardname(Vcard*);
static void initcardfiles(Vcard *chain);
+static char*
+ecreatelinename(Vfile *cf, Vline *l)
+{
+ char *s;
+ s = smprint("%d:%s%s%s",
+ getcurrentlinenumber(cf, l->name),
+ l->group ? l->group : "",
+ l->group ? "." : "",
+ l->name);
+ if (!s)
+ sysfatal("createlinename: %r");
+ return s;
+}
+
static Vfile*
emkvfile(int level, Vcard *c, Vline *l, Vparam *p, Vfile *cfile)
{
@@ -506,6 +575,7 @@
{
File *dirf, *paramf, *dataf;
Vline *l, *nl;
+ char *s;
if (!vf->card) {
respond(r, "invalid card file");
@@ -512,14 +582,21 @@
return nil;
}
- dirf = createfile(r->fid->file, r->ifcall.name, user, DMDIR|0777, nil);
+ nl = mallocz(sizeof(Vline), 1);
+ nl->name = estrdup(r->ifcall.name);
+ nl->value = estrdup("");
+
+ s = ecreatelinename(vf, nl);
+
+ dirf = createfile(r->fid->file, s, user, DMDIR|0777, nil);
+ free(s);
if (!dirf) {
responderror(r);
+ free(nl->name);
+ free(nl->value);
+ free(nl);
return nil;
}
- nl = mallocz(sizeof(Vline), 1);
- nl->name = estrdup(r->ifcall.name);
- nl->value = estrdup("");
if (!vf->card->content) {
vf->card->content = nl;
@@ -958,14 +1035,11 @@
for (l = c->content; l; l = l->next) {
vf = emkvfile(Qline, c, l, nil, cf);
- if (l->group && *l->group) {
- s = smprint("%s.%s", l->group, l->name);
- }
- fl = createfile(fc, (l->group && *l->group ? s : l->name), user, DMDIR|0777, vf);
- if (l->group) {
- free(s);
- s = nil;
- }
+ s = ecreatelinename(cf, l);
+ inclinenumber(cf, l->name);
+ fl = createfile(fc, s, user, DMDIR|0777, vf);
+ free(s);
+ s = nil;
vf = emkvfile(Qdata, c, l, nil, cf);
f = createfile(fl, "data", user, 0666, vf);
closefile(f);