2 commits - lib/ext lib/kolab_sync_backend.php lib/kolab_sync_data_email.php lib/kolab_sync_data_gal.php
Aleksander Machniak
machniak at kolabsys.com
Wed Sep 12 15:24:32 CEST 2012
lib/ext/Syncroton/Command/FolderSync.php | 2
lib/ext/Syncroton/Command/ItemOperations.php | 56 +++++++--
lib/ext/Syncroton/Command/Provision.php | 2
lib/ext/Syncroton/Command/Search.php | 48 ++------
lib/ext/Syncroton/Command/SendMail.php | 10 +
lib/ext/Syncroton/Command/SmartForward.php | 2
lib/ext/Syncroton/Command/SmartReply.php | 2
lib/ext/Syncroton/Command/Sync.php | 104 +++++++++++++----
lib/ext/Syncroton/Data/Contacts.php | 71 +++++++++++-
lib/ext/Syncroton/Data/IDataSearch.php | 7 -
lib/ext/Syncroton/Model/AEntry.php | 70 +++++++----
lib/ext/Syncroton/Model/Contact.php | 4
lib/ext/Syncroton/Model/Device.php | 3
lib/ext/Syncroton/Model/Email.php | 24 ++--
lib/ext/Syncroton/Model/EmailAttachment.php | 4
lib/ext/Syncroton/Model/EmailBody.php | 2
lib/ext/Syncroton/Model/IDevice.php | 13 ++
lib/ext/Syncroton/Model/IEntry.php | 21 +++
lib/ext/Syncroton/Model/StoreRequest.php | 2
lib/ext/Syncroton/Model/StoreResponse.php | 37 +++---
lib/ext/Syncroton/Registry.php | 2
lib/ext/Syncroton/Server.php | 3
lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php | 112 +++++++++----------
lib/ext/Syncroton/Wbxml/Encoder.php | 6 -
lib/kolab_sync_backend.php | 1
lib/kolab_sync_data_email.php | 102 +++++++++++------
lib/kolab_sync_data_gal.php | 73 +++++++-----
27 files changed, 504 insertions(+), 279 deletions(-)
New commits:
commit b9a488314de4423bb5525828409f8cde271151ea
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Sep 12 15:23:47 2012 +0200
Update Syncroton, update code for API changes
diff --git a/lib/ext/Syncroton/Command/FolderSync.php b/lib/ext/Syncroton/Command/FolderSync.php
index 9017798..99be44c 100644
--- a/lib/ext/Syncroton/Command/FolderSync.php
+++ b/lib/ext/Syncroton/Command/FolderSync.php
@@ -185,7 +185,7 @@ class Syncroton_Command_FolderSync extends Syncroton_Command_Wbxml
foreach($adds as $folder) {
$add = $changes->appendChild($this->_outputDom->createElementNS('uri:FolderHierarchy', 'Add'));
- $folder->appendXML($add);
+ $folder->appendXML($add, $this->_device);
// store folder in backend
if (empty($folder->id)) {
diff --git a/lib/ext/Syncroton/Command/ItemOperations.php b/lib/ext/Syncroton/Command/ItemOperations.php
index 7692970..a89bd5f 100644
--- a/lib/ext/Syncroton/Command/ItemOperations.php
+++ b/lib/ext/Syncroton/Command/ItemOperations.php
@@ -44,7 +44,8 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
if (isset($xml->Fetch)) {
foreach ($xml->Fetch as $fetch) {
$fetchArray = array(
- 'store' => (string)$fetch->Store
+ 'store' => (string)$fetch->Store,
+ 'options' => array()
);
// try to fetch element from namespace AirSync
@@ -55,6 +56,13 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
$fetchArray['serverId'] = (string)$airSync->ServerId;
}
+ // try to fetch element from namespace Search
+ $search = $fetch->children('uri:Search');
+
+ if (isset($search->LongId)) {
+ $fetchArray['longId'] = (string)$search->LongId;
+ }
+
// try to fetch element from namespace AirSyncBase
$airSyncBase = $fetch->children('uri:AirSyncBase');
@@ -66,15 +74,26 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
// try to fetch element from namespace AirSyncBase
$airSyncBase = $fetch->Options->children('uri:AirSyncBase');
- if (isset($airSyncBase->BodyPreference)) {
- // required
- $fetchArray['bodyPreferenceType'] = (int) $airSyncBase->BodyPreference->Type;
-
- // optional
- if (isset($airSyncBase->BodyPreference->TruncationSize)) {
- $fetchArray['truncationSize'] = (int) $airSyncBase->BodyPreference->TruncationSize;
- }
- }
+ if (isset($airSyncBase->BodyPreference)) {
+ foreach ($airSyncBase->BodyPreference as $bodyPreference) {
+ $type = (int) $bodyPreference->Type;
+ $fetchArray['options']['bodyPreferences'][$type] = array(
+ 'type' => $type
+ );
+
+ // optional
+ if (isset($bodyPreference->TruncationSize)) {
+ $fetchArray['options']['bodyPreferences'][$type]['truncationSize'] = (int) $bodyPreference->TruncationSize;
+ }
+
+ // optional
+ if (isset($bodyPreference->AllOrNone)) {
+ $fetchArray['options']['bodyPreferences'][$type]['allOrNone'] = (int) $bodyPreference->AllOrNone;
+ }
+ }
+ }
+
+
}
$this->_fetches[] = $fetchArray;
}
@@ -92,6 +111,7 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
// add aditional namespaces
$this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSyncBase' , 'uri:AirSyncBase');
$this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:AirSync' , 'uri:AirSync');
+ $this->_outputDom->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:Search' , 'uri:Search');
$itemOperations = $this->_outputDom->documentElement;
@@ -112,8 +132,18 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
$properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
$dataController
- ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['collectionId'])), $fetch['serverId'])
- ->appendXML($properties);
+ ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['collectionId'], 'options' => $fetch['options'])), $fetch['serverId'])
+ ->appendXML($properties, $this->_device);
+ $fetchTag->appendChild($properties);
+
+ } elseif (isset($fetch['longId'])) {
+ $fetchTag->appendChild($this->_outputDom->createElementNS('uri:ItemOperations', 'Status', Syncroton_Command_ItemOperations::STATUS_SUCCESS));
+ $fetchTag->appendChild($this->_outputDom->createElementNS('uri:Search', 'LongId', $fetch['longId']));
+
+ $properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
+ $dataController
+ ->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => $fetch['longId'], 'options' => $fetch['options'])), $fetch['longId'])
+ ->appendXML($properties, $this->_device);
$fetchTag->appendChild($properties);
} elseif (isset($fetch['fileReference'])) {
@@ -123,7 +153,7 @@ class Syncroton_Command_ItemOperations extends Syncroton_Command_Wbxml
$properties = $this->_outputDom->createElementNS('uri:ItemOperations', 'Properties');
$dataController
->getFileReference($fetch['fileReference'])
- ->appendXML($properties);
+ ->appendXML($properties, $this->_device);
$fetchTag->appendChild($properties);
}
} catch (Syncroton_Exception_NotFound $e) {
diff --git a/lib/ext/Syncroton/Command/Provision.php b/lib/ext/Syncroton/Command/Provision.php
index c4e582b..417267c 100644
--- a/lib/ext/Syncroton/Command/Provision.php
+++ b/lib/ext/Syncroton/Command/Provision.php
@@ -126,7 +126,7 @@ class Syncroton_Command_Provision extends Syncroton_Command_Wbxml
$easProvisionDoc = $data->appendChild($this->_outputDom->createElementNS('uri:Provision', 'EASProvisionDoc'));
$this->_policyBackend
->get($this->_device->policyId)
- ->appendXML($easProvisionDoc);
+ ->appendXML($easProvisionDoc, $this->_device);
}
$this->_deviceBackend->update($this->_device);
diff --git a/lib/ext/Syncroton/Command/Search.php b/lib/ext/Syncroton/Command/Search.php
index ccef6ab..cf9eddd 100644
--- a/lib/ext/Syncroton/Command/Search.php
+++ b/lib/ext/Syncroton/Command/Search.php
@@ -56,46 +56,22 @@ class Syncroton_Command_Search extends Syncroton_Command_Wbxml
throw new RuntimeException('class must be instanceof Syncroton_Data_IDataSearch');
}
- $storeResponse = new Syncroton_Model_StoreResponse(array(
- 'status' => self::STATUS_SUCCESS,
- ));
-
try {
$options = $this->_store->options;
// Search
- $results = $dataController->search($this->_store->query, $options);
-
- // Calculate requested range
- $start = $options['range'][0];
- $limit = $options['range'][1] + 1;
- $total = count($results);
- $storeResponse->total = $total;
-
- if ($total) {
- if ($start > $total) {
- $start = $total;
- }
- if ($limit > $total) {
- $limit = max($start+1, $total);
- }
-
- if ($start > 0 || $limit < $total) {
- $results = array_slice($results, $start, $limit-$start);
- }
-
- $storeResponse->range = array($start, $start + count($results) - 1);
- }
-
- foreach ($results as $result) {
- if (empty($result->properties)) {
- $result->properties = $dataController->getSearchEntry($result->longId, $this->_store->options);
- }
-
- $storeResponse->result[] = $result;
- }
+ $storeResponse = $dataController->search($this->_store);
+ $storeResponse->status = self::STATUS_SUCCESS;
+
} catch (Exception $e) {
- $storeResponse->status = self::STATUS_SERVER_ERROR;
+ if ($this->_logger instanceof Zend_Log)
+ $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " search exception: " . $e->getMessage());
+ if ($this->_logger instanceof Zend_Log)
+ $this->_logger->debug(__METHOD__ . '::' . __LINE__ . " saerch exception trace : " . $e->getTraceAsString());
+
+ $storeResponse = new Syncroton_Model_StoreResponse(array(
+ 'status' => self::STATUS_SERVER_ERROR
+ ));
}
$search = $this->_outputDom->documentElement;
@@ -105,7 +81,7 @@ class Syncroton_Command_Search extends Syncroton_Command_Wbxml
$response = $search->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Response'));
$store = $response->appendChild($this->_outputDom->createElementNS($this->_defaultNameSpace, 'Store'));
- $storeResponse->appendXML($store);
+ $storeResponse->appendXML($store, $this->_device);
return $this->_outputDom;
}
diff --git a/lib/ext/Syncroton/Command/SendMail.php b/lib/ext/Syncroton/Command/SendMail.php
index d1875a2..603a61f 100644
--- a/lib/ext/Syncroton/Command/SendMail.php
+++ b/lib/ext/Syncroton/Command/SendMail.php
@@ -34,9 +34,13 @@ class Syncroton_Command_SendMail extends Syncroton_Command_Wbxml
if ($this->_requestParameters['contentType'] == 'message/rfc822') {
$this->_mime = $this->_requestBody;
$this->_saveInSent = $this->_requestParameters['saveInSent'] == 'T';
+ $this->_replaceMime = false;
- $this->_collectionId = $this->_requestParameters['collectionId'];
- $this->_itemId = $this->_requestParameters['itemId'];
+ $this->_source = array(
+ 'collectionId' => $this->_requestParameters['collectionId'],
+ 'itemId' => $this->_requestParameters['itemId'],
+ 'instanceId' => null
+ );
} else {
$xml = simplexml_import_dom($this->_requestBody);
@@ -81,7 +85,7 @@ class Syncroton_Command_SendMail extends Syncroton_Command_Wbxml
'status' => $ses->getCode(),
));
- $response->appendXML($this->_outputDom->documentElement);
+ $response->appendXML($this->_outputDom->documentElement, $this->_device);
return $this->_outputDom;
}
diff --git a/lib/ext/Syncroton/Command/SmartForward.php b/lib/ext/Syncroton/Command/SmartForward.php
index aeedff4..4a9d841 100644
--- a/lib/ext/Syncroton/Command/SmartForward.php
+++ b/lib/ext/Syncroton/Command/SmartForward.php
@@ -39,7 +39,7 @@ class Syncroton_Command_SmartForward extends Syncroton_Command_SendMail
'status' => $ses->getCode(),
));
- $response->appendXML($this->_outputDom->documentElement);
+ $response->appendXML($this->_outputDom->documentElement, $this->_device);
return $this->_outputDom;
}
diff --git a/lib/ext/Syncroton/Command/SmartReply.php b/lib/ext/Syncroton/Command/SmartReply.php
index 5778581..59149ee 100644
--- a/lib/ext/Syncroton/Command/SmartReply.php
+++ b/lib/ext/Syncroton/Command/SmartReply.php
@@ -39,7 +39,7 @@ class Syncroton_Command_SmartReply extends Syncroton_Command_SendMail
'status' => $ses->getCode(),
));
- $response->appendXML($this->_outputDom->documentElement);
+ $response->appendXML($this->_outputDom->documentElement, $this->_device);
return $this->_outputDom;
}
diff --git a/lib/ext/Syncroton/Command/Sync.php b/lib/ext/Syncroton/Command/Sync.php
index 74ad41d..ea28966 100644
--- a/lib/ext/Syncroton/Command/Sync.php
+++ b/lib/ext/Syncroton/Command/Sync.php
@@ -105,6 +105,8 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
protected $_maxWindowSize = 100;
+ protected $_heartbeatInterval = null;
+
/**
* process the XML file and add, change, delete or fetches data
*/
@@ -113,6 +115,12 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
// input xml
$xml = simplexml_import_dom($this->_requestBody);
+ if (isset($xml->HeartbeatInterval)) {
+ $this->_heartbeatInterval = (int)$xml->HeartbeatInterval;
+ } elseif (isset($xml->Wait)) {
+ $this->_heartbeatInterval = (int)$xml->Wait * 60;
+ }
+
$this->_globalWindowSize = isset($xml->WindowSize) ? (int)$xml->WindowSize : 100;
if ($this->_globalWindowSize > $this->_maxWindowSize) {
@@ -368,6 +376,38 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$totalChanges = 0;
+ // continue only if there are changes or no time is left
+ if ($this->_heartbeatInterval > 0) {
+ $intervalStart = time();
+
+ do {
+ foreach($this->_collections as $collectionData) {
+ // countinue immediately if folder does not exist
+ if (! ($collectionData->folder instanceof Syncroton_Model_IFolder)) {
+ break 2;
+
+ // countinue immediately if syncstate is invalid
+ } elseif (! ($collectionData->syncState instanceof Syncroton_Model_ISyncState)) {
+ break 2;
+
+ } else {
+ $dataController = Syncroton_Data_Factory::factory($collectionData->folder->class , $this->_device, $this->_syncTimeStamp);
+
+ $estimate = $dataController->getCountOfChanges($this->_contentStateBackend, $collectionData->folder, $collectionData->syncState);
+
+ // countinue immediately if there are changes available
+ if ($estimate > 0) {
+ break 2;
+ }
+ }
+ }
+
+ // wait some PING_TIMEOUT seconds until neext loop
+ sleep(Syncroton_Command_Ping::PING_TIMEOUT);
+
+ } while (time() - $intervalStart < $this->_heartbeatInterval);
+ }
+
foreach($this->_collections as $collectionData) {
$collectionChanges = 0;
@@ -472,19 +512,15 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$this->_logger->info(__METHOD__ . '::' . __LINE__ . " found (added/changed/deleted) " . count($serverModifications['added']) . '/' . count($serverModifications['changed']) . '/' . count($serverModifications['deleted']) . ' entries for sync from server to client');
}
-
- if (!empty($clientModifications['added']) || !empty($clientModifications['changed']) || !empty($clientModifications['deleted']) ||
- !empty($serverModifications['added']) || !empty($serverModifications['changed']) || !empty($serverModifications['deleted'])) {
- $collectionData->syncState->counter++;
- }
-
// collection header
$collection = $collections->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Collection'));
if (!empty($collectionData->folder->class)) {
$collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Class', $collectionData->folder->class));
}
- $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey', $collectionData->syncState->counter));
+
+ $syncKeyNode = $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'SyncKey'));
+
$collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'CollectionId', $collectionData->collectionId));
$collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS));
@@ -525,7 +561,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$dataController
->getEntry($collectionData, $serverId)
- ->appendXML($applicationData);
+ ->appendXML($applicationData, $this->_device);
$fetch->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'Status', self::STATUS_SUCCESS));
@@ -552,7 +588,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$newContentStates = array();
foreach($serverModifications['added'] as $id => $serverId) {
- if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
+ if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) {
break;
}
@@ -584,7 +620,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$dataController
->getEntry($collectionData, $serverId)
- ->appendXML($applicationData);
+ ->appendXML($applicationData, $this->_device);
$commands->appendChild($add);
@@ -600,7 +636,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
'folder_id' => $collectionData->folder,
'contentid' => $serverId,
'creation_time' => $this->_syncTimeStamp,
- 'creation_synckey' => $collectionData->syncState->counter
+ 'creation_synckey' => $collectionData->syncState->counter + 1
));
unset($serverModifications['added'][$id]);
}
@@ -609,7 +645,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
* process entries changed on server side
*/
foreach($serverModifications['changed'] as $id => $serverId) {
- if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
+ if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) {
break;
}
@@ -621,7 +657,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$dataController
->getEntry($collectionData, $serverId)
- ->appendXML($applicationData);
+ ->appendXML($applicationData, $this->_device);
$commands->appendChild($change);
@@ -641,7 +677,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$deletedContentStates = array();
foreach($serverModifications['deleted'] as $id => $serverId) {
- if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges === $this->_globalWindowSize) {
+ if($collectionChanges === $collectionData->windowSize || $totalChanges + $collectionChanges >= $this->_globalWindowSize) {
break;
}
@@ -665,18 +701,38 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
unset($serverModifications['deleted'][$id]);
}
- if ($commands->hasChildNodes() === true) {
+ $countOfPendingChanges = (count($serverModifications['added']) + count($serverModifications['changed']) + count($serverModifications['deleted']));
+ if ($countOfPendingChanges > 0) {
+ $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
+ } else {
+ $serverModifications = null;
+ }
- $countOfPendingChanges = (count($serverModifications['added']) + count($serverModifications['changed']) + count($serverModifications['deleted']));
- if ($countOfPendingChanges > 0) {
- $collection->appendChild($this->_outputDom->createElementNS('uri:AirSync', 'MoreAvailable'));
- }
-
+ if ($commands->hasChildNodes() === true) {
$collection->appendChild($commands);
}
$totalChanges += $collectionChanges;
+ // increase SyncKey if needed
+ if ((
+ // sent the clients updates?
+ !empty($clientModifications['added']) ||
+ !empty($clientModifications['changed']) ||
+ !empty($clientModifications['deleted'])
+ ) || (
+ // sends the server updates to the client?
+ $commands->hasChildNodes() === true
+ ) || (
+ // changed the pending data?
+ $collectionData->syncState->pendingdata != $serverModifications
+ )
+ ) {
+ // then increase SyncKey
+ $collectionData->syncState->counter++;
+ }
+ $syncKeyNode->appendChild($this->_outputDom->createTextNode($collectionData->syncState->counter));
+
if ($this->_logger instanceof Zend_Log)
$this->_logger->info(__METHOD__ . '::' . __LINE__ . " new synckey is ". $collectionData->syncState->counter);
}
@@ -684,9 +740,6 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
if (isset($collectionData->syncState) && $collectionData->syncState instanceof Syncroton_Model_ISyncState &&
$collectionData->syncState->counter != $collectionData->syncKey) {
- // increment sync timestamp by 1 second
- $this->_syncTimeStamp->modify('+1 sec');
-
// store pending data in sync state when needed
if(isset($countOfPendingChanges) && $countOfPendingChanges > 0) {
$collectionData->syncState->pendingdata = array(
@@ -707,7 +760,9 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
$keepPreviousSyncKey = true;
}
- $collectionData->syncState->lastsync = $this->_syncTimeStamp;
+ $collectionData->syncState->lastsync = clone $this->_syncTimeStamp;
+ // increment sync timestamp by 1 second
+ $collectionData->syncState->lastsync->modify('+1 sec');
try {
$transactionId = Syncroton_Registry::getTransactionManager()->startTransaction(Syncroton_Registry::getDatabase());
@@ -718,6 +773,7 @@ class Syncroton_Command_Sync extends Syncroton_Command_Wbxml
// store contentstates for new entries added to client
if (isset($newContentStates)) {
foreach($newContentStates as $state) {
+ #$state->creation_synckey = $collectionData->syncState->counter;
$this->_contentStateBackend->create($state);
}
}
diff --git a/lib/ext/Syncroton/Data/Contacts.php b/lib/ext/Syncroton/Data/Contacts.php
index 1b8718a..1f191c2 100644
--- a/lib/ext/Syncroton/Data/Contacts.php
+++ b/lib/ext/Syncroton/Data/Contacts.php
@@ -37,24 +37,40 @@ class Syncroton_Data_Contacts extends Syncroton_Data_AData implements Syncroton_
* (non-PHPdoc)
* @see Syncroton_Data_IDataSearch::search()
*/
- public function search($query, $options)
+ public function search(Syncroton_Model_StoreRequest $store)
{
- $found = array();
+ $storeResponse = new Syncroton_Model_StoreResponse();
$serverIds = $this->getServerEntries('addressbookFolderId', Syncroton_Command_Sync::FILTER_NOTHING);
+ $total = 0;
+ $found = array();
+
foreach ($serverIds as $serverId) {
$contact = $this->getEntry(new Syncroton_Model_SyncCollection(array('collectionId' => 'addressbookFolderId')), $serverId);
- if ($contact->firstName == $query) {
+ if ($contact->firstName == $store->query) {
+ $total++;
+
+ if (count($found) == $store->options['range'][1]+1) {
+ continue;
+ }
$found[] = new Syncroton_Model_StoreResponseResult(array(
'longId' => 'addressbookFolderId-' . $serverId,
- 'properties' => $this->getSearchEntry('addressbookFolderId-' . $serverId, $options)
+ 'properties' => $this->getSearchEntry('addressbookFolderId-' . $serverId, $store->options)
));
}
}
- return $found;
+ if (count($found) > 0) {
+ $storeResponse->result = $found;
+ $storeResponse->range = array(0, count($found) - 1);
+ $storeResponse->total = $total;
+ } else {
+ $storeResponse->total = $total;
+ }
+
+ return $storeResponse;
}
protected function _initData()
@@ -129,12 +145,57 @@ class Syncroton_Data_Contacts extends Syncroton_Data_AData implements Syncroton_
'firstName' => 'Cornelius',
'lastName' => 'WeiÃ'
))
+ ),
+ 'anotherAddressbookFolderId' => array(
+ 'contact1' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Lars',
+ 'lastName' => 'Kneschke'
+ )),
+ 'contact2' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Cornelius',
+ 'lastName' => 'WeiÃ'
+ )),
+ 'contact3' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Lars',
+ 'lastName' => 'Kneschke'
+ )),
+ 'contact4' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Cornelius',
+ 'lastName' => 'WeiÃ'
+ )),
+ 'contact5' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Lars',
+ 'lastName' => 'Kneschke'
+ )),
+ 'contact6' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Cornelius',
+ 'lastName' => 'WeiÃ'
+ )),
+ 'contact7' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Lars',
+ 'lastName' => 'Kneschke'
+ )),
+ 'contact8' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Cornelius',
+ 'lastName' => 'WeiÃ'
+ )),
+ 'contact9' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Lars',
+ 'lastName' => 'Kneschke'
+ )),
+ 'contact10' => new Syncroton_Model_Contact(array(
+ 'firstName' => 'Cornelius',
+ 'lastName' => 'WeiÃ'
+ ))
)
);
foreach ($testData['addressbookFolderId'] as $data) {
$this->createEntry('addressbookFolderId', $data);
}
+ foreach ($testData['anotherAddressbookFolderId'] as $data) {
+ $this->createEntry('anotherAddressbookFolderId', $data);
+ }
}
}
}
diff --git a/lib/ext/Syncroton/Data/IDataSearch.php b/lib/ext/Syncroton/Data/IDataSearch.php
index 025a9f8..d499efe 100644
--- a/lib/ext/Syncroton/Data/IDataSearch.php
+++ b/lib/ext/Syncroton/Data/IDataSearch.php
@@ -31,10 +31,9 @@ interface Syncroton_Data_IDataSearch
/**
* Search command handler
*
- * @param array $query Search query parameters
- * @param array $options Search options
+ * @param Syncroton_Model_StoreRequest $store Search query parameters
*
- * @return array List of Syncroton_Model_StoreResponseResult
+ * @return Syncroton_Model_StoreResponse
*/
- public function search($query, $options);
+ public function search(Syncroton_Model_StoreRequest $store);
}
diff --git a/lib/ext/Syncroton/Model/AEntry.php b/lib/ext/Syncroton/Model/AEntry.php
index 21e2e3c..ed8c496 100644
--- a/lib/ext/Syncroton/Model/AEntry.php
+++ b/lib/ext/Syncroton/Model/AEntry.php
@@ -26,6 +26,10 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
protected $_dateTimeFormat = "Y-m-d\TH:i:s.000\Z";
+ /**
+ * (non-PHPdoc)
+ * @see Syncroton_Model_IEntry::__construct()
+ */
public function __construct($properties = null)
{
if ($properties instanceof SimpleXMLElement) {
@@ -39,9 +43,9 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
* (non-PHPdoc)
* @see Syncroton_Model_IEntry::appendXML()
*/
- public function appendXML(DOMElement $_domParrent)
+ public function appendXML(DOMElement $domParrent, Syncroton_Model_IDevice $device)
{
- $this->_addXMLNamespaces($_domParrent);
+ $this->_addXMLNamespaces($domParrent);
foreach($this->_elements as $elementName => $value) {
// skip empty values
@@ -55,25 +59,31 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
continue;
}
+ $elementVersion = isset($elementProperties['supportedSince']) ? $elementProperties['supportedSince'] : '12.0';
+
+ if (version_compare($device->acsversion, $elementVersion, '<')) {
+ continue;
+ }
+
$nameSpace = 'uri:' . $nameSpace;
if (isset($elementProperties['childElement'])) {
- $element = $_domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName));
+ $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName));
foreach($value as $subValue) {
- $subElement = $_domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementProperties['childElement']));
+ $subElement = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementProperties['childElement']));
- $this->_appendXMLElement($subElement, $elementProperties, $subValue);
+ $this->_appendXMLElement($device, $subElement, $elementProperties, $subValue);
$element->appendChild($subElement);
}
- $_domParrent->appendChild($element);
+ $domParrent->appendChild($element);
} else {
- $element = $_domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName));
+ $element = $domParrent->ownerDocument->createElementNS($nameSpace, ucfirst($elementName));
- $this->_appendXMLElement($element, $elementProperties, $value);
+ $this->_appendXMLElement($device, $element, $elementProperties, $value);
- $_domParrent->appendChild($element);
+ $domParrent->appendChild($element);
}
}
@@ -113,6 +123,10 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
}
+ /**
+ * (non-PHPdoc)
+ * @see Syncroton_Model_IEntry::setFromArray()
+ */
public function setFromArray(array $properties)
{
$this->_elements = array();
@@ -155,45 +169,46 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
/**
* add needed xml namespaces to DomDocument
*
- * @param unknown_type $_domParrent
+ * @param unknown_type $domParrent
*/
- protected function _addXMLNamespaces(DOMElement $_domParrent)
+ protected function _addXMLNamespaces(DOMElement $domParrent)
{
foreach($this->_properties as $namespace => $namespaceProperties) {
// don't add default namespace again
- if($_domParrent->ownerDocument->documentElement->namespaceURI != 'uri:'.$namespace) {
- $_domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:'.$namespace, 'uri:'.$namespace);
+ if($domParrent->ownerDocument->documentElement->namespaceURI != 'uri:'.$namespace) {
+ $domParrent->ownerDocument->documentElement->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:'.$namespace, 'uri:'.$namespace);
}
}
}
- protected function _appendXMLElement(DOMElement $element, $elementProperties, $value)
+ protected function _appendXMLElement(Syncroton_Model_IDevice $device, DOMElement $element, $elementProperties, $value)
{
if ($value instanceof Syncroton_Model_IEntry) {
- $value->appendXML($element);
+ $value->appendXML($element, $device);
} else {
if ($value instanceof DateTime) {
$value = $value->format($this->_dateTimeFormat);
} elseif (isset($elementProperties['encoding']) && $elementProperties['encoding'] == 'base64') {
if (is_resource($value)) {
- stream_filter_append($value, 'convert.base64-encode');
+ rewind($value);
$value = stream_get_contents($value);
- } else {
- $value = base64_encode($value);
}
+ $value = base64_encode($value);
}
- // strip off any non printable control characters
- if (!ctype_print($value)) {
- $value = $this->_removeControlChars($value);
- }
-
if ($elementProperties['type'] == 'byteArray') {
- $element->setAttributeNS('uri:Syncroton', 'Syncroton:encoding', 'oqaque');
- }
-
- $element->appendChild($element->ownerDocument->createTextNode($value));
+ $element->setAttributeNS('uri:Syncroton', 'Syncroton:encoding', 'opaque');
+ // encode to base64; the wbxml encoder will base64_decode it again
+ // this way we can also transport data, which would break the xmlparser otherwise
+ $element->appendChild($element->ownerDocument->createCDATASection(base64_encode($value)));
+ } else {
+ // strip off any non printable control characters
+ if (!ctype_print($value)) {
+ $value = $this->_removeControlChars($value);
+ }
+ $element->appendChild($element->ownerDocument->createTextNode($value));
+ }
}
}
@@ -208,7 +223,6 @@ abstract class Syncroton_Model_AEntry implements Syncroton_Model_IEntry, Iterato
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', null, $dirty);
}
-
/**
*
* @param unknown_type $element
diff --git a/lib/ext/Syncroton/Model/Contact.php b/lib/ext/Syncroton/Model/Contact.php
index 047628f..16485c2 100644
--- a/lib/ext/Syncroton/Model/Contact.php
+++ b/lib/ext/Syncroton/Model/Contact.php
@@ -33,7 +33,7 @@ class Syncroton_Model_Contact extends Syncroton_Model_AEntry
'body' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailBody')
),
'Contacts' => array(
- 'alias' => array('type' => 'string'),
+ 'alias' => array('type' => 'string', 'supportedSince' => '14.0'),
'anniversary' => array('type' => 'datetime'),
'assistantName' => array('type' => 'string'),
'assistantPhoneNumber' => array('type' => 'string'),
@@ -82,7 +82,7 @@ class Syncroton_Model_Contact extends Syncroton_Model_AEntry
'suffix' => array('type' => 'string'),
'title' => array('type' => 'string'),
'webPage' => array('type' => 'string'),
- 'weightedRank' => array('type' => 'string'),
+ 'weightedRank' => array('type' => 'string', 'supportedSince' => '14.0'),
'yomiCompanyName' => array('type' => 'string'),
'yomiFirstName' => array('type' => 'string'),
'yomiLastName' => array('type' => 'string'),
diff --git a/lib/ext/Syncroton/Model/Device.php b/lib/ext/Syncroton/Model/Device.php
index 5e382c6..3a0fdd6 100644
--- a/lib/ext/Syncroton/Model/Device.php
+++ b/lib/ext/Syncroton/Model/Device.php
@@ -14,13 +14,12 @@
*
* @package Model
*/
-
class Syncroton_Model_Device implements Syncroton_Model_IDevice
{
const TYPE_IPHONE = 'iphone';
const TYPE_WEBOS = 'webos';
const TYPE_ANDROID = 'android';
- const TYPE_ANDROID_40 = 'android40';
+ const TYPE_ANDROID_40 = 'android40';
const TYPE_SMASUNGGALAXYS2 = 'samsunggti9100'; // Samsung Galaxy S-3
public function __construct(array $_data = array())
diff --git a/lib/ext/Syncroton/Model/Email.php b/lib/ext/Syncroton/Model/Email.php
index 1e74a70..65cb674 100644
--- a/lib/ext/Syncroton/Model/Email.php
+++ b/lib/ext/Syncroton/Model/Email.php
@@ -33,7 +33,7 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
),
'Email' => array(
'busyStatus' => array('type' => 'number'),
- 'categories' => array('type' => 'container', 'childElement' => 'category'),
+ 'categories' => array('type' => 'container', 'childElement' => 'category', 'supportedSince' => '14.0'),
'cc' => array('type' => 'string'),
'completeTime' => array('type' => 'datetime'),
'contentClass' => array('type' => 'string'),
@@ -42,7 +42,7 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
'displayTo' => array('type' => 'string'),
'dTStamp' => array('type' => 'datetime'),
'endTime' => array('type' => 'datetime'),
- 'flag' => array('type' => 'container'),
+ 'flag' => array('type' => 'container', 'class' => 'Syncroton_Model_EmailFlag'),
'from' => array('type' => 'string'),
'globalObjId' => array('type' => 'string'),
'importance' => array('type' => 'number'),
@@ -66,16 +66,16 @@ class Syncroton_Model_Email extends Syncroton_Model_AEntry
'to' => array('type' => 'string'),
),
'Email2' => array(
- 'accountId' => array('type' => 'string'),
- 'conversationId' => array('type' => 'byteArray'), // @todo handle this
- 'conversationIndex' => array('type' => 'byteArray'), // @todo handle this
- 'lastVerbExecuted' => array('type' => 'number'),
- 'lastVerbExecutionTime' => array('type' => 'datetime'),
- 'meetingMessageType' => array('type' => 'number'),
- 'receivedAsBcc' => array('type' => 'number'),
- 'sender' => array('type' => 'string'),
- 'umCallerID' => array('type' => 'string'),
- 'umUserNotes' => array('type' => 'string'),
+ 'accountId' => array('type' => 'string', 'supportedSince' => '14.1'),
+ 'conversationId' => array('type' => 'byteArray', 'supportedSince' => '14.0'),
+ 'conversationIndex' => array('type' => 'byteArray', 'supportedSince' => '14.0'),
+ 'lastVerbExecuted' => array('type' => 'number', 'supportedSince' => '14.0'),
+ 'lastVerbExecutionTime' => array('type' => 'datetime', 'supportedSince' => '14.0'),
+ 'meetingMessageType' => array('type' => 'number', 'supportedSince' => '14.1'),
+ 'receivedAsBcc' => array('type' => 'number', 'supportedSince' => '14.0'),
+ 'sender' => array('type' => 'string', 'supportedSince' => '14.0'),
+ 'umCallerID' => array('type' => 'string', 'supportedSince' => '14.0'),
+ 'umUserNotes' => array('type' => 'string', 'supportedSince' => '14.0'),
),
);
}
diff --git a/lib/ext/Syncroton/Model/EmailAttachment.php b/lib/ext/Syncroton/Model/EmailAttachment.php
index 59f0360..e415ad4 100644
--- a/lib/ext/Syncroton/Model/EmailAttachment.php
+++ b/lib/ext/Syncroton/Model/EmailAttachment.php
@@ -34,8 +34,8 @@ class Syncroton_Model_EmailAttachment extends Syncroton_Model_AEntry
'method' => array('type' => 'string'),
),
'Email2' => array(
- 'umAttDuration' => array('type' => 'number'),
- 'umAttOrder' => array('type' => 'number'),
+ 'umAttDuration' => array('type' => 'number', 'supportedSince' => '14.0'),
+ 'umAttOrder' => array('type' => 'number', 'supportedSince' => '14.0'),
),
);
}
\ No newline at end of file
diff --git a/lib/ext/Syncroton/Model/EmailBody.php b/lib/ext/Syncroton/Model/EmailBody.php
index 92a886b..3b0f16b 100644
--- a/lib/ext/Syncroton/Model/EmailBody.php
+++ b/lib/ext/Syncroton/Model/EmailBody.php
@@ -36,7 +36,7 @@ class Syncroton_Model_EmailBody extends Syncroton_Model_AEntry
'data' => array('type' => 'string'),
'truncated' => array('type' => 'number'),
'part' => array('type' => 'number'),
- 'preview' => array('type' => 'string'),
+ 'preview' => array('type' => 'string', 'supportedSince' => '14.0'),
),
);
}
\ No newline at end of file
diff --git a/lib/ext/Syncroton/Model/IDevice.php b/lib/ext/Syncroton/Model/IDevice.php
index e2c347e..b1177cb 100644
--- a/lib/ext/Syncroton/Model/IDevice.php
+++ b/lib/ext/Syncroton/Model/IDevice.php
@@ -24,8 +24,19 @@
* @property string pinglifetime
* @property string remotewipe
* @property string useragent
+ * @property string imei
+ * @property string model
+ * @property string friendlyname
+ * @property string os
+ * @property string oslanguage
+ * @property string phonenumber
+ * @property string pinglifetime
+ * @property string pingfolder
+ * @property string contactsfilter_id
+ * @property string calendarfilter_id
+ * @property string tasksfilter_id
+ * @property string emailfilter_id
*/
-
interface Syncroton_Model_IDevice
{
/**
diff --git a/lib/ext/Syncroton/Model/IEntry.php b/lib/ext/Syncroton/Model/IEntry.php
index 7d9293d..34f6d53 100644
--- a/lib/ext/Syncroton/Model/IEntry.php
+++ b/lib/ext/Syncroton/Model/IEntry.php
@@ -22,9 +22,22 @@
interface Syncroton_Model_IEntry
{
+ /**
+ *
+ * @param unknown_type $properties
+ */
public function __construct($properties = null);
- public function appendXML(DOMElement $_domParrent);
+ /**
+ *
+ * @param DOMElement $_domParrent
+ */
+ /**
+ *
+ * @param DOMElement $_domParrent
+ * @param Syncroton_Model_IDevice $device
+ */
+ public function appendXML(DOMElement $_domParrent, Syncroton_Model_IDevice $device);
/**
* return array of valid properties
@@ -32,7 +45,11 @@ interface Syncroton_Model_IEntry
* @return array
*/
public function getProperties();
-
+
+ /**
+ *
+ * @param array $properties
+ */
public function setFromArray(array $properties);
/**
diff --git a/lib/ext/Syncroton/Model/StoreRequest.php b/lib/ext/Syncroton/Model/StoreRequest.php
index 170c3cb..f013b33 100644
--- a/lib/ext/Syncroton/Model/StoreRequest.php
+++ b/lib/ext/Syncroton/Model/StoreRequest.php
@@ -83,7 +83,7 @@ class Syncroton_Model_StoreRequest
} elseif (isset($xmlStore->Query)) {
if (isset($xmlStore->Query->And)) {
if (isset($xmlStore->Query->And->FreeText)) {
- $this->_store['query']['and']['freetext'] = (string) $xmlStore->Query->And->FreeText;
+ $this->_store['query']['and']['freeText'] = (string) $xmlStore->Query->And->FreeText;
}
if (isset($xmlStore->Query->And->ConversationId)) {
$this->_store['query']['and']['conversationId'] = (string) $xmlStore->Query->And->ConversationId;
diff --git a/lib/ext/Syncroton/Model/StoreResponse.php b/lib/ext/Syncroton/Model/StoreResponse.php
index 2708f0f..84fe036 100644
--- a/lib/ext/Syncroton/Model/StoreResponse.php
+++ b/lib/ext/Syncroton/Model/StoreResponse.php
@@ -2,7 +2,8 @@
/**
* Syncroton
*
- * @package Model
+ * @package Syncroton
+ * @subpackage Model
* @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3
* @copyright Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
* @author Lars Kneschke <l.kneschke at metaways.de>
@@ -13,24 +14,28 @@
*
* @package Syncroton
* @subpackage Model
+ * @property string status
+ * @property array result
+ * @property array range
+ * @property int total
*/
class Syncroton_Model_StoreResponse extends Syncroton_Model_AEntry
{
/**
* status constants
*/
- const STATUS_SUCCESS = 1;
- const STATUS_INVALIDREQUEST = 2;
- const STATUS_SERVERERROR = 3;
- const STATUS_BADLINK = 4;
- const STATUS_ACCESSDENIED = 5;
- const STATUS_NOTFOUND = 6;
- const STATUS_CONNECTIONFAILED = 7;
- const STATUS_TOOCOMPLEX = 8;
- const STATUS_TIMEDOUT = 10;
+ const STATUS_SUCCESS = 1;
+ const STATUS_INVALIDREQUEST = 2;
+ const STATUS_SERVERERROR = 3;
+ const STATUS_BADLINK = 4;
+ const STATUS_ACCESSDENIED = 5;
+ const STATUS_NOTFOUND = 6;
+ const STATUS_CONNECTIONFAILED = 7;
+ const STATUS_TOOCOMPLEX = 8;
+ const STATUS_TIMEDOUT = 10;
const STATUS_FOLDERSYNCREQUIRED = 11;
- const STATUS_ENDOFRANGE = 12;
- const STATUS_ACCESSBLOCKED = 13;
+ const STATUS_ENDOFRANGE = 12;
+ const STATUS_ACCESSBLOCKED = 13;
const STATUS_CREDENTIALSREQUIRED = 14;
protected $_xmlBaseElement = 'Store';
@@ -44,7 +49,11 @@ class Syncroton_Model_StoreResponse extends Syncroton_Model_AEntry
)
);
- public function appendXML(DOMElement $_domParrent)
+ /**
+ * (non-PHPdoc)
+ * @see Syncroton_Model_AEntry::appendXML()
+ */
+ public function appendXML(DOMElement $_domParrent, Syncroton_Model_IDevice $device)
{
$this->_addXMLNamespaces($_domParrent);
@@ -62,7 +71,7 @@ class Syncroton_Model_StoreResponse extends Syncroton_Model_AEntry
case 'result':
foreach ($value as $result) {
$element = $_domParrent->ownerDocument->createElementNS($nameSpace, 'Result');
- $result->appendXML($element);
+ $result->appendXML($element, $device);
$_domParrent->appendChild($element);
}
break;
diff --git a/lib/ext/Syncroton/Registry.php b/lib/ext/Syncroton/Registry.php
index c971456..6903c5d 100644
--- a/lib/ext/Syncroton/Registry.php
+++ b/lib/ext/Syncroton/Registry.php
@@ -35,6 +35,8 @@ class Syncroton_Registry extends ArrayObject
const TASKS_DATA_CLASS = 'tasks_data_class';
const GAL_DATA_CLASS = 'gal_data_class';
+ const DEFAULT_POLICY = 'default_policy';
+
const DATABASE = 'database';
const TRANSACTIONMANAGER = 'transactionmanager';
diff --git a/lib/ext/Syncroton/Server.php b/lib/ext/Syncroton/Server.php
index 2a9555a..7cd61bb 100644
--- a/lib/ext/Syncroton/Server.php
+++ b/lib/ext/Syncroton/Server.php
@@ -335,7 +335,8 @@ class Syncroton_Server
'deviceid' => $requestParameters['deviceId'],
'devicetype' => $requestParameters['deviceType'],
'useragent' => $requestParameters['userAgent'],
- 'acsversion' => $requestParameters['protocolVersion']
+ 'acsversion' => $requestParameters['protocolVersion'],
+ 'policyId' => Syncroton_Registry::isRegistered(Syncroton_Registry::DEFAULT_POLICY) ? Syncroton_Registry::get(Syncroton_Registry::DEFAULT_POLICY) : null
)));
}
diff --git a/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php b/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php
index 9badae6..699638e 100644
--- a/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php
+++ b/lib/ext/Syncroton/Wbxml/Dtd/ActiveSync/CodePage1.php
@@ -23,63 +23,63 @@ class Syncroton_Wbxml_Dtd_ActiveSync_CodePage1 extends Syncroton_Wbxml_Dtd_Activ
protected $_codePageName = 'Contacts';
protected $_tags = array(
- 'Anniversary' => 0x05,
- 'AssistantName' => 0x06,
- 'AssistnamePhoneNumber' => 0x07,
- 'Birthday' => 0x08,
- 'Body' => 0x09,
- 'BodySize' => 0x0a,
- 'BodyTruncated' => 0x0b,
- 'Business2PhoneNumber' => 0x0c,
- 'BusinessAddressCity' => 0x0d,
- 'BusinessAddressCountry' => 0x0e,
+ 'Anniversary' => 0x05,
+ 'AssistantName' => 0x06,
+ 'AssistantPhoneNumber' => 0x07,
+ 'Birthday' => 0x08,
+ 'Body' => 0x09,
+ 'BodySize' => 0x0a,
+ 'BodyTruncated' => 0x0b,
+ 'Business2PhoneNumber' => 0x0c,
+ 'BusinessAddressCity' => 0x0d,
+ 'BusinessAddressCountry' => 0x0e,
'BusinessAddressPostalCode' => 0x0f,
- 'BusinessAddressState' => 0x10,
- 'BusinessAddressStreet' => 0x11,
- 'BusinessFaxNumber' => 0x12,
- 'BusinessPhoneNumber' => 0x13,
- 'CarPhoneNumber' => 0x14,
- 'Categories' => 0x15,
- 'Category' => 0x16,
- 'Children' => 0x17,
- 'Child' => 0x18,
- 'CompanyName' => 0x19,
- 'Department' => 0x1a,
- 'Email1Address' => 0x1b,
- 'Email2Address' => 0x1c,
- 'Email3Address' => 0x1d,
- 'FileAs' => 0x1e,
- 'FirstName' => 0x1f,
- 'Home2PhoneNumber' => 0x20,
- 'HomeAddressCity' => 0x21,
- 'HomeAddressCountry' => 0x22,
- 'HomeAddressPostalCode' => 0x23,
- 'HomeAddressState' => 0x24,
- 'HomeAddressStreet' => 0x25,
- 'HomeFaxNumber' => 0x26,
- 'HomePhoneNumber' => 0x27,
- 'JobTitle' => 0x28,
- 'LastName' => 0x29,
- 'MiddleName' => 0x2a,
- 'MobilePhoneNumber' => 0x2b,
- 'OfficeLocation' => 0x2c,
- 'OtherAddressCity' => 0x2d,
- 'OtherAddressCountry' => 0x2e,
+ 'BusinessAddressState' => 0x10,
+ 'BusinessAddressStreet' => 0x11,
+ 'BusinessFaxNumber' => 0x12,
+ 'BusinessPhoneNumber' => 0x13,
+ 'CarPhoneNumber' => 0x14,
+ 'Categories' => 0x15,
+ 'Category' => 0x16,
+ 'Children' => 0x17,
+ 'Child' => 0x18,
+ 'CompanyName' => 0x19,
+ 'Department' => 0x1a,
+ 'Email1Address' => 0x1b,
+ 'Email2Address' => 0x1c,
+ 'Email3Address' => 0x1d,
+ 'FileAs' => 0x1e,
+ 'FirstName' => 0x1f,
+ 'Home2PhoneNumber' => 0x20,
+ 'HomeAddressCity' => 0x21,
+ 'HomeAddressCountry' => 0x22,
+ 'HomeAddressPostalCode' => 0x23,
+ 'HomeAddressState' => 0x24,
+ 'HomeAddressStreet' => 0x25,
+ 'HomeFaxNumber' => 0x26,
+ 'HomePhoneNumber' => 0x27,
+ 'JobTitle' => 0x28,
+ 'LastName' => 0x29,
+ 'MiddleName' => 0x2a,
+ 'MobilePhoneNumber' => 0x2b,
+ 'OfficeLocation' => 0x2c,
+ 'OtherAddressCity' => 0x2d,
+ 'OtherAddressCountry' => 0x2e,
'OtherAddressPostalCode' => 0x2f,
- 'OtherAddressState' => 0x30,
- 'OtherAddressStreet' => 0x31,
- 'PagerNumber' => 0x32,
- 'RadioPhoneNumber' => 0x33,
- 'Spouse' => 0x34,
- 'Suffix' => 0x35,
- 'Title' => 0x36,
- 'WebPage' => 0x37,
- 'YomiCompanyName' => 0x38,
- 'YomiFirstName' => 0x39,
- 'YomiLastName' => 0x3a,
- 'Rtf' => 0x3b,
- 'Picture' => 0x3c,
- 'Alias' => 0x3d,
- 'WeightedRank' => 0x3e
+ 'OtherAddressState' => 0x30,
+ 'OtherAddressStreet' => 0x31,
+ 'PagerNumber' => 0x32,
+ 'RadioPhoneNumber' => 0x33,
+ 'Spouse' => 0x34,
+ 'Suffix' => 0x35,
+ 'Title' => 0x36,
+ 'WebPage' => 0x37,
+ 'YomiCompanyName' => 0x38,
+ 'YomiFirstName' => 0x39,
+ 'YomiLastName' => 0x3a,
+ 'Rtf' => 0x3b,
+ 'Picture' => 0x3c,
+ 'Alias' => 0x3d,
+ 'WeightedRank' => 0x3e
);
}
\ No newline at end of file
diff --git a/lib/ext/Syncroton/Wbxml/Encoder.php b/lib/ext/Syncroton/Wbxml/Encoder.php
index 667cfec..746ea67 100644
--- a/lib/ext/Syncroton/Wbxml/Encoder.php
+++ b/lib/ext/Syncroton/Wbxml/Encoder.php
@@ -292,9 +292,9 @@ class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract
// handle the tag
$identity = $this->_codePage->getIdentity($_tag);
- if (is_array($_attributes) && isset($_attributes['Syncroton:encoding'])) {
+ if (is_array($_attributes) && isset($_attributes['uri:Syncroton;encoding'])) {
$encoding = 'opaque';
- unset($_attributes['Syncroton:encoding']);
+ unset($_attributes['uri:Syncroton;encoding']);
} else {
$encoding = 'termstring';
}
@@ -312,7 +312,7 @@ class Syncroton_Wbxml_Encoder extends Syncroton_Wbxml_Abstract
// handle the data
if($_data !== NULL) {
if ($encoding == 'opaque') {
- $this->_writeOpaqueString($_data);
+ $this->_writeOpaqueString(base64_decode($_data));
} else {
$this->_writeTerminatedString($_data);
}
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index cebfdfb..a041d7f 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -336,7 +336,7 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
/**
* Returns properties of a message for Search response
*
- * @param string $longId Message identifier
+ * @param string $longId Message identifier
* @param array $options Search options
*
* @return Syncroton_Model_Email Email object
@@ -787,17 +787,16 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
/**
* ActiveSync Search handler
*
- * @param array $query Search query parameters
- * @param array $options Search options
+ * @param Syncroton_Model_StoreRequest $store Search query
*
- * @return array List of Syncroton_Model_StoreResponseResult objects
+ * @return Syncroton_Model_StoreResponse Complete Search response
*/
- public function search($query, $options)
+ public function search(Syncroton_Model_StoreRequest $store)
{
- list ($folders, $search_str) = $this->parse_search_query($query, $options);
+ list($folders, $search_str) = $this->parse_search_query($store);
if (empty($search_str)) {
- return array();
+ throw new Exception('Empty/invalid search request');
}
$result = array();
@@ -838,48 +837,76 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
}
}
- return array_values($result);
+ $result = array_values($result);
+ $response = new Syncroton_Model_StoreResponse();
+
+ // Calculate requested range
+ $start = (int) $store->options['range'][0];
+ $limit = (int) $store->options['range'][1] + 1;
+ $total = count($result);
+ $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) {
+ $result = array_slice($result, $start, $limit-$start);
+ }
+
+ $response->range = array($start, $start + count($result) - 1);
+ }
+
+ // Build result array, convert to ActiveSync format
+ foreach ($result as $idx => $rec) {
+ $rec->properties = $this->getSearchEntry($rec->longId, $store->options);
+ $response->result[] = $rec;
+ unset($result[$idx]);
+ }
+
+ return $response;
}
/**
* Converts ActiveSync search parameters into IMAP search string
*/
- protected function parse_search_query($query, $options)
+ protected function parse_search_query($store)
{
- if (empty($query)) {
- return array();
- }
-
+ $options = $store->options;
+ $query = $store->query;
$search_str = '';
$folders = array();
- if (!is_array($query)) {
- $search = $query;
+ if (empty($query) || !is_array($query)) {
+ return array();
}
- else {
- if (isset($query['and']['freeText']) && strlen($query['and']['freeText'])) {
- $search = $query['and']['freeText'];
- }
- if (!empty($query['and']['collections'])) {
- foreach ($query['and']['collections'] as $collection) {
- $folders = array_merge($folders, $this->extractFolders($collection));
- }
- }
+ if (isset($query['and']['freeText']) && strlen($query['and']['freeText'])) {
+ $search = $query['and']['freeText'];
+ }
- if (!empty($query['and']['greaterThan'])
- && !empty($query['and']['greaterThan']['dateReceived'])
- && !empty($query['and']['greaterThan']['value'])
- ) {
- $search_str .= ' SINCE ' . $query['and']['greaterThan']['value']->format('d-M-Y');
+ if (!empty($query['and']['collections'])) {
+ foreach ($query['and']['collections'] as $collection) {
+ $folders = array_merge($folders, $this->extractFolders($collection));
}
+ }
- if (!empty($query['and']['lessThan'])
- && !empty($query['and']['lessThan']['dateReceived'])
- && !empty($query['and']['lessThan']['value'])
- ) {
- $search_str .= ' BEFORE ' . $query['and']['lessThan']['value']->format('d-M-Y');
- }
+ if (!empty($query['and']['greaterThan'])
+ && !empty($query['and']['greaterThan']['dateReceived'])
+ && !empty($query['and']['greaterThan']['value'])
+ ) {
+ $search_str .= ' SINCE ' . $query['and']['greaterThan']['value']->format('d-M-Y');
+ }
+
+ if (!empty($query['and']['lessThan'])
+ && !empty($query['and']['lessThan']['dateReceived'])
+ && !empty($query['and']['lessThan']['value'])
+ ) {
+ $search_str .= ' BEFORE ' . $query['and']['lessThan']['value']->format('d-M-Y');
}
if ($search !== null) {
diff --git a/lib/kolab_sync_data_gal.php b/lib/kolab_sync_data_gal.php
index d7bb2e8..ed47c46 100644
--- a/lib/kolab_sync_data_gal.php
+++ b/lib/kolab_sync_data_gal.php
@@ -124,16 +124,15 @@ class kolab_sync_data_gal extends kolab_sync_data implements Syncroton_Data_IDat
}
/**
- * Returns properties of a message for Search response
+ * Returns properties of a contact for Search response
*
- * @param string $longId Message identifier
- * @param array $options Search options
+ * @param array $data Contact data
+ * @param array $options Search options
*
- * @return Syncroton_Model_Email Email object
+ * @return Syncroton_Model_GAL Contact (GAL) object
*/
- public function getSearchEntry($longId, $options)
+ public function getSearchEntry($data, $options)
{
- $data = $this->getObject($longId);
$result = array();
// Contacts namespace fields
@@ -175,15 +174,18 @@ class kolab_sync_data_gal extends kolab_sync_data implements Syncroton_Data_IDat
/**
* ActiveSync Search handler
*
- * @param string|array $query Search query parameters
- * @param array $options Search options
+ * @param Syncroton_Model_StoreRequest $store Search query parameters
*
- * @return array List of Syncroton_Model_StoreResponseResult objects
+ * @return Syncroton_Model_StoreResponse Complete Search response
+ * @throws Exception
*/
- public function search($query, $options)
+ public function search(Syncroton_Model_StoreRequest $store)
{
+ $options = $store->options;
+ $query = $store->query;
+
if (empty($query) || !is_string($query)) {
- return array();
+ throw new Exception('Empty/invalid search request');
}
$records = array();
@@ -234,30 +236,41 @@ class kolab_sync_data_gal extends kolab_sync_data implements Syncroton_Data_IDat
// sort the records
ksort($records, SORT_LOCALE_STRING);
- $result = array();
+ $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) {
- $longId = $rec['ID'];
- $result[] = new Syncroton_Model_StoreResponseResult(array(
- 'longId' => $longId,
+ $response->result[] = new Syncroton_Model_StoreResponseResult(array(
+ 'longId' => $rec['ID'],
+ 'properties' => $this->getSearchEntry($rec, $options),
));
-
- $this->result[$longId] = $rec;
unset($records[$idx]);
}
- return $result;
- }
-
- /**
- * Return contact object from LDAP
- *
- * @param string $id Contact identifier
- *
- * @return array Object data
- */
- protected function getObject($id)
- {
- return $this->result[$id];
+ return $response;
}
/**
commit 9c1bfe24c4de02ded9141a222414e91d4b1049aa
Author: Aleksander Machniak <alec at alec.pl>
Date: Tue Sep 4 12:55:22 2012 +0200
Add References header setting on mail reply
diff --git a/lib/kolab_sync_backend.php b/lib/kolab_sync_backend.php
index 29235a1..440f982 100644
--- a/lib/kolab_sync_backend.php
+++ b/lib/kolab_sync_backend.php
@@ -890,6 +890,7 @@ class kolab_sync_backend
'cc' => 'Cc',
'bcc' => 'Bcc',
'message-id' => 'Message-ID',
+ 'references' => 'References',
'content-type' => 'Content-Type',
'content-transfer-encoding' => 'Content-Transfer-Encoding',
);
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 22207a0..cebfdfb 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -694,6 +694,11 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
$body = rtrim($body) . "\n" . ltrim($message_body);
}
+ // Add References header
+ if (empty($headers['References'])) {
+ $headers['References'] = trim($message->headers->references . ' ' . $message->headers->messageID);
+ }
+
// Create complete message source
$body = $this->backend->build_mime($headers, $body);
More information about the commits
mailing list