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