SyncML fixes

This commit is contained in:
Lars Kneschke 2006-06-01 13:32:55 +00:00
parent 84485d8bca
commit d8450c3c9c
4 changed files with 817 additions and 0 deletions

View File

@ -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;
}
}

View 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__);
}
}
}
?>

View 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');

View 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));
}
}