gunnar: server/pear/Horde_SyncML/patches/Horde_SyncML-0.7.0dev20091215 t_SyncML_HK_GW_CombinedFixes.diff, NONE, 1.1
cvs at kolab.org
cvs at kolab.org
Sat Jan 23 00:09:38 CET 2010
Author: gunnar
Update of /kolabrepository/server/pear/Horde_SyncML/patches/Horde_SyncML-0.7.0dev20091215
In directory doto:/tmp/cvs-serv24892/pear/Horde_SyncML/patches/Horde_SyncML-0.7.0dev20091215
Added Files:
t_SyncML_HK_GW_CombinedFixes.diff
Log Message:
Distribute the remaining set of patches on the corresponding packages. Remove obsolete patches.
--- NEW FILE: t_SyncML_HK_GW_CombinedFixes.diff ---
From: Gunnar Wrobel <p at rdus.de>
Subject: [PATCH] t/SyncML/HK/GW/CombinedFixes
Combined set of Univention SyncML patches.
FIXME: At least one of these has been rejected upstream. Rework the patch and update this one. Actually this patch should be
splitted into the single parts.
Signed-off-by: Gunnar Wrobel <p at rdus.de>
---
a/horde-webmail/SyncML/Backend.php | 18 ++++++
a/horde-webmail/SyncML/Backend/Horde.php | 80 ++++++++++++++++++++++++++++
a/horde-webmail/SyncML/Constants.php | 2 +-
a/horde-webmail/SyncML/Device.php | 69 ++++++++++++++++++++++++
a/horde-webmail/SyncML/Sync.php | 27 +++++++++-
6 files changed, 228 insertions(+), 3 deletions(-)
diff --git a/a/horde-webmail/SyncML/Backend.php b/a/horde-webmail/SyncML/Backend.php
index b445b3a..a13174a 100644
--- a/a/horde-webmail/SyncML/Backend.php
+++ b/a/horde-webmail/SyncML/Backend.php
@@ -567,6 +567,24 @@ class SyncML_Backend {
}
/**
+ * Checks if the entry specified by $cuid has been modified on the server.
+ *
+ * @param string $databaseURI URI of Database to sync. Like
+ * calendar, tasks, contacts or notes.
+ * May include optional parameters:
+ * tasks?options=ignorecompleted.
+ * @param string $cuid Client ID of this entry
+ * @param integer $from_ts Start timestamp.
+ *
+ * @return boolean True if the client entry has been modified on
+ * the server. False otherwise.
+ */
+ function unchanged($databaseURI, $cuid, $from_ts)
+ {
+ die ("Not implemented!");
+ }
+
+ /**
* Authenticates the user at the backend.
*
* For some types of authentications (notably auth:basic) the username
diff --git a/a/horde-webmail/SyncML/Backend/Horde.php b/a/horde-webmail/SyncML/Backend/Horde.php
index a9be55d..a71b5f8 100644
--- a/a/horde-webmail/SyncML/Backend/Horde.php
+++ b/a/horde-webmail/SyncML/Backend/Horde.php
@@ -204,6 +204,11 @@ class SyncML_Backend_Horde extends SyncML_Backend {
__FILE__, __LINE__, PEAR_LOG_DEBUG);
continue;
}
+ if ($suid_ts > $to_ts) {
+ // Add delayed to the next sync operation
+ $this->logMessage("Add ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ continue;
+ }
$this->logMessage(
"Adding to client from db $database, server id $suid",
__FILE__, __LINE__, PEAR_LOG_DEBUG);
@@ -251,6 +256,11 @@ class SyncML_Backend_Horde extends SyncML_Backend {
__FILE__, __LINE__, PEAR_LOG_DEBUG);
continue;
}
+ if ($suid_ts > $to_ts) {
+ // Change delayed to the next sync operation
+ $this->logMessage("Change ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ continue;
+ }
$cuid = $this->_getCuid($database, $suid);
if (!$cuid) {
$this->logMessage(
@@ -311,6 +321,11 @@ class SyncML_Backend_Horde extends SyncML_Backend {
__FILE__, __LINE__, PEAR_LOG_DEBUG);
continue;
}
+ if ($suid_ts > $to_ts) {
+ // Delete delayed to the next sync operation
+ $this->logMessage("Delete ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ continue;
+ }
$cuid = $this->_getCuid($database, $suid);
if (!$cuid) {
$this->logMessage(
@@ -512,6 +527,71 @@ class SyncML_Backend_Horde extends SyncML_Backend {
}
/**
+ * Checks if the entry specified by $cuid has been modified on the server.
+ *
+ * @param string $databaseURI URI of Database to sync. Like
+ * calendar, tasks, contacts or notes.
+ * May include optional parameters:
+ * tasks?options=ignorecompleted.
+ * @param string $cuid Client ID of this entry
+ * @param integer $from_ts Last server sync time.
+ *
+ * @return boolean True if the client entry has been modified on
+ * the server. False otherwise.
+ */
+ function getConflict($databaseURI, $cuid, $server_ts)
+ {
+ global $registry;
+
+ $database = $this->_normalize($databaseURI);
+
+ // Only server needs to do a cuid<->suid map
+ if ($this->_backendMode == SYNCML_BACKENDMODE_SERVER) {
+ $suid = $this->_getSuid($database, $cuid);
+ } else {
+ $suid = $cuid;
+ }
+ $this->logMessage("checking modification date of entry suid $suid in $database", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+
+ if ($suid) {
+ $mod_ts = $registry->call($database . '/getActionTimestamp', array($suid, 'modify', SyncML_Backend::getParameter($databaseURI,'source')));
+ $client_ts = $this->_getChangeTS($database, $suid);
+ // Check that the last server anchor is smaller than the
+ // last modification stamp (this means that a change
+ // occurred after the last sync started). This might still
+ // be a client change so check that the last client update
+ // also happened before the last modification)
+ if ($server_ts < $mod_ts && $client_ts < $mod_ts) {
+ // Duplicate the server entry
+ $this->logMessage("Conflict detected. Returning conflicting server entry $suid.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ $device = &$_SESSION['SyncML.state']->getDevice();
+ $contentType = $device->getPreferredContentType($databaseURI);
+ return $this->retrieveEntry($databaseURI, $suid, $contentType);
+ }
+ }
+ return false;
+ }
+
+ function duplicateConflict($databaseURI, $content)
+ {
+ global $registry;
+
+ $database = $this->_normalize($databaseURI);
+ $device = &$_SESSION['SyncML.state']->getDevice();
+ $contentType = $device->getPreferredContentType($databaseURI);
+ $content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/', '\1', $content, 1);
+ $duid = $registry->call($database. '/import',
+ array($content, $contentType,
+ SyncML_Backend::getParameter($databaseURI,'source')));
+ if (is_a($duid, 'PEAR_Error')) {
+ $this->logMessage("duplicating entry failed.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ return false;
+ }
+ $this->logMessage("duplicated server entry to $duid.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ return true;
+ }
+
+ /**
* Authenticates the user at the backend.
*
* For some types of authentications (notably auth:basic) the username
diff --git a/a/horde-webmail/SyncML/Constants.php b/a/horde-webmail/SyncML/Constants.php
index e0d0f9b..7ca925a 100644
--- a/a/horde-webmail/SyncML/Constants.php
+++ b/a/horde-webmail/SyncML/Constants.php
@@ -66,7 +66,7 @@ define('RESPONSE_RESET_CONTENT', 205);
define('RESPONSE_PARTIAL_CONTENT', 206);
define('RESPONSE_CONFLICT_RESOLVED_WITH_MERGE', 207);
define('RESPONSE_CONFLICT_RESOLVED_WITH_CLIENT_WINNING', 208);
-define('RESPONSE_CONFILCT_RESOLVED_WITH_DUPLICATE', 209);
+define('RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE', 209);
define('RESPONSE_DELETE_WITHOUT_ARCHIVE', 210);
define('RESPONSE_ITEM_NO_DELETED', 211);
define('RESPONSE_AUTHENTICATION_ACCEPTED', 212);
diff --git a/a/horde-webmail/SyncML/Device.php b/a/horde-webmail/SyncML/Device.php
index 196dfbb..dd793c7 100644
--- a/a/horde-webmail/SyncML/Device.php
+++ b/a/horde-webmail/SyncML/Device.php
@@ -159,6 +159,8 @@ class SyncML_Device {
SYNCML_LOGFILE_DATA,
"\nInput received from client ($contentType):\n$content\n");
+ $content = $this->_completeEmptyAttributes($content, $contentType);
+
// Always remove client UID. UID will be seperately passed in XML.
$content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
'\1', $content, 1);
@@ -167,6 +169,73 @@ class SyncML_Device {
}
/**
+ * Complete any attributes that the client supports but did not
+ * provide. In case the user did delete an attribute on the client
+ * this action is required to indicate to the server that the
+ * attribute needs to be deleted. A completely missing attribute
+ * would be considered as "no change" by the server.
+ *
+ * @param string $content The content to convert
+ * @param string $contentType The contentType of the content
+ *
+ * @return string The converted content
+ */
+ function _completeEmptyAttributes($content, $contentType)
+ {
+
+ $di = $_SESSION['SyncML.state']->deviceInfo;
+
+ if (empty($di) || !isset($di->_CTCap) || !isset($di->_CTCap[$contentType])) {
+ return $content;
+ }
+
+ require_once 'Horde/iCalendar.php';
+ $iCal = new Horde_iCalendar();
+ if (!$iCal->parsevCalendar($content)) {
+ // We cant parse the content, return it unchanged
+ return $content;
+ }
+ $components = $iCal->getComponents();
+ $attributes = $di->_CTCap[$contentType];
+
+ foreach ($components as $component) {
+ foreach ($attributes as $name => $properties) {
+ if ($name == 'BEGIN' || $name == 'END') {
+ continue;
+ }
+ $values = $component->getAllAttributes($name);
+ if (!isset($properties->_params)) {
+ if (empty($values)) {
+ // Undefined attribute -> replace it with
+ // the correct empty value
+ $component->setAttributeEmpty($name);
+ }
+ } else {
+ foreach ($properties->_params as $key => $property) {
+ if (!empty($values)) {
+ $present = true;
+ } else {
+ $present = false;
+ foreach ($values as $value) {
+ if (in_array($key, array_keys($value['params']))) {
+ $present = true;
+ break;
+ }
+ }
+ }
+ if (!$present) {
+ // Undefined attribute -> replace it with
+ // the correct empty value
+ $component->setAttributeEmpty($name, array($key => null), true);
+ }
+ }
+ }
+ }
+ }
+ return $iCal->exportvCalendar();
+ }
+
+ /**
* Converts the content from the backend to a format suitable for the
* client device.
*
diff --git a/a/horde-webmail/SyncML/Sync.php b/a/horde-webmail/SyncML/Sync.php
index 2342389..57e233b 100644
--- a/a/horde-webmail/SyncML/Sync.php
+++ b/a/horde-webmail/SyncML/Sync.php
@@ -283,7 +283,13 @@ class SyncML_Sync {
}
} elseif ($item->elementType == 'Delete') {
/* Handle client delete requests. */
+ $duplicate = $backend->getConflict($hordedatabase, $cuid, $this->_serverAnchorLast);
$ok = $backend->deleteEntry($database, $cuid);
+ $duplicated = false;
+ if ($duplicate) {
+ $duplicated = $backend->duplicateConflict($hordedatabase, $duplicate);
+ }
+
if (!$ok && $tasksincalendar) {
$backend->logMessage(
'Task ' . $cuid . ' deletion sent with calendar request',
@@ -293,8 +299,14 @@ class SyncML_Sync {
if ($ok) {
$this->_client_delete_count++;
- $item->responseCode = RESPONSE_OK;
$backend->logMessage('Deleted entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ if (!$duplicated) {
+ $item->responseCode = RESPONSE_OK;
+ } else {
+ $this->_client_add_count++;
+ $backend->logMessage('Duplicated entry ' . $suid . ' due to client/server conflict', __FILE__, __LINE__, PEAR_LOG_INFO);
+ $item->responseCode = RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE;
+ }
} else {
$this->_errors++;
$item->responseCode = RESPONSE_ITEM_NO_DELETED;
@@ -303,13 +315,24 @@ class SyncML_Sync {
} elseif ($item->elementType == 'Replace') {
/* Handle client replace requests. */
+ $duplicate = $backend->getConflict($hordedatabase, $cuid, $this->_serverAnchorLast);
$suid = $backend->replaceEntry($hordedatabase, $content,
$contentType, $cuid);
+ $duplicated = false;
+ if ($duplicate) {
+ $duplicated = $backend->duplicateConflict($hordedatabase, $duplicate);
+ }
if (!is_a($suid, 'PEAR_Error')) {
$this->_client_replace_count++;
- $item->responseCode = RESPONSE_OK;
$backend->logMessage('Replaced entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
+ if (!$duplicated) {
+ $item->responseCode = RESPONSE_OK;
+ } else {
+ $this->_client_add_count++;
+ $backend->logMessage('Duplicated entry ' . $suid . ' due to client/server conflict', __FILE__, __LINE__, PEAR_LOG_INFO);
+ $item->responseCode = RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE;
+ }
} else {
$backend->logMessage($suid->message, __FILE__, __LINE__, PEAR_LOG_DEBUG);
--
tg: (6938161..) t/SyncML/HK/GW/CombinedFixes (depends on: master)
--
TOPGIT patch commit log
=======================
commit 3c12e523cdbac5e2d0c1add78fcb25f500af2877
Author: Gunnar Wrobel <p at rdus.de>
Date: Sun Feb 1 18:22:13 2009 +0000
Added patch release/HK-GW-SyncML.patch from the mercurial release queue.
More information about the commits
mailing list