Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
34 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/kolab_sync_data_contacts.php b/lib/kolab_sync_data_contacts.php
index 0562377..7038064 100644
--- a/lib/kolab_sync_data_contacts.php
+++ b/lib/kolab_sync_data_contacts.php
@@ -1,637 +1,637 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* COntacts data class for Syncroton
*/
class kolab_sync_data_contacts extends kolab_sync_data
{
/**
* Mapping from ActiveSync Contacts namespace fields
*/
protected $mapping = array(
'anniversary' => 'anniversary',
'assistantName' => 'assistant:0',
//'assistantPhoneNumber' => 'assistantphonenumber',
'birthday' => 'birthday',
'body' => 'notes',
'businessAddressCity' => 'address.work.locality',
'businessAddressCountry' => 'address.work.country',
'businessAddressPostalCode' => 'address.work.code',
'businessAddressState' => 'address.work.region',
'businessAddressStreet' => 'address.work.street',
'businessFaxNumber' => 'phone.workfax.number',
'businessPhoneNumber' => 'phone.work.number',
'carPhoneNumber' => 'phone.car.number',
//'categories' => 'categories',
'children' => 'children',
'companyName' => 'organization',
'department' => 'department',
//'email1Address' => 'email:0',
//'email2Address' => 'email:1',
//'email3Address' => 'email:2',
//'fileAs' => 'fileas', //@TODO: ?
'firstName' => 'firstname',
//'home2PhoneNumber' => 'home2phonenumber',
'homeAddressCity' => 'address.home.locality',
'homeAddressCountry' => 'address.home.country',
'homeAddressPostalCode' => 'address.home.code',
'homeAddressState' => 'address.home.region',
'homeAddressStreet' => 'address.home.street',
'homeFaxNumber' => 'phone.homefax.number',
'homePhoneNumber' => 'phone.home.number',
'jobTitle' => 'jobtitle',
'lastName' => 'surname',
'middleName' => 'middlename',
'mobilePhoneNumber' => 'phone.mobile.number',
//'officeLocation' => 'officelocation',
'otherAddressCity' => 'address.office.locality',
'otherAddressCountry' => 'address.office.country',
'otherAddressPostalCode' => 'address.office.code',
'otherAddressState' => 'address.office.region',
'otherAddressStreet' => 'address.office.street',
'pagerNumber' => 'phone.pager.number',
'picture' => 'photo',
//'radioPhoneNumber' => 'radiophonenumber',
//'rtf' => 'rtf',
'spouse' => 'spouse',
'suffix' => 'suffix',
'title' => 'prefix',
'webPage' => 'website.homepage.url',
//'yomiCompanyName' => 'yomicompanyname',
//'yomiFirstName' => 'yomifirstname',
//'yomiLastName' => 'yomilastname',
// Mapping from ActiveSync Contacts2 namespace fields
//'accountName' => 'accountname',
//'companyMainPhone' => 'companymainphone',
//'customerId' => 'customerid',
//'governmentId' => 'governmentid',
'iMAddress' => 'im:0',
'iMAddress2' => 'im:1',
'iMAddress3' => 'im:2',
'managerName' => 'manager:0',
//'mMS' => 'mms',
'nickName' => 'nickname',
);
/**
* Kolab object type
*
* @var string
*/
protected $modelName = 'contact';
/**
* Type of the default folder
*
* @var int
*/
protected $defaultFolderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT;
/**
* Default container for new entries
*
* @var string
*/
protected $defaultFolder = 'Contacts';
/**
* Type of user created folders
*
* @var int
*/
protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED;
/**
* Identifier of special Global Address List folder
*
* @var string
*/
protected $galFolder = 'GAL';
/**
* Name of special Global Address List folder
*
* @var string
*/
protected $galFolderName = 'Global Address Book';
protected $galPrefix = 'GAL:';
protected $galSources;
protected $galResult;
protected $galCache;
/**
* Creates model object
*
* @param Syncroton_Model_SyncCollection $collection Collection data
* @param string $serverId Local entry identifier
*/
public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId)
{
$data = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId);
$result = array();
if (empty($data)) {
throw new Syncroton_Exception_NotFound("Contact $serverId not found");
}
// Contacts namespace fields
foreach ($this->mapping as $key => $name) {
$value = $this->getKolabDataItem($data, $name);
switch ($name) {
case 'photo':
if ($value) {
// ActiveSync limits photo size to 48KB (of base64 encoded string)
if (strlen($value) * 1.33 > 48 * 1024) {
- continue;
+ continue 2;
}
}
break;
case 'birthday':
case 'anniversary':
$value = self::date_from_kolab($value);
break;
case 'notes':
$value = $this->body_from_kolab($value, $collection);
break;
}
if (empty($value) || is_array($value)) {
continue;
}
$result[$key] = $value;
}
// email address(es): email1Address, email2Address, email3Address
for ($x=0; $x<3; $x++) {
if ($email = $data['email'][$x]) {
if (is_array($email)) {
$email = $email['address'];
}
if ($email) {
$result['email' . ($x+1) . 'Address'] = $email;
}
}
}
return new Syncroton_Model_Contact($result);
}
/**
* convert contact from xml to libkolab array
*
* @param Syncroton_Model_IEntry $data Contact to convert
* @param string $folderId Folder identifier
* @param array $entry Existing entry
*
* @return array Kolab object array
*/
public function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null)
{
$contact = !empty($entry) ? $entry : array();
// Contacts namespace fields
foreach ($this->mapping as $key => $name) {
$value = $data->$key;
switch ($name) {
case 'address.work.street':
if (strtolower($this->device->devicetype) == 'palm') {
// palm pre sends the whole address in the <Contacts:BusinessStreet> tag
$value = null;
}
break;
case 'website.homepage.url':
// remove facebook urls
if (preg_match('/^fb:\/\//', $value)) {
$value = null;
}
break;
case 'notes':
$value = $this->getBody($value, Syncroton_Model_EmailBody::TYPE_PLAINTEXT);
// If note isn't specified keep old note
if ($value === null) {
continue 2;
}
break;
case 'photo':
// If photo isn't specified keep old photo
if ($value === null) {
continue 2;
}
break;
case 'birthday':
case 'anniversary':
if ($value) {
// convert date to string format, so libkolab will store
// it with no time and timezone what could be incorrectly re-calculated (#2555)
$value = $value->format('Y-m-d');
}
break;
}
$this->setKolabDataItem($contact, $name, $value);
}
// email address(es): email1Address, email2Address, email3Address
$emails = array();
for ($x=0; $x<3; $x++) {
$key = 'email' . ($x+1) . 'Address';
if ($value = $data->$key) {
// 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[] = array('address' => $value, 'type' => $type);
}
}
$contact['email'] = $emails;
return $contact;
}
/**
* Return list of supported folders for this backend
*
* @return array
*/
public function getAllFolders()
{
$list = parent::getAllFolders();
if ($this->isMultiFolder() && $this->hasGAL()) {
$list[$this->galFolder] = new Syncroton_Model_Folder(array(
'displayName' => $this->galFolderName, // @TODO: localization?
'serverId' => $this->galFolder,
'parentId' => 0,
'type' => 14,
));
}
return $list;
}
/**
* Updates a folder
*/
public function updateFolder(Syncroton_Model_IFolder $folder)
{
if ($folder->serverId === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Updating GAL folder is not possible");
}
return parent::updateFolder($folder);
}
/**
* Deletes a folder
*/
public function deleteFolder($folder)
{
if ($folder instanceof Syncroton_Model_IFolder) {
$folder = $folder->serverId;
}
if ($folder === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Deleting GAL folder is not possible");
}
return parent::deleteFolder($folder);
}
/**
* Empty folder (remove all entries and optionally subfolders)
*
* @param string $folderId Folder identifier
* @param array $options Options
*/
public function emptyFolderContents($folderid, $options)
{
if ($folderid === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Emptying GAL folder is not possible");
}
return parent::emptyFolderContents($folderid, $options);
}
/**
* Moves object into another location (folder)
*
* @param string $srcFolderId Source folder identifier
* @param string $serverId Object identifier
* @param string $dstFolderId Destination folder identifier
*
* @throws Syncroton_Exception_Status
* @return string New object identifier
*/
public function moveItem($srcFolderId, $serverId, $dstFolderId)
{
if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Moving GAL entries is not possible");
}
if ($srcFolderId === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Moving/Deleting GAL entries is not possible");
}
if ($dstFolderId === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Creating GAL entries is not possible");
}
return parent::moveItem($srcFolderId, $serverId, $dstFolderId);
}
/**
* Add entry
*
* @param string $folderId Folder identifier
* @param Syncroton_Model_IEntry $entry Entry object
*
* @return string ID of the created entry
*/
public function createEntry($folderId, Syncroton_Model_IEntry $entry)
{
if ($folderId === $this->galFolder && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Creating GAL entries is not possible");
}
return parent::createEntry($folderId, $entry);
}
/**
* update existing entry
*
* @param string $folderId
* @param string $serverId
* @param SimpleXMLElement $entry
*
* @return string ID of the updated entry
*/
public function updateEntry($folderId, $serverId, Syncroton_Model_IEntry $entry)
{
if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Updating GAL entries is not possible");
}
return parent::updateEntry($folderId, $serverId, $entry);
}
/**
* delete entry
*
* @param string $folderId
* @param string $serverId
* @param array $collectionData
*/
public function deleteEntry($folderId, $serverId, $collectionData)
{
if (strpos($serverId, $this->galPrefix) === 0 && $this->hasGAL()) {
throw new Syncroton_Exception_AccessDenied("Deleting GAL entries is not possible");
}
return parent::deleteEntry($folderId, $serverId, $collectionData);
}
/**
* Returns filter query array according to specified ActiveSync FilterType
*
* @param int $filter_type Filter type
*
* @param array Filter query
*/
protected function filter($filter_type = 0)
{
// specify object type, contact folders in Kolab might
// contain also ditribution-list objects, we'll skip them
return array(array('type', '=', $this->modelName));
}
/**
* Check if GAL synchronization is enabled for current device
*/
protected function hasGAL()
{
return count($this->getGALSources());
}
/**
* Search for existing entries
*
* @param string $folderid Folder identifier
* @param array $filter Search filter
* @param int $result_type Type of the result (see RESULT_* constants)
*
* @return array|int Search result as count or array of uids/objects
*/
protected function searchEntries($folderid, $filter = array(), $result_type = self::RESULT_UID)
{
// GAL Folder exists, return result from LDAP only
if ($folderid === $this->galFolder && $this->hasGAL()) {
return $this->searchGALEntries($filter, $result_type);
}
$result = parent::searchEntries($folderid, $filter, $result_type);
// Merge results from LDAP
if ($this->hasGAL() && !$this->isMultiFolder()) {
$gal_result = $this->searchGALEntries($filter, $result_type);
if ($result_type == self::RESULT_COUNT) {
$result += $gal_result;
}
else {
$result = array_merge($result, $gal_result);
}
}
return $result;
}
/**
* Fetches the entry from the backend
*/
protected function getObject($folderid, $entryid, &$folder = null)
{
if (strpos($entryid, $this->galPrefix) === 0 && $this->hasGAL()) {
return $this->getGALEntry($entryid);
}
return parent::getObject($folderid, $entryid, $folder);
}
/**
* Search for existing LDAP entries
*
* @param array $filter Search filter
* @param int $result_type Type of the result (see RESULT_* constants)
*
* @return array|int Search result as count or array of uids/objects
*/
protected function searchGALEntries($filter, $result_type)
{
// For GAL we don't check for changes.
// When something changed a new UID will be generated so the update
// will be done as delete + create
foreach ($filter as $f) {
if ($f[0] == 'changed') {
return $result_type == self::RESULT_COUNT ? 0 : array();
}
}
if ($this->galCache && ($result = $this->galCache->get('index')) !== null) {
$result = explode("\n", $result);
return $result_type == self::RESULT_COUNT ? count($result) : $result;
}
$result = array();
foreach ($this->getGALSources() as $source) {
if ($book = kolab_sync_data_gal::get_address_book($source['id'])) {
$book->reset();
$book->set_page(1);
$book->set_pagesize(10000);
$set = $book->list_records();
while ($contact = $set->next()) {
$result[] = $this->createGALEntryUID($contact, $source['id']);
}
}
}
if ($this->galCache) {
$this->galCache->set('index', implode("\n", $result));
}
return $result_type == self::RESULT_COUNT ? count($result) : $result;
}
/**
* Return specified LDAP entry
*
* @param string $serverId Entry identifier
*
* @return array Contact data
*/
protected function getGALEntry($serverId)
{
list($source, $timestamp, $uid) = $this->resolveGALEntryUID($serverId);
if ($source && $uid && ($book = kolab_sync_data_gal::get_address_book($source))) {
$book->reset();
$set = $book->search('uid', array($uid), rcube_addressbook::SEARCH_STRICT, true, true);
$result = $set->first();
if ($result['uid'] == $uid && $result['changed'] == $timestamp) {
// As in kolab_sync_data_gal we use only one email address
if (empty($result['email'])) {
$emails = $book->get_col_values('email', $result, true);
$result['email'] = array($emails[0]);
}
return $result;
}
}
}
/**
* Return LDAP address books list
*
* @return array Address books array
*/
protected function getGALSources()
{
if ($this->galSources === null) {
$rcube = rcube::get_instance();
$gal_sync = $rcube->config->get('activesync_gal_sync');
$enabled = false;
if ($gal_sync === true) {
$enabled = true;
}
else if (is_array($gal_sync)) {
$enabled = $this->deviceTypeFilter($gal_sync);
}
$this->galSources = $enabled ? kolab_sync_data_gal::get_address_sources() : array();
if ($cache_type = $rcube->config->get('activesync_gal_cache', 'db')) {
$cache_ttl = $rcube->config->get('activesync_gal_cache_ttl', '1d');
$this->galCache = $rcube->get_cache('activesync_gal', $cache_type, $cache_ttl, false);
// expunge cache every now and then
if (rand(0, 10) === 0) {
$this->galCache->expunge();
}
}
}
return $this->galSources;
}
/**
* Builds contact identifier from contact data and source id
*/
protected function createGALEntryUID($contact, $source_id)
{
return $this->galPrefix . sprintf('%s:%s:%s', rcube_ldap::dn_encode($source_id), $contact['changed'], $contact['uid']);
}
/**
* Extracts contact identification data from contact identifier
*/
protected function resolveGALEntryUID($uid)
{
if (strpos($uid, $this->galPrefix) === 0) {
$items = explode(':', substr($uid, strlen($this->galPrefix)));
$items[0] = rcube_ldap::dn_decode($items[0]);
return $items; // source, timestamp, uid
}
return array();
}
}
diff --git a/lib/kolab_sync_data_gal.php b/lib/kolab_sync_data_gal.php
index 09238f4..ca07087 100644
--- a/lib/kolab_sync_data_gal.php
+++ b/lib/kolab_sync_data_gal.php
@@ -1,390 +1,390 @@
<?php
/**
+--------------------------------------------------------------------------+
| Kolab Sync (ActiveSync for Kolab) |
| |
| Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com> |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU Affero General Public License as published |
| by the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/> |
+--------------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+--------------------------------------------------------------------------+
*/
/**
* GAL (Global Address List) data backend for Syncroton
*/
class kolab_sync_data_gal extends kolab_sync_data implements Syncroton_Data_IDataSearch
{
const MAX_SEARCH_RESULT = 100;
/**
* LDAP search result
*
* @var array
*/
protected $result = array();
/**
* LDAP address books list
*
* @var array
*/
public static $address_books = array();
/**
* Mapping from ActiveSync Contacts namespace fields
*/
protected $mapping = array(
'alias' => 'nickname',
'company' => 'organization',
'displayName' => 'name',
'emailAddress' => 'email',
'firstName' => 'firstname',
'lastName' => 'surname',
'mobilePhone' => 'phone.mobile',
'office' => 'office',
'picture' => 'photo',
'phone' => 'phone',
'title' => 'jobtitle',
);
/**
* Kolab object type
*
* @var string
*/
protected $modelName = 'contact';
/**
* Type of the default folder
*
* @var int
*/
protected $defaultFolderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT;
/**
* Default container for new entries
*
* @var string
*/
protected $defaultFolder = 'Contacts';
/**
* Type of user created folders
*
* @var int
*/
protected $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED;
/**
* the constructor
*
* @param Syncroton_Model_IDevice $device
* @param DateTime $syncTimeStamp
*/
public function __construct(Syncroton_Model_IDevice $device, DateTime $syncTimeStamp)
{
parent::__construct($device, $syncTimeStamp);
// Use configured fields mapping
$rcube = rcube::get_instance();
$fieldmap = (array) $rcube->config->get('activesync_gal_fieldmap');
if (!empty($fieldmap)) {
$fieldmap = array_intersec_key($fieldmap, array_keys($this->mapping));
$this->mapping = array_merge($this->mapping, $fieldmap);
}
}
/**
* Not used but required by parent class
*/
public function toKolab(Syncroton_Model_IEntry $data, $folderId, $entry = null)
{
}
/**
* Not used but required by parent class
*/
public function getEntry(Syncroton_Model_SyncCollection $collection, $serverId)
{
}
/**
* Returns properties of a contact for Search response
*
* @param array $data Contact data
* @param array $options Search options
*
* @return Syncroton_Model_GAL Contact (GAL) object
*/
public function getSearchEntry($data, $options)
{
$result = array();
// Contacts namespace fields
foreach ($this->mapping as $key => $name) {
$value = $this->getLDAPDataItem($data, $name);
if (empty($value) || is_array($value)) {
continue;
}
switch ($name) {
case 'photo':
// @TODO: MaxPictures option
// ActiveSync limits photo size of GAL contact to 100KB
$maxsize = 102400;
if (!empty($options['picture']['maxSize'])) {
$maxsize = min($maxsize, $options['picture']['maxSize']);
}
if (strlen($value) > $maxsize) {
- continue;
+ continue 2;
}
$value = new Syncroton_Model_GALPicture(array(
'data' => $value, // binary
'status' => Syncroton_Model_GALPicture::STATUS_SUCCESS,
));
break;
}
$result[$key] = $value;
}
return new Syncroton_Model_GAL($result);
}
/**
* ActiveSync Search handler
*
* @param Syncroton_Model_StoreRequest $store Search query parameters
*
* @return Syncroton_Model_StoreResponse Complete Search response
* @throws Exception
*/
public function search(Syncroton_Model_StoreRequest $store)
{
$options = $store->options;
$query = $store->query;
if (empty($query) || !is_string($query)) {
throw new Exception('Empty/invalid search request');
}
$records = array();
$rcube = rcube::get_instance();
// @TODO: caching with Options->RebuildResults support
$books = self::get_address_sources();
$mode = 2; // use prefix mode
$fields = $rcube->config->get('contactlist_fields');
if (empty($fields)) {
$fields = '*';
}
foreach ($books as $idx => $book) {
$book = self::get_address_book($idx);
if (!$book) {
continue;
}
$book->set_page(1);
$book->set_pagesize(self::MAX_SEARCH_RESULT);
$result = $book->search($fields, $query, $mode, true, true, 'email');
if (!$result->count) {
continue;
}
// get records
$result = $book->list_records();
while ($row = $result->next()) {
$row['sourceid'] = $idx;
// make sure 'email' item is there, convert all email:* into one
$row['email'] = $book->get_col_values('email', $row, true);
$key = $this->contact_key($row);
unset($row['_raw_attrib']); // save some memory, @TODO: do this in rcube_ldap
$records[$key] = $row;
}
// We don't want to search all sources if we've got already a lot of contacts
if (count($records) >= self::MAX_SEARCH_RESULT) {
break;
}
}
// sort the records
ksort($records, SORT_LOCALE_STRING);
$records = array_values($records);
$response = new Syncroton_Model_StoreResponse();
// Calculate requested range
$start = (int) $options['range'][0];
$limit = (int) $options['range'][1] + 1;
$total = count($records);
$response->total = $total;
// Get requested chunk of data set
if ($total) {
if ($start > $total) {
$start = $total;
}
if ($limit > $total) {
$limit = max($start+1, $total);
}
if ($start > 0 || $limit < $total) {
$records = array_slice($records, $start, $limit-$start);
}
$response->range = array($start, $start + count($records) - 1);
}
// Build result array, convert to ActiveSync format
foreach ($records as $idx => $rec) {
$response->result[] = new Syncroton_Model_StoreResponseResult(array(
'longId' => $rec['ID'],
'properties' => $this->getSearchEntry($rec, $options),
));
unset($records[$idx]);
}
return $response;
}
/**
* Return instance of the internal address book class
*
* @param string $id Address book identifier
*
* @return rcube_contacts Address book object
*/
public static function get_address_book($id)
{
$config = rcube::get_instance()->config;
$ldap_config = (array) $config->get('ldap_public');
// use existing instance
if (isset(self::$address_books[$id]) && (self::$address_books[$id] instanceof rcube_addressbook)) {
$book = self::$address_books[$id];
}
else if ($id && $ldap_config[$id]) {
$book = new rcube_ldap($ldap_config[$id], $config->get('ldap_debug'),
$config->mail_domain($_SESSION['storage_host']));
}
if (!$book) {
rcube::raise_error(array(
'code' => 700, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Addressbook source ($id) not found!"),
true, false);
return null;
}
/*
// set configured sort order
if ($sort_col = $this->config->get('addressbook_sort_col'))
$book->set_sort_order($sort_col);
*/
// add to the 'books' array for shutdown function
self::$address_books[$id] = $book;
return $book;
}
/**
* Return LDAP address books list
*
* @return array Address books array
*/
public static function get_address_sources()
{
$config = rcube::get_instance()->config;
$ldap_config = (array) $config->get('ldap_public');
$async_books = $config->get('activesync_addressbooks');
if ($async_books === null) {
$async_books = (array) $config->get('autocomplete_addressbooks');
}
$list = array();
foreach ((array)$async_books as $id) {
$prop = $ldap_config[$id];
if (!empty($prop) && is_array($prop)) {
$list[$id] = array(
'id' => $id,
'name' => $prop['name'],
);
}
}
return $list;
}
/**
* Creates contact key for sorting by
*/
protected function contact_key($row)
{
$key = $row['name'] . ':' . $row['sourceid'];
// add email to a key to not skip contacts with the same name
if (!empty($row['email'])) {
if (is_array($row['email'])) {
$key .= ':' . implode(':', $row['email']);
}
else {
$key .= ':' . $row['email'];
}
}
return $key;
}
/**
* Extracts data from Roundcube LDAP data array
*/
protected function getLDAPDataItem($data, $name)
{
list($name, $index) = explode(':', $name);
$name = str_replace('.', ':', $name);
if (isset($data[$name])) {
if ($index) {
return is_array($data[$name]) ? $data[$name][$index] : null;
}
return is_array($data[$name]) ? array_shift($data[$name]) : $data[$name];
}
return null;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Apr 24, 12:49 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18797352
Default Alt Text
(34 KB)

Event Timeline