Skip to content

Commit

Permalink
Merge pull request #4889 from cyrusimap/vcard_v3_v4_transform_bis
Browse files Browse the repository at this point in the history
More vCard v3 <-> v4 translations
  • Loading branch information
ksmurchison committed Apr 18, 2024
2 parents 9e7ba08 + 8ccb3a7 commit 23b88ca
Show file tree
Hide file tree
Showing 8 changed files with 471 additions and 156 deletions.
89 changes: 60 additions & 29 deletions cassandane/tiny-tests/Carddav/put_get_v3_v4
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use Cassandane::Tiny;

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

Expand All @@ -12,21 +12,48 @@ sub test_put_get_v3_v4
$self->assert_str_equals($Id, 'foo');
my $href = "$Id/bar.vcf";
my $uid = "3b678b69-ca41-461e-b2c7-f96b9fe48d68";
my $image = "R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
my $photo = "R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
my $logo = "http://bubbagump.com/logo.jpg";
my $sound = "ABCDEF";
my $lat = "30.3912";
my $lon = "-88.8610";
my $tel = "+1-800-555-1212";
my $email1 = "shrimp\@bubbagump.com";
my $email2 = "bubba\@bubbagump.com";
my $tzid = "America/New_York";

my $card = <<EOF;
BEGIN:VCARD
VERSION:3.0
UID:$uid
PHOTO;ENCODING=b;TYPE=GIF:$image
PHOTO;ENCODING=b;TYPE=video,GIF:$photo
LOGO;VALUE=uri;TYPE=JPEG:$logo
N:Gump;Forrest;;Mr.
FN:Forrest Gump
ORG:Bubba Gump Shrimp Co.
TITLE:Shrimp Man
REV:2008-04-24T19:52:43Z
GEO:$lat;$lon
TEL;TYPE=pref,foo,work:$tel
EMAIL;TYPE=pref:$email1
EMAIL:$email2
TZ:-05:00
TZ;VALUE=TEXT:$tzid
END:VCARD
EOF

# patterns for matching parameters
my $typesep = "(,|;TYPE=)"; # either comma-separated values or separate params
my $binary = "ENCODING=[B|b]";
my $utcoff = "[U|u][T|t][C|c]-[O|o][F|f][F|f][S|s][E|e][T|t]";
my $video = "[V|v][I|i][D|d][E|e][O|o]";
my $work = "[W|w][O|o][R|r][K|k]";
my $pref = "[P|p][R|r][E|e][F|f]";
my $text = "[T|t][E|e][X|x][T|t]";
my $uri = "[U|u][R|r][I|i]";
my $gif = "[G|g][I|i][F|f]";
my $mp3 = "[M|m][P|p]3";

my %Headers = (
'Content-Type' => 'text/vcard',
'Authorization' => $CardDAV->auth_header(),
Expand All @@ -45,43 +72,47 @@ EOF
my $newcard = $response->{content};
$newcard =~ s/\r?\n[ \t]+//gs; # unfold long properties
$self->assert_matches(qr/UID:urn:uuid:$uid/, $newcard);
$self->assert_matches(qr/PHOTO:data:image\/gif;base64,$image/, $newcard);
$self->assert_matches(qr/PHOTO;TYPE=$video:data:image\/gif;base64,$photo/,
$newcard);
$self->assert_matches(qr/LOGO;MEDIATYPE=image\/jpeg:$logo/, $newcard);
$self->assert_matches(qr/GEO(;VALUE=$uri)?:geo:$lat,$lon/, $newcard);
$self->assert_matches(qr/TEL;TYPE=foo$typesep$work;PREF=1:/, $newcard);
$self->assert_matches(qr/EMAIL;PREF=1:$email1/, $newcard);
$self->assert_matches(qr/EMAIL:$email2/, $newcard);
$self->assert_matches(qr/TZ;VALUE=$utcoff:-0500/, $newcard);
$self->assert_matches(qr/TZ(;VALUE=$text)?:$tzid/, $newcard);

xlog $self, "PUT same vCard as v4 with URL (urn) UID";
$card =~ s/VERSION:3.0/VERSION:4.0/;
$card =~ s/UID:/UID:urn:uuid:/;
$card =~ s/PHOTO;ENCODING=b;TYPE=GIF:/PHOTO:data:image\/gif;base64,/;
xlog $self, "PUT same vCard as v4 with some edits";
$newcard =~ s|END:|SOUND;MEDIATYPE=audio/mp3:data:;base64,$sound\r\nEND:|;
$newcard =~ s/:$tel/;VALUE=URL:tel:$tel/;
$newcard =~ s/EMAIL;PREF=1:/EMAIL;PREF=2:/;
$newcard =~ s/:$email2/;PREF=1:$email2/;
# $newcard =~ s/-0500/-05/; #not supported by libicalvcard yet
$newcard =~ s/TZ;VALUE=TEXT:/TZ:/;

$Response = $CardDAV->{ua}->request('PUT', $CardDAV->request_url($href), {
content => $card,
content => $newcard,
headers => \%Headers,
});
$self->assert_num_equals(204, $Response->{status});

xlog $self, "GET as vCard v3";
$tel =~ s/\+/\\+/; # escape the '+' for matching

$response = $CardDAV->Request('GET', $href, '',
'Accept' => 'text/vcard; version=3.0');
$newcard = $response->{content};
$newcard =~ s/\r?\n[ \t]+//gs; # unfold long properties
$self->assert_matches(qr/UID:$uid/, $newcard);
$self->assert_matches(qr/PHOTO;ENCODING=[bB];TYPE=GIF:$image/, $newcard);

xlog $self, "PUT vCard v3 with text UID";
$card =~ s/VERSION:4.0/VERSION:3.0/;
$card =~ s/UID:urn:uuid:/UID:/;
$card =~ s/PHOTO:data:image\/gif;base64,/PHOTO;ENCODING=b;TYPE=GIF:/;

xlog $self, "GET as vCard v4";
$response = $CardDAV->Request('GET', $href, '',
'Accept' => 'text/vcard; version=4.0');
$newcard = $response->{content};
$newcard =~ s/\r?\n[ \t]+//gs; # unfold long properties
$self->assert_matches(qr/UID:urn:uuid:$uid/, $newcard);
$self->assert_matches(qr/PHOTO:data:image\/gif;base64,$image/, $newcard);

$Response = $CardDAV->{ua}->request('PUT', $CardDAV->request_url($href), {
content => $card,
headers => \%Headers,
});
$self->assert_num_equals(204, $Response->{status});
$self->assert_matches(qr/PHOTO;TYPE=$video(,$gif)?;$binary(;TYPE=$gif)?:$photo/,
$newcard);
$self->assert_matches(qr/LOGO;VALUE=$uri;TYPE=JPEG:$logo/, $newcard);
$self->assert_matches(qr/SOUND;$binary;TYPE=$mp3:$sound/, $newcard);
$self->assert_matches(qr/GEO:$lat;$lon/, $newcard);
$self->assert_matches(qr/TEL;TYPE=foo$typesep$work$typesep$pref:$tel/,
$newcard);
$self->assert_matches(qr/EMAIL:$email1/, $newcard);
$self->assert_matches(qr/EMAIL;TYPE=$pref:$email2/, $newcard);
$self->assert_matches(qr/TZ(;VALUE=$utcoff)?:-05(:)?00/, $newcard);
$self->assert_matches(qr/TZ;VALUE=$text:$tzid/, $newcard);
}
3 changes: 2 additions & 1 deletion cassandane/tiny-tests/JMAPContacts/card_set_create_media
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ sub test_card_set_create_media
res47 => {
'@type' => 'MediaResource',
kind => 'logo',
mediaType => 'image/jpeg',
uri => 'https://www.example.com/pub/logos/abccorp.jpg'
},
res1 => {
Expand All @@ -62,7 +63,7 @@ sub test_card_set_create_media
my $card = $res->{content};
$card =~ s/\r?\n[ \t]+//gs; # unfold long properties

$self->assert_matches(qr|LOGO(;VALUE=URI)?;PROP-ID=res47:https://www.example.com/pub/logos/abccorp.jpg|, $card);
$self->assert_matches(qr|LOGO;PROP-ID=res47;MEDIATYPE=image/jpeg:https://www.example.com/pub/logos/abccorp.jpg|, $card);
$self->assert_matches(qr|SOUND(;VALUE=URI)?;PROP-ID=res45:CID:JOHNQ.part8.19960229T080000.xyzMail\@example.com|, $card);
$self->assert_matches(qr|PHOTO;PROP-ID=res1:data:image/jpeg;base64,c29tZSBwaG90bw==|, $card);
$self->assert_does_not_match(qr|JSPROP|, $card);
Expand Down
11 changes: 2 additions & 9 deletions imap/carddav_db.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,15 +1477,8 @@ EXPORTED int carddav_writecard_x(struct carddav_db *carddavdb,
vcardproperty_get_first_parameter(prop,
VCARD_TYPE_PARAMETER))) {
vcardenumarray *types = vcardparameter_get_type(param);
size_t i;
for (i = 0; i < vcardenumarray_size(types); i++) {
const vcardenumarray_element *type =
vcardenumarray_element_at(types, i);
if (!strcasecmpsafe(type->xvalue, "pref")) {
ispref = 1;
break;
}
}
vcardenumarray_element pref = { .val = VCARD_TYPE_PREF };
if (vcardenumarray_find(types, &pref) >= 0) ispref = 1;
}
strarray_appendm(&emails, propval);
strarray_append(&emails, ispref ? "1" : "");
Expand Down
16 changes: 9 additions & 7 deletions imap/jmap_contact.c
Original file line number Diff line number Diff line change
Expand Up @@ -6218,6 +6218,14 @@ static void _add_vcard_params(json_t *obj, vcardproperty *prop,
const char *type = NULL, *val = NULL;

switch (e->val) {
case VCARD_TYPE_PREF:
if (param_flags & ALLOW_PREF_PARAM) {
/* v3 TYPE=PREF */
json_object_set_new(obj, "pref", json_integer(1));
continue;
}
break;

case VCARD_TYPE_HOME:
val = "private";

Expand Down Expand Up @@ -6248,15 +6256,9 @@ static void _add_vcard_params(json_t *obj, vcardproperty *prop,
break;

default:
if (!e->xvalue && prop_kind == VCARD_RELATED_PROPERTY) {
if (prop_kind == VCARD_RELATED_PROPERTY) {
type = "relation";
}
else if ((param_flags & ALLOW_PREF_PARAM) &&
!strcasecmpsafe(e->xvalue, "PREF")) {
/* v3 TYPE=PREF */
json_object_set_new(obj, "pref", json_integer(1));
continue;
}
break;
}

Expand Down
Loading

0 comments on commit 23b88ca

Please sign in to comment.