mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-18 14:03:19 +01:00
2dedbf0f7c
added real working state machine SyncML conformance improvment
231 lines
8.6 KiB
PHP
231 lines
8.6 KiB
PHP
<?php
|
|
/**
|
|
* $Horde: framework/SyncML/SyncML/Sync.php,v 1.7 2004/09/14 04:27:05 chuck Exp $
|
|
*
|
|
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
|
*
|
|
* @author Anthony Mills <amills@pyramid6.com>
|
|
* @version $Revision$
|
|
* @since Horde 3.0
|
|
* @package Horde_SyncML
|
|
*/
|
|
class Horde_SyncML_Sync {
|
|
|
|
/**
|
|
* Target, either contacts, notes, events,
|
|
*/
|
|
var $_targetLocURI;
|
|
|
|
var $_sourceLocURI;
|
|
|
|
/**
|
|
* Return if all commands success.
|
|
*/
|
|
var $globalSuccess;
|
|
|
|
/**
|
|
* This is the content type to use to export data.
|
|
*/
|
|
var $preferedContentType;
|
|
|
|
/**
|
|
* Do have the sync data loaded from the database already?
|
|
*/
|
|
var $syncDataLoaded;
|
|
|
|
function &factory($alert)
|
|
{
|
|
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
switch ($alert) {
|
|
case ALERT_TWO_WAY:
|
|
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
|
|
return $sync = &new Horde_SyncML_Sync_TwoWaySync();
|
|
|
|
case ALERT_SLOW_SYNC:
|
|
include_once 'Horde/SyncML/Sync/SlowSync.php';
|
|
return $sync = &new Horde_SyncML_Sync_SlowSync();
|
|
|
|
case ALERT_ONE_WAY_FROM_CLIENT:
|
|
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
|
|
return $sync = &new Horde_SyncML_Sync_OneWayFromClientSync();
|
|
|
|
case ALERT_REFRESH_FROM_CLIENT:
|
|
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
|
|
return $sync = &new Horde_SyncML_Sync_RefreshFromClientSync();
|
|
|
|
case ALERT_ONE_WAY_FROM_SERVER:
|
|
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
|
|
return $sync = &new Horde_SyncML_Sync_OneWayFromServerSync();
|
|
|
|
case ALERT_REFRESH_FROM_SERVER:
|
|
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
|
|
return $sync = &new Horde_SyncML_Sync_RefreshFromServerSync();
|
|
}
|
|
|
|
require_once 'PEAR.php';
|
|
return PEAR::raiseError('Alert ' . $alert . ' not found.');
|
|
}
|
|
|
|
function nextSyncCommand($currentCmdID, &$syncCommand, &$output)
|
|
{
|
|
$result = $this->runSyncCommand($syncCommand);
|
|
return $syncCommand->output($currentCmdID, $output);
|
|
}
|
|
|
|
function startSync($currentCmdID, &$output)
|
|
{
|
|
return $currentCmdID;
|
|
}
|
|
|
|
function endSync($currentCmdID, &$output)
|
|
{
|
|
return $currentCmdID;
|
|
}
|
|
|
|
/**
|
|
* Here's where the actual processing of a client-sent Sync
|
|
* Command takes place. Entries are added, deleted or replaced
|
|
* from the server database by using Horde API (Registry) calls.
|
|
*/
|
|
function runSyncCommand(&$command) {
|
|
#Horde::logMessage('SyncML: content type is ' . $command->getContentType() .' moreData '. $command->_moreData, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
global $registry;
|
|
|
|
$history = $GLOBALS['egw']->contenthistory;
|
|
|
|
$state = &$_SESSION['SyncML.state'];
|
|
|
|
if(isset($state->_moreData['luid'])) {
|
|
if(($command->_luid == $state->_moreData['luid'])) {
|
|
Horde::logMessage('SyncML: got next moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
$lastChunks = implode('',$state->_moreData['chunks']);
|
|
$command->_content = $lastChunks.$command->_content;
|
|
$stringlen1 = strlen($lastChunks);
|
|
$stringlen2 = strlen($command->_content);
|
|
|
|
if(!$command->_moreData && strlen($command->_content) != $state->_moreData['contentSize']) {
|
|
$command->_status = RESPONSE_SIZE_MISMATCH;
|
|
$state->_moreData = array();
|
|
|
|
return;
|
|
} elseif(!$command->_moreData && strlen($command->_content) == $state->_moreData['contentSize']) {
|
|
$state->_moreData = array();
|
|
Horde::logMessage('SyncML: chunk ended successful type is ' . $command->getContentType() .' content is '. $command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
}
|
|
} else {
|
|
// alert 223 needed too
|
|
#$command->_status = ALERT_NO_END_OF_DATA;
|
|
|
|
$state->_moreData = array();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// don't add/replace the data currently, they are not yet complete
|
|
if($command->_moreData == TRUE) {
|
|
$state->_moreData['chunks'][] = $command->_content;
|
|
$state->_moreData['luid'] = $command->_luid;
|
|
|
|
// gets only set with the first chunk of data
|
|
if(isset($command->_contentSize))
|
|
$state->_moreData['contentSize'] = $command->_contentSize;
|
|
|
|
$command->_status = RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED;
|
|
Horde::logMessage('SyncML: added moreData chunk '.$command->getContent(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
return;
|
|
}
|
|
|
|
$hordeType = $type = $this->_targetLocURI;
|
|
// remove the './' from the beginning
|
|
$hordeType = str_replace('./','',$hordeType);
|
|
if(!$contentType = $command->getContentType()) {
|
|
$contentType = $state->getPreferedContentType($type);
|
|
}
|
|
|
|
if ($this->_targetLocURI == 'calendar' && strpos($command->getContent(), 'BEGIN:VTODO') !== false) {
|
|
$hordeType = 'tasks';
|
|
}
|
|
|
|
$syncElementItems = $command->getSyncElementItems();
|
|
|
|
foreach($syncElementItems as $syncItem) {
|
|
|
|
$guid = false;
|
|
|
|
if (is_a($command, 'Horde_SyncML_Command_Sync_Add')) {
|
|
$guid = $registry->call($hordeType . '/import',
|
|
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
|
|
|
if (!is_a($guid, 'PEAR_Error')) {
|
|
$ts = $history->getTSforAction($guid, 'add');
|
|
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
|
$state->log("Client-Add");
|
|
Horde::logMessage('SyncML: added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
} else {
|
|
$state->log("Client-AddFailure");
|
|
Horde::logMessage('SyncML: Error in adding client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
|
}
|
|
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Delete')) {
|
|
// We can't remove the mapping entry as we need to keep
|
|
// the timestamp information.
|
|
$guid = $state->removeUID($type, $syncItem->getLocURI());
|
|
#$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
|
Horde::logMessage('SyncML: about to delete entry ' . $type .' / '. $guid . ' due to client request '.$syncItem->getLocURI(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
|
$registry->call($hordeType . '/delete', array($guid));
|
|
#$ts = $history->getTSforAction($guid, 'delete');
|
|
#$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
|
$state->log("Client-Delete");
|
|
Horde::logMessage('SyncML: deleted entry ' . $guid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
} else {
|
|
$state->log("Client-DeleteFailure");
|
|
Horde::logMessage('SyncML: Failure deleting client entry, maybe gone already on server. msg:'. $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
|
}
|
|
} elseif (is_a($command, 'Horde_SyncML_Command_Sync_Replace')) {
|
|
$guid = $state->getGlobalUID($type, $syncItem->getLocURI());
|
|
$ok = false;
|
|
if ($guid) {
|
|
Horde::logMessage('SyncML: locuri'. $syncItem->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_ERR);
|
|
// Entry exists: replace current one.
|
|
$ok = $registry->call($hordeType . '/replace',
|
|
array($guid, $state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
|
if (!is_a($ok, 'PEAR_Error')) {
|
|
$ts = $history->getTSforAction($guid, 'modify');
|
|
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
|
Horde::logMessage('SyncML: replaced entry due to client request guid: ' .$guid. ' ts: ' .$ts, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
$state->log("Client-Replace");
|
|
$ok = true;
|
|
} else {
|
|
// Entry may have been deleted; try adding it.
|
|
$ok = false;
|
|
}
|
|
}
|
|
|
|
if (!$ok) {
|
|
// Entry does not exist in map or database: add a new one.
|
|
Horde::logMessage('SyncML: try to add contentype ' . $contentType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
$guid = $registry->call($hordeType . '/import',
|
|
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
|
if (!is_a($guid, 'PEAR_Error')) {
|
|
$ts = $history->getTSforAction($guid, 'add');
|
|
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
|
$state->log("Client-AddReplace");
|
|
Horde::logMessage('SyncML: r/ added client entry as ' . $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
} else {
|
|
Horde::logMessage('SyncML: Error in replacing/add client entry:' . $guid->message, __FILE__, __LINE__, PEAR_LOG_ERR);
|
|
$state->log("Client-AddFailure");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $guid;
|
|
}
|
|
}
|