summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bruederli <bruederli@kolabsys.com>2013-06-19 15:52:29 (GMT)
committerThomas Bruederli <bruederli@kolabsys.com>2013-06-19 15:52:29 (GMT)
commit8eead5b68b4f563ddaaf373315fb93a1104adf3d (patch)
tree7e7306abf623bacab696650496ff3da6bfd473cc
parente325881f6e5be23fc106c6b552b1d86fb263fa72 (diff)
downloadiRony-8eead5b68b4f563ddaaf373315fb93a1104adf3d.tar.gz
Move folder listing, creation and updating functions to utility class for usage in both, CalDAV and CardDAV backends
-rw-r--r--lib/Kolab/CalDAV/CalendarBackend.php111
-rw-r--r--lib/Kolab/CardDAV/AddressBook.php6
-rw-r--r--lib/Kolab/CardDAV/ContactsBackend.php32
-rw-r--r--lib/Kolab/Utils/DAVBackend.php156
4 files changed, 182 insertions, 123 deletions
diff --git a/lib/Kolab/CalDAV/CalendarBackend.php b/lib/Kolab/CalDAV/CalendarBackend.php
index 17fe833..89e2d25 100644
--- a/lib/Kolab/CalDAV/CalendarBackend.php
+++ b/lib/Kolab/CalDAV/CalendarBackend.php
@@ -59,31 +59,22 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
$folders = kolab_storage::get_folders('event');
$this->calendars = $this->folders = $this->aliases = array();
- // convert to UTF8 and sort
- $names = array();
- foreach ($folders as $folder) {
- $folders[$folder->name] = $folder;
- $names[$folder->name] = html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET); // decode &raquo;
- }
-
- asort($names, SORT_LOCALE_STRING);
-
- foreach ($names as $utf7name => $name) {
- $id = DAVBackend::get_uid($folders[$utf7name]);
- $folder = $this->folders[$id] = $folders[$utf7name];
+ 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->calendars[$id] = array(
'id' => $id,
'uri' => $id,
- '{DAV:}displayname' => $name,
+ '{DAV:}displayname' => html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET),
'{http://apple.com/ns/ical/}calendar-color' => $folder->get_color(),
'{http://calendarserver.org/ns/}getctag' => sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']),
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')),
'{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('opaque'),
);
- $this->aliases[$utf7name] = $id;
+ $this->aliases[$folder->name] = $id;
- // these properties are used for sahring supprt (not yet active)
+ // these properties are used for sharing supprt (not yet active)
if (false && $folder->get_namespace() != 'personal') {
$rights = $folder->get_myrights();
$this->calendars[$id]['{http://calendarserver.org/ns/}shared-url'] = '/calendars/' . $folder->get_owner() . '/' . $id;
@@ -184,43 +175,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
{
console(__METHOD__, $calendarUri, $properties);
- $props = array(
- 'name' => 'Untitled',
- 'type' => 'event',
- 'subscribed' => true
- );
-
- foreach ($properties as $prop => $val) {
- switch ($prop) {
- case '{DAV:}displayname':
- $parts = explode('/', $val);
- $props['name'] = array_pop($parts);
- $props['parent'] = join('/', $parts);
- break;
-
- case '{http://apple.com/ns/ical/}calendar-color':
- $props['color'] = substr(trim($val, '#'), 0, 6);
- break;
-
- case '{urn:ietf:params:xml:ns:caldav}calendar-description':
- default:
- // unsupported property
- }
- }
-
- if (!empty($props['name']) && ($fname = kolab_storage::folder_update($props))) {
- rcube::raise_error(array(
- 'code' => 600, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Error creating a new calendar folder '$props[name]':" . kolab_storage::$last_error),
- true, false);
- return false;
- }
-
- // save UID in folder annotations
- if ($folder = kolab_storage::get_folder($fname)) {
- DAVBackend::set_uid($folder, $calendarUri);
- }
+ return DAVBackend::folder_create('event', $properties, $calendarUri);
}
/**
@@ -264,57 +219,7 @@ class CalendarBackend extends CalDAV\Backend\AbstractBackend
console(__METHOD__, $calendarId, $mutations);
$folder = $this->get_storage_folder($calendarId);
- $errors = array();
- $updates = array();
-
- foreach ($mutations as $prop => $val) {
- switch ($prop) {
- case '{DAV:}displayname':
- // restrict renaming to personal folders only
- if ($folder->get_namespace() == 'personal') {
- $parts = preg_split('!(\s*/\s*|\s+[»:]\s+)!', $val);
- $updates['oldname'] = $folder->name;
- $updates['name'] = array_pop($parts);
- $updates['parent'] = join('/', $parts);
- }
- else {
- //$updates['displayname'] = $val;
- $errors[403][$prop] = null;
- }
- break;
-
- case '{http://apple.com/ns/ical/}calendar-color':
- $updates['color'] = substr(trim($val, '#'), 0, 6);
- break;
-
- case '{urn:ietf:params:xml:ns:caldav}calendar-description':
- default:
- // unsupported property
- $errors[403][$prop] = null;
- }
- }
-
- // execute folder update
- if (!empty($updates)) {
- // 'name' and 'parent' properties are always required
- if (empty($updates['name'])) {
- $parts = explode('/', $folder->name);
- $updates['name'] = rcube_charset::convert(array_pop($parts), 'UTF7-IMAP');
- $updates['parent'] = join('/', $parts);
- $updates['oldname'] = $folder->name;
- }
-
- if (!kolab_storage::folder_update($updates)) {
- rcube::raise_error(array(
- 'code' => 600, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Error updating properties for folder $folder->name:" . kolab_storage::$last_error),
- true, false);
- return false;
- }
- }
-
- return empty($errors) ? true : $errors;
+ return DAVBackend::folder_update($folder, $mutations);
}
/**
diff --git a/lib/Kolab/CardDAV/AddressBook.php b/lib/Kolab/CardDAV/AddressBook.php
index 5c4a830..23e4080 100644
--- a/lib/Kolab/CardDAV/AddressBook.php
+++ b/lib/Kolab/CardDAV/AddressBook.php
@@ -51,7 +51,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements \Sabre\CardDAV\I
$this->id = $addressBookInfo['id'];
$this->storage = $carddavBackend->get_storage_folder($this->id);
- $this->ready = is_object($this->storage) && is_a($this->storage, 'kolab_storage_folder');
+ $this->ready = $this->id == '__all__' || (is_object($this->storage) && is_a($this->storage, 'kolab_storage_folder'));
}
@@ -77,7 +77,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements \Sabre\CardDAV\I
*/
public function getOwner()
{
- if ($this->storage->get_namespace() == 'personal') {
+ if (!$this->storage || $this->storage->get_namespace() == 'personal') {
return $this->addressBookInfo['principaluri'];
}
else {
@@ -100,7 +100,7 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements \Sabre\CardDAV\I
public function getACL()
{
// return ACL information based on IMAP MYRIGHTS
- $rights = $this->storage->get_myrights();
+ $rights = $this->storage ? $this->storage->get_myrights() : null;
if ($rights && !PEAR::isError($rights)) {
// user has at least read access to calendar folders listed
$acl = array(
diff --git a/lib/Kolab/CardDAV/ContactsBackend.php b/lib/Kolab/CardDAV/ContactsBackend.php
index 35a1e3d..f24961f 100644
--- a/lib/Kolab/CardDAV/ContactsBackend.php
+++ b/lib/Kolab/CardDAV/ContactsBackend.php
@@ -57,23 +57,14 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
$folders = kolab_storage::get_folders('contact');
$this->sources = $this->folders = array();
- // convert to UTF8 and sort
- $names = array();
- foreach ($folders as $folder) {
- $folders[$folder->name] = $folder;
- $names[$folder->name] = html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET);
- }
-
- asort($names, SORT_LOCALE_STRING);
-
- foreach ($names as $utf7name => $name) {
- $id = DAVBackend::get_uid($folders[$utf7name]);
- $folder = $this->folders[$id] = $folders[$utf7name];
+ 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->sources[$id] = array(
'id' => $id,
'uri' => $id,
- '{DAV:}displayname' => $name,
+ '{DAV:}displayname' => html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET),
'{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(),
);
@@ -137,8 +128,8 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
console(__METHOD__, $addressBookId, $mutations);
- // TODO: implement this
- return false;
+ $folder = $this->get_storage_folder($addressBookId);
+ return DAVBackend::folder_update($folder, $mutations);
}
/**
@@ -153,7 +144,7 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
console(__METHOD__, $principalUri, $url, $properties);
- // TODO: implement this
+ return DAVBackend::folder_create('contact', $properties, $url);
}
/**
@@ -166,7 +157,14 @@ class ContactsBackend extends CardDAV\Backend\AbstractBackend
{
console(__METHOD__, $addressBookId);
- // TODO: implement this
+ $folder = $this->get_storage_folder($addressBookId);
+ if ($folder && !kolab_storage::folder_delete($folder->name)) {
+ rcube::raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Error deleting calendar folder $folder->name"),
+ true, false);
+ }
}
/**
diff --git a/lib/Kolab/Utils/DAVBackend.php b/lib/Kolab/Utils/DAVBackend.php
index 97985a2..8a4139b 100644
--- a/lib/Kolab/Utils/DAVBackend.php
+++ b/lib/Kolab/Utils/DAVBackend.php
@@ -23,8 +23,10 @@
namespace Kolab\Utils;
+use \rcube;
use \kolab_storage;
use \rcube_utils;
+use \rcube_charset;
/**
*
@@ -92,6 +94,35 @@ class DAVBackend
}
/**
+ * Sort the given list of kolab folders by namespace/name
+ *
+ * @param array List of kolab_storage_folder objects
+ * @return array Sorted list of folders
+ */
+ public static function sort_folders($folders)
+ {
+ $nsnames = array('personal' => array(), 'shared' => array(), 'other' => array());
+ foreach ($folders as $folder) {
+ $folders[$folder->name] = $folder;
+ $ns = $folder->get_namespace();
+ $nsnames[$ns][$folder->name] = html_entity_decode($folder->get_name(), ENT_COMPAT, RCUBE_CHARSET); // decode &raquo;
+ }
+
+ $names = array();
+ foreach ($nsnames as $ns => $dummy) {
+ asort($nsnames[$ns], SORT_LOCALE_STRING);
+ $names += $nsnames[$ns];
+ }
+
+ $out = array();
+ foreach ($names as $utf7name => $name) {
+ $out[] = $folders[$utf7name];
+ }
+
+ return $out;
+ }
+
+ /**
* Build an absolute URL with the given parameters
*/
public static function abs_url($parts = array())
@@ -115,4 +146,129 @@ class DAVBackend
return $url;
}
+ /**
+ * Updates properties for a recourse (kolab folder)
+ *
+ * The mutations array uses the propertyName in clark-notation as key,
+ * and the array value for the property value. In the case a property
+ * should be deleted, the property value will be null.
+ *
+ * This method must be atomic. If one property cannot be changed, the
+ * entire operation must fail.
+ *
+ * If the operation was successful, true is returned.
+ * If the operation failed, detailed information about any
+ * failures is returned.
+ *
+ * @param object $folder kolab_storage_folder instance to operate on
+ * @param array $mutations Hash array with propeties to change
+ * @return bool|array
+ */
+ public static function folder_update($folder, array $mutations)
+ {
+ $errors = array();
+ $updates = array();
+
+ foreach ($mutations as $prop => $val) {
+ switch ($prop) {
+ case '{DAV:}displayname':
+ // restrict renaming to personal folders only
+ if ($folder->get_namespace() == 'personal') {
+ $parts = preg_split('!(\s*/\s*|\s+[:]\s+)!', $val);
+ $updates['oldname'] = $folder->name;
+ $updates['name'] = array_pop($parts);
+ $updates['parent'] = join('/', $parts);
+ }
+ else {
+ $updates['displayname'] = $val;
+ }
+ break;
+
+ case '{http://apple.com/ns/ical/}calendar-color':
+ $updates['color'] = substr(trim($val, '#'), 0, 6);
+ break;
+
+ case '{urn:ietf:params:xml:ns:caldav}calendar-description':
+ default:
+ // unsupported property
+ $errors[403][$prop] = null;
+ }
+ }
+
+ // execute folder update
+ if (!empty($updates)) {
+ // 'name' and 'parent' properties are always required
+ if (empty($updates['name'])) {
+ $parts = explode('/', $folder->name);
+ $updates['name'] = rcube_charset::convert(array_pop($parts), 'UTF7-IMAP');
+ $updates['parent'] = join('/', $parts);
+ $updates['oldname'] = $folder->name;
+ }
+
+ if (!kolab_storage::folder_update($updates)) {
+ rcube::raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Error updating properties for folder $folder->name:" . kolab_storage::$last_error),
+ true, false);
+ return false;
+ }
+ }
+
+ return empty($errors) ? true : $errors;
+ }
+
+ /**
+ * Creates a new resource (i.e. IMAP folder) of a given type
+ *
+ * If the creation was a success, an id must be returned that can be used to reference
+ * this resource in other methods.
+ *
+ * @param array $properties
+ * @param string $type
+ * @param string $uid
+ * @return false|string
+ */
+ public function folder_create(string $type, array $properties, string $uid)
+ {
+ $props = array(
+ 'type' => $type,
+ 'name' => 'Untitled',
+ 'subscribed' => true,
+ );
+
+ foreach ($properties as $prop => $val) {
+ switch ($prop) {
+ case '{DAV:}displayname':
+ $parts = explode('/', $val);
+ $props['name'] = array_pop($parts);
+ $props['parent'] = join('/', $parts);
+ break;
+
+ case '{http://apple.com/ns/ical/}calendar-color':
+ $props['color'] = substr(trim($val, '#'), 0, 6);
+ break;
+
+ case '{urn:ietf:params:xml:ns:caldav}calendar-description':
+ default:
+ // unsupported property
+ }
+ }
+
+ if (!empty($props['name']) && ($fname = kolab_storage::folder_update($props))) {
+ rcube::raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Error creating a new calendar folder '$props[name]':" . kolab_storage::$last_error),
+ true, false);
+ return false;
+ }
+
+ // save UID in folder annotations
+ if ($folder = kolab_storage::get_folder($fname)) {
+ self::set_uid($folder, $uid);
+ }
+
+ return $uid;
+ }
}