Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120833486
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
34 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Apr 24, 12:49 PM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18797352
Default Alt Text
(34 KB)
Attached To
Mode
rS syncroton
Attached
Detach File
Event Timeline