summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2013-06-20 08:06:43 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2013-06-20 08:06:43 (GMT)
commita7b85e71e8e06ddefaed655c602ac34b36d2e7f5 (patch)
tree341b3a08ee46f9c95fad98ceb8a51bdfb7611f7c
parent103dd18e627de21a4ecebbd2eded10ac16e71d27 (diff)
downloadiRony-a7b85e71e8e06ddefaed655c602ac34b36d2e7f5.tar.gz
Improve CardDAV backend:
- Introduce aliases to make address books accessible via their folder name - make it play nice with the Mac OS Address Book which cannot handle multiple address books see https://code.google.com/p/sabredav/wiki/OSXAddressbook
-rw-r--r--lib/Kolab/CardDAV/AddressBook.php2
-rw-r--r--lib/Kolab/CardDAV/ContactsBackend.php152
-rw-r--r--lib/Kolab/CardDAV/UserAddressBooks.php16
3 files changed, 154 insertions, 16 deletions
diff --git a/lib/Kolab/CardDAV/AddressBook.php b/lib/Kolab/CardDAV/AddressBook.php
index 23e4080..285ed9c 100644
--- a/lib/Kolab/CardDAV/AddressBook.php
+++ b/lib/Kolab/CardDAV/AddressBook.php
@@ -112,7 +112,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements \Sabre\CardDAV\I
);
$owner = $this->getOwner();
- $is_owner = $owner == $this->calendarInfo['principaluri'];
+ $is_owner = $owner == $this->addressBookInfo['principaluri'];
if ($is_owner || strpos($rights, 'i') !== false) {
$acl[] = array(
diff --git a/lib/Kolab/CardDAV/ContactsBackend.php b/lib/Kolab/CardDAV/ContactsBackend.php
index f24961f..8ed0df0 100644
--- a/lib/Kolab/CardDAV/ContactsBackend.php
+++ b/lib/Kolab/CardDAV/ContactsBackend.php
@@ -41,6 +41,7 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
private $sources;
private $folders;
+ private $aliases;
private $useragent;
@@ -55,12 +56,12 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
// get all folders that have "contact" type
$folders = kolab_storage::get_folders('contact');
- $this->sources = $this->folders = array();
+ $this->sources = $this->folders = $this->aliases = array();
foreach (DAVBackend::sort_folders($folders) as $folder) {
$id = DAVBackend::get_uid($folder);
- $this->folders[$id] = $folder;
$fdata = $folder->get_imap_data(); // fetch IMAP folder data for CTag generation
+ $this->folders[$id] = $folder;
$this->sources[$id] = array(
'id' => $id,
'uri' => $id,
@@ -68,6 +69,11 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
'{http://calendarserver.org/ns/}getctag' => sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']),
'{urn:ietf:params:xml:ns:caldav}supported-address-data' => new CardDAV\Property\SupportedAddressData(),
);
+ $this->aliases[$folder->name] = $id;
+
+ // map default folder to the magic 'all' resource
+ if ($folder->default)
+ $this->folders['__all__'] = $folder;
}
return $this->sources;
@@ -82,6 +88,11 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
*/
public function get_storage_folder($id)
{
+ // resolve alias name
+ if ($this->aliases[$id]) {
+ $id = $this->aliases[$id];
+ }
+
if ($this->folders[$id]) {
return $this->folders[$id];
}
@@ -99,10 +110,27 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
*/
public function getAddressBooksForUser($principalUri)
{
- console(__METHOD__, $principalUri);
+ console(__METHOD__, $principalUri, $this->useragent);
$this->_read_sources();
+ // special case for the apple address book which only supports one (!) address book
+ if ($this->useragent == 'macosx' && count($this->sources) > 1) {
+ $ctags = array('f');
+ foreach ($this->sources as $source) {
+ $ctags[] = $source['{http://calendarserver.org/ns/}getctag'];
+ }
+
+ return array(array(
+ 'id' => '__all__',
+ 'uri' => '__all__',
+ '{DAV:}displayname' => 'All',
+ '{http://calendarserver.org/ns/}getctag' => join(':', $ctags),
+ '{urn:ietf:params:xml:ns:caldav}supported-address-data' => new CardDAV\Property\SupportedAddressData(),
+ 'principaluri' => $principalUri,
+ ));
+ }
+
$addressBooks = array();
foreach ($this->sources as $id => $source) {
$source['principaluri'] = $principalUri;
@@ -112,6 +140,26 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
return $addressBooks;
}
+ /**
+ * Returns properties for a specific node identified by name/uri
+ *
+ * @param string Node name/uri
+ * @return array Hash array with address book properties or null if not found
+ */
+ public function getAddressBookByName($addressBookUri)
+ {
+ console(__METHOD__, $addressBookUri);
+
+ $this->_read_sources();
+ $id = $addressBookUri;
+
+ // resolve aliases (calendar by folder name)
+ if ($this->aliases[$addressBookUri]) {
+ $id = $this->aliases[$addressBookUri];
+ }
+
+ return $this->sources[$id];
+ }
/**
* Updates an addressbook's properties
@@ -128,8 +176,11 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
console(__METHOD__, $addressBookId, $mutations);
+ if ($addressBookId == '__all__')
+ return false;
+
$folder = $this->get_storage_folder($addressBookId);
- return DAVBackend::folder_update($folder, $mutations);
+ return $folder ? DAVBackend::folder_update($folder, $mutations) : false;
}
/**
@@ -157,6 +208,9 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
console(__METHOD__, $addressBookId);
+ if ($addressBookId == '__all__')
+ return;
+
$folder = $this->get_storage_folder($addressBookId);
if ($folder && !kolab_storage::folder_delete($folder->name)) {
rcube::raise_error(array(
@@ -181,16 +235,25 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
* calculating them. If they are specified, you can also ommit carddata.
* This may speed up certain requests, especially with large cards.
*
- * @param mixed $addressbookId
+ * @param mixed $addressBookId
* @return array
*/
- public function getCards($addressbookId)
+ public function getCards($addressBookId)
{
- console(__METHOD__, $addressbookId);
+ console(__METHOD__, $addressBookId);
+
+ // recursively fetch contacts from all folders
+ if ($addressBookId == '__all__') {
+ $cards = array();
+ foreach ($this->sources as $id => $source) {
+ $cards = array_merge($cards, $this->getCards($id));
+ }
+ return $cards;
+ }
$query = array();
$cards = array();
- if ($storage = $this->get_storage_folder($addressbookId)) {
+ if ($storage = $this->get_storage_folder($addressBookId)) {
foreach ((array)$storage->select($query) as $contact) {
$cards[] = array(
'id' => $contact['uid'],
@@ -220,9 +283,19 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
console(__METHOD__, $addressBookId, $cardUri);
$uid = basename($cardUri, '.vcf');
- $storage = $this->get_storage_folder($addressBookId);
- if ($storage && ($contact = $storage->get_object($uid))) {
+ // search all folders for the given card
+ if ($addressBookId == '__all__') {
+ $contact = $this->get_card_by_uid($uid, $storage);
+ }
+ else {
+ $storage = $this->get_storage_folder($addressBookId);
+ $contact = $storage->get_object($uid);
+ }
+
+ if ($contact) {
+ $rights = $this->storage ? $this->storage->get_myrights() : null;
+
return array(
'id' => $contact['uid'],
'uri' => $contact['uid'] . '.vcf',
@@ -260,7 +333,7 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
*/
public function createCard($addressBookId, $cardUri, $cardData)
{
- console(__METHOD__, $addressbookId, $cardUri, $cardData);
+ console(__METHOD__, $addressBookId, $cardUri, $cardData);
$uid = basename($cardUri, '.vcf');
$storage = $this->get_storage_folder($addressBookId);
@@ -310,10 +383,9 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
*/
public function updateCard($addressBookId, $cardUri, $cardData)
{
- console(__METHOD__, $addressbookId, $cardUri, $cardData);
+ console(__METHOD__, $addressBookId, $cardUri, $cardData);
$uid = basename($cardUri, '.vcf');
- $storage = $this->get_storage_folder($addressBookId);
$object = $this->parse_vcard($cardData, $uid);
// sanity check
@@ -327,8 +399,28 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
return null;
}
+ if ($addressBookId == '__all__') {
+ $old = $this->get_card_by_uid($uid, $storage);
+ }
+ else {
+ if ($storage = $this->get_storage_folder($addressBookId))
+ $old = $storage->get_object($uid);
+ }
+
+ if (!$storage) {
+ rcube::raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Unable to find storage folder for contact $addressBookId/$cardUri"),
+ true, false);
+ return null;
+ }
+
+ if (!$this->is_writeable($storage)) {
+ throw new DAV\Exception\MethodNotAllowed('Insufficient privileges to update this card');
+ }
+
// copy meta data (starting with _) from old object
- $old = $storage->get_object($uid);
foreach ((array)$old as $key => $val) {
if (!isset($object[$key]) && $key[0] == '_')
$object[$key] = $val;
@@ -359,7 +451,7 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
*/
public function deleteCard($addressBookId, $cardUri)
{
- console(__METHOD__, $addressbookId, $cardUri);
+ console(__METHOD__, $addressBookId, $cardUri);
// TODO: implement this
}
@@ -371,6 +463,7 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
$ua_classes = array(
'thunderbird' => 'Thunderbird/\d',
+ 'macosx' => 'AddressBook/\d.+\sCardDAVPlugin',
);
foreach ($ua_classes as $class => $regex) {
@@ -382,6 +475,35 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
}
+ /**
+ * Find an object and the containing folder by UID
+ *
+ * @param string Object UID
+ * @param object Return parameter for the kolab_storage_folder instance
+ * @return array|false
+ */
+ private function get_card_by_uid($uid, &$storage)
+ {
+ $obj = kolab_storage::get_object($uid, 'contact');
+ if ($obj) {
+ $storage = kolab_storage::get_folder($obj['_mbox']);
+ return $obj;
+ }
+
+ return false;
+ }
+
+ /**
+ * Internal helper method to determine whether the given kolab_storage_folder is writeable
+ *
+ */
+ private function is_writeable($storage)
+ {
+ $rights = $storage->get_myrights();
+ return (strpos($rights, 'i') !== false || $storage->get_namespace() == 'personal');
+ }
+
+
/********** Data conversion utilities ***********/
private $phonetypes = array(
diff --git a/lib/Kolab/CardDAV/UserAddressBooks.php b/lib/Kolab/CardDAV/UserAddressBooks.php
index 60be0f0..02707f0 100644
--- a/lib/Kolab/CardDAV/UserAddressBooks.php
+++ b/lib/Kolab/CardDAV/UserAddressBooks.php
@@ -48,4 +48,20 @@ class UserAddressBooks extends \Sabre\CardDAV\UserAddressBooks implements DAV\IE
return $objs;
}
+ /**
+ * Returns a single addressbook, by name
+ *
+ * @param string $name
+ * @return \AddressBook
+ */
+ public function getChild($name)
+ {
+ if ($addressbook = $this->carddavBackend->getAddressBookByName($name)) {
+ $addressbook['principaluri'] = $this->principalUri;
+ return new AddressBook($this->carddavBackend, $addressbook);
+ }
+
+ throw new DAV\Exception\NotFound('Addressbook with name \'' . $name . '\' could not be found');
+ }
+
}