mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-14 09:58:16 +01:00
Big SyncML patch from Philip Herbert <pherbert(at)knauber.de>:
- change the processing of slowsync, to use the content_map instead of trying to build a new one. This caused duplication issues on the client if multiple similar records where stored, because only the first one found in the server-db was matched, These duplicate entries at client side had no entry at serverside, so deleting the wrong one on the client (the content with a valid map entry) could cause unwanted data loss at server side, because it is impossible for the user to see what is a duplicate, and what is not. see also: http://www.nabble.com/again---syncml-duplication-issue-to20333619s3741.html - reenabled UID from syncml clients, because it was partly used this caused issues during SlowSync if the content was changed. - infolog, calendar if a uid is found in the provided data, allway try to find the corresponding content first using only the UID, instead of using the content-id taken from content_map. also fixed: - a few fixes in ./notes - creating an entry on the client that can not be imported, (Example, Nokia E Series Appointment without a Title) will no longer create an invalid content-map entry However, at client side this is still counted in the Protocol as Server-Add
This commit is contained in:
parent
c8b2d0d5d3
commit
1baa158195
@ -164,12 +164,15 @@ class addressbook_sif extends addressbook_bo
|
|||||||
* @param string $_sifdata
|
* @param string $_sifdata
|
||||||
* @return boolean/int/string contact-id or false, if not found
|
* @return boolean/int/string contact-id or false, if not found
|
||||||
*/
|
*/
|
||||||
function search($_sifdata)
|
function search($_sifdata,$contentID=null)
|
||||||
{
|
{
|
||||||
if(!$contact = $this->siftoegw($_sifdata))
|
if(!$contact = $this->siftoegw($_sifdata))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($contentID) {
|
||||||
|
$contact['contact_id'] = $contentID;
|
||||||
|
}
|
||||||
// patch from Di Guest says: we need to ignore the n_fileas
|
// patch from Di Guest says: we need to ignore the n_fileas
|
||||||
unset($contact['n_fileas']);
|
unset($contact['n_fileas']);
|
||||||
// we probably need to ignore even more as we do in vcaladdressbook
|
// we probably need to ignore even more as we do in vcaladdressbook
|
||||||
|
@ -170,12 +170,16 @@ class addressbook_vcal extends addressbook_bo
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function search($_vcard)
|
function search($_vcard, $contentID=null)
|
||||||
{
|
{
|
||||||
if(!($contact = $this->vcardtoegw($_vcard))) {
|
if(!($contact = $this->vcardtoegw($_vcard))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($contentID) {
|
||||||
|
$contact['contact_id'] = $contentID;
|
||||||
|
}
|
||||||
|
|
||||||
unset($contact['private']);
|
unset($contact['private']);
|
||||||
unset($contact['note']);
|
unset($contact['note']);
|
||||||
unset($contact['n_fn']);
|
unset($contact['n_fn']);
|
||||||
|
@ -169,7 +169,6 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$event['start'] = $event['start'] + $DSTCorrection;
|
$event['start'] = $event['start'] + $DSTCorrection;
|
||||||
$event['end'] = $event['end'] + $DSTCorrection;
|
$event['end'] = $event['end'] + $DSTCorrection;
|
||||||
*/
|
*/
|
||||||
$eventGUID = $GLOBALS['egw']->common->generate_uid('calendar',$event['id']);
|
|
||||||
|
|
||||||
$vevent = Horde_iCalendar::newComponent('VEVENT',$vcal);
|
$vevent = Horde_iCalendar::newComponent('VEVENT',$vcal);
|
||||||
$parameters = $attributes = array();
|
$parameters = $attributes = array();
|
||||||
@ -440,7 +439,7 @@ class calendar_ical extends calendar_boupdate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$attributes['UID'] = $event['uid'];
|
//$attributes['UID'] = $event['uid'];
|
||||||
foreach($attributes as $key => $value)
|
foreach($attributes as $key => $value)
|
||||||
{
|
{
|
||||||
foreach(is_array($value)&&$parameters[$key]['VALUE']!='DATE' ? $value : array($value) as $valueID => $valueData)
|
foreach(is_array($value)&&$parameters[$key]['VALUE']!='DATE' ? $value : array($value) as $valueID => $valueData)
|
||||||
@ -1298,7 +1297,6 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$vcardData['end'] = $attributes['value'];
|
$vcardData['end'] = $attributes['value'];
|
||||||
break;
|
break;
|
||||||
case 'DTSTART':
|
case 'DTSTART':
|
||||||
//error_log (" CALENDAR ROBV DTSTART: ". $attributes['value']);
|
|
||||||
$vcardData['start'] = $attributes['value'];
|
$vcardData['start'] = $attributes['value'];
|
||||||
break;
|
break;
|
||||||
case 'LOCATION':
|
case 'LOCATION':
|
||||||
@ -1405,6 +1403,12 @@ class calendar_ical extends calendar_boupdate
|
|||||||
$event['id'] = $uid_event['id'];
|
$event['id'] = $uid_event['id'];
|
||||||
unset($uid_event);
|
unset($uid_event);
|
||||||
}
|
}
|
||||||
|
// not use weak uids that might come from syncml clients
|
||||||
|
if (isset($event['uid']) && (strlen($event['uid']) < 20 || is_numeric($event['uid'])))
|
||||||
|
{
|
||||||
|
error_log ("unset weak uid");
|
||||||
|
unset ($event['uid']);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'TRANSP':
|
case 'TRANSP':
|
||||||
$vcardData['non_blocking'] = $attributes['value'] == 'TRANSPARENT';
|
$vcardData['non_blocking'] = $attributes['value'] == 'TRANSPARENT';
|
||||||
@ -1516,17 +1520,25 @@ class calendar_ical extends calendar_boupdate
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function search($_vcalData)
|
function search($_vcalData, $contentID=null)
|
||||||
{
|
{
|
||||||
if(!$event = $this->icaltoegw($_vcalData)) {
|
if(!$event = $this->icaltoegw($_vcalData)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($event['uid'] && ($uidmatch = $this->read($event['uid'])))
|
||||||
|
{
|
||||||
|
return $uidmatch['id'];
|
||||||
|
}
|
||||||
|
|
||||||
$query = array(
|
$query = array(
|
||||||
'cal_start='.$this->date2ts($event['start'],true), // true = Server-time
|
'cal_start='.$this->date2ts($event['start'],true), // true = Server-time
|
||||||
'cal_end='.$this->date2ts($event['end'],true),
|
'cal_end='.$this->date2ts($event['end'],true),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($contentID) {
|
||||||
|
$query[] = 'egw_cal.cal_id='.(int)$contentID;
|
||||||
|
}
|
||||||
|
|
||||||
#foreach(array('title','location','priority','public','non_blocking') as $name) {
|
#foreach(array('title','location','priority','public','non_blocking') as $name) {
|
||||||
foreach(array('title','location','public','non_blocking') as $name) {
|
foreach(array('title','location','public','non_blocking') as $name) {
|
||||||
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
||||||
|
@ -205,7 +205,7 @@ class calendar_sif extends calendar_boupdate
|
|||||||
return $finalEvent;
|
return $finalEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
function search($_sifdata) {
|
function search($_sifdata, $contentID=null) {
|
||||||
if(!$event = $this->siftoegw($_sifdata)) {
|
if(!$event = $this->siftoegw($_sifdata)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -215,6 +215,10 @@ class calendar_sif extends calendar_boupdate
|
|||||||
'cal_end='.$this->date2ts($event['end'],true),
|
'cal_end='.$this->date2ts($event['end'],true),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($contentID) {
|
||||||
|
$query[] = 'egw_cal.cal_id='.(int)$contentID;
|
||||||
|
}
|
||||||
|
|
||||||
#foreach(array('title','location','priority','public','non_blocking') as $name) {
|
#foreach(array('title','location','priority','public','non_blocking') as $name) {
|
||||||
foreach(array('title','location','public','non_blocking') as $name) {
|
foreach(array('title','location','public','non_blocking') as $name) {
|
||||||
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
||||||
|
@ -128,12 +128,23 @@ class infolog_ical extends infolog_bo
|
|||||||
return $this->write($taskData);
|
return $this->write($taskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchVTODO($_vcalData)
|
function searchVTODO($_vcalData, $contentID=null)
|
||||||
{
|
{
|
||||||
if(!$egwData = $this->vtodotoegw($_vcalData)) {
|
if(!$egwData = $this->vtodotoegw($_vcalData)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$myfilter = array('col_filter' => array('info_uid'=>$egwData['info_uid'])) ;
|
||||||
|
if ($egwData['info_uid'] && ($found=parent::search($myfilter)) && ($uidmatch = array_shift($found)))
|
||||||
|
{
|
||||||
|
return $uidmatch['info_id'];
|
||||||
|
};
|
||||||
|
unset($egwData['info_uid']);
|
||||||
|
|
||||||
|
if ($contentID) {
|
||||||
|
$egwData['info_id'] = $contentID;
|
||||||
|
}
|
||||||
|
|
||||||
#unset($egwData['info_priority']);
|
#unset($egwData['info_priority']);
|
||||||
|
|
||||||
$filter = array('col_filter' => $egwData);
|
$filter = array('col_filter' => $egwData);
|
||||||
@ -223,6 +234,12 @@ class infolog_ical extends infolog_bo
|
|||||||
$taskData['info_id'] = $uid_task['id'];
|
$taskData['info_id'] = $uid_task['id'];
|
||||||
unset($uid_task);
|
unset($uid_task);
|
||||||
}
|
}
|
||||||
|
// not use weak uids that might come from syncml clients
|
||||||
|
if (isset($event['uid']) && (strlen($event['uid']) < 20 || is_numeric($event['uid'])))
|
||||||
|
{
|
||||||
|
unset ($event['uid']);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'PERCENT-COMPLETE':
|
case 'PERCENT-COMPLETE':
|
||||||
$taskData['info_percent'] = (int) $attributes['value'];
|
$taskData['info_percent'] = (int) $attributes['value'];
|
||||||
@ -300,13 +317,16 @@ class infolog_ical extends infolog_bo
|
|||||||
return $this->write($note);
|
return $this->write($note);
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchVNOTE($_vcalData, $_type)
|
function searchVNOTE($_vcalData, $_type, $contentID=null)
|
||||||
{
|
{
|
||||||
if(!$note = $this->vnotetoegw($_vcalData)) {
|
if(!$note = $this->vnotetoegw($_vcalData,$_type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($contentID) {
|
||||||
|
$note['info_id'] = $contentID;
|
||||||
|
}
|
||||||
|
|
||||||
$filter = array('col_filter' => $egwData);
|
$filter = array('col_filter' => $note);
|
||||||
if($foundItems = $this->search($filter)) {
|
if($foundItems = $this->search($filter)) {
|
||||||
if(count($foundItems) > 0) {
|
if(count($foundItems) > 0) {
|
||||||
$itemIDs = array_keys($foundItems);
|
$itemIDs = array_keys($foundItems);
|
||||||
@ -335,6 +355,8 @@ class infolog_ical extends infolog_bo
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// should better be imported as subject, but causes duplicates
|
||||||
|
// TODO: should be examined
|
||||||
$note['info_des'] = $txt;
|
$note['info_des'] = $txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,10 +243,13 @@ class infolog_sif extends infolog_bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchSIF($_sifData, $_sifType) {
|
function searchSIF($_sifData, $_sifType, $contentID=null) {
|
||||||
if(!$egwData = $this->siftoegw($_sifData, $_sifType)) {
|
if(!$egwData = $this->siftoegw($_sifData, $_sifType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if ($contentID) {
|
||||||
|
$egwData['info_id'] = $contentID;
|
||||||
|
}
|
||||||
|
|
||||||
$filter = array('col_filter' => $egwData);
|
$filter = array('col_filter' => $egwData);
|
||||||
if($foundItems = $this->search($filter)) {
|
if($foundItems = $this->search($filter)) {
|
||||||
|
@ -112,7 +112,7 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
|||||||
Horde::logMessage("SyncML: Anchor match, TwoWaySync since " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
Horde::logMessage("SyncML: Anchor match, TwoWaySync since " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
} else {
|
} else {
|
||||||
Horde::logMessage("SyncML: Anchor mismatch, enforcing SlowSync clientlast $clientlast serverlast ".$this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
Horde::logMessage("SyncML: Anchor mismatch, enforcing SlowSync clientlast $clientlast serverlast ".$this->_metaAnchorLast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
// Mismatch, enforce slow sync.
|
// Mismatch, enforce slow sync. 508=RESPONSE_REFRESH_REQUIRED 201=ALERT_SLOW_SYNC
|
||||||
$this->_alert = 201;
|
$this->_alert = 201;
|
||||||
$code = 508;
|
$code = 508;
|
||||||
// create new synctype
|
// create new synctype
|
||||||
@ -122,7 +122,9 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
|||||||
if(isset($this->_targetLocURIParameters))
|
if(isset($this->_targetLocURIParameters))
|
||||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||||
$state->setSync($this->_targetLocURI, $sync);
|
$state->setSync($this->_targetLocURI, $sync);
|
||||||
$state->removeAllUID($this->_targetLocURI);
|
// PH : no longer delete entire content_map entries for client before SlowSync,
|
||||||
|
// use content_map to verify if content is mapped correctly
|
||||||
|
//$state->removeAllUID($this->_targetLocURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = &new Horde_SyncML_Command_Status($code, 'Alert');
|
$status = &new Horde_SyncML_Command_Status($code, 'Alert');
|
||||||
|
@ -1000,7 +1000,7 @@ class Horde_SyncML_State {
|
|||||||
case 'text/x-vcalendar':
|
case 'text/x-vcalendar':
|
||||||
case 'text/x-vevent':
|
case 'text/x-vevent':
|
||||||
case 'text/x-vtodo':
|
case 'text/x-vtodo':
|
||||||
$content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
// $content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1023,7 +1023,7 @@ class Horde_SyncML_State {
|
|||||||
case 'text/x-vcalendar':
|
case 'text/x-vcalendar':
|
||||||
case 'text/x-vevent':
|
case 'text/x-vevent':
|
||||||
case 'text/x-vtodo':
|
case 'text/x-vtodo':
|
||||||
$content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
// $content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +304,25 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in SlowSync
|
||||||
|
* Removes all locid<->guid mappings for the given type,
|
||||||
|
* that are older than $ts.
|
||||||
|
*
|
||||||
|
* Returns always true.
|
||||||
|
*/
|
||||||
|
function removeOldUID($type, $ts)
|
||||||
|
{
|
||||||
|
$mapID = $this->_locName . $this->_sourceURI . $type;
|
||||||
|
$where[] = "map_id = '".$mapID."' AND map_timestamp < '".$GLOBALS['egw']->db->to_timestamp($ts)."'";
|
||||||
|
|
||||||
|
Horde::logMessage("SyncML: state->removeOldUID(type=$type)", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
|
|
||||||
|
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the locid<->guid mapping for the given locid. Returns
|
* Removes the locid<->guid mapping for the given locid. Returns
|
||||||
* the guid that was removed or false if no mapping entry was
|
* the guid that was removed or false if no mapping entry was
|
||||||
@ -344,12 +363,6 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
|||||||
{
|
{
|
||||||
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
#Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
#Horde::logMessage("SyncML: setUID ". $this->getUIDMapping($guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
#Horde::logMessage("SyncML: setUID ". $this->getUIDMapping($guid), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
// 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]);
|
|
||||||
#}
|
|
||||||
|
|
||||||
// problem: entries created from client, come here with the (long) server guid,
|
// problem: entries created from client, come here with the (long) server guid,
|
||||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||||
|
@ -25,10 +25,12 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
|||||||
$history = $GLOBALS['egw']->contenthistory;
|
$history = $GLOBALS['egw']->contenthistory;
|
||||||
$state = &$_SESSION['SyncML.state'];
|
$state = &$_SESSION['SyncML.state'];
|
||||||
|
|
||||||
$adds = &$state->getAddedItems($hordeType);
|
|
||||||
|
|
||||||
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
||||||
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
$serverAnchorNext = $state->getServerAnchorNext($syncType);
|
||||||
|
|
||||||
|
// now we remove all UID from contentmap that have not been verified in this slowsync
|
||||||
|
$state->removeOldUID($syncType, $serverAnchorNext);
|
||||||
|
$adds = &$state->getAddedItems($hordeType);
|
||||||
|
Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
$counter = 0;
|
$counter = 0;
|
||||||
|
|
||||||
if(is_array($adds)) {
|
if(is_array($adds)) {
|
||||||
@ -147,7 +149,7 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
|||||||
$guid = false;
|
$guid = false;
|
||||||
|
|
||||||
$guid = $registry->call($hordeType . '/search',
|
$guid = $registry->call($hordeType . '/search',
|
||||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType, $state->getGlobalUID($type, $syncItem->getLocURI()) ));
|
||||||
|
|
||||||
if ($guid) {
|
if ($guid) {
|
||||||
# entry exists in database already. Just update the mapping
|
# entry exists in database already. Just update the mapping
|
||||||
@ -156,10 +158,11 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
|||||||
$state->log("Client-Replace");
|
$state->log("Client-Replace");
|
||||||
} else {
|
} else {
|
||||||
# Entry does not exist in database: add a new one.
|
# Entry does not exist in database: add a new one.
|
||||||
|
$state->removeUID($type, $syncItem->getLocURI());
|
||||||
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
Horde::logMessage('SyncML: try to add contentype ' . $contentType .' to '. $hordeType, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||||
$guid = $registry->call($hordeType . '/import',
|
$guid = $registry->call($hordeType . '/import',
|
||||||
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType));
|
||||||
if (!is_a($guid, 'PEAR_Error')) {
|
if (!is_a($guid, 'PEAR_Error') && $guid != false) {
|
||||||
$ts = $state->getSyncTSforAction($guid, 'add');
|
$ts = $state->getSyncTSforAction($guid, 'add');
|
||||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||||
$state->log("Client-AddReplace");
|
$state->log("Client-AddReplace");
|
||||||
|
Loading…
Reference in New Issue
Block a user