Page MenuHomePhorge

D5232.1775316716.diff
No OneTemporary

Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None

D5232.1775316716.diff

diff --git a/lib/kolab_sync_data_contacts.php b/lib/kolab_sync_data_contacts.php
--- a/lib/kolab_sync_data_contacts.php
+++ b/lib/kolab_sync_data_contacts.php
@@ -192,16 +192,12 @@
$result[$key] = $value;
}
+ $emails = $this->getKolabContactEmails($data);
+
// email address(es): email1Address, email2Address, email3Address
for ($x = 0; $x < 3; $x++) {
- if (!empty($data['email'][$x])) {
- $email = $data['email'][$x];
- if (is_array($email)) {
- $email = $email['address'];
- }
- if ($email) {
- $result['email' . ($x + 1) . 'Address'] = $email;
- }
+ if (!empty($emails[$x])) {
+ $result['email' . ($x + 1) . 'Address'] = $emails[$x];
}
}
@@ -269,31 +265,7 @@
}
// email address(es): email1Address, email2Address, email3Address
- $emails = [];
- for ($x = 0; $x < 3; $x++) {
- $key = 'email' . ($x + 1) . 'Address';
- $value = $data->$key ?? null;
- if ($value) {
- // Android sends email address as: Lars Kneschke <l.kneschke@metaways.de>
- if (preg_match('/(.*)<(.+@[^@]+)>/', $value, $matches)) {
- $value = trim($matches[2]);
- }
-
- // sanitize email address, it can contain broken (non-unicode) characters (#3287)
- $value = rcube_charset::clean($value);
-
- // try to find address type, at least we can do this if
- // address wasn't changed
- $type = '';
- foreach ((array)$contact['email'] as $email) {
- if ($email['address'] == $value) {
- $type = $email['type'];
- }
- }
- $emails[] = ['address' => $value, 'type' => $type];
- }
- }
- $contact['email'] = $emails;
+ $this->setKolabContactEmails($contact, $data);
return $contact;
}
@@ -638,4 +610,99 @@
return [];
}
+
+ /**
+ * Extract list of email addresses from a Kolab contact
+ */
+ protected function getKolabContactEmails($contact)
+ {
+ // Contacts from XML (Kolab3) contain 'email' item set with an array that contains address and type
+ // or is just an address.
+ // Contacts from DAV (Kolab4) contain 'email:<type>' items with an array of email addresses.
+
+ $emails = [];
+ foreach (['email', 'email:work', 'email:other', 'email:home'] as $key) {
+ foreach ($contact[$key] ?? [] as $item) {
+ if (is_string($item) && strpos($item, '@')) {
+ $emails[] = $item;
+ } elseif (is_array($item) && !empty($item)) {
+ if (isset($item['address'])) {
+ $emails[] = $item['address'];
+ } else {
+ $emails = array_merge($emails, $item);
+ }
+ }
+ }
+ }
+
+ // Remove duplicates and empty values
+ return array_values(array_filter(array_unique($emails)));
+ }
+
+ /**
+ * Set Kolab contact email addresses
+ */
+ protected function setKolabContactEmails(&$contact, $data)
+ {
+ // On Kolab3 (XML) contacts have 'email' item that is a list of arrays that contain address and type
+ // or is just an address. No types.
+ // On Kolab4 (DAV) contacts have 'email:home', 'email:other' and 'email:home' items with
+ // an array of email addresses each.
+
+ // Get addresses from ActiveSync properties (email1Address, email2Address, email3Address)
+ $emails = [];
+ for ($x = 0; $x < 3; $x++) {
+ $key = 'email' . ($x + 1) . 'Address';
+ $email = $data->$key ?? null;
+ if ($email) {
+ // sanitize email address, it can contain broken (non-unicode) characters (#3287)
+ $email = rcube_charset::clean($email);
+
+ // Android sends email address as: Lars Kneschke <l.kneschke@metaways.de>
+ if (preg_match('/(.*)<(.+@[^@]+)>/', $email, $matches)) {
+ $email = trim($matches[2]);
+ }
+
+ $emails[] = $email;
+ }
+ }
+
+ // Warning: If contact has more than 3 addresses in Kolab they will be removed
+
+ if ($this->backend instanceof kolab_sync_storage_kolab4) {
+ // Remove addresses that do not exist anymore
+ $existing = [];
+ foreach (['email:work', 'email:other', 'email:home'] as $key) {
+ if (!empty($contact[$key])) {
+ $contact[$key] = array_values(array_intersect($contact[$key], $emails));
+ $existing = array_merge($existing, $contact[$key]);
+ if (empty($contact[$key])) {
+ unset($contact[$key]);
+ }
+ }
+ }
+
+ // Add new addresses
+ foreach (array_diff($emails, $existing) as $email) {
+ if (!isset($contact['email:other'])) {
+ $contact['email:other'] = [];
+ }
+ $contact['email:other'][] = $email;
+ }
+ } else {
+ foreach ($emails as $idx => $email) {
+ // try to find address type, at least we can do this if address wasn't changed
+ $type = '';
+ foreach ($contact['email'] ?? [] as $existing) {
+ if (isset($existing['address']) && $existing['address'] == $email) {
+ $type = $existing['type'] ?? '';
+ }
+ }
+
+ $emails[$idx] = ['address' => $email, 'type' => $type];
+ }
+
+ $contact['email'] = $emails;
+ }
+ }
}
diff --git a/tests/Sync/Sync/ContactsTest.php b/tests/Sync/Sync/ContactsTest.php
--- a/tests/Sync/Sync/ContactsTest.php
+++ b/tests/Sync/Sync/ContactsTest.php
@@ -79,10 +79,19 @@
$root .= "/ns:Commands/ns:Add";
$this->assertStringMatchesFormat("CRC%s", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue);
- $this->assertSame('Jack', $xpath->query("{$root}/ns:ApplicationData/Contacts:FirstName")->item(0)->nodeValue);
- $this->assertSame('Strong', $xpath->query("{$root}/ns:ApplicationData/Contacts:LastName")->item(0)->nodeValue);
- $this->assertSame('Jane', $xpath->query("{$root}/ns:ApplicationData/Contacts:FirstName")->item(1)->nodeValue);
- $this->assertSame('Doe', $xpath->query("{$root}/ns:ApplicationData/Contacts:LastName")->item(1)->nodeValue);
+ $r = "{$root}[1]/ns:ApplicationData";
+ $this->assertSame('Jack', $xpath->query("{$r}/Contacts:FirstName")->item(0)->nodeValue);
+ $this->assertSame('Strong', $xpath->query("{$r}/Contacts:LastName")->item(0)->nodeValue);
+ $this->assertSame('jack@kolab.org', $xpath->query("{$r}/Contacts:Email1Address")->item(0)->nodeValue);
+ $this->assertNull($xpath->query("{$r}/Contacts:Email2Address")->item(0));
+ $this->assertNull($xpath->query("{$r}/Contacts:Email3Address")->item(0));
+ $r = "{$root}[2]/ns:ApplicationData";
+ $this->assertSame('Jane', $xpath->query("{$r}/Contacts:FirstName")->item(0)->nodeValue);
+ $this->assertSame('J.', $xpath->query("{$r}/Contacts:MiddleName")->item(0)->nodeValue);
+ $this->assertSame('Doe', $xpath->query("{$r}/Contacts:LastName")->item(0)->nodeValue);
+ $this->assertNull($xpath->query("{$r}/Contacts:Email1Address")->item(0));
+ $this->assertNull($xpath->query("{$r}/Contacts:Email2Address")->item(0));
+ $this->assertNull($xpath->query("{$r}/Contacts:Email3Address")->item(0));
return $syncKey;
}
@@ -117,6 +126,10 @@
<ClientId>42</ClientId>
<ApplicationData>
<Contacts:FirstName>Lars</Contacts:FirstName>
+ <Contacts:LastName>Ulrich</Contacts:LastName>
+ <Contacts:Email1Address>lars@kolab.org</Contacts:Email1Address>
+ <Contacts:Email2Address>lars.tw@kolab.org</Contacts:Email2Address>
+ <Contacts:Email3Address>lars.th@kolab.org</Contacts:Email3Address>
</ApplicationData>
</Add>
</Commands>
@@ -141,7 +154,13 @@
$serverId = $xpath->query("ns:ServerId", $root)->item(0)->nodeValue;
$this->assertStringMatchesFormat("CRC%s", $serverId);
- // TODO: Test the content on the server
+ // Assert the content on the server
+ $contacts = $this->getDavObjects('Contacts', 'contact');
+ $this->assertCount(3, $contacts);
+ usort($contacts, function ($c1, $c2) { return $c1['surname'] <=> $c2['surname']; });
+ $this->assertSame('Lars', $contacts[2]['firstname']);
+ $this->assertSame('Ulrich', $contacts[2]['surname']);
+ $this->assertSame(['lars@kolab.org', 'lars.tw@kolab.org', 'lars.th@kolab.org'], $contacts[2]['email:other']);
return [$syncKey, $serverId];
}
diff --git a/tests/SyncTestCase.php b/tests/SyncTestCase.php
--- a/tests/SyncTestCase.php
+++ b/tests/SyncTestCase.php
@@ -323,6 +323,26 @@
return $decoder->decode();
}
+ /**
+ * Get objects from a DAV folder
+ */
+ protected function getDavObjects($foldername, $type, $query = [])
+ {
+ $dav = $this->getDavStorage();
+
+ foreach ($dav->get_folders($type) as $folder) {
+ if ($folder->get_name() === $foldername) {
+ $result = [];
+ foreach ($folder->select($query) as $object) {
+ $result[] = $object;
+ }
+ return $result;
+ }
+ }
+
+ throw new \Exception("Folder not found");
+ }
+
/**
* Initialize DAV storage
*/
diff --git a/tests/src/contact.vcard1 b/tests/src/contact.vcard1
--- a/tests/src/contact.vcard1
+++ b/tests/src/contact.vcard1
@@ -1,6 +1,6 @@
BEGIN:VCARD
VERSION:3.0
-UID:urn:uuid:abcdef-0123-4567-89ab-abcdefabcdef
+UID:abcdef-0123-4567-89ab-abcdefabcdef
FN:Jane Doe
N:Doe;Jane;J.;;
END:VCARD
diff --git a/tests/src/contact.vcard2 b/tests/src/contact.vcard2
--- a/tests/src/contact.vcard2
+++ b/tests/src/contact.vcard2
@@ -1,6 +1,7 @@
BEGIN:VCARD
VERSION:3.0
-UID:urn:uuid:abcdef-0123-4567-89ab-abcdefabc123
+UID:abcdef-0123-4567-89ab-abcdefabc123
FN:Jack Strong
N:Strong;Jack;;;
+EMAIL;TYPE=work:jack@kolab.org
END:VCARD

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 3:31 PM (2 d, 4 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18830175
Default Alt Text
D5232.1775316716.diff (10 KB)

Event Timeline