diff --git a/config/dav.inc.php.sample.orig b/config/dav.inc.php.sample --- a/config/dav.inc.php.sample.orig +++ b/config/dav.inc.php.sample @@ -113,6 +116,45 @@ 'changed' => 'modifytimestamp', ), ); + +// Expose all resources as an LDAP-based address book in the pricipals address book collection. +// This enables Non-Kolab-Clients to add resources to an event. +// Properties of this option are the same as for $config['kolabdav_ldap_directory'] entries. +$config['kolabdav_ldap_resources'] = array( + 'name' => 'Global Resources', + 'hosts' => 'localhost', + 'port' => 389, + 'use_tls' => false, + 'user_specific' => false, + 'search_base_dn' => 'ou=People,dc=example,dc=org', + 'search_bind_dn' => 'uid=kolab-service,ou=Special Users,dc=example,dc=org', + 'search_bind_pw' => 'Welcome2KolabSystems', + 'search_filter' => '(&(objectClass=inetOrgPerson)(mail=%fu))', + 'base_dn' => 'ou=Resources,dc=example,dc=org', + 'bind_dn' => 'uid=kolab-service,ou=Special Users,dc=example,dc=org', + 'bind_pass' => 'Welcome2KolabSystems', + 'ldap_version' => 3, + 'filter' => '(|(objectclass=groupofuniquenames)(objectclass=groupofurls)(objectclass=kolabsharedfolder))', + 'search_fields' => array('displayname', 'mail'), + 'sort' => array('displayname', 'sn', 'givenname', 'cn'), + 'scope' => 'sub', + 'searchonly' => false, // Set to false to enable listing + 'sizelimit' => '1000', + 'timelimit' => '0', + 'fieldmap' => array( + // Internal => LDAP + 'name' => 'cn', + 'email' => 'mail', + 'owner' => 'owner', + 'description' => 'description', + 'attributes' => 'kolabdescattribute', + 'members' => 'uniquemember', + // these mappings are required for owner display + 'phone' => 'telephoneNumber', + 'mobile' => 'mobile', + ), +); + */ // Enable caching for LDAP directory data. diff --git a/lib/Kolab/CardDAV/ContactsBackend.php.orig b/lib/Kolab/CardDAV/ContactsBackend.php --- a/lib/Kolab/CardDAV/ContactsBackend.php.orig +++ b/lib/Kolab/CardDAV/ContactsBackend.php @@ -47,6 +47,7 @@ ); public $ldap_directory; + public $ldap_resources; private $sources; private $folders; @@ -358,6 +359,12 @@ $contact = $this->ldap_directory->getContactObject($uid); } } + // read card data from LDAP resources + else if ($addressBookId == LDAPResources::DIRECTORY_NAME) { + if (is_object($this->ldap_resources)) { + $contact = $this->ldap_resources->getContactObject($uid); + } + } else { $storage = $this->get_storage_folder($addressBookId); $contact = $storage->get_object($uid, '*'); diff --git a/lib/Kolab/CardDAV/LDAPDirectory.php.orig b/lib/Kolab/CardDAV/LDAPDirectory.php --- a/lib/Kolab/CardDAV/LDAPDirectory.php.orig +++ b/lib/Kolab/CardDAV/LDAPDirectory.php @@ -42,14 +42,14 @@ { const DIRECTORY_NAME = 'ldap-directory'; - private $config; - private $ldap; - private $carddavBackend; - private $principalUri; - private $addressBookInfo = array(); - private $cache; - private $query; - private $filter; + protected $config; + protected $ldap; + protected $carddavBackend; + protected $principalUri; + protected $addressBookInfo = array(); + protected $cache; + protected $query; + protected $filter; /** * Default constructor diff --git a/lib/Kolab/CardDAV/LDAPResources.php b/lib/Kolab/CardDAV/LDAPResources.php --- /dev/null +++ b/lib/Kolab/CardDAV/LDAPResources.php @@ -0,0 +1,67 @@ +config = $config; + $this->principalUri = $principalUri; + + $this->addressBookInfo = array( + 'id' => self::DIRECTORY_NAME, + 'uri' => self::DIRECTORY_NAME, + '{DAV:}displayname' => $config['name'] ?: "LDAP Resources", + '{urn:ietf:params:xml:ns:carddav}supported-address-data' => new Property\SupportedAddressData(), + 'principaluri' => $principalUri, + ); + + // used for vcard serialization + $this->carddavBackend = $carddavBackend ?: new ContactsBackend(); + $this->carddavBackend->ldap_resources = $this; + + // initialize cache. We need a different address space from GAL + // so don't mix our caches + $rcube = rcube::get_instance(); + if ($rcube->config->get('kolabdav_res_cache')) { + $this->cache = $rcube->get_cache_shared('kolabdav_res'); + + // expunge cache every now and then + if (rand(0,10) === 0) { + $this->cache->expunge(); + } + } + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + function getName() + { + return self::DIRECTORY_NAME; + } + +} diff --git a/lib/Kolab/CardDAV/Plugin.php.orig b/lib/Kolab/CardDAV/Plugin.php --- a/lib/Kolab/CardDAV/Plugin.php.orig +++ b/lib/Kolab/CardDAV/Plugin.php @@ -67,9 +67,14 @@ */ public function propFindEarly(DAV\PropFind $propFind, DAV\INode $node) { - // publish global ldap address book for this principal - if ($node instanceof DAVACL\IPrincipal && empty($this->directories) && \rcube::get_instance()->config->get('kolabdav_ldap_directory')) { - $this->directories[] = self::ADDRESSBOOK_ROOT . '/' . $node->getName() . '/' . LDAPDirectory::DIRECTORY_NAME; + // publish global ldap address book and resources list for this principal + if ($node instanceof DAVACL\IPrincipal && empty($this->directories)) { + if (\rcube::get_instance()->config->get('kolabdav_ldap_directory')) { + $this->directories[] = self::ADDRESSBOOK_ROOT . '/' . $node->getName() . '/' . LDAPDirectory::DIRECTORY_NAME; + } + if (\rcube::get_instance()->config->get('kolabdav_ldap_resources')) { + $this->directories[] = self::ADDRESSBOOK_ROOT . '/' . $node->getName() . '/' . LDAPResources::DIRECTORY_NAME; + } } parent::propFindEarly($propFind, $node); @@ -236,7 +241,7 @@ } // query on LDAP node: pass along filter query - if ($node instanceof LDAPDirectory) { + if ($node instanceof LDAPDirectory || $node instanceof LDAPResources) { $query = new CardDAV\AddressBookQueryParser($dom); $query->parse(); diff --git a/lib/Kolab/CardDAV/UserAddressBooks.php.orig b/lib/Kolab/CardDAV/UserAddressBooks.php --- a/lib/Kolab/CardDAV/UserAddressBooks.php.orig +++ b/lib/Kolab/CardDAV/UserAddressBooks.php @@ -37,6 +37,7 @@ { // pseudo-singleton instance private $ldap_directory; + private $ldap_resources; /** * Returns a list of addressbooks @@ -55,6 +56,10 @@ $objs[] = $this->getLDAPDirectory(); } + if (rcube::get_instance()->config->get('kolabdav_ldap_resources')) { + $objs[] = $this->getLDAPResources(); + } + return $objs; } @@ -69,6 +74,9 @@ if ($name == LDAPDirectory::DIRECTORY_NAME) { return $this->getLDAPDirectory(); } + if ($name == LDAPResources::DIRECTORY_NAME) { + return $this->getLDAPResources(); + } if ($addressbook = $this->carddavBackend->getAddressBookByName($name)) { $addressbook['principaluri'] = $this->principalUri; @@ -93,6 +101,21 @@ return $this->ldap_directory; } + /** + * Getter for the singleton instance of the LDAP resources + */ + private function getLDAPResources() + { + if (!$this->ldap_resources) { + $rcube = rcube::get_instance(); + $config = $rcube->config->get('kolabdav_ldap_resources'); + $config['debug'] = $rcube->config->get('ldap_debug'); + $this->ldap_resources = new LDAPResources($config, $this->principalUri, $this->carddavBackend); + } + + return $this->ldap_resources; + } + /** * Returns the list of properties