egroupware/phpgwapi/inc/horde/Horde/SyncML/Sync.php
Ralf Becker 7b6a1013fc SyncML patches from patrick.bihan-faou-AT-mindstep.com (without
logout+mbstring stuff), small modification to use the already exiting
methodes to generate full name and fileas)
The code is commited to trunk only at the moment to allow testing of it.
If everything goes well, we intend to commit it to 1.4 branch too.
Here's the original description of the patch by Patrick:
- handles the default config for current versions of funambol (i.e. the
scard/stask/snote/scal locations)
- tries to be a bit smarter on how the data content should be encoded
based on what the client specified (sif+base64/vcard, / fragmented or
not, etc.)
- workaround a bug in some versions of funambol, where funambol does not
specify the proper sif type for the type of requested data
- imported patch #117 from egw's tracker
- make sure that the logs generated by the horde code go to stderr so
they can be view in the webserver's logs
- as much as possible reduce code duplication. For example, the
categories are handled in the parent classes for both the SIF avn VCAL
formats for each type of data (addressbook,infolog,calendar).
- make sure the code can handle more than one categories in each
  direction
- treat the 'sony ericsson' vendor string just like 'sonyericsson', the
newer phones apparently have a space in the vendor string... (this
touches some files in the icalsrv as well)
- handle notes: these should now work with everything (funambol or
  other)
- remove more code duplication: the syncml "api" for the various data
types (calendar, contacts, infolog) is now common for both the vcard and
sif data formats (cf the files that need to be removed)
- handle the "privat" filter in infolog like the "private" filter (some
part of the code use the name without the trailing e)
- imported patch # 267 from egw's tracker
2007-09-29 10:29:48 +00:00

232 lines
8.6 KiB
PHP

<?php
/**
* $Horde: framework/SyncML/SyncML/Sync.php,v 1.7 2004/09/14 04:27:05 chuck Exp $
*
* Copyright 2003-2004 Anthony Mills <amills@pyramid6.com>
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
* @author Anthony Mills <amills@pyramid6.com>
* @version $Revision$
* @since Horde 3.0
* @package Horde_SyncML
*/
class Horde_SyncML_Sync {
/**
* Target, either contacts, notes, events,
*/
var $_targetLocURI;
var $_sourceLocURI;
/**
* Return if all commands success.
*/
var $globalSuccess;
/**
* This is the content type to use to export data.
*/
var $preferedContentType;
/**
* Do have the sync data loaded from the database already?
*/
var $syncDataLoaded;
function &factory($alert)
{
Horde::logMessage('SyncML: new sync for alerttype ' . $alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
switch ($alert) {
case ALERT_TWO_WAY:
include_once 'Horde/SyncML/Sync/TwoWaySync.php';
return $sync = &new Horde_SyncML_Sync_TwoWaySync();
case ALERT_SLOW_SYNC:
include_once 'Horde/SyncML/Sync/SlowSync.php';
return $sync = &new Horde_SyncML_Sync_SlowSync();
case ALERT_ONE_WAY_FROM_CLIENT:
include_once 'Horde/SyncML/Sync/OneWayFromClientSync.php';
return $sync = &new Horde_SyncML_Sync_OneWayFromClientSync();
case ALERT_REFRESH_FROM_CLIENT:
include_once 'Horde/SyncML/Sync/RefreshFromClientSync.php';
return $sync = &new Horde_SyncML_Sync_RefreshFromClientSync();
case ALERT_ONE_WAY_FROM_SERVER:
include_once 'Horde/SyncML/Sync/OneWayFromServerSync.php';
return $sync = &new Horde_SyncML_Sync_OneWayFromServerSync();
case ALERT_REFRESH_FROM_SERVER:
include_once 'Horde/SyncML/Sync/RefreshFromServerSync.php';
return $sync = &new Horde_SyncML_Sync_RefreshFromServerSync();
}
require_once 'PEAR.php';
return PEAR::raiseError('Alert ' . $alert . ' not found.');
}
function nextSyncCommand($currentCmdID, &$syncCommand, &$output)
{
$result = $this->runSyncCommand($syncCommand);
return $syncCommand->output($currentCmdID, $output);
}
function startSync($currentCmdID, &$output)
{
return $currentCmdID;
}
function endSync($currentCmdID, &$output)
{
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;
$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;
$hordeType = $state->getHordeType($hordeType);
if(!$contentType = $command->getContentType()) {
$contentType = $state->getPreferedContentType($type);
}
if (($contentType == 'text/x-vcalendar' || $contentType == 'text/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;
}
}