mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-25 09:23:28 +01:00
SyncML fixes
This commit is contained in:
parent
84485d8bca
commit
d8450c3c9c
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/State.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/SyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Command/Sync/ContentSyncElement.php,v 1.12 2004/07/02 19:24:44 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_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_Sync_SyncElement {
|
||||
|
||||
/**
|
||||
* The content: vcard data, etc.
|
||||
*/
|
||||
var $_content;
|
||||
|
||||
/**
|
||||
* Local to server: our Horde guid.
|
||||
*/
|
||||
var $_locURI;
|
||||
|
||||
var $_targetURI;
|
||||
var $_contentType;
|
||||
|
||||
function setSourceURI($uri)
|
||||
{
|
||||
$this->_locURI = $uri;
|
||||
}
|
||||
|
||||
function getSourceURI()
|
||||
{
|
||||
return $this->_locURI;
|
||||
}
|
||||
|
||||
function setTargetURI($uri)
|
||||
{
|
||||
$this->_targetURI = $uri;
|
||||
}
|
||||
|
||||
function getTargetURI()
|
||||
{
|
||||
return $this->_targetURI;
|
||||
}
|
||||
|
||||
function setContentType($c)
|
||||
{
|
||||
$this->_contentType = $c;
|
||||
}
|
||||
|
||||
function setContentFormat($_format)
|
||||
{
|
||||
$this->_contentFormat = $_format;
|
||||
}
|
||||
|
||||
function getContentType()
|
||||
{
|
||||
return $this->_contentType;
|
||||
}
|
||||
|
||||
function getContent()
|
||||
{
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
function setContent($content)
|
||||
{
|
||||
$this->_content = $content;
|
||||
}
|
||||
|
||||
function endElement($uri, $element)
|
||||
{
|
||||
switch ($this->_xmlStack) {
|
||||
case 2:
|
||||
if ($element == 'Data') {
|
||||
$this->_content = trim($this->_chars);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
parent::endElement($uri, $element);
|
||||
}
|
||||
|
||||
function outputCommand($currentCmdID, &$output, $command)
|
||||
{
|
||||
$state = $_SESSION['SyncML.state'];
|
||||
|
||||
$attrs = array();
|
||||
$output->startElement($state->getURI(), $command, $attrs);
|
||||
|
||||
$output->startElement($state->getURI(), 'CmdID', $attrs);
|
||||
$chars = $currentCmdID;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'CmdID');
|
||||
|
||||
if (isset($this->_contentType)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Type', $attrs);
|
||||
$output->characters($this->_contentType);
|
||||
$output->endElement($state->getURIMeta(), 'Type');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if (isset($this->_content)
|
||||
|| isset($this->_locURI) || isset($this->targetURI)) {
|
||||
$output->startElement($state->getURI(), 'Item', $attrs);
|
||||
// send only when sending adds
|
||||
if ($this->_locURI != null && (strtolower($command) == 'add')) {
|
||||
$output->startElement($state->getURI(), 'Source', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = substr($this->_locURI,0,39);
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Source');
|
||||
}
|
||||
|
||||
if(isset($this->_contentFormat)) {
|
||||
$output->startElement($state->getURI(), 'Meta', $attrs);
|
||||
$output->startElement($state->getURIMeta(), 'Format', $attrs);
|
||||
$output->characters($this->_contentFormat);
|
||||
$output->endElement($state->getURIMeta(), 'Format');
|
||||
$output->endElement($state->getURI(), 'Meta');
|
||||
}
|
||||
|
||||
if ($this->_targetURI != null) {
|
||||
$output->startElement($state->getURI(), 'Target', $attrs);
|
||||
$output->startElement($state->getURI(), 'LocURI', $attrs);
|
||||
$chars = $this->_targetURI;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'LocURI');
|
||||
$output->endElement($state->getURI(), 'Target');
|
||||
}
|
||||
if (isset($this->_content)) {
|
||||
$output->startElement($state->getURI(), 'Data', $attrs);
|
||||
#$chars = '<![CDATA['.$this->_content.']]>';
|
||||
$chars = $this->_content;
|
||||
$output->characters($chars);
|
||||
$output->endElement($state->getURI(), 'Data');
|
||||
}
|
||||
$output->endElement($state->getURI(), 'Item');
|
||||
}
|
||||
|
||||
$output->endElement($state->getURI(), $command);
|
||||
|
||||
$currentCmdID++;
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
}
|
409
phpgwapi/inc/horde/Horde/SyncML/State_egw.php
Normal file
409
phpgwapi/inc/horde/Horde/SyncML/State_egw.php
Normal file
@ -0,0 +1,409 @@
|
||||
<?php
|
||||
|
||||
include_once dirname(__FILE__).'/State.php';
|
||||
|
||||
class EGW_SyncML_State extends Horde_SyncML_State
|
||||
{
|
||||
/**
|
||||
* Returns the timestamp (if set) of the last change to the
|
||||
* obj:guid, that was caused by the client. This is stored to
|
||||
* avoid mirroring these changes back to the client.
|
||||
*/
|
||||
function getChangeTS($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$db = clone($GLOBALS['phpgw']->db);
|
||||
|
||||
$cols = array('map_timestamp');
|
||||
|
||||
$where = array
|
||||
(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
|
||||
#Horde::logMessage('SyncML: getChangeTS for ' . $mapID .' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$db->select('egw_contentmap', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
if($db->next_record())
|
||||
{
|
||||
#Horde::logMessage('SyncML: getChangeTS changets is ' . $db->from_timestamp($db->f('map_timestamp')), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $db->from_timestamp($db->f('map_timestamp'));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the clients device info if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* a array containing all available infos about the device
|
||||
*/
|
||||
function getClientDeviceInfo()
|
||||
{
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$cols = array
|
||||
(
|
||||
'dev_dtdversion',
|
||||
'dev_numberofchanges',
|
||||
'dev_largeobjs',
|
||||
'dev_swversion',
|
||||
'dev_oem',
|
||||
'dev_model',
|
||||
'dev_manufacturer',
|
||||
'dev_devicetype',
|
||||
'dev_deviceid',
|
||||
'dev_datastore',
|
||||
);
|
||||
|
||||
$where = array
|
||||
(
|
||||
'dev_id' => $deviceID,
|
||||
);
|
||||
|
||||
$db->select('egw_syncmldevinfo', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
if($db->next_record())
|
||||
{
|
||||
$devInfo = array
|
||||
(
|
||||
'DTDVersion' => $db->f('dev_dtdversion'),
|
||||
'supportNumberOfChanges' => $db->f('dev_numberofchanges'),
|
||||
'supportLargeObjs' => $db->f('dev_largeobjs'),
|
||||
'softwareVersion' => $db->f('dev_swversion'),
|
||||
'oem' => $db->f('dev_oem'),
|
||||
'model' => $db->f('dev_model'),
|
||||
'manufacturer' => $db->f('dev_manufacturer'),
|
||||
'deviceType' => $db->f('dev_devicetype'),
|
||||
'deviceID' => $db->f('dev_deviceid'),
|
||||
'dataStore' => unserialize($db->f('dev_datastore')),
|
||||
);
|
||||
|
||||
return $devInfo;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Horde server guid (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) for a given client
|
||||
* locid. Returns false if no such id is stored yet.
|
||||
*
|
||||
* Opposite of getLocId which returns the locid for a given guid.
|
||||
*/
|
||||
function getGlobalUID($type, $locid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
#Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$cols = array('map_guid');
|
||||
|
||||
$where = array
|
||||
(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
'map_expired' => 0,
|
||||
);
|
||||
|
||||
$db->select('egw_contentmap', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
if($db->next_record())
|
||||
{
|
||||
return $db->f('map_guid');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a EGW GUID (like
|
||||
* kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as
|
||||
* used by the sync client (like 12) returns false if no such id
|
||||
* is stored yet.
|
||||
*/
|
||||
function getLocID($type, $guid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$cols = array('map_locuid');
|
||||
|
||||
$where = array
|
||||
(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid
|
||||
);
|
||||
Horde::logMessage('SyncML: search LocID for ' . $mapID .' / '.$guid, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$db->select('egw_contentmap', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
if($db->next_record())
|
||||
{
|
||||
Horde::logMessage('SyncML: found LocID: '.$db->f('map_locuid'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return $db->f('map_locuid');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information about the previous sync if any. Returns
|
||||
* false if no info found or a DateTreeObject with at least the
|
||||
* following attributes:
|
||||
*
|
||||
* ClientAnchor: the clients Next Anchor of the previous sync.
|
||||
* ServerAnchor: the Server Next Anchor of the previous sync.
|
||||
*/
|
||||
function getSyncSummary($type)
|
||||
{
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$cols = array('sync_serverts','sync_clientts');
|
||||
|
||||
$where = array
|
||||
(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type
|
||||
);
|
||||
|
||||
$db->select('egw_syncmlsummary', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if($db->next_record())
|
||||
{
|
||||
#Horde::logMessage("SyncML: get SYNCSummary for $deviceID serverts: ".$db->f('sync_serverts')." clients: ".$db->f('sync_clientts'), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$retData = array
|
||||
(
|
||||
'ClientAnchor' => $db->f('sync_clientts'),
|
||||
'ServerAnchor' => $db->f('sync_serverts'),
|
||||
);
|
||||
return $retData;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function isAuthorized()
|
||||
{
|
||||
if (!$this->_isAuthorized) {
|
||||
|
||||
if(!isset($this->_locName) && !isset($this->_password))
|
||||
{
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Username and password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(!isset($this->_password))
|
||||
{
|
||||
Horde::logMessage('SyncML: Authentication not yet possible currently. Password not available' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(strstr($this->_locName,'@') === False)
|
||||
{
|
||||
$this->_locName .= '@'.$GLOBALS['egw_info']['server']['default_domain'];
|
||||
}
|
||||
|
||||
#Horde::logMessage('SyncML: authenticate with username: ' . $this->_locName . ' and password: ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
if($GLOBALS['sessionid'] = $GLOBALS['egw']->session->create($this->_locName,$this->_password,'text','u'))
|
||||
{
|
||||
$this->_isAuthorized = true;
|
||||
Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_isAuthorized = false;
|
||||
Horde::logMessage('SyncML: Authentication of ' . $this->_locName . ' failed' , __FILE__, __LINE__, PEAR_LOG_INFO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// store sessionID in a variable, because ->verify maybe resets that value
|
||||
$sessionID = session_id();
|
||||
if(!$GLOBALS['egw']->session->verify($sessionID, 'staticsyncmlkp3')) {
|
||||
Horde::logMessage('SyncML_EGW: egw session(' .$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_isAuthorized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the locid<->guid mapping for the given locid. Returns
|
||||
* the guid that was removed or false if no mapping entry was
|
||||
* found.
|
||||
*/
|
||||
function removeUID($type, $locid)
|
||||
{
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$cols = array('map_guid');
|
||||
|
||||
$where = array
|
||||
(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid
|
||||
);
|
||||
|
||||
$db->select('egw_contentmap', $cols, $where, __LINE__, __FILE__);
|
||||
|
||||
if(!$db->next_record())
|
||||
{
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : nothing to remove", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
return false;
|
||||
}
|
||||
|
||||
$guid = $db->f('map_guid');
|
||||
|
||||
#Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$db->delete('egw_contentmap', $where, __LINE__, __FILE__);
|
||||
|
||||
return $guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a given client $locid and Horde server $guid pair into the
|
||||
* map table to allow mapping between the client's and server's
|
||||
* IDs. Actually there are two maps: from the localid to the guid
|
||||
* and vice versa. The localid is converted to a key as follows:
|
||||
* this->_locName . $this->_sourceURI . $type . $locid so you can
|
||||
* have different syncs with different devices. If an entry
|
||||
* already exists, it is overwritten.
|
||||
*/
|
||||
function setUID($type, $locid, $guid, $ts=0)
|
||||
{
|
||||
// fix $guid, it maybe was to long for some devices
|
||||
// format is appname-id-systemid
|
||||
$guidParts = explode('-',$guid);
|
||||
if(count($guidParts) == 3)
|
||||
{
|
||||
$guid = $GLOBALS['egw']->common->generate_uid($guidParts[0],$guidParts[1]);
|
||||
}
|
||||
|
||||
if($ts == 0)
|
||||
{
|
||||
$ts = time();
|
||||
}
|
||||
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ".count($guidParts), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$db = clone($GLOBALS['egw']->db);
|
||||
|
||||
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||
|
||||
// delete all client id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_locuid' => $locid,
|
||||
);
|
||||
$db->delete('egw_contentmap', $where, __LINE__, __FILE__);
|
||||
|
||||
// delete all egw id's
|
||||
$where = array(
|
||||
'map_id' => $mapID,
|
||||
'map_guid' => $guid,
|
||||
);
|
||||
$db->delete('egw_contentmap', $where, __LINE__, __FILE__);
|
||||
|
||||
$data = $where + array(
|
||||
'map_locuid' => $locid,
|
||||
'map_timestamp' => $ts,
|
||||
'map_expired' => 0,
|
||||
);
|
||||
$db->insert('egw_contentmap', $data, $where, __LINE__, __FILE__);
|
||||
|
||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts $mapID", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* write clients device info to database
|
||||
*/
|
||||
function writeClientDeviceInfo()
|
||||
{
|
||||
if (!isset($this->_clientDeviceInfo) || !is_array($this->_clientDeviceInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
$data = array
|
||||
(
|
||||
'dev_id' => $deviceID,
|
||||
'dev_dtdversion' => $this->_clientDeviceInfo['DTDVersion'],
|
||||
'dev_numberofchanges' => $this->_clientDeviceInfo['supportNumberOfChanges'],
|
||||
'dev_largeobjs' => $this->_clientDeviceInfo['supportLargeObjs'],
|
||||
'dev_swversion' => $this->_clientDeviceInfo['softwareVersion'],
|
||||
'dev_oem' => $this->_clientDeviceInfo['oem'],
|
||||
'dev_model' => $this->_clientDeviceInfo['model'],
|
||||
'dev_manufacturer' => $this->_clientDeviceInfo['manufacturer'],
|
||||
'dev_devicetype' => $this->_clientDeviceInfo['deviceType'],
|
||||
'dev_deviceid' => $this->_clientDeviceInfo['deviceID'],
|
||||
'dev_datastore' => serialize($this->_clientDeviceInfo['dataStore']),
|
||||
);
|
||||
|
||||
$where = array
|
||||
(
|
||||
'dev_id' => $deviceID,
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->insert('egw_syncmldevinfo', $data, $where, __LINE__, __FILE__);
|
||||
}
|
||||
|
||||
/**
|
||||
* After a successful sync, the client and server's Next Anchors
|
||||
* are written to the database so they can be used to negotiate
|
||||
* upcoming syncs.
|
||||
*/
|
||||
function writeSyncSummary()
|
||||
{
|
||||
#parent::writeSyncSummary();
|
||||
|
||||
if (!isset($this->_serverAnchorNext) || !is_array($this->_serverAnchorNext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$deviceID = $this->_locName . $this->_sourceURI;
|
||||
|
||||
foreach((array)$this->_serverAnchorNext as $type => $a)
|
||||
{
|
||||
Horde::logMessage("SyncML: write SYNCSummary for $deviceID $type serverts: $a clients: ".$this->_clientAnchorNext[$type], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$where = array
|
||||
(
|
||||
'dev_id' => $deviceID,
|
||||
'sync_path' => $type,
|
||||
);
|
||||
|
||||
$data = $where + array
|
||||
(
|
||||
'sync_serverts' => $a,
|
||||
'sync_clientts' => $this->_clientAnchorNext[$type]
|
||||
);
|
||||
|
||||
$GLOBALS['egw']->db->insert('egw_syncmlsummary', $data, $where, __LINE__, __FILE__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -73,6 +73,9 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
// can happen.
|
||||
#LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
|
||||
$cmd->setContentFormat('b64');
|
||||
}
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
|
247
phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php
Normal file
247
phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php
Normal file
@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
include_once 'Horde/SyncML/Sync.php';
|
||||
include_once 'Horde/SyncML/Command/Sync/ContentSyncElement.php';
|
||||
|
||||
/**
|
||||
* $Horde: framework/SyncML/SyncML/Sync/TwoWaySync.php,v 1.12 2004/07/26 09:24:38 jan 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>
|
||||
* @author Karsten Fourmont <fourmont@gmx.de>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @since Horde 3.0
|
||||
* @package Horde_SyncML
|
||||
*/
|
||||
class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
|
||||
|
||||
function endSync($currentCmdID, &$output)
|
||||
{
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = str_replace('./','',$syncType);
|
||||
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
$currentCmdID = $this->handleSync($currentCmdID,
|
||||
$hordeType,
|
||||
$syncType,
|
||||
$output,
|
||||
$refts);
|
||||
if ($syncType == 'calendar' && $state->handleTasksInCalendar()) {
|
||||
Horde::logMessage("SyncML: handling tasks in calendar sync", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$currentCmdID = $this->handleSync($currentCmdID, 'tasks', $syncType,
|
||||
$output, $refts);
|
||||
}
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function handleSync($currentCmdID, $hordeType, $syncType,&$output, $refts) {
|
||||
global $registry;
|
||||
|
||||
// array of Items which got modified, but got never send to the client before
|
||||
$missedAdds = array();
|
||||
|
||||
$history = $GLOBALS['phpgw']->contenthistory;
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$counter = 0;
|
||||
|
||||
$changes = &$state->getChangedItems($hordeType);
|
||||
$deletes = &$state->getDeletedItems($hordeType);
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
|
||||
Horde::logMessage("SyncML: ".count($changes).' changed items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($deletes).' deleted items found for '.$hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
while($guid = array_shift($changes)) {
|
||||
$guid_ts = $history->getTSforAction($guid, 'modify');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp modify guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: change: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: change $guid hs_ts:$guid_ts dt_ts:" . $state->getChangeTS($syncType, $guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
// somehow we missed to add, lets store the uid, so we add this entry later
|
||||
$missedAdds[] = $guid;
|
||||
Horde::logMessage("SyncML: unable to create change for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a replace request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
|
||||
if(is_a($contentType, 'PEAR_Error')) {
|
||||
// Client did not sent devinfo
|
||||
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
|
||||
}
|
||||
$c = $registry->call($hordeType. '/export',
|
||||
array('guid' => $guid, 'contentType' => $contentType));
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
Horde::logMessage("SyncML: change: $guid export content: $c", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
# LK $cmd->setContent($state->convertServer2Client($c, $contentType));
|
||||
$cmd->setContent($c);
|
||||
$cmd->setSourceURI($guid);
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
|
||||
$cmd->setContentFormat('b64');
|
||||
}
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace');
|
||||
$state->log('Server-Replace');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' && $hordeType != 'siftasks') {
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
}
|
||||
Horde::logMessage("SyncML: handling sync (changes done) ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// deletes
|
||||
while($guid = array_shift($deletes))
|
||||
{
|
||||
$guid_ts = $history->getTSforAction($guid, 'delete');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp delete guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: delete $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
if (!$locid) {
|
||||
Horde::logMessage("SyncML: unable to create delete for $guid: locid not found in map", __FILE__, __LINE__, PEAR_LOG_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: delete: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
// Create a Delete request for client.
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$cmd->setTargetURI($locid);
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Delete');
|
||||
$state->log('Server-Delete');
|
||||
$state->removeUID($syncType, $locid);
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalender' && $hordeType != 'sifcontacts' &&$hordeType != 'siftasks') {
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
#Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Get adds.
|
||||
if(count($missedAdds) > 0) {
|
||||
Horde::logMessage("SyncML: add missed changes as adds ".count($adds).' / '.$missedAdds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, array_merge($adds, $missedAdds));
|
||||
$adds = &$state->getAddedItems($hordeType);
|
||||
Horde::logMessage("SyncML: merged adds counter ".count($adds).' / '.$adds[0], __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
}
|
||||
|
||||
while($guid = array_shift($adds)) {
|
||||
$guid_ts = $history->getTSforAction($guid, 'add');
|
||||
$sync_ts = $state->getChangeTS($syncType, $guid);
|
||||
Horde::logMessage("SyncML: timestamp add $guid guid_ts: $guid_ts sync_ts: $sync_ts", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
if ($sync_ts && $sync_ts == $guid_ts) {
|
||||
// Change was done by us upon request of client.
|
||||
// Don't mirror that back to the client.
|
||||
Horde::logMessage("SyncML: add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
|
||||
$locid = $state->getLocID($syncType, $guid);
|
||||
|
||||
if ($locid && $refts == 0) {
|
||||
// For slow sync (ts=0): do not add data for which we
|
||||
// have a locid again. This is a heuristic to avoid
|
||||
// duplication of entries.
|
||||
Horde::logMessage("SyncML: skipping add of guid $guid as there already is a locid $locid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
Horde::logMessage("SyncML: add: $guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
// Create an Add request for client.
|
||||
$contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI);
|
||||
if(is_a($contentType, 'PEAR_Error')) {
|
||||
// Client did not sent devinfo
|
||||
$contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI));
|
||||
}
|
||||
|
||||
$cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement();
|
||||
$c = $registry->call($hordeType . '/export',
|
||||
array(
|
||||
'guid' => $guid ,
|
||||
'contentType' => $contentType ,
|
||||
)
|
||||
);
|
||||
|
||||
if (!is_a($c, 'PEAR_Error')) {
|
||||
// Item in history but not in database. Strange, but can happen.
|
||||
$cmd->setContent($c);
|
||||
if($hordeType == 'sifcalendar' || $hordeType == 'sifcontacts' || $hordeType == 'siftasks') {
|
||||
$cmd->setContentFormat('b64');
|
||||
}
|
||||
$cmd->setContentType($contentType['ContentType']);
|
||||
$cmd->setSourceURI($guid);
|
||||
$currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add');
|
||||
$state->log('Server-Add');
|
||||
|
||||
// return if we have to much data
|
||||
if(++$counter >= MAX_ENTRIES && $hordeType != 'sifcalendar' && $hordeType != 'sifcontacts' &&$hordeType != 'siftasks') {
|
||||
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
|
||||
return $currentCmdID;
|
||||
}
|
||||
}
|
||||
}
|
||||
Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
$state->clearSync($syncType);
|
||||
|
||||
return $currentCmdID;
|
||||
}
|
||||
|
||||
function loadData()
|
||||
{
|
||||
global $registry;
|
||||
|
||||
$state = &$_SESSION['SyncML.state'];
|
||||
$syncType = $this->_targetLocURI;
|
||||
$hordeType = str_replace('./','',$syncType);
|
||||
$refts = $state->getServerAnchorLast($syncType);
|
||||
|
||||
Horde::logMessage("SyncML: reading changed items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setChangedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'modify', 'timestamp' => $refts)));
|
||||
|
||||
Horde::logMessage("SyncML: reading deleted items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setDeletedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'delete', 'timestamp' => $refts)));
|
||||
|
||||
Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
$state->setAddedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'add', 'timestamp' => $refts)));
|
||||
|
||||
$this->_syncDataLoaded = TRUE;
|
||||
|
||||
return count($state->getChangedItems($hordeType)) +
|
||||
count($state->getDeletedItems($hordeType)) +
|
||||
count($state->getAddedItems($hordeType));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user