1016 lines
33 KiB
PHP
1016 lines
33 KiB
PHP
<?php
|
|
/**
|
|
* Horde Turba driver for the Kolab IMAP Server.
|
|
*
|
|
* Copyright 2004-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file LICENSE for license information (ASL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/apache.
|
|
*
|
|
* @author Thomas Jarosch <thomas.jarosch@intra2net.com>
|
|
* @author Gunnar Wrobel <wrobel@pardus.de>
|
|
* @author Stuart Binge <omicron@mighty.co.za>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/apache ASL
|
|
* @package Turba
|
|
*/
|
|
class Turba_Driver_Kolab extends Turba_Driver
|
|
{
|
|
/**
|
|
* The Kolab_Storage backend.
|
|
*
|
|
* @var Horde_Kolab_Storage
|
|
*/
|
|
protected $_kolab;
|
|
|
|
/**
|
|
* Indicates if the driver has been connected to a specific addressbook or
|
|
* not.
|
|
*
|
|
* @var boolean
|
|
*/
|
|
protected $_connected = false;
|
|
|
|
/**
|
|
* The current addressbook.
|
|
*
|
|
* @var Horde_Kolab_Storage_Data
|
|
*/
|
|
protected $_data;
|
|
|
|
/**
|
|
* The current addressbook, serving groups.
|
|
*
|
|
* @var Horde_Kolab_Storage_Data
|
|
*/
|
|
protected $_listData;
|
|
|
|
/**
|
|
* The current addressbook represented as share.
|
|
*
|
|
* @var Horde_Share_Object
|
|
*/
|
|
protected $_share;
|
|
|
|
/**
|
|
* The cached contacts.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_contacts_cache;
|
|
|
|
/**
|
|
* What can this backend do?
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_capabilities = array(
|
|
'delete_addressbook' => true,
|
|
'delete_all' => true,
|
|
);
|
|
|
|
/**
|
|
* Any additional options passed to Turba_Object constructors.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_objectOptions = array('removeMissing' => true);
|
|
|
|
/**
|
|
* Attempts to open a Kolab Groupware folder.
|
|
*/
|
|
public function __construct($name = '', $params = array())
|
|
{
|
|
if (empty($params['storage'])) {
|
|
throw new InvalidArgumentException('Missing required storage handler.');
|
|
}
|
|
$this->_kolab = $params['storage'];
|
|
unset($params['storage']);
|
|
|
|
if (isset($params['share'])) {
|
|
$this->_share = $params['share'];
|
|
}
|
|
if (isset($params['name'])) {
|
|
$name = $params['name'];
|
|
}
|
|
|
|
parent::__construct($name, $params);
|
|
}
|
|
|
|
/**
|
|
* Translates the keys of the first hash from the generalized Turba
|
|
* attributes to the driver-specific fields. The translation is based on
|
|
* the contents of $this->map.
|
|
*
|
|
* @param array $hash Hash using Turba keys.
|
|
*
|
|
* @return array Translated version of $hash.
|
|
*/
|
|
public function toDriverKeys(array $hash)
|
|
{
|
|
if (isset($hash['__tags'])) {
|
|
if (!is_array($hash['__tags'])) {
|
|
$hash['__tags'] = $GLOBALS['injector']
|
|
->getInstance('Turba_Tagger')
|
|
->split($hash['__tags']);
|
|
}
|
|
usort($hash['__tags'], 'strcoll');
|
|
$hash['__internaltags'] = serialize($hash['__tags']);
|
|
}
|
|
|
|
$hash = parent::toDriverKeys($hash);
|
|
|
|
if (isset($hash['name'])) {
|
|
$hash['name'] = array('full-name' => $hash['name']);
|
|
}
|
|
|
|
/* TODO: use Horde_Kolab_Format_Xml_Type_Composite_* */
|
|
foreach (array('full-name',
|
|
'given-name',
|
|
'middle-names',
|
|
'last-name',
|
|
'initials',
|
|
'prefix',
|
|
'suffix') as $sub) {
|
|
if (isset($hash[$sub])) {
|
|
$hash['name'][$sub] = $hash[$sub];
|
|
unset($hash[$sub]);
|
|
}
|
|
}
|
|
|
|
if (isset($hash['__type']) && $hash['__type'] == 'Group' &&
|
|
isset($hash['name']['full-name'])) {
|
|
$hash['display-name'] = $hash['name']['full-name'];
|
|
}
|
|
|
|
if (isset($hash['emails'])) {
|
|
$list = new Horde_Mail_Rfc822_List($hash['emails']);
|
|
$hash['email'] = array();
|
|
foreach ($list as $address) {
|
|
$hash['email'][] = array('smtp-address' => $address->bare_address);
|
|
}
|
|
unset($hash['emails']);
|
|
}
|
|
|
|
foreach (array('phone-business1',
|
|
'phone-business2',
|
|
'phone-businessfax',
|
|
'phone-car',
|
|
'phone-company',
|
|
'phone-home1',
|
|
'phone-home2',
|
|
'phone-homefax',
|
|
'phone-mobile',
|
|
'phone-pager',
|
|
'phone-radio',
|
|
'phone-assistant') as $sub) {
|
|
if (isset($hash[$sub])) {
|
|
if (!isset($hash['phone'])) {
|
|
$hash['phone'] = array();
|
|
}
|
|
$hash['phone'][] = array('type' => substr($sub, 6),
|
|
'number' => $hash[$sub]);
|
|
unset($hash[$sub]);
|
|
}
|
|
}
|
|
|
|
$address = array();
|
|
foreach (array('addr-business-street',
|
|
'addr-business-locality',
|
|
'addr-business-region',
|
|
'addr-business-postal-code',
|
|
'addr-business-country') as $sub) {
|
|
if (isset($hash[$sub])) {
|
|
$address[substr($sub, 14)] = $hash[$sub];
|
|
unset($hash[$sub]);
|
|
}
|
|
}
|
|
if ($address) {
|
|
$hash['address'] = array();
|
|
$address['type'] = 'business';
|
|
$hash['address'][] = $address;
|
|
}
|
|
$address = array();
|
|
foreach (array('addr-home-street',
|
|
'addr-home-locality',
|
|
'addr-home-region',
|
|
'addr-home-postal-code',
|
|
'addr-home-country') as $sub) {
|
|
if (isset($hash[$sub])) {
|
|
$address[substr($sub, 10)] = $hash[$sub];
|
|
unset($hash[$sub]);
|
|
}
|
|
}
|
|
if ($address) {
|
|
if (!isset($hash['address'])) {
|
|
$hash['address'] = array();
|
|
}
|
|
$address['type'] = 'home';
|
|
$hash['address'][] = $address;
|
|
}
|
|
|
|
if (isset($hash['categories'])) {
|
|
$hash['categories'] = unserialize($hash['categories']);
|
|
}
|
|
|
|
if (!empty($hash['birthday'])) {
|
|
$hash['birthday'] = new DateTime($hash['birthday']);
|
|
}
|
|
if (!empty($hash['anniversary'])) {
|
|
$hash['anniversary'] = new DateTime($hash['anniversary']);
|
|
}
|
|
|
|
return $hash;
|
|
}
|
|
|
|
/**
|
|
* Translates a hash from being keyed on driver-specific fields to being
|
|
* keyed on the generalized Turba attributes. The translation is based on
|
|
* the contents of $this->map.
|
|
*
|
|
* @param array $entry A hash using driver-specific keys.
|
|
*
|
|
* @return array Translated version of $entry.
|
|
*/
|
|
public function toTurbaKeys(array $entry)
|
|
{
|
|
if (isset($entry['__type']) &&
|
|
$entry['__type'] == 'Group' &&
|
|
isset($entry['display-name'])) {
|
|
$entry['last-name'] = $entry['display-name'];
|
|
}
|
|
|
|
return parent::toTurbaKeys($entry);
|
|
}
|
|
|
|
/**
|
|
* Returns the Kolab data handler for contacts in the current address book.
|
|
*
|
|
* @return Horde_Kolab_Storage_Data The data handler.
|
|
*/
|
|
protected function _getData()
|
|
{
|
|
if ($this->_data === null) {
|
|
$this->_data = $this->_createData('contact');
|
|
}
|
|
|
|
return $this->_data;
|
|
}
|
|
|
|
/**
|
|
* Returns the Kolab data handler for distribution lists in the current
|
|
* address book.
|
|
*
|
|
* @return Horde_Kolab_Storage_Data The data handler.
|
|
*/
|
|
protected function _getListData()
|
|
{
|
|
if ($this->_listData === null) {
|
|
$this->_listData = $this->_createData('distribution-list');
|
|
}
|
|
|
|
return $this->_listData;
|
|
}
|
|
|
|
/**
|
|
* Returns a new Kolab data handler for the current address book.
|
|
*
|
|
* @param string $type An object type, either 'contact' or
|
|
* 'distribution-list'.
|
|
*
|
|
* @return Horde_Kolab_Storage_Data A data handler.
|
|
*/
|
|
protected function _createData($type)
|
|
{
|
|
if (!empty($this->_share)) {
|
|
$share = $this->_share;
|
|
} else {
|
|
if (empty($this->_name)) {
|
|
throw new Turba_Exception(
|
|
'The addressbook has been left undefined but is required!'
|
|
);
|
|
}
|
|
|
|
$share = $GLOBALS['injector']
|
|
->getInstance('Turba_Shares')
|
|
->getShare($this->_name);
|
|
}
|
|
|
|
$data = $this->_kolab->getData($share->get('folder'), $type);
|
|
$this->setContactOwner($share->get('owner'));
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Connect to the Kolab backend.
|
|
*
|
|
* @throws Turba_Exception
|
|
*/
|
|
public function connect()
|
|
{
|
|
if ($this->_connected) {
|
|
return;
|
|
}
|
|
|
|
/* Fetch the contacts first */
|
|
$raw_contacts = $this->_getData()->getObjects();
|
|
if (!$raw_contacts) {
|
|
$raw_contacts = array();
|
|
}
|
|
$contacts = array();
|
|
foreach ($raw_contacts as $id => $contact) {
|
|
if ($contact->getType() != 'contact') {
|
|
continue;
|
|
}
|
|
$backendId = $contact->getBackendId();
|
|
$contact = $contact->getData();
|
|
$contact['__type'] = 'Object';
|
|
$contact['__key'] = Horde_Url::uriB64Encode($id);
|
|
|
|
if (isset($contact['categories'])) {
|
|
$contact['categories'] = serialize($contact['categories']);
|
|
}
|
|
|
|
if (isset($contact['picture'])) {
|
|
$name = $contact['picture'];
|
|
$stream = $this->_getData()->getAttachment($backendId, $name);
|
|
if ($stream) {
|
|
$contact['photo'] = new Horde_Stream_Existing(array(
|
|
'stream' => $stream
|
|
));
|
|
foreach ($contact['_attachments']['type'] as $type => $list) {
|
|
if (array_search($name, $list) !== false) {
|
|
$contact['phototype'] = $type;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($contact['name'])) {
|
|
foreach ($contact['name'] as $detail => $value) {
|
|
$contact[$detail] = $value;
|
|
}
|
|
unset($contact['name']);
|
|
}
|
|
|
|
if (isset($contact['phone'])) {
|
|
foreach ($contact['phone'] as $phone) {
|
|
$contact['phone-' . $phone['type']] = $phone['number'];
|
|
}
|
|
unset($contact['phone']);
|
|
}
|
|
|
|
if (isset($contact['email'])) {
|
|
$contact['emails'] = array();
|
|
foreach ($contact['email'] as $email) {
|
|
$contact['emails'][] = $email['smtp-address'];
|
|
}
|
|
if ($contact['emails']) {
|
|
$contact['email'] = $contact['emails'][0];
|
|
} else {
|
|
unset($contact['email']);
|
|
}
|
|
$contact['emails'] = implode(', ', $contact['emails']);
|
|
}
|
|
|
|
if (isset($contact['address'])) {
|
|
foreach ($contact['address'] as $address) {
|
|
foreach ($address as $detail => $value) {
|
|
if ($detail != 'type') {
|
|
$contact['addr-' . $address['type'] . '-' . $detail] = $value;
|
|
}
|
|
}
|
|
}
|
|
unset($contact['address']);
|
|
}
|
|
|
|
if (!empty($contact['birthday'])) {
|
|
$contact['birthday'] = $contact['birthday']->format('Y-m-d');
|
|
}
|
|
if (!empty($contact['anniversary'])) {
|
|
$contact['anniversary'] = $contact['anniversary']->format('Y-m-d');
|
|
}
|
|
|
|
$contacts[Horde_Url::uriB64Encode($id)] = $contact;
|
|
}
|
|
|
|
/* Now we retrieve distribution-lists */
|
|
$raw_groups = $this->_getListData()->getObjects();
|
|
$groups = array();
|
|
if ($raw_groups) {
|
|
foreach ($raw_groups as $id => $group) {
|
|
if ($group->getType() != 'distribution-list') {
|
|
continue;
|
|
}
|
|
$group = $group->getData();
|
|
$group['__type'] = 'Group';
|
|
$group['__key'] = Horde_Url::uriB64Encode($id);
|
|
if (isset($group['categories'])) {
|
|
$group['categories'] = serialize($group['categories']);
|
|
}
|
|
$groups[Horde_Url::uriB64Encode($id)] = $group;
|
|
}
|
|
}
|
|
|
|
/* Store the results in our cache */
|
|
$this->_contacts_cache = array_merge($contacts, $groups);
|
|
|
|
$this->_connected = true;
|
|
}
|
|
|
|
/**
|
|
* Searches the address book with the given criteria and returns a
|
|
* filtered list of results. If the criteria parameter is an empty array,
|
|
* all records will be returned.
|
|
*
|
|
* @param array $criteria Array containing the search criteria.
|
|
* @param array $fields List of fields to return.
|
|
* @param array $blobFields Array of fields containing binary data.
|
|
*
|
|
* @return array Hash containing the search results.
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _search(array $criteria, array $fields,
|
|
array $blobFields = array(), $count_only = false)
|
|
{
|
|
$this->connect();
|
|
|
|
if (!count($criteria)) {
|
|
return $count_only
|
|
? count($this->_contacts_cache)
|
|
: array_values($this->_contacts_cache);
|
|
}
|
|
|
|
// keep only entries matching criteria
|
|
$ids = array();
|
|
foreach ($criteria as $key => $criteria) {
|
|
$ids[] = $this->_doSearch($criteria, strval($key));
|
|
}
|
|
$ids = $this->_removeDuplicated($ids);
|
|
|
|
/* Now we have a list of names, get the rest. */
|
|
if ($ids) {
|
|
$result = $this->_read(
|
|
'uid',
|
|
array_map(array('Horde_Url', 'uriB64Encode'), $ids),
|
|
null,
|
|
$fields
|
|
);
|
|
} else {
|
|
$result = array();
|
|
}
|
|
|
|
Horde::log(sprintf('Kolab returned %s results', count($result)), 'DEBUG');
|
|
|
|
return $count_only ? count($result) : array_values($result);
|
|
}
|
|
|
|
/**
|
|
* Applies the filter criteria to a list of entries
|
|
*
|
|
* @param array $criteria Array containing the search criteria.
|
|
* @param array $fields List of fields to return.
|
|
*
|
|
* @return array Array containing the ids of the selected entries.
|
|
*/
|
|
protected function _doSearch($criteria, $glue)
|
|
{
|
|
$ids = array();
|
|
|
|
foreach ($criteria as $vals) {
|
|
if (!empty($vals['OR'])) {
|
|
$ids[] = $this->_doSearch($vals['OR'], 'OR');
|
|
} elseif (!empty($vals['AND'])) {
|
|
$ids[] = $this->_doSearch($vals['AND'], 'AND');
|
|
} else {
|
|
/* If we are here, and we have a ['field'] then we
|
|
* must either do the 'AND' or the 'OR' search. */
|
|
if (isset($vals['field'])) {
|
|
$ids[] = $this->_selectEntries($vals);
|
|
} else {
|
|
foreach ($vals as $test) {
|
|
if (!empty($test['OR'])) {
|
|
$ids[] = $this->_doSearch($test['OR'], 'OR');
|
|
} elseif (!empty($test['AND'])) {
|
|
$ids[] = $this->_doSearch($test['AND'], 'AND');
|
|
} else {
|
|
$ids[] = $this->_doSearch(array($test), $glue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($glue == 'AND') {
|
|
$ids = $this->_getAND($ids);
|
|
} elseif ($glue == 'OR') {
|
|
$ids = $this->_removeDuplicated($ids);
|
|
}
|
|
|
|
return $ids;
|
|
}
|
|
|
|
/**
|
|
* Applies one filter criterium to a list of entries
|
|
*
|
|
* @param $test Test criterium
|
|
*
|
|
* @return array Array containing the ids of the selected entries
|
|
*/
|
|
protected function _selectEntries($test)
|
|
{
|
|
$ids = array();
|
|
|
|
if (!isset($test['field'])) {
|
|
Horde::log('Search field not set. Returning all entries.', 'DEBUG');
|
|
foreach ($this->_contacts_cache as $entry) {
|
|
$ids[] = $entry['uid'];
|
|
}
|
|
} else {
|
|
$field = $test['field'];
|
|
$value = isset($test['test'])
|
|
? $test['test']
|
|
: '';
|
|
|
|
// Special emails hack
|
|
if ($field == 'email') {
|
|
$field = 'emails';
|
|
$test['op'] = 'LIKE';
|
|
$test['begin'] = false;
|
|
}
|
|
if (!isset($test['op']) || $test['op'] == '=') {
|
|
foreach ($this->_contacts_cache as $entry) {
|
|
if (isset($entry[$field]) && $entry[$field] == $value) {
|
|
$ids[] = $entry['uid'];
|
|
}
|
|
}
|
|
} else {
|
|
// 'op' is LIKE
|
|
foreach ($this->_contacts_cache as $entry) {
|
|
if (empty($value) ||
|
|
(isset($entry[$field]) &&
|
|
((empty($test['begin']) &&
|
|
stripos($entry[$field], $value) !== false) ||
|
|
(!empty($test['begin']) &&
|
|
stripos($entry[$field], $value) === 0)))) {
|
|
$ids[] = $entry['uid'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ids;
|
|
}
|
|
|
|
/**
|
|
* Returns only those names that are duplicated in $ids
|
|
*
|
|
* @param array $ids A nested array of arrays containing names
|
|
*
|
|
* @return array Array containing the 'AND' of all arrays in $ids
|
|
*/
|
|
protected function _getAND($ids)
|
|
{
|
|
$matched = $results = array();
|
|
|
|
/* If there is only 1 array, simply return it. */
|
|
if (count($ids) < 2) {
|
|
return $ids[0];
|
|
}
|
|
|
|
for ($i = 0; $i < count($ids); ++$i) {
|
|
if (is_array($ids[$i])) {
|
|
$results = array_merge($results, $ids[$i]);
|
|
}
|
|
}
|
|
|
|
$search = array_count_values($results);
|
|
foreach ($search as $key => $value) {
|
|
if ($value == count($ids)) {
|
|
$matched[] = $key;
|
|
}
|
|
}
|
|
|
|
return $matched;
|
|
}
|
|
|
|
/**
|
|
* Returns an array with all duplicate names removed.
|
|
*
|
|
* @param array $ids Nested array of arrays containing names.
|
|
*
|
|
* @return array Array containg the 'OR' of all arrays in $ids.
|
|
*/
|
|
protected function _removeDuplicated($ids)
|
|
{
|
|
$unames = array();
|
|
for ($i = 0; $i < count($ids); ++$i) {
|
|
if (is_array($ids[$i])) {
|
|
$unames = array_merge($unames, $ids[$i]);
|
|
}
|
|
}
|
|
|
|
return array_unique($unames);
|
|
}
|
|
|
|
/**
|
|
* Reads the given data from the address book and returns the results.
|
|
*
|
|
* @param string $key The primary key field to use.
|
|
* @param mixed $ids The ids of the contacts to load.
|
|
* @param string $owner Only return contacts owned by this user.
|
|
* @param array $fields List of fields to return.
|
|
* @param array $blobFields Array of fields containing binary data.
|
|
* @param array $dateFields Array of fields containing date data.
|
|
* @since 4.2.0
|
|
*
|
|
* @return array Hash containing the search results.
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _read($key, $ids, $owner, array $fields,
|
|
array $blobFields = array(),
|
|
array $dateFields = array())
|
|
{
|
|
$this->connect();
|
|
|
|
$results = array();
|
|
|
|
if (!is_array($ids)) {
|
|
$ids = array($ids);
|
|
}
|
|
|
|
$count = count($fields);
|
|
foreach ($ids as $id) {
|
|
if (!isset($this->_contacts_cache[$id])) {
|
|
continue;
|
|
}
|
|
$object = $this->_contacts_cache[$id];
|
|
|
|
if (!isset($object['__type']) || $object['__type'] == 'Object') {
|
|
if ($count) {
|
|
$result = array();
|
|
foreach ($fields as $field) {
|
|
if (isset($object[$field])) {
|
|
$result[$field] = $object[$field];
|
|
}
|
|
}
|
|
$results[] = $result;
|
|
} else {
|
|
$results[] = $object;
|
|
}
|
|
} else {
|
|
$member_ids = array();
|
|
if (isset($object['member'])) {
|
|
foreach ($object['member'] as $member) {
|
|
if (isset($member['uid'])) {
|
|
$id = Horde_Url::uriB64Encode($member['uid']);
|
|
$found = false;
|
|
try {
|
|
$this->getObject($id);
|
|
$found = true;
|
|
} catch (Horde_Exception_NotFound $e) {
|
|
foreach (Turba::listShares() as $share) {
|
|
$driver = $GLOBALS['injector']
|
|
->getInstance('Turba_Factory_Driver')
|
|
->create($share->getName());
|
|
try {
|
|
$driver->getObject($id);
|
|
$id = $share->getName() . ':' . $id;
|
|
$found = true;
|
|
break;
|
|
} catch (Horde_Exception_NotFound $e) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if ($found) {
|
|
$member_ids[] = $id;
|
|
}
|
|
continue;
|
|
}
|
|
$display_name = $member['display-name'];
|
|
$smtp_address = $member['smtp-address'];
|
|
$criteria = array(
|
|
'AND' => array(
|
|
array(
|
|
'field' => 'full-name',
|
|
'op' => 'LIKE',
|
|
'test' => $display_name,
|
|
'begin' => false,
|
|
),
|
|
array(
|
|
'field' => 'emails',
|
|
'op' => 'LIKE',
|
|
'test' => $smtp_address,
|
|
'begin' => false,
|
|
),
|
|
),
|
|
);
|
|
$fields = array('uid');
|
|
|
|
// we expect only one result here!!!
|
|
$contacts = $this->_search($criteria, $fields);
|
|
|
|
// and drop everything else except the first search
|
|
// result
|
|
$member_ids[] = $contacts[0]['__key'];
|
|
}
|
|
$object['__members'] = serialize($member_ids);
|
|
unset($object['member']);
|
|
}
|
|
$results[] = $object;
|
|
}
|
|
}
|
|
|
|
if (!$results) {
|
|
throw new Horde_Exception_NotFound();
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Adds the specified contact to the addressbook.
|
|
*
|
|
* @param array $attributes The attribute values of the contact.
|
|
* @param array $blob_fields Fields that represent binary data.
|
|
* @param array $date_fields Fields that represent dates. @since 4.2.0
|
|
*
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _add(array $attributes, array $blob_fields = array(), array $date_fields = array())
|
|
{
|
|
$this->connect();
|
|
$this->_store($attributes);
|
|
}
|
|
|
|
protected function _canAdd()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Removes the specified object from the Kolab message store.
|
|
*/
|
|
protected function _delete($object_key, $object_id)
|
|
{
|
|
$this->connect();
|
|
|
|
if ($object_key == 'uid') {
|
|
$object_id = Horde_Url::uriB64Encode($object_id);
|
|
} elseif ($object_key != '__key') {
|
|
throw new Turba_Exception(sprintf('Key for deleting must be a UID or ID not %s!', $object_key));
|
|
}
|
|
|
|
if (!isset($this->_contacts_cache[$object_id])) {
|
|
throw new Turba_Exception(sprintf(_("Object with UID %s does not exist!"), $object_id));
|
|
}
|
|
|
|
$data = isset($this->_contacts_cache[$object_id]['__type']) &&
|
|
$this->_contacts_cache[$object_id]['__type'] == 'Group'
|
|
? $this->_getListData()
|
|
: $this->_getData();
|
|
|
|
$result = $data->delete($this->_contacts_cache[$object_id]['uid']);
|
|
|
|
/* Invalidate cache. */
|
|
$this->_connected = false;
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Deletes all contacts from a specific address book.
|
|
*
|
|
* @param string $sourceName The source to remove all contacts from.
|
|
*
|
|
* @return array An array of UIDs
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _deleteAll($sourceName = null)
|
|
{
|
|
$this->connect();
|
|
$uids = array_map(array('Horde_Url', 'uriB64Decode'), array_keys($this->_contacts_cache));
|
|
|
|
/* Delete contacts */
|
|
$this->_getData()->deleteAll();
|
|
$this->_getListData()->deleteAll();
|
|
|
|
return $uids;
|
|
}
|
|
|
|
/**
|
|
* Saves the specified object in the SQL database.
|
|
*
|
|
* @param Turba_Object $object The object to save
|
|
*
|
|
* @return string The object id, possibly updated.
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _save(Turba_Object $object)
|
|
{
|
|
$this->connect();
|
|
return $this->_store($this->toDriverKeys($object->getAttributes()),
|
|
$object->getValue('__uid'));
|
|
}
|
|
|
|
/**
|
|
* Stores an object in the Kolab message store.
|
|
*
|
|
* TODO
|
|
*
|
|
* @return string The object id, possibly updated.
|
|
* @throws Turba_Exception
|
|
*/
|
|
protected function _store($attributes, $object_id = null)
|
|
{
|
|
if (isset($attributes['__type']) && $attributes['__type'] == 'Group') {
|
|
$this->_convertMembers($attributes);
|
|
$data = $this->_getListData();
|
|
} else {
|
|
if (isset($attributes['photo']) && isset($attributes['phototype'])) {
|
|
$filename = 'photo.'
|
|
. Horde_Mime_Magic::mimeToExt($attributes['phototype']);
|
|
$attributes['_attachments'][$filename] = array(
|
|
'type' => $attributes['phototype'],
|
|
'content' => Horde_Stream_Wrapper_String::getStream($attributes['photo'])
|
|
);
|
|
$attributes['picture'] = $filename;
|
|
unset($attributes['photo'], $attributes['phototype']);
|
|
}
|
|
|
|
// EAS sets the date fields to '' instead of null -> fix it up
|
|
$fix_date_fields = array('birthday', 'anniversary');
|
|
foreach ($fix_date_fields as $fix_date) {
|
|
if (empty($attributes[$fix_date])) {
|
|
unset($attributes[$fix_date]);
|
|
}
|
|
}
|
|
$data = $this->_getData();
|
|
}
|
|
|
|
if ($object_id === null) {
|
|
$object_id = $data->create($attributes);
|
|
} else {
|
|
$data->modify($attributes);
|
|
}
|
|
|
|
/* Invalidate cache. */
|
|
$this->_connected = false;
|
|
|
|
return Horde_Url::uriB64Encode($object_id);
|
|
}
|
|
|
|
/**
|
|
* TODO
|
|
*/
|
|
protected function _convertMembers(&$attributes)
|
|
{
|
|
if (isset($attributes['__members'])) {
|
|
$member_ids = unserialize($attributes['__members']);
|
|
$attributes['member'] = array();
|
|
foreach ($member_ids as $member_id) {
|
|
$source_id = null;
|
|
if (strpos($member_id, ':')) {
|
|
list($source_id, $member_id) = explode(':', $member_id, 2);
|
|
}
|
|
$mail = array('uid' => Horde_Url::uriB64Decode($member_id));
|
|
$member = null;
|
|
if ($source_id) {
|
|
try {
|
|
$driver = $GLOBALS['injector']->getInstance('Turba_Factory_Driver')->create($source_id);
|
|
try {
|
|
$member = $driver->getObject($member_id);
|
|
$name = $member->getValue('name');
|
|
if (!empty($name)) {
|
|
$mail['display-name'] = $name;
|
|
}
|
|
$emails = $member->getValue('emails');
|
|
if ($emails) {
|
|
$emails = explode(',', $emails);
|
|
$mail['smtp-address'] = trim($emails[0]);
|
|
if (!isset($mail['display-name'])) {
|
|
$mail['display-name'] = $mail['smtp-address'];
|
|
}
|
|
}
|
|
} catch (Horde_Exception_NotFound $e) {
|
|
}
|
|
} catch (Turba_Exception $e) {
|
|
}
|
|
} elseif (isset($this->_contacts_cache[$member_id])) {
|
|
$member = $this->_contacts_cache[$member_id];
|
|
if (!empty($member['full-name'])) {
|
|
$mail['display-name'] = $member['full-name'];
|
|
}
|
|
if (!empty($member['emails'])) {
|
|
$emails = explode(',', $member['emails']);
|
|
$mail['smtp-address'] = trim($emails[0]);
|
|
if (!isset($mail['display-name'])) {
|
|
$mail['display-name'] = $mail['smtp-address'];
|
|
}
|
|
}
|
|
}
|
|
$attributes['member'][] = $mail;
|
|
}
|
|
unset($attributes['__members']);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Create an object key for a new object.
|
|
*
|
|
* @param array $attributes The attributes (in driver keys) of the
|
|
* object being added.
|
|
*
|
|
* @return string A unique ID for the new object.
|
|
*/
|
|
protected function _makeKey(array $attributes)
|
|
{
|
|
return Horde_Url::uriB64Encode(
|
|
isset($attributes['uid'])
|
|
? $attributes['uid']
|
|
: $this->_generateUid());
|
|
}
|
|
|
|
/**
|
|
* Creates an object UID for a new object.
|
|
*
|
|
* @return string A unique ID for the new object.
|
|
*/
|
|
protected function _makeUid()
|
|
{
|
|
return $this->_generateUid();
|
|
}
|
|
|
|
/**
|
|
* Create an object key for a new object.
|
|
*
|
|
* @return string A unique ID for the new object.
|
|
*/
|
|
protected function _generateUid()
|
|
{
|
|
return $this->_getData()->generateUID();
|
|
}
|
|
|
|
/**
|
|
* Creates a new Horde_Share for this source type.
|
|
*
|
|
* @param string $share_name The share name
|
|
* @param array $params The params for the share.
|
|
*
|
|
* @return Horde_Share The share object.
|
|
*/
|
|
public function createShare($share_name, array $params)
|
|
{
|
|
if (!isset($params['name'])) {
|
|
$params['name'] = _('Contacts');
|
|
}
|
|
if (!empty($params['params']['default'])) {
|
|
$params['default'] = true;
|
|
unset($params['params']['default']);
|
|
}
|
|
return Turba::createShare($share_name, $params);
|
|
}
|
|
|
|
/**
|
|
* Check if the passed in share is the default share for this source.
|
|
*
|
|
* @param Horde_Share_Object $share The share object.
|
|
* @param array $srcconfig The cfgSource entry for the share.
|
|
*
|
|
* @return boolean TODO
|
|
*/
|
|
public function checkDefaultShare(Horde_Share_Object $share,
|
|
array $srcconfig)
|
|
{
|
|
$params = @unserialize($share->get('params'));
|
|
return isset($params['default'])
|
|
? $params['default']
|
|
: false;
|
|
}
|
|
|
|
/**
|
|
* Runs any actions after setting a new default notepad.
|
|
*
|
|
* @param string $share The default share ID.
|
|
*/
|
|
public function setDefaultShare($share)
|
|
{
|
|
$addressbooks = $GLOBALS['injector']->getInstance('Turba_Shares')
|
|
->listShares(
|
|
$GLOBALS['registry']->getAuth(),
|
|
array('perm' => Horde_Perms::SHOW,
|
|
'attributes' => $GLOBALS['registry']->getAuth()));
|
|
foreach ($addressbooks as $id => $addressbook) {
|
|
if ($id == $share) {
|
|
$addressbook->set('default', true);
|
|
$addressbook->save();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|