forked from extern/egroupware
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
|
||||
* @return boolean/int/string contact-id or false, if not found
|
||||
*/
|
||||
function search($_sifdata)
|
||||
function search($_sifdata,$contentID=null)
|
||||
{
|
||||
if(!$contact = $this->siftoegw($_sifdata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($contentID) {
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
// patch from Di Guest says: we need to ignore the n_fileas
|
||||
unset($contact['n_fileas']);
|
||||
// we probably need to ignore even more as we do in vcaladdressbook
|
||||
|
@ -170,12 +170,16 @@ class addressbook_vcal extends addressbook_bo
|
||||
return $result;
|
||||
}
|
||||
|
||||
function search($_vcard)
|
||||
function search($_vcard, $contentID=null)
|
||||
{
|
||||
if(!($contact = $this->vcardtoegw($_vcard))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($contentID) {
|
||||
$contact['contact_id'] = $contentID;
|
||||
}
|
||||
|
||||
unset($contact['private']);
|
||||
unset($contact['note']);
|
||||
unset($contact['n_fn']);
|
||||
|
@ -169,7 +169,6 @@ class calendar_ical extends calendar_boupdate
|
||||
$event['start'] = $event['start'] + $DSTCorrection;
|
||||
$event['end'] = $event['end'] + $DSTCorrection;
|
||||
*/
|
||||
$eventGUID = $GLOBALS['egw']->common->generate_uid('calendar',$event['id']);
|
||||
|
||||
$vevent = Horde_iCalendar::newComponent('VEVENT',$vcal);
|
||||
$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(is_array($value)&&$parameters[$key]['VALUE']!='DATE' ? $value : array($value) as $valueID => $valueData)
|
||||
@ -490,7 +489,7 @@ class calendar_ical extends calendar_boupdate
|
||||
}
|
||||
|
||||
$version = $vcal->getAttribute('VERSION');
|
||||
|
||||
|
||||
if(!is_array($this->supportedFields))
|
||||
{
|
||||
$this->setSupportedFields();
|
||||
@ -1298,7 +1297,6 @@ class calendar_ical extends calendar_boupdate
|
||||
$vcardData['end'] = $attributes['value'];
|
||||
break;
|
||||
case 'DTSTART':
|
||||
//error_log (" CALENDAR ROBV DTSTART: ". $attributes['value']);
|
||||
$vcardData['start'] = $attributes['value'];
|
||||
break;
|
||||
case 'LOCATION':
|
||||
@ -1405,7 +1403,13 @@ class calendar_ical extends calendar_boupdate
|
||||
$event['id'] = $uid_event['id'];
|
||||
unset($uid_event);
|
||||
}
|
||||
break;
|
||||
// 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;
|
||||
case 'TRANSP':
|
||||
$vcardData['non_blocking'] = $attributes['value'] == 'TRANSPARENT';
|
||||
break;
|
||||
@ -1516,17 +1520,25 @@ class calendar_ical extends calendar_boupdate
|
||||
return false;
|
||||
}
|
||||
|
||||
function search($_vcalData)
|
||||
function search($_vcalData, $contentID=null)
|
||||
{
|
||||
if(!$event = $this->icaltoegw($_vcalData)) {
|
||||
return false;
|
||||
}
|
||||
if ($event['uid'] && ($uidmatch = $this->read($event['uid'])))
|
||||
{
|
||||
return $uidmatch['id'];
|
||||
}
|
||||
|
||||
$query = array(
|
||||
'cal_start='.$this->date2ts($event['start'],true), // true = Server-time
|
||||
'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','public','non_blocking') as $name) {
|
||||
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
||||
|
@ -205,7 +205,7 @@ class calendar_sif extends calendar_boupdate
|
||||
return $finalEvent;
|
||||
}
|
||||
|
||||
function search($_sifdata) {
|
||||
function search($_sifdata, $contentID=null) {
|
||||
if(!$event = $this->siftoegw($_sifdata)) {
|
||||
return false;
|
||||
}
|
||||
@ -214,7 +214,11 @@ class calendar_sif extends calendar_boupdate
|
||||
'cal_start='.$this->date2ts($event['start'],true), // true = Server-time
|
||||
'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','public','non_blocking') as $name) {
|
||||
if (isset($event[$name])) $query['cal_'.$name] = $event[$name];
|
||||
|
@ -128,11 +128,22 @@ class infolog_ical extends infolog_bo
|
||||
return $this->write($taskData);
|
||||
}
|
||||
|
||||
function searchVTODO($_vcalData)
|
||||
function searchVTODO($_vcalData, $contentID=null)
|
||||
{
|
||||
if(!$egwData = $this->vtodotoegw($_vcalData)) {
|
||||
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']);
|
||||
|
||||
@ -223,6 +234,12 @@ class infolog_ical extends infolog_bo
|
||||
$taskData['info_id'] = $uid_task['id'];
|
||||
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;
|
||||
case 'PERCENT-COMPLETE':
|
||||
$taskData['info_percent'] = (int) $attributes['value'];
|
||||
@ -300,13 +317,16 @@ class infolog_ical extends infolog_bo
|
||||
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;
|
||||
}
|
||||
if ($contentID) {
|
||||
$note['info_id'] = $contentID;
|
||||
}
|
||||
|
||||
$filter = array('col_filter' => $egwData);
|
||||
$filter = array('col_filter' => $note);
|
||||
if($foundItems = $this->search($filter)) {
|
||||
if(count($foundItems) > 0) {
|
||||
$itemIDs = array_keys($foundItems);
|
||||
@ -335,6 +355,8 @@ class infolog_ical extends infolog_bo
|
||||
}
|
||||
else
|
||||
{
|
||||
// should better be imported as subject, but causes duplicates
|
||||
// TODO: should be examined
|
||||
$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)) {
|
||||
return false;
|
||||
}
|
||||
if ($contentID) {
|
||||
$egwData['info_id'] = $contentID;
|
||||
}
|
||||
|
||||
$filter = array('col_filter' => $egwData);
|
||||
if($foundItems = $this->search($filter)) {
|
||||
|
@ -112,9 +112,9 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
Horde::logMessage("SyncML: Anchor match, TwoWaySync since " . $clientlast, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
} else {
|
||||
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;
|
||||
$code = 508;
|
||||
$code = 508;
|
||||
// create new synctype
|
||||
$sync = &Horde_SyncML_Sync::factory($this->_alert);
|
||||
$sync->_targetLocURI = $this->_targetLocURI;
|
||||
@ -122,7 +122,9 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
|
||||
if(isset($this->_targetLocURIParameters))
|
||||
$sync->_targetLocURIParameters = $this->_targetLocURIParameters;
|
||||
$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');
|
||||
|
@ -1000,7 +1000,7 @@ class Horde_SyncML_State {
|
||||
case 'text/x-vcalendar':
|
||||
case 'text/x-vevent':
|
||||
case 'text/x-vtodo':
|
||||
$content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||
// $content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1023,7 +1023,7 @@ class Horde_SyncML_State {
|
||||
case 'text/x-vcalendar':
|
||||
case 'text/x-vevent':
|
||||
case 'text/x-vtodo':
|
||||
$content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||
// $content = preg_replace('/^UID:.*\n/m', '', $content, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -301,6 +301,25 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', array('map_id' => $mapID), __LINE__, __FILE__, 'syncml');
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -325,7 +344,7 @@ class EGW_SyncML_State extends Horde_SyncML_State
|
||||
}
|
||||
|
||||
Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||||
|
||||
|
||||
$GLOBALS['egw']->db->delete('egw_contentmap', $where, __LINE__, __FILE__, 'syncml');
|
||||
|
||||
return $guid;
|
||||
@ -344,13 +363,7 @@ 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 ". $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,
|
||||
// but getUIDMapping does not know them and can not map server-guid <--> client guid
|
||||
$guid = $this->getUIDMapping($_guid);
|
||||
|
@ -25,10 +25,12 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
$history = $GLOBALS['egw']->contenthistory;
|
||||
$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);
|
||||
|
||||
// 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;
|
||||
|
||||
if(is_array($adds)) {
|
||||
@ -147,7 +149,7 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
|
||||
$guid = false;
|
||||
|
||||
$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) {
|
||||
# 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");
|
||||
} else {
|
||||
# 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);
|
||||
$guid = $registry->call($hordeType . '/import',
|
||||
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');
|
||||
$state->setUID($type, $syncItem->getLocURI(), $guid, $ts);
|
||||
$state->log("Client-AddReplace");
|
||||
|
Loading…
Reference in New Issue
Block a user