Skip to content

Commit

Permalink
jmap_contatc.c: handle ordered N/ADR with PHONETICs
Browse files Browse the repository at this point in the history
  • Loading branch information
ksmurchison committed Aug 24, 2023
1 parent 603e141 commit 69d055a
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 9 deletions.
79 changes: 79 additions & 0 deletions cassandane/tiny-tests/JMAPContacts/card-get-ordered-phonetics
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!perl
use Cassandane::Tiny;
use utf8;

sub test_card_get_ordered_phonetics
:min_version_3_9 :needs_component_jmap
{
my ($self) = @_;
my $jmap = $self->{jmap};

my $service = $self->{instance}->get_service("http");
$ENV{DEBUGDAV} = 1;
my $carddav = Net::CardDAVTalk->new(
user => 'cassandane',
password => 'pass',
host => $service->host(),
port => $service->port(),
scheme => 'http',
url => '/',
expandurl => 1,
);

my $id = 'ae2640cc-234a-4dd9-95cc-3106258445b9';
my $href = "Default/$id.vcf";
my $card = <<EOF;
BEGIN:VCARD
VERSION:4.0
UID:$id
N;ALTID=n1;PHONETIC=IPA:/smɪθ/;/d͡ʒɑn/;;;;;
N;JSCOMPS=";1;0";ALTID=n1:Smith;John;;;;;
FN;DERIVED=TRUE:John Smith
CREATED:20230824T143619Z
END:VCARD
EOF

$card =~ s/\r?\n/\r\n/gs;
$carddav->Request('PUT', $href, $card, 'Content-Type' => 'text/vcard');

my $res = $jmap->CallMethods([
['ContactCard/get', {
}, 'R1']
]);

my $want_jscard = {
'@type' => 'Card',
version => '1.0',
addressBookId => 'Default',
'cyrusimap.org:href' => $carddav->fullpath() . $href,
id => $id,
uid => $id,
created => '2023-08-24T14:36:19Z',
vCardProps => [
[ 'version', {}, 'text', '4.0' ]
],
name => {
phoneticSystem => 'ipa',
isOrdered => JSON::true,
components => [
{ kind => 'given', value => 'John' , phonetic => "/d͡ʒɑn/" },
{ kind => 'surname', value => 'Smith', phonetic => "/smɪθ/" }
]
},
};

my $have_jscard = $res->[0][1]{list}[0];

# Delete generated fields
delete $have_jscard->{blobId};
delete $have_jscard->{'cyrusimap.org:blobId'};
delete $have_jscard->{'cyrusimap.org:size'};

# Normalize and compare cards
normalize_jscard($want_jscard);
normalize_jscard($have_jscard);

warn Dumper($want_jscard);
warn Dumper($have_jscard);
$self->assert_deep_equals($want_jscard, $have_jscard);
}
42 changes: 33 additions & 9 deletions imap/jmap_contact.c
Original file line number Diff line number Diff line change
Expand Up @@ -6268,7 +6268,7 @@ static void jscomps_from_vcard(json_t *obj, vcardproperty *prop,
vcardparameter *param;
vcardstrarray *sa;
const char *val, *val_prop_name = "value";
json_t *comps, *comp;
json_t *comps, *comp = NULL;
size_t i, j = 0;

param = vcardproperty_get_first_parameter(prop, VCARD_PHONETIC_PARAMETER);
Expand Down Expand Up @@ -6342,12 +6342,19 @@ static void jscomps_from_vcard(json_t *obj, vcardproperty *prop,
}

if (*val) {
json_array_append_new(json_object_get_vanew(obj,
"components", "[]"),
json_pack("{s:s s:o}",
"kind", kind,
val_prop_name,
jmap_utf8string(val)));
/* This assumes that JSCOMPS are identical
for props paired by ALTID */
comps = json_object_get_vanew(obj, "components", "[]");
if (json_array_size(comps) > j) {
/* Grab the existing component by position */
comp = json_array_get(comps, j);
}
else {
comp = json_pack("{s:s}", "kind", kind);
json_array_append_new(comps, comp);
}
json_object_set_new(comp, val_prop_name, jmap_utf8string(val));
j++;
}
}

Expand Down Expand Up @@ -6376,7 +6383,16 @@ static void jscomps_from_vcard(json_t *obj, vcardproperty *prop,

comps = json_object_get_vanew(obj, "components", "[]");
if (json_array_size(comps) > j) {
comp = json_array_get(comps, j);
size_t k;

/* Find the existing component by name */
json_array_foreach(comps, k, comp) {
if (!strcmp(ckind->name,
json_string_value(json_object_get(comp, "kind")))) {
break;
}
}
if (k > json_array_size(comps)) continue;
}
else {
comp = json_pack("{s:s}", "kind", ckind->name);
Expand Down Expand Up @@ -7262,7 +7278,15 @@ static json_t *jmap_card_from_vcard(const char *userid,
props = ptrarray_new();
hash_insert(altid, props, props_by_altid);
}
ptrarray_append(props, prop);
if ((prop_kind == VCARD_N_PROPERTY || prop_kind == VCARD_ADR_PROPERTY) &&
vcardproperty_get_first_parameter(prop, VCARD_JSCOMPS_PARAMETER)) {
/* Always place props with JSCOMPS at the head of the list
so the comp order is set before handling PHONETICS */
ptrarray_insert(props, 0, prop);
}
else {
ptrarray_append(props, prop);
}

if (prop_kind == VCARD_VERSION_PROPERTY) {
crock.version = vcardproperty_get_version(prop);
Expand Down

0 comments on commit 69d055a

Please sign in to comment.