Skip to content

Commit

Permalink
Merge pull request #4697 from cyrusimap/carddav_db_value_fix
Browse files Browse the repository at this point in the history
carddav_db.c: actually store N and NICKNAME values
  • Loading branch information
ksmurchison authored Oct 23, 2023
2 parents d093790 + d5ccab4 commit 0552750
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 26 deletions.
72 changes: 72 additions & 0 deletions cassandane/Cassandane/Cyrus/Carddav.pm
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,78 @@ EOF
$self->assert_not_null($res->{"{DAV:}response"});
}

sub test_filter
:needs_component_httpd
{
my ($self) = @_;

my $CardDAV = $self->{carddav};

my $xml = <<EOF;
<C:addressbook-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:prop>
<D:getetag/>
<C:address-data content-type="text/vcard" version="3.0"/>
</D:prop>
<C:filter>
<C:prop-filter name="NICKNAME">
<C:text-match collation="i;unicode-casemap" match-type="equals"
>eric</C:text-match>
</C:prop-filter>
</C:filter>
</C:addressbook-query>
EOF

my $homeset = "/dav/addressbooks/user/cassandane";
my $bookId = "Default";

my $uid1 = "3b678b69-ca41-461e-b2c7-f96b9fe48d68";
my $uid2 = "addr1\@example.com";
my $uid3 = "addr2\@example.com";

my $vcard1 = Net::CardDAVTalk::VCard->new_fromstring(<<EOF);
BEGIN:VCARD
VERSION:3.0
UID:$uid1
N:Gump;Forrest;;Mr.
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
REV:2008-04-24T19:52:43Z
END:VCARD
EOF

my $vcard2 = Net::CardDAVTalk::VCard->new_fromstring(<<EOF);
BEGIN:VCARD
VERSION:4.0
NICKNAME:me
UID:$uid2
FN:Cyrus Daboo
EMAIL:cdaboo\@example.com
END:VCARD
EOF

my $vcard3 = Net::CardDAVTalk::VCard->new_fromstring(<<EOF);
BEGIN:VCARD
VERSION:4.0
NICKNAME:eric
UID:$uid3
FN:Eric York
END:VCARD
EOF

my $href1 = $CardDAV->NewContact($bookId, $vcard1);
my $href2 = $CardDAV->NewContact($bookId, $vcard2);
my $href3 = $CardDAV->NewContact($bookId, $vcard3);

my $res = $CardDAV->Request('REPORT', "$homeset/$bookId",
$xml, Depth => 0, 'Content-Type' => 'text/xml');

$self->assert_str_equals("$homeset/$href3",
$res->{"{DAV:}response"}[0]{"{DAV:}href"}{content});
}

sub test_multiget
:needs_component_httpd :min_version_3_7
{
Expand Down
19 changes: 16 additions & 3 deletions imap/carddav_db.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,27 +1111,36 @@ EXPORTED int carddav_writecard(struct carddav_db *carddavdb,
{
struct vparse_entry *ventry;

strarray_t values = STRARRAY_INITIALIZER;
strarray_t emails = STRARRAY_INITIALIZER;
strarray_t member_uids = STRARRAY_INITIALIZER;

for (ventry = vcard->properties; ventry; ventry = ventry->next) {
const char *name = ventry->name;
const char *propval = ventry->v.value;

if (!name) continue;

char *propval = vparse_get_value(ventry);
if (!propval) continue;

if (!strcasecmp(name, "uid")) {
cdata->vcard_uid = propval;
strarray_appendm(&values, propval);
propval = NULL;
}
else if (!strcasecmp(name, "n")) {
cdata->name = propval;
strarray_appendm(&values, propval);
propval = NULL;
}
else if (!strcasecmp(name, "fn")) {
cdata->fullname = propval;
strarray_appendm(&values, propval);
propval = NULL;
}
else if (!strcasecmp(name, "nickname")) {
cdata->nickname = propval;
strarray_appendm(&values, propval);
propval = NULL;
}
else if (!strcasecmp(name, "email")) {
/* XXX - insert if primary */
Expand All @@ -1142,8 +1151,9 @@ EXPORTED int carddav_writecard(struct carddav_db *carddavdb,
!strcasecmp(param->value, "pref"))
ispref = 1;
}
strarray_append(&emails, propval);
strarray_appendm(&emails, propval);
strarray_append(&emails, ispref ? "1" : "");
propval = NULL;
}
else if (!strcasecmp(name, "member") ||
!strcasecmp(name, "x-addressbookserver-member")) {
Expand All @@ -1167,12 +1177,15 @@ EXPORTED int carddav_writecard(struct carddav_db *carddavdb,
else if (!strcasecmp(name, "version")) {
cdata->version = propval[0] - '0';
}

free(propval);
}

int r = carddav_write(carddavdb, cdata);
if (!r) r = carddav_write_emails(carddavdb, cdata->dav.rowid, &emails, ispinned);
if (!r) r = carddav_write_groups(carddavdb, cdata->dav.rowid, &member_uids);

strarray_fini(&values);
strarray_fini(&emails);
strarray_fini(&member_uids);

Expand Down
74 changes: 51 additions & 23 deletions lib/vparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,34 @@ static const struct prop_encode {
{ NULL, 1 }
};

static void _entry_value_to_tgt(const struct vparse_entry *entry,
struct vparse_target *tgt, int is_uri)
{
if (entry->multivaluesep) {
int i;
for (i = 0; i < entry->v.values->count; i++) {
if (i) buf_putc(tgt->buf, entry->multivaluesep);
_value_to_tgt(strarray_nth(entry->v.values, i), tgt, 1);
}
}
else if (is_uri == 1) {
_value_to_tgt(entry->v.value, tgt, 0);
}
else {
const struct prop_encode *prop;
int encode = 1; /* default to encoding */

for (prop = prop_encode_map; prop->name; prop++) {
if (!strcasecmp(prop->name, entry->name)) {
encode = (prop->encode == -1) ? !is_uri : prop->encode;
break;
}
}

_value_to_tgt(entry->v.value, tgt, encode);
}
}

static void _entry_to_tgt(const struct vparse_entry *entry, struct vparse_target *tgt)
{
struct vparse_param *param;
Expand Down Expand Up @@ -963,29 +991,7 @@ static void _entry_to_tgt(const struct vparse_entry *entry, struct vparse_target

buf_putc(tgt->buf, ':');

if (entry->multivaluesep) {
int i;
for (i = 0; i < entry->v.values->count; i++) {
if (i) buf_putc(tgt->buf, entry->multivaluesep);
_value_to_tgt(strarray_nth(entry->v.values, i), tgt, 1);
}
}
else if (is_uri == 1) {
_value_to_tgt(entry->v.value, tgt, 0);
}
else {
const struct prop_encode *prop;
int encode = 1; /* default to encoding */

for (prop = prop_encode_map; prop->name; prop++) {
if (!strcasecmp(prop->name, entry->name)) {
encode = (prop->encode == -1) ? !is_uri : prop->encode;
break;
}
}

_value_to_tgt(entry->v.value, tgt, encode);
}
_entry_value_to_tgt(entry, tgt, is_uri);

_endline(tgt);
}
Expand Down Expand Up @@ -1083,6 +1089,28 @@ EXPORTED void vparse_set_value(struct vparse_entry *entry, const char *value)
entry->multivaluesep = '\0';
}

EXPORTED char *vparse_get_value(struct vparse_entry *entry)
{
if (!entry) return NULL;

struct vparse_param *param;
int is_uri = -1;

for (param = entry->params; param; param = param->next) {
if (!strcasecmp(param->name, "VALUE")) {
is_uri = !strcasecmp(param->value, "uri");
break;
}
}

struct buf buf = BUF_INITIALIZER;
struct vparse_target tgt = { &buf, 0 };

_entry_value_to_tgt(entry, &tgt, is_uri);

return buf_release(&buf);
}

EXPORTED void vparse_delete_entries(struct vparse_card *card, const char *group, const char *name)
{
hash_table props_using_label_counts = HASH_TABLE_INITIALIZER;
Expand Down
1 change: 1 addition & 0 deletions lib/vparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ extern void vparse_replace_entry(struct vparse_card *card, const char *group, co
extern void vparse_set_value(struct vparse_entry *entry, const char *value);
/* XXX - multivalue should be strarray_t */
//extern void vparse_set_multivalue(struct vparse_entry *entry, const strarray_t *values);
extern char *vparse_get_value(struct vparse_entry *entry);

extern void vparse_delete_params(struct vparse_entry *entry, const char *name);
extern struct vparse_param *vparse_get_param(struct vparse_entry *entry, const char *name);
Expand Down

0 comments on commit 0552750

Please sign in to comment.