diff --git a/phpgwapi/inc/horde/Horde/RPC/syncml.php b/phpgwapi/inc/horde/Horde/RPC/syncml.php index db3921949c..99fc9ae72e 100644 --- a/phpgwapi/inc/horde/Horde/RPC/syncml.php +++ b/phpgwapi/inc/horde/Horde/RPC/syncml.php @@ -127,8 +127,8 @@ class Horde_RPC_syncml extends Horde_RPC { $xml, $m)) { $this->_charset = $m[1]; } - NLS::setCharset($this->_charset); - String::setDefaultCharset($this->_charset); + #NLS::setCharset($this->_charset); + #String::setDefaultCharset($this->_charset); /* Create the XML parser and set method references. */ $this->_parser = xml_parser_create_ns($this->_charset); diff --git a/phpgwapi/inc/horde/Horde/SyncML.php b/phpgwapi/inc/horde/Horde/SyncML.php index be3550cd62..5f61c842ff 100644 --- a/phpgwapi/inc/horde/Horde/SyncML.php +++ b/phpgwapi/inc/horde/Horde/SyncML.php @@ -155,19 +155,25 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { // It would seem multisync does not send the user name once it // has been authorized. Make sure we have a valid session id. - session_id('syncml' . preg_replace('/[^a-zA-Z0-9]/', '', $sourceURI . $sessionID)); + if(!empty($_GET['syncml_sessionid'])) { + session_id($_GET['syncml_sessionid']); + Horde::logMessage('SyncML['. session_id() .']: reusing existing session', __FILE__, __LINE__, PEAR_LOG_INFO); + } else { + #session_id('syncml' . preg_replace('/[^a-zA-Z0-9]/', '', $sourceURI . $sessionID)); + session_id('syncml-' . md5(uniqid(rand(), true))); + Horde::logMessage('SyncML['. session_id() .']: starting new session for '.$this->_locName, __FILE__, __LINE__, PEAR_LOG_INFO); + } @session_start(); - Horde::logMessage('SyncML: session id = ' . session_id(), __FILE__, __LINE__, PEAR_LOG_DEBUG); if (!isset($_SESSION['SyncML.state'])) { // Create a new state if one does not already exist. - Horde::logMessage('SyncML: new session state', __FILE__, __LINE__, PEAR_LOG_DEBUG); + Horde::logMessage('SyncML['. session_id() .']: create new session state variable', __FILE__, __LINE__, PEAR_LOG_DEBUG); # LK $_SESSION['SyncML.state'] = &new Horde_SyncML_State($sourceURI, $locName, $sessionID); $_SESSION['SyncML.state'] = &new EGW_SyncML_State($sourceURI, $locName, $sessionID); } - if($_SESSION['SyncML.state']->_isAuthorized) - Horde::logMessage('SyncML: is session authorized', __FILE__, __LINE__, PEAR_LOG_DEBUG); + #if($_SESSION['SyncML.state']->_isAuthorized) + # Horde::logMessage('SyncML['. session_id() .']: is session authorized', __FILE__, __LINE__, PEAR_LOG_DEBUG); return $_SESSION['SyncML.state']; } @@ -202,11 +208,13 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { */ // // Find the state. + #Horde::logMessage('SymcML: SyncHdr done. Try to load state from session.', __FILE__, __LINE__, PEAR_LOG_DEBUG); $state = $this->getStateFromSession($this->_sourceURI, $this->_locName, $this->_sessionID); $state->setVersion($this->_version); $state->setMsgID($this->_msgID); $state->setTargetURI($this->_targetURI); + $state->setWBXML(is_a($this->_output, 'XML_WBXML_Encoder')); if(isset($this->_credData) && isset($this->_locName) && !$state->isAuthorized()) { $state->setPassword($this->_credData); @@ -262,7 +270,7 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { } $this->_credData = $tmp[1]; - Horde::logMessage('SyncML: $this->_locName: ' . $this->_locName, __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage('SyncML['. session_id() .']: $this->_locName: ' . $this->_locName, __FILE__, __LINE__, PEAR_LOG_DEBUG); } break; @@ -344,15 +352,16 @@ class Horde_SyncML_SyncMLHdr extends Horde_SyncML_ContentHandler { $output->endElement($uri, 'LocURI'); $output->endElement($uri, 'Source'); - #if(!strpos($this->_targetURI,'syncit')) - #{ - # $output->startElement($uri, 'RespURI', $attrs); - # $output->characters($this->_targetURI.'?syncid='.$GLOBALS['sessionid'].'-'.$GLOBALS['phpgw_info']['user']['kp3']); - # $output->characters($this->_targetURI.'?after=20040101T133000Z-syncid=lars'); - # $output->characters($this->_targetURI.'?sincit=10'); - # $output->characters('http://192.168.4.227/horde/rpc.php?after=20040101T133000Z-username=lars'); - # $output->endElement($uri, 'RespURI'); - #} + if(session_id() != '') { + $output->startElement($uri, 'RespURI', $attrs); + if($_SERVER['HTTPS'] == 'on') { + $httpPrefix = 'https://'; + } else { + $httpPrefix = 'http://'; + } + $output->characters($httpPrefix . $_SERVER['SERVER_NAME'] .':'. $_SERVER['SERVER_PORT'] . $_SERVER['PHP_SELF'] . '?syncml_sessionid=' . session_id()); + $output->endElement($uri, 'RespURI'); + } /* $output->startElement($uri, 'Meta', $attrs); @@ -437,6 +446,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { $state = & $_SESSION['SyncML.state']; $this->_actionCommands = false; // so far, we have not seen commands that require action from our side + $state->_sendFinal = false; // $this->_output->startElement($uri, $element, $attrs); @@ -477,7 +487,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { // We've got to do something! This can't be the last // packet. $this->_actionCommands = true; - Horde::logMessage("SyncML: found action commands <$element> " . $this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_INFO); + Horde::logMessage('SyncML['. session_id() ."]: found action commands <$element> " . $this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_DEBUG); } switch($element) @@ -490,7 +500,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { # break; case 'Sync': $state->setSyncStatus(CLIENT_SYNC_STARTED); - Horde::logMessage('SyncML: syncStatus(client sync started) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO); + Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync started) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG); break; } break; @@ -502,65 +512,92 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { } } - function endElement($uri, $element) - { - switch ($this->_xmlStack) { - case 2: - // - $state = & $_SESSION['SyncML.state']; - - // send the sync reply - // we do still have some data to send OR - // we should reply to the Sync command - $sync = &new Horde_SyncML_Command_Sync(); - $this->_currentCmdID = $sync->syncToClient($this->_currentCmdID, $this->_output); - - // send the Final tag if possible - if($state->getSyncStatus() != SERVER_SYNC_DATA_PENDING && $state->getSyncStatus() != CLIENT_SYNC_STARTED) - { - $final = &new Horde_SyncML_Command_Final(); - $this->_currentCmdID = $final->output($this->_currentCmdID, $this->_output); - } - - $this->_output->endElement($uri, $element); - - Horde::logMessage('SyncML: syncStatus ' . $state->getSyncStatus() .'actionCommands: '.$this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_INFO); - if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_FINNISHED) { - // this packet did not contain any real actions, just status and map. - // This means, we're through! The session can be closed and - // the Anchors saved for the next Sync - $state = & $_SESSION['SyncML.state']; - Horde::logMessage('SyncML: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO); - $state->writeSyncSummary(); - $log = $state->getLog(); - $s=""; - foreach($log as $k => $v) { - $s .= " $k=$v"; - } - Horde::logMessage('SyncML: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO); - // session can be closed here! - #session_unset(); - #session_destroy(); - } + function endElement($uri, $element) { + switch ($this->_xmlStack) { + case 2: + // + $state = & $_SESSION['SyncML.state']; + + if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED && $state->getAlert222Received() == true) { + $state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED); + $state->setAlert222Received(false); + } + + // send the sync reply + // we do still have some data to send OR + // we should reply to the Sync command + if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) { + Horde::logMessage('SyncML sending syncdata to client '. CLIENT_SYNC_ACKNOWLEDGED .'/'. SERVER_SYNC_FINNISHED .'/'. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO); + $sync = &new Horde_SyncML_Command_Sync(); + $this->_currentCmdID = $sync->syncToClient($this->_currentCmdID, $this->_output); + } + + // send the Final tag if possible + #if($state->getSyncStatus() != SERVER_SYNC_DATA_PENDING && $state->getSyncStatus() != CLIENT_SYNC_STARTED) { + if($state->getSyncStatus() >= SERVER_SYNC_FINNISHED || $state->_sendFinal) { + $final = &new Horde_SyncML_Command_Final(); + $this->_currentCmdID = $final->output($this->_currentCmdID, $this->_output); + } + + $this->_output->endElement($uri, $element); + + Horde::logMessage('SyncML['. session_id() .']: syncStatus ' . $state->getSyncStatus() .'actionCommands: '.$this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_FINNISHED) { + // this packet did not contain any real actions, just status and map. + // This means, we're through! The session can be closed and + // the Anchors saved for the next Sync + $state = & $_SESSION['SyncML.state']; + Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO); + $state->writeSyncSummary(); + $log = $state->getLog(); + $s=""; + foreach($log as $k => $v) { + $s .= " $k=$v"; + } + Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO); + # Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO); + # // session can be closed here! + # session_unset(); + # session_destroy(); + } + + if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_ACKNOWLEDGED) { + // this packet did not contain any real actions, just status and map. + // This means, we're through! The session can be closed and + // the Anchors saved for the next Sync + $state = & $_SESSION['SyncML.state']; + Horde::logMessage('SyncML['. session_id() .']: sync' . session_id() . ' completed successfully!', __FILE__, __LINE__, PEAR_LOG_INFO); + $state->writeSyncSummary(); + $log = $state->getLog(); + $s=""; + foreach($log as $k => $v) { + $s .= " $k=$v"; + } + Horde::logMessage('SyncML['. session_id() .']: summary:' . $s, __FILE__, __LINE__, PEAR_LOG_INFO); - if (!$this->_actionCommands && $state->getSyncStatus() == SERVER_SYNC_FINNISHED && $this->_clientSentFinal) { - Horde::logMessage('SyncML: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO); - // session can be closed here! - session_unset(); - session_destroy(); - } - break; - - case 3: - // - $state = & $_SESSION['SyncML.state']; - - // this should be moved to case 2: - if($element == 'Final') - { - // make sure that we request devinfo, if we not have them already + Horde::logMessage('SyncML['. session_id() .']: destroying sync session '.session_id(), __FILE__, __LINE__, PEAR_LOG_INFO); + // session can be closed here! + session_unset(); + session_destroy(); + } + if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED) { + $state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED); + Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync acknowledged) '.$state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG); + } + + break; + + case 3: + // + $state = & $_SESSION['SyncML.state']; + + // this should be moved to case 2: + if($element == 'Final') + { + // make sure that we request devinfo, if we not have them already - if(!$state->getClientDeviceInfo()) +/* if(!$state->getClientDeviceInfo()) { $attrs = array(); $this->_output->startElement($state->getURI(), 'Get', $attrs); @@ -587,43 +624,49 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { $this->_output->endElement($state->getURI(), 'Item'); $this->_output->endElement($state->getURI(), 'Get'); - } - } - $this->_currentCommand->endElement($uri, $element); + } */ + } + + $this->_currentCommand->endElement($uri, $element); + + switch($element) { + case 'Final': + if($state->getSyncStatus() == CLIENT_SYNC_STARTED) { + $state->setSyncStatus(CLIENT_SYNC_FINNISHED); + Horde::logMessage('SyncML['. session_id() .']: syncStatus(client sync finnished) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG); + } + + if($state->getSyncStatus() == SERVER_SYNC_FINNISHED) { + $state->setSyncStatus(SERVER_SYNC_ACKNOWLEDGED); + Horde::logMessage('SyncML['. session_id() .']: syncStatus(server sync acknowledged) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG); + } + + $this->_clientSentFinal = true; + #Horde::logMessage('SyncML['. session_id() .']: Sync _syncTag = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO); + + break; + + default: + $this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output); + break; + } + + unset($this->_currentCommand); + break; - switch($element) - { - case 'Final': - if($state->getSyncStatus() == CLIENT_SYNC_STARTED) - { - $state->setSyncStatus(CLIENT_SYNC_FINNISHED); - Horde::logMessage('SyncML: syncStatus(client sync finnished) ' . $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO); - } - $this->_clientSentFinal = true; - Horde::logMessage('SyncML: Sync _syncTag = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_INFO); - break; - default: - $this->_currentCmdID = $this->_currentCommand->output($this->_currentCmdID, $this->_output); - break; - } - - unset($this->_currentCommand); - break; - - default: - // - $this->_currentCommand->endElement($uri, $element); - break; - } - - parent::endElement($uri, $element); - } - - function characters($str) - { - if (isset($this->_currentCommand)) { - $this->_currentCommand->characters($str); - } - } + default: + // + $this->_currentCommand->endElement($uri, $element); + break; + } + + parent::endElement($uri, $element); + } + + function characters($str) { + if (isset($this->_currentCommand)) { + $this->_currentCommand->characters($str); + } + } } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php index 84c6ebdc96..14563615a2 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Alert.php @@ -196,11 +196,29 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command { $output->endElement($state->getURI(), 'Item'); $output->endElement($state->getURI(), 'Alert'); + $state->_sendFinal = true; + $currentCmdID++; } - } - else - { + } elseif ($this->_alert == ALERT_NEXT_MESSAGE) { + $status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert'); + $status->setCmdRef($this->_cmdID); + if ($this->_targetLocURI != null) { + $status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI)); + } + if ($this->_sourceLocURI != null) { + $status->setSourceRef($this->_sourceLocURI); + } + $status->setItemSourceLocURI($this->_sourceLocURI); + $status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI); + $currentCmdID = $status->output($currentCmdID, $output); + + $state->setAlert222Received(true); + + #if($state->getSyncStatus() > CLIENT_SYNC_STARTED && $state->getSyncStatus() < CLIENT_SYNC_ACKNOWLEDGED) { + # $state->setSyncStatus(CLIENT_SYNC_ACKNOWLEDGED); + #} + } else { $status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert'); $status->setCmdRef($this->_cmdID); if ($this->_sourceLocURI != null) { diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php index c3abf081fb..2efc029223 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php @@ -44,6 +44,10 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { var $_itemDataAnchorLast; + var $_itemTargetLocURI; + + var $_itemSourceLocURI; + function Horde_SyncML_Command_Status($response = null, $cmd = null) { if ($response != null) { @@ -85,13 +89,6 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { $output->characters($chars); $output->endElement($state->getURI(), 'Cmd'); - if (isset($this->_sourceRef)) { - $output->startElement($state->getURI(), 'SourceRef', $attrs); - $chars = $this->_sourceRef; - $output->characters($chars); - $output->endElement($state->getURI(), 'SourceRef'); - } - if (isset($this->_targetRef)) { $output->startElement($state->getURI(), 'TargetRef', $attrs); $chars = $this->_targetRef; @@ -99,6 +96,13 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { $output->endElement($state->getURI(), 'TargetRef'); } + if (isset($this->_sourceRef)) { + $output->startElement($state->getURI(), 'SourceRef', $attrs); + $chars = $this->_sourceRef; + $output->characters($chars); + $output->endElement($state->getURI(), 'SourceRef'); + } + // If we are responding to the SyncHdr and we are not // authorized then request basic authorization. // @@ -170,9 +174,61 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { $output->endElement($state->getURI(), 'Item'); } + if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) { + $output->startElement($state->getURI(), 'Item', $attrs); + + $output->startElement($state->getURI(), 'Target', $attrs); + $output->startElement($state->getURI(), 'LocURI', $attrs); + $output->characters($this->_itemTargetLocURI); + $output->endElement($state->getURI(), 'LocURI'); + $output->endElement($state->getURI(), 'Target'); + + $output->startElement($state->getURI(), 'Source', $attrs); + $output->startElement($state->getURI(), 'LocURI', $attrs); + $output->characters($this->_itemSourceLocURI); + $output->endElement($state->getURI(), 'LocURI'); + $output->endElement($state->getURI(), 'Source'); + + $output->endElement($state->getURI(), 'Item'); + } + $output->endElement($state->getURI(), 'Status'); $currentCmdID++; + + // moredata pending request them +/* if($this->_response == RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED) { + $output->startElement($state->getURI(), 'Alert', $attrs); + + $output->startElement($state->getURI(), 'CmdID', $attrs); + $chars = $currentCmdID; + $output->characters($chars); + $output->endElement($state->getURI(), 'CmdID'); + + $output->startElement($state->getURI(), 'Data', $attrs); + $output->characters(ALERT_NEXT_MESSAGE); + $output->endElement($state->getURI(), 'Data'); + + if (isset($this->_itemTargetLocURI) && isset($this->_itemSourceLocURI)) { + $output->startElement($state->getURI(), 'Item', $attrs); + + $output->startElement($state->getURI(), 'Target', $attrs); + $output->startElement($state->getURI(), 'LocURI', $attrs); + $output->characters($this->_itemTargetLocURI); + $output->endElement($state->getURI(), 'LocURI'); + $output->endElement($state->getURI(), 'Target'); + + $output->startElement($state->getURI(), 'Source', $attrs); + $output->startElement($state->getURI(), 'LocURI', $attrs); + $output->characters($this->_itemSourceLocURI); + $output->endElement($state->getURI(), 'LocURI'); + $output->endElement($state->getURI(), 'Source'); + } + + $output->endElement($state->getURI(), 'Alert'); + + $currentCmdID++; + } */ } return $currentCmdID; @@ -248,4 +304,23 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { $this->_itemDataAnchorLast = $itemDataAnchorLast; } + /** + * Setter for property itemSourceLocURI. + * + * @param string $itemSourceLocURI New value of property itemSourceLocURI. + */ + function setItemSourceLocURI($itemSourceLocURI) + { + $this->_itemSourceLocURI = $itemSourceLocURI; + } + + /** + * Setter for property itemTargetLocURI. + * + * @param string $itemTargetLocURI New value of property itemTargetLocURI. + */ + function setItemTargetLocURI($itemTargetLocURI) + { + $this->_itemTargetLocURI = $itemTargetLocURI; + } } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php index bf900e7c58..addcd4c199 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php @@ -22,46 +22,48 @@ include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php'; */ class Horde_SyncML_Command_Sync extends Horde_Syncml_Command { - var $_isInSource; - var $_currentSyncElement; - var $_syncElements = array(); + var $_isInSource; + var $_currentSyncElement; + var $_syncElements = array(); + + function output($currentCmdID, &$output) { + + $state = &$_SESSION['SyncML.state']; + + $attrs = array(); + + Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG); + + $status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync'); + + // $status->setState($state); + + $status->setCmdRef($this->_cmdID); + + if ($this->_targetURI != null) { + $status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI)); + } + + if ($this->_sourceURI != null) { + $status->setSourceRef($this->_sourceURI); + } + + $currentCmdID = $status->output($currentCmdID, $output); + + if($sync = $state->getSync($this->_targetURI)) { + $currentCmdID = $sync->startSync($currentCmdID, $output); + + foreach ($this->_syncElements as $element) { + $currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output); + } + } - function output($currentCmdID, &$output) - { - $state = &$_SESSION['SyncML.state']; - - $attrs = array(); - - Horde::logMessage('SyncML: $this->_targetURI = ' . $this->_targetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG); - - $status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Sync'); - // $status->setState($state); - $status->setCmdRef($this->_cmdID); - - if ($this->_targetURI != null) { - $status->setTargetRef((isset($this->_targetURIParameters) ? $this->_targetURI.'?/'.$this->_targetURIParameters : $this->_targetURI)); - } - - if ($this->_sourceURI != null) { - $status->setSourceRef($this->_sourceURI); - } - - $currentCmdID = $status->output($currentCmdID, $output); - - $sync = $state->getSync($this->_targetURI); - $currentCmdID = $sync->startSync($currentCmdID, $output); - - foreach ($this->_syncElements as $element ) { - $currentCmdID = $sync->nextSyncCommand($currentCmdID, $element, $output); - } - - return $currentCmdID; - } - - function getTargetURI() - { - return $this->_targetURI; - } + return $currentCmdID; + } + + function getTargetURI() { + return $this->_targetURI; + } function startElement($uri, $element, $attrs) { @@ -96,7 +98,7 @@ class Horde_SyncML_Command_Sync extends Horde_Syncml_Command { Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG); $state = $_SESSION['SyncML.state']; - if($state->getSyncStatus() == CLIENT_SYNC_FINNISHED || $state->getSyncStatus() == SERVER_SYNC_DATA_PENDING) + if($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED) { $deviceInfo = $state->getClientDeviceInfo(); $state->setSyncStatus(SERVER_SYNC_DATA_PENDING); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php index e45da9fd85..ffa14efe5d 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php @@ -108,7 +108,7 @@ class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_ || isset($this->_locURI) || isset($this->targetURI)) { $output->startElement($state->getURI(), 'Item', $attrs); // send only when sending adds - if ($this->_locURI != null && strtolower($command) == 'add') { + 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); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/Replace.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/Replace.php index 7fa8ee6a79..dc08fb741d 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/Replace.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/Replace.php @@ -16,17 +16,18 @@ include_once 'Horde/SyncML/Command/Sync/SyncElement.php'; * @package Horde_SyncML */ class Horde_SyncML_Command_Sync_Replace extends Horde_SyncML_Command_Sync_SyncElement { - - function output($currentCmdID, &$output) - { - $status = &new Horde_SyncML_Command_Status($this->_status, 'Replace'); - $status->setCmdRef($this->_cmdID); - - if (isset($this->_luid)) { - $status->setSourceRef($this->_luid); - } - - return $status->output($currentCmdID, $output); - } + function output($currentCmdID, &$output) { + $status = &new Horde_SyncML_Command_Status($this->_status, 'Replace'); + $status->setCmdRef($this->_cmdID); + + if (isset($this->_luid)) { + $status->setSourceRef($this->_luid); + } + + #$status->setItemSourceLocURI($this->_sourceLocURI); + #$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI); + + return $status->output($currentCmdID, $output); + } } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/SyncElement.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/SyncElement.php index 6d48990275..d4d742a07f 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/SyncElement.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/SyncElement.php @@ -6,6 +6,7 @@ include_once 'Horde/SyncML/Command.php'; * $Horde: framework/SyncML/SyncML/Command/Sync/SyncElement.php,v 1.11 2004/07/02 19:24:44 chuck Exp $ * * Copyright 2003-2004 Anthony Mills + * Copyright 2005-2006 Lars Kneschke * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -17,75 +18,104 @@ include_once 'Horde/SyncML/Command.php'; */ class Horde_SyncML_Command_Sync_SyncElement extends Horde_SyncML_Command { - var $_luid; - var $_guid; - var $_isSource; - var $_content; - var $_contentType; - var $_status = RESPONSE_OK; + var $_luid; + var $_guid; + var $_isSource; + var $_content; + var $_contentType; + var $_status = RESPONSE_OK; + var $_items; + + function &factory($command, $params = null) { + include_once 'Horde/SyncML/Command/Sync/SyncElementItem.php'; + @include_once 'Horde/SyncML/Command/Sync/' . $command . '.php'; + + $class = 'Horde_SyncML_Command_Sync_' . $command; + + if (class_exists($class)) { + #Horde::logMessage('SyncML: Class definition of ' . $class . ' found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG); + return $element = &new $class($params); + } else { + Horde::logMessage('SyncML: Class definition of ' . $class . ' not found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG); + require_once 'PEAR.php'; + return PEAR::raiseError('Class definition of ' . $class . ' not found.'); + } + } - function &factory($command, $params = null) - { - @include_once 'Horde/SyncML/Command/Sync/' . $command . '.php'; - $class = 'Horde_SyncML_Command_Sync_' . $command; - if (class_exists($class)) { - #Horde::logMessage('SyncML: Class definition of ' . $class . ' found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG); - return $element = &new $class($params); - } else { - Horde::logMessage('SyncML: Class definition of ' . $class . ' not found in SyncElement::factory.', __FILE__, __LINE__, PEAR_LOG_DEBUG); - require_once 'PEAR.php'; - return PEAR::raiseError('Class definition of ' . $class . ' not found.'); - } - } + function startElement($uri, $element, $attrs) { + parent::startElement($uri, $element, $attrs); + + switch ($this->_xmlStack) { + case 3: + if ($element == 'Source') { + $this->_isSource = true; + } + break; + } + } + + function endElement($uri, $element) { + $search = array('/ *\n/','/ *$/m'); + $replace = array('',''); + + switch ($this->_xmlStack) { + case 1: + // Need to add sync elements to the Sync method? + #error_log('total # of items: '.count($this->_items)); + #error_log(print_r($this->_items[10], true)); + break; + case 2; + if($element == 'Item') { + $item = new Horde_SyncML_Command_Sync_SyncElementItem(); - function startElement($uri, $element, $attrs) - { - parent::startElement($uri, $element, $attrs); - - switch ($this->_xmlStack) { - case 3: - if ($element == 'Source') { - $this->_isSource = true; - } - break; - } - } - - function endElement($uri, $element) - { - $search = array('/ *\n/','/ *$/m'); - $replace = array('',''); - switch ($this->_xmlStack) { - case 1: - // Need to add sync elements to the Sync method? - break; - - case 3: - if ($element == 'Source') { - $this->_isSource = false; - } elseif ($element == 'Data') { - $this->_content = $this->_chars; - } elseif ($element == 'MoreData') { - $this->_moreData = TRUE; - } elseif ($element == 'Type') { - if(!isset($this->_contentType)) - $this->_contentType = trim($this->_chars); - } - break; - - case 4: - if ($element == 'LocURI' && $this->_isSource) { - $this->_luid = trim($this->_chars); - } elseif ($element == 'Type') { - $this->_contentType = trim($this->_chars); - } elseif ($element == 'Size') { - $this->_contentSize = trim($this->_chars); - } - break; - } - - parent::endElement($uri, $element); - } + if($this->_luid) { + $item->setLocURI($this->_luid); + $item->setContent($this->_content); + $item->setContentType($this->_contentType); + + if($this->_contentSize) + $item->setContentType($this->_contentSize); + if($this->_moreData) + $item->setMoreData($this->_moreData); + + $this->_items[$this->_luid] = $item; + } + + unset($this->_content); + unset($this->_contentSize); + unset($this->_luid); + } + break; + case 3: + if ($element == 'Source') { + $this->_isSource = false; + } elseif ($element == 'Data') { + $this->_content = $this->_chars; + } elseif ($element == 'MoreData') { + $this->_moreData = TRUE; + } elseif ($element == 'Type') { + if(empty($this->_contentType)) + $this->_contentType = trim($this->_chars); + } + break; + + case 4: + if ($element == 'LocURI' && $this->_isSource) { + $this->_luid = trim($this->_chars); + } elseif ($element == 'Type') { + $this->_contentType = trim($this->_chars); + } elseif ($element == 'Size') { + $this->_contentSize = trim($this->_chars); + } + break; + } + + parent::endElement($uri, $element); + } + + function getSyncElementItems() { + return (array)$this->_items; + } function getLocURI() { diff --git a/phpgwapi/inc/horde/Horde/SyncML/State.php b/phpgwapi/inc/horde/Horde/SyncML/State.php index 52454e86ab..4921e16393 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State.php @@ -126,8 +126,10 @@ define('NAME_SPACE_URI_DEVINF_1_1', 'syncml:devinf1.1'); define('CLIENT_SYNC_STARTED', 1); define('CLIENT_SYNC_FINNISHED', 2); -define('SERVER_SYNC_DATA_PENDING', 3); -define('SERVER_SYNC_FINNISHED', 4); +define('CLIENT_SYNC_ACKNOWLEDGED', 3); +define('SERVER_SYNC_DATA_PENDING', 4); +define('SERVER_SYNC_FINNISHED', 5); +define('SERVER_SYNC_ACKNOWLEDGED', 6); define('MAX_DATA', 19); define('MAX_ENTRIES', 10); @@ -148,52 +150,55 @@ define('MAX_ENTRIES', 10); * @package Horde_SyncML */ class Horde_SyncML_State { - - var $_sessionID; - - var $_verProto; - - var $_msgID; - - var $_targetURI; - - var $_sourceURI; - - var $_version; - - var $_locName; - - var $_password; - - var $_isAuthorized; - - var $_uri; - - var $_uriMeta; - - var $_syncs = array(); - - var $_clientAnchorNext = array(); // written to db after successful sync - - var $_serverAnchorLast = array(); - - var $_serverAnchorNext = array(); // written to db after successful sync - - var $_clientDeviceInfo = array(); - - // array list of changed items, which need to be synced to the client - var $_changedItems; - - // array list of deleted items, which need to be synced to the client - var $_deletedItems; - - // array list of added items, which need to be synced to the client - var $_addedItems; - - // bool flag that we need to more data - var $_syncStatus; - - var $_log = array(); + + var $_sessionID; + + var $_verProto; + + var $_msgID; + + var $_targetURI; + + var $_sourceURI; + + var $_version; + + var $_locName; + + var $_password; + + var $_isAuthorized; + + var $_uri; + + var $_uriMeta; + + var $_syncs = array(); + + var $_clientAnchorNext = array(); // written to db after successful sync + + var $_serverAnchorLast = array(); + + var $_serverAnchorNext = array(); // written to db after successful sync + + var $_clientDeviceInfo = array(); + + // array list of changed items, which need to be synced to the client + var $_changedItems; + + // array list of deleted items, which need to be synced to the client + var $_deletedItems; + + // array list of added items, which need to be synced to the client + var $_addedItems; + + // bool flag that we need to more data + var $_syncStatus; + + var $_log = array(); + + // stores if we received Alert 222 already + var $_receivedAlert222 = false; /** * Creates a new instance of Horde_SyncML_State. @@ -465,11 +470,11 @@ class Horde_SyncML_State { * by a element. They require * just . So don't use an ns for non wbxml devices. */ -# if ($this->isWBXML()) { + if ($this->isWBXML()) { return $this->_uri; -# } else { -# return ''; -# } + } else { + return ''; + } } function getURIMeta() { @@ -625,15 +630,42 @@ class Horde_SyncML_State { */ function getPreferedContentType($type) { - if ($type == 'contacts') { - return 'text/x-vcard'; - } elseif ($type == 'notes') { - return 'text/x-vnote'; - } elseif ($type == 'tasks') { - return 'text/x-vcalendar'; - } elseif ($type == 'calendar') { - return 'text/x-vcalendar'; - } +# if ($type == 'contacts') { +# return 'text/x-vcard'; +# } elseif ($type == 'notes') { +# return 'text/x-vnote'; +# } elseif ($type == 'tasks') { +# return 'text/x-vcalendar'; +# } elseif ($type == 'calendar') { +# return 'text/x-vcalendar'; +# } + switch($type) { + case 'contacts': + return 'text/x-vcard'; + break; + + case 'sifcontacts': + case './sifcontacts': + return 'text/x-s4j-sifc'; + break; + + case 'siftasks': + case './siftasks': + return 'text/x-s4j-sift'; + break; + + case 'notes': + return 'text/x-vnote'; + break; + + case 'tasks': + return 'text/x-vcalendar'; + break; + + case 'calendar': + return 'text/x-vcalendar'; + break; + } } /** @@ -889,4 +921,12 @@ class Horde_SyncML_State { exit; } + function getAlert222Received() { + return $this->_receivedAlert222; + } + + function setAlert222Received($_status) { + $this->_receivedAlert222 = (bool)$_status; + } + } diff --git a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php index 3fdb4df99f..13b56a3886 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State_egw.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State_egw.php @@ -23,13 +23,13 @@ class EGW_SyncML_State extends Horde_SyncML_State 'map_guid' => $guid, ); - Horde::logMessage('SyncML: getChangeTS for ' . $mapID .' / '. $guid, __FILE__, __LINE__, PEAR_LOG_DEBUG); + #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); + #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')); } @@ -103,7 +103,7 @@ class EGW_SyncML_State extends Horde_SyncML_State { $mapID = $this->_locName . $this->_sourceURI . $type; - Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage('SyncML: search GlobalUID for ' . $mapID .' / '.$locid, __FILE__, __LINE__, PEAR_LOG_DEBUG); $db = clone($GLOBALS['egw']->db); @@ -145,11 +145,12 @@ class EGW_SyncML_State extends Horde_SyncML_State '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'); } @@ -180,10 +181,10 @@ class EGW_SyncML_State extends Horde_SyncML_State $db->select('egw_syncmlsummary', $cols, $where, __LINE__, __FILE__); - Horde::logMessage("SyncML: get SYNCSummary for $deviceID", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #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); + #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'), @@ -211,12 +212,12 @@ class EGW_SyncML_State extends Horde_SyncML_State $this->_locName .= '@'.$GLOBALS['phpgw_info']['server']['default_domain']; } - Horde::logMessage('SyncML: Authenticate ' . $this->_locName . ' - ' . $this->_password, __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage('SyncML: Authenticate ' . $this->_locName . ' - ' . $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); + #Horde::logMessage('SyncML_EGW: Authentication of ' . $this->_locName . '/' . $GLOBALS['sessionid'] . ' succeded' , __FILE__, __LINE__, PEAR_LOG_DEBUG); } else { @@ -264,7 +265,7 @@ class EGW_SyncML_State extends Horde_SyncML_State $guid = $db->f('map_guid'); - Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: state->removeUID(type=$type,locid=$locid) : removing guid:$guid", __FILE__, __LINE__, PEAR_LOG_DEBUG); $db->delete('egw_contentmap', $where, __LINE__, __FILE__); @@ -295,7 +296,7 @@ class EGW_SyncML_State extends Horde_SyncML_State $ts = time(); } - Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ".count($guidParts), __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts ".count($guidParts), __FILE__, __LINE__, PEAR_LOG_DEBUG); $db = clone($GLOBALS['egw']->db); @@ -312,9 +313,10 @@ class EGW_SyncML_State extends Horde_SyncML_State 'map_expired' => 0, ); + $db->delete('egw_contentmap', $where, __LINE__, __FILE__); $db->insert('egw_contentmap', $data, $where, __LINE__, __FILE__); - Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts $mapID", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: setUID $type, $locid, $guid, $ts $mapID", __FILE__, __LINE__, PEAR_LOG_DEBUG); } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync.php index 433ae979a1..bb443a3138 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync.php @@ -85,158 +85,146 @@ class Horde_SyncML_Sync { 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; - - #require_once 'Horde/History.php'; - #$history = &Horde_History::singleton(); - $history = $GLOBALS['phpgw']->contenthistory; - - $state = &$_SESSION['SyncML.state']; - - if(isset($state->_moreData['luid'])) - { - if(($command->_luid == $state->_moreData['luid'])) - { - $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(); - - return; - } - - } - 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; - - 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'; - } - - $guid = false; - if (is_a($command, 'Horde_SyncML_Command_Sync_Add')) { - $guid = $registry->call($hordeType . '/import', - array($state->convertClient2Server($command->getContent(), $contentType), $contentType)); - if (!is_a($guid, 'PEAR_Error')) { - $ts = $history->getTSforAction($guid, 'add'); - $state->setUID($type, $command->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, $command->getLocURI()); - #$guid = $state->getGlobalUID($type, $command->getLocURI()); - Horde::logMessage('SyncML: about to delete entry ' . $type .' / '. $guid . ' due to client request '.$command->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, $command->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, $command->getLocURI()); - $ok = false; - if ($guid) { - Horde::logMessage('SyncML: locuri'. $command->getLocURI() . ' guid ' . $guid , __FILE__, __LINE__, PEAR_LOG_ERR); - // Entry exists: replace current one. - $ok = $registry->call($hordeType . '/replace', - array($guid, $state->convertClient2Server($command->getContent(), $contentType), $contentType)); - if (!is_a($ok, 'PEAR_Error')) { - $ts = $history->getTSforAction($guid, 'modify'); - $state->setUID($type, $command->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($command->getContent(), $contentType), $contentType)); - if (!is_a($guid, 'PEAR_Error')) { - $ts = $history->getTSforAction($guid, 'add'); - $state->setUID($type, $command->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; - } + /** + * 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; + } } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php index c54fe8fce2..2a6bdd1c1e 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/SlowSync.php @@ -36,60 +36,190 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync { # $adds = &$state->getAddedItems($hordeType); #} - Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: ".count($adds). ' added items found for '.$hordeType , __FILE__, __LINE__, PEAR_LOG_DEBUG); $serverAnchorNext = $state->getServerAnchorNext($syncType); $counter = 0; while($guid = array_shift($adds)) { - #$guid_ts = max($history->getTSforAction($guid, 'add'),$history->getTSforAction($guid, 'modify')); - $sync_ts = $state->getChangeTS($syncType, $guid); - Horde::logMessage("SyncML: slowsync timestamp add: $guid sync_ts: $sync_ts anchorNext: ". $serverAnchorNext.' / '.time(), __FILE__, __LINE__, PEAR_LOG_DEBUG); - // $sync_ts it got synced from client to server someone - // $sync_ts >= $serverAnchorNext it got synced from client to server in this sync package already - if ($sync_ts && $sync_ts >= $serverAnchorNext) { - // Change was done by us upon request of client. - // Don't mirror that back to the client. - //Horde::logMessage("SyncML: slowsync add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG); - continue; - } + #$guid_ts = max($history->getTSforAction($guid, 'add'),$history->getTSforAction($guid, 'modify')); + $sync_ts = $state->getChangeTS($syncType, $guid); + #Horde::logMessage("SyncML: slowsync timestamp add: $guid sync_ts: $sync_ts anchorNext: ". $serverAnchorNext.' / '.time(), __FILE__, __LINE__, PEAR_LOG_DEBUG); + // $sync_ts it got synced from client to server someone + // $sync_ts >= $serverAnchorNext it got synced from client to server in this sync package already + if ($sync_ts && $sync_ts >= $serverAnchorNext) { + // Change was done by us upon request of client. + // Don't mirror that back to the client. + //Horde::logMessage("SyncML: slowsync add: $guid ignored, came from client", __FILE__, __LINE__, PEAR_LOG_DEBUG); + continue; + } -# $locid = $state->getLocID($syncType, $guid); -# + #$locid = $state->getLocID($syncType, $guid); - // Create an Add request for client. + // Create an Add request for client. # LK $contentType = $state->getPreferedContentTypeClient($syncType); - $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI); - $cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement(); - $c = $registry->call($hordeType . '/export', - array('guid' => $guid, - 'contentType' => $contentType)); - Horde::logMessage("SyncML: slowsync add to server $c", __FILE__, __LINE__, PEAR_LOG_DEBUG); - if (!is_a($c, 'PEAR_Error')) { - // Item in history but not in database. Strange, but - // can happen. -#LK $cmd->setContent($state->convertServer2Client($c, $contentType)); - $cmd->setContent($c); - $cmd->setContentType($contentType['ContentType']); - $cmd->setSourceURI($guid); - $currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Add'); - $state->log('Server-Add'); + $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI); + if(is_a($contentType, 'PEAR_Error')) { + // Client did not sent devinfo + $contentType = array('ContentType' => $state->getPreferedContentType($this->_targetLocURI)); + } - // return if we have to much data - if(++$counter >= MAX_ENTRIES) - { - $state->setSyncStatus(SERVER_SYNC_DATA_PENDING); - return $currentCmdID; - } - } - } - Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG); + $cmd = &new Horde_SyncML_Command_Sync_ContentSyncElement(); + $c = $registry->call($hordeType . '/export', array('guid' => $guid, 'contentType' => $contentType)); + #Horde::logMessage("SyncML: slowsync add to server $c", __FILE__, __LINE__, PEAR_LOG_DEBUG); + if (!is_a($c, 'PEAR_Error')) { + // Item in history but not in database. Strange, but + // can happen. + #LK $cmd->setContent($state->convertServer2Client($c, $contentType)); + $cmd->setContent($c); + $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) + { + $state->setSyncStatus(SERVER_SYNC_DATA_PENDING); + return $currentCmdID; + } + } + } + #Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG); $state->clearSync($syncType); return $currentCmdID; } + + /** + * Here's where the actual processing of a client-sent Sync + * Command takes place. Entries are added 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); + + $syncElementItems = $command->getSyncElementItems(); + + foreach($syncElementItems as $syncItem) { + if(!$contentType = $syncItem->getContentType()) { + $contentType = $state->getPreferedContentType($type); + } + + if ($this->_targetLocURI == 'calendar' && strpos($syncItem->getContent(), 'BEGIN:VTODO') !== false) { + $hordeType = 'tasks'; + } + + $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_Replace')) { + #$guid = $state->getGlobalUID($type, $syncItem->getLocURI()); + $guid = $registry->call($hordeType . '/search', + array($state->convertClient2Server($syncItem->getContent(), $contentType), $contentType)); + $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 .' LocURI: '. $syncItem->getLocURI() .' 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 .' 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')) { + $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 true; + } + function loadData() { @@ -99,7 +229,7 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync { $syncType = $this->_targetLocURI; $hordeType = str_replace('./','',$syncType); - Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: reading added items from database for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG); $state->setAddedItems($hordeType, $registry->call($hordeType. '/list', array())); $adds = &$state->getAddedItems($hordeType); $this->_syncDataLoaded = TRUE; diff --git a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php index e8f2becee5..58ee44802e 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Sync/TwoWaySync.php @@ -45,74 +45,71 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { 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(); - - #require_once 'Horde/History.php'; - #$history = &Horde_History::singleton(); - $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. -# LK $contentType = $state->getPreferedContentTypeClient($syncType); - $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI); - $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']); - $currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace'); - $state->log('Server-Replace'); - - // return if we have to much data - if(++$counter >= MAX_ENTRIES) - { - $state->setSyncStatus(SERVER_SYNC_DATA_PENDING); - return $currentCmdID; - } - } - } - Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG); + 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']); + $currentCmdID = $cmd->outputCommand($currentCmdID, $output, 'Replace'); + $state->log('Server-Replace'); + + // return if we have to much data + if(++$counter >= MAX_ENTRIES) { + $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)) @@ -148,72 +145,74 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { return $currentCmdID; } } - Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG); + #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)) - { - #if($tempCounter > 10) continue; - $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. -# LK $contentType = $state->getPreferedContentTypeClient($syncType); - $contentType = $state->getPreferedContentTypeClient($this->_sourceLocURI); - - $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. -#LK $cmd->setContent($state->convertServer2Client($c, $contentType)); - $cmd->setContent($c); - $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) - { - $state->setSyncStatus(SERVER_SYNC_DATA_PENDING); - return $currentCmdID; - } - } - } - Horde::logMessage("SyncML: handling sync ".$currentCmdID, __FILE__, __LINE__, PEAR_LOG_DEBUG); - - $state->clearSync($syncType); - - return $currentCmdID; - } + // 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); + $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) { + $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() { @@ -224,13 +223,13 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync { $hordeType = str_replace('./','',$syncType); $refts = $state->getServerAnchorLast($syncType); - Horde::logMessage("SyncML: reading changed items from database", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: reading changed items from database", __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", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: reading deleted items from database", __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", __FILE__, __LINE__, PEAR_LOG_DEBUG); + #Horde::logMessage("SyncML: reading added items from database", __FILE__, __LINE__, PEAR_LOG_DEBUG); $state->setAddedItems($hordeType, $registry->call($hordeType. '/listBy', array('action' => 'add', 'timestamp' => $refts))); $this->_syncDataLoaded = TRUE; diff --git a/phpgwapi/inc/horde/config/conf.php b/phpgwapi/inc/horde/config/conf.php index 038ec99f90..a00cc7652e 100644 --- a/phpgwapi/inc/horde/config/conf.php +++ b/phpgwapi/inc/horde/config/conf.php @@ -19,9 +19,9 @@ $conf['auth']['params']['username'] = 'Administrator'; $conf['auth']['params']['requestuser'] = false; $conf['auth']['driver'] = 'auto'; $conf['log']['priority'] = PEAR_LOG_DEBUG; -$conf['log']['ident'] = 'HORDE'; +$conf['log']['ident'] = 'EGWSYNC'; $conf['log']['params'] = array(); -$conf['log']['name'] = '/tmp/horde.log'; +$conf['log']['name'] = '/tmp/egroupware_syncml.log'; $conf['log']['params']['append'] = true; $conf['log']['type'] = 'file'; $conf['log']['enabled'] = true; diff --git a/phpgwapi/inc/horde/config/registry.php b/phpgwapi/inc/horde/config/registry.php index fae6c9c3b5..88d177b6be 100644 --- a/phpgwapi/inc/horde/config/registry.php +++ b/phpgwapi/inc/horde/config/registry.php @@ -91,6 +91,16 @@ $this->applications['egwcontactssync'] = array( 'menu_parent' => 'organizing' ); +$this->applications['egwsifcontactssync'] = array( + 'fileroot' => EGW_SERVER_ROOT.'/syncml/sifcontacts', + 'webroot' => $this->applications['horde']['webroot'] . '/mnemo', + 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif', + 'name' => _("SIF Contacts"), + 'status' => 'active', + 'provides' => 'sifcontacts', + 'menu_parent' => 'organizing' +); + $this->applications['egwcalendarsync'] = array( 'fileroot' => EGW_SERVER_ROOT.'/syncml/calendar', 'webroot' => $this->applications['horde']['webroot'] . '/mnemo', @@ -111,3 +121,13 @@ $this->applications['egwtaskssync'] = array( 'menu_parent' => 'organizing' ); +$this->applications['egwsiftaskssync'] = array( + 'fileroot' => EGW_SERVER_ROOT.'/syncml/siftasks', + 'webroot' => $this->applications['horde']['webroot'] . '/mnemo', + 'icon' => $this->applications['horde']['webroot'] . '/mnemo/graphics/mnemo.gif', + 'name' => _("SIFTasks"), + 'status' => 'active', + 'provides' => 'siftasks', + 'menu_parent' => 'organizing' +); +