2005-06-19 21:00:58 +02:00
|
|
|
<?php
|
|
|
|
/**
|
2009-07-15 21:31:25 +02:00
|
|
|
* eGroupWare - SyncML based on Horde 3
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
|
|
|
*
|
2009-07-15 21:31:25 +02:00
|
|
|
* Using the PEAR Log class (which need to be installed!)
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
2009-07-15 21:31:25 +02:00
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package api
|
|
|
|
* @subpackage horde
|
|
|
|
* @author Anthony Mills <amills@pyramid6.com>
|
|
|
|
* @author Joerg Lehrke <jlehrke@noc.de>
|
|
|
|
* @copyright (c) The Horde Project (http://www.horde.org/)
|
|
|
|
* @version $Id$
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
2009-07-15 21:31:25 +02:00
|
|
|
include_once 'Horde/SyncML/State.php';
|
|
|
|
include_once 'Horde/SyncML/Command.php';
|
|
|
|
|
2005-06-19 21:00:58 +02:00
|
|
|
class Horde_SyncML_Command_Put extends Horde_SyncML_Command {
|
|
|
|
|
2009-07-15 21:31:25 +02:00
|
|
|
/**
|
|
|
|
* Name of the command.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
var $_cmdName = 'Put';
|
|
|
|
|
2005-06-19 21:00:58 +02:00
|
|
|
/**
|
|
|
|
* @var string $_manufacturer
|
|
|
|
*/
|
|
|
|
|
|
|
|
var $_manufacturer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $_model
|
|
|
|
*/
|
|
|
|
|
|
|
|
var $_model;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $_oem
|
|
|
|
*/
|
|
|
|
|
|
|
|
var $_oem;
|
|
|
|
|
2009-07-15 21:31:25 +02:00
|
|
|
/**
|
|
|
|
* @var array $_deviceInfo
|
|
|
|
*/
|
|
|
|
|
|
|
|
var $_deviceInfo;
|
|
|
|
|
2005-06-19 21:00:58 +02:00
|
|
|
/**
|
|
|
|
* @var string $_softwareVersion
|
|
|
|
*/
|
|
|
|
|
|
|
|
var $_softwareVersion;
|
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
function endElement($uri, $element) {
|
2009-07-15 21:31:25 +02:00
|
|
|
switch (count($this->_stack)) {
|
2006-08-15 16:42:13 +02:00
|
|
|
case 5:
|
2009-07-15 21:31:25 +02:00
|
|
|
switch ($element) {
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'DataStore':
|
2009-07-15 21:31:25 +02:00
|
|
|
$this->_deviceInfo['dataStore'][$this->_sourceReference] = array (
|
2006-08-15 16:42:13 +02:00
|
|
|
'maxGUIDSize' => $this->_maxGUIDSize,
|
|
|
|
'rxPreference' => $this->_rxPreference,
|
|
|
|
'txPreference' => $this->_txPreference,
|
|
|
|
'syncCapabilities' => $this->_syncCapabilities,
|
2009-07-15 21:31:25 +02:00
|
|
|
'properties' => $this->_properties,
|
2006-08-15 16:42:13 +02:00
|
|
|
);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'DevID':
|
|
|
|
$this->_deviceInfo['deviceID'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'DevTyp':
|
|
|
|
$this->_deviceInfo['deviceType'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'FwV':
|
|
|
|
$this->_deviceInfo['firmwareVersion'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'HwV':
|
|
|
|
$this->_deviceInfo['hardwareVersion'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'Man':
|
|
|
|
$this->_deviceInfo['manufacturer'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'Mod':
|
|
|
|
$this->_deviceInfo['model'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'OEM':
|
|
|
|
$this->_deviceInfo['oem'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'SwV':
|
|
|
|
$this->_deviceInfo['softwareVersion'] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'SupportLargeObjs':
|
|
|
|
$this->_deviceInfo['supportLargeObjs'] = true;
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'SupportNumberOfChanges':
|
|
|
|
$this->_deviceInfo['supportNumberOfChanges'] = true;
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'UTC':
|
|
|
|
$this->_deviceInfo['UTC'] = true;
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'VerDTD':
|
|
|
|
$this->_deviceInfo['DTDVersion'] = trim($this->_chars);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
switch($element) {
|
|
|
|
case 'MaxGUIDSize':
|
|
|
|
$this->_maxGUIDSize = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'Rx-Pref':
|
|
|
|
$this->_rxPreference = array(
|
|
|
|
'contentType' => $this->_contentType,
|
|
|
|
'contentVersion' => $this->_contentVersion,
|
|
|
|
);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'SourceRef':
|
|
|
|
$this->_sourceReference = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'Tx-Pref':
|
|
|
|
$this->_txPreference = array(
|
|
|
|
'contentType' => $this->_contentType,
|
|
|
|
'contentVersion' => $this->_contentVersion,
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 7:
|
|
|
|
switch($element) {
|
|
|
|
case 'CTType':
|
|
|
|
$this->_contentType = trim($this->_chars);
|
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 12:29:48 +02:00
|
|
|
if (substr($this->_contentType, 0, 14) == "text/x-s4j-sif")
|
|
|
|
{
|
|
|
|
// workaround a little bug in sync4j for mobile v3.1.3 (and possibly others)
|
|
|
|
// where the content-type is set to just one value regardless of
|
|
|
|
// the source... this further leads to a failure to send updates
|
|
|
|
// by the server since it does not know how to convert say tasks to text/x-s4j-sifc
|
|
|
|
// (it should be text/x-s4j-sift).
|
|
|
|
switch ($this->_sourceReference)
|
|
|
|
{
|
|
|
|
case 'contact':
|
2009-11-17 08:13:21 +01:00
|
|
|
case 'card':
|
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 12:29:48 +02:00
|
|
|
if ($this->_contentType != "text/x-s4j-sifc")
|
|
|
|
{
|
|
|
|
error_log("forcing 'contact' content type to 'text/x-s4j-sifc' instead of '".$this->_contentType."'");
|
|
|
|
$this->_contentType = "text/x-s4j-sifc";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'calendar':
|
|
|
|
case 'appointment':
|
|
|
|
if ($this->_contentType != "text/x-s4j-sife")
|
|
|
|
{
|
|
|
|
error_log("forcing 'calendar' content type to 'text/x-s4j-sife' instead of '".$this->_contentType."'");
|
|
|
|
$this->_contentType = "text/x-s4j-sife";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'task':
|
|
|
|
if ($this->_contentType != "text/x-s4j-sift")
|
|
|
|
{
|
|
|
|
error_log("forcing 'task' content type to 'text/x-s4j-sift' instead of '".$this->_contentType."'");
|
|
|
|
$this->_contentType = "text/x-s4j-sift";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'note':
|
|
|
|
if ($this->_contentType != "text/x-s4j-sifn")
|
|
|
|
{
|
|
|
|
error_log("forcing 'note' content type to 'text/x-s4j-sifn' instead of '".$this->_contentType."'");
|
|
|
|
$this->_contentType = "text/x-s4j-sifn";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
#error_log("Leaving ContentType='".$this->_contentType."' as is for source '".$this->_sourceReference."'");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-08-15 16:42:13 +02:00
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'SyncType':
|
|
|
|
$this->_syncCapabilities[] = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
case 'VerCT':
|
|
|
|
$this->_contentVersion = trim($this->_chars);
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
|
|
|
case 'Property':
|
|
|
|
if (isset($this->_PropName)) {
|
|
|
|
$this->_properties[$this->_contentType][$this->_contentVersion][$this->_PropName] = array(
|
|
|
|
'Size' => $this->_PropSize,
|
|
|
|
'NoTruncate' => $this->_PropNoTruncate,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
2006-08-15 16:42:13 +02:00
|
|
|
}
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
|
|
|
|
case 8:
|
|
|
|
switch($element) {
|
|
|
|
case 'PropName':
|
|
|
|
$this->_PropName = trim($this->_chars);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'Size':
|
|
|
|
$this->_PropSize = trim($this->_chars);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'NoTruncate':
|
|
|
|
$this->_PropNoTruncate = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
beak;
|
2006-08-15 16:42:13 +02:00
|
|
|
}
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
parent::endElement($uri, $element);
|
|
|
|
}
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2007-12-19 08:45:36 +01:00
|
|
|
function finalizeDeviceInfo()
|
|
|
|
{
|
|
|
|
// get some more information about the device from out of band data
|
|
|
|
|
|
|
|
$ua = $_SERVER['HTTP_USER_AGENT'];
|
|
|
|
|
2010-01-05 11:09:47 +01:00
|
|
|
if (($pos = strpos($ua, 'Funambol'))!== false) {
|
2009-07-15 21:31:25 +02:00
|
|
|
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
2010-01-05 11:09:47 +01:00
|
|
|
$this->_deviceInfo['model'] = 'generic';
|
|
|
|
$this->_deviceInfo['softwareVersion'] = 3.1; // force special treatment
|
|
|
|
$type = substr($ua, $pos + 9);
|
|
|
|
if (preg_match("/^(.*) [^\d]*(\d+\.?\d*)[\.|\d]*\s*$/i", $type, $matches)) {
|
|
|
|
// Funambol uses the hardware Manufacturer we don't care about
|
|
|
|
$this->_deviceInfo['model'] = trim($matches[1]);
|
|
|
|
$this->_deviceInfo['softwareVersion'] = floatval($matches[2]);
|
|
|
|
}
|
2009-07-15 21:31:25 +02:00
|
|
|
if (!isset($this->_deviceInfo['deviceType'])) {
|
|
|
|
switch (strtolower(trim($matches[1]))) {
|
2007-12-20 21:59:22 +01:00
|
|
|
case 'pocket pc plug-in':
|
2007-12-19 08:45:36 +01:00
|
|
|
$this->_deviceInfo['deviceType'] = 'windowsmobile';
|
|
|
|
break;
|
2009-07-15 21:31:25 +02:00
|
|
|
case 'outlook plug-in':
|
|
|
|
default:
|
|
|
|
$this->_deviceInfo['deviceType'] = 'workstation';
|
|
|
|
break;
|
2007-12-19 08:45:36 +01:00
|
|
|
}
|
|
|
|
}
|
2010-01-05 11:09:47 +01:00
|
|
|
|
2007-12-19 08:45:36 +01:00
|
|
|
}
|
|
|
|
|
2009-07-15 21:31:25 +02:00
|
|
|
switch (strtolower($this->_deviceInfo['deviceID'])) {
|
2007-12-19 08:45:36 +01:00
|
|
|
case 'fmz-thunderbird-plugin':
|
2009-07-15 21:31:25 +02:00
|
|
|
if (empty($this->_devinceInfo['manufacturer'])) {
|
2007-12-19 08:45:36 +01:00
|
|
|
$this->_deviceInfo['manufacturer'] = 'Funambol';
|
2009-07-15 21:31:25 +02:00
|
|
|
}
|
|
|
|
if (empty($this->_devinceInfo['model'])) {
|
2007-12-19 08:45:36 +01:00
|
|
|
$this->_deviceInfo['model'] = 'ThunderBird';
|
2009-07-15 21:31:25 +02:00
|
|
|
}
|
|
|
|
if (empty($this->_devinceInfo['softwareVersion'])) {
|
|
|
|
$this->_deviceInfo['softwareVersion'] = '3.0';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (preg_match('/Funambol.*/i', $this->_deviceInfo['manufacturer'])) {
|
|
|
|
$this->_deviceInfo['supportLargeObjs'] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (strtolower($this->_deviceInfo['manufacturer'])) {
|
|
|
|
case 'sonyericsson':
|
|
|
|
case 'sony ericsson':
|
|
|
|
if (strtolower($this->_deviceInfo['model']) == 'w890i') {
|
|
|
|
$this->_deviceInfo['supportLargeObjs'] = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'synthesis ag':
|
|
|
|
foreach ($this->_deviceInfo['dataStore'] as &$ctype) {
|
|
|
|
$ctype['maxGUIDSize'] = 255;
|
|
|
|
}
|
2007-12-19 08:45:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
function output($currentCmdID, &$output ) {
|
|
|
|
$state = &$_SESSION['SyncML.state'];
|
2009-07-15 21:31:25 +02:00
|
|
|
|
|
|
|
$status = new Horde_SyncML_Command_Status((($state->isAuthorized()) ? RESPONSE_OK : RESPONSE_INVALID_CREDENTIALS), $this->_cmdName);
|
2006-08-15 16:42:13 +02:00
|
|
|
$status->setCmdRef($this->_cmdID);
|
2009-07-15 21:31:25 +02:00
|
|
|
|
|
|
|
if ($state->getVersion() == 2) {
|
|
|
|
$ref = './devinf12';
|
|
|
|
} elseif ($state->getVersion() == 1) {
|
|
|
|
$ref = './devinf11';
|
|
|
|
} else {
|
|
|
|
$ref = './devinf10';
|
|
|
|
}
|
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
$status->setSourceRef($ref);
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
if($state->isAuthorized()) {
|
2007-12-19 08:45:36 +01:00
|
|
|
$this->finalizeDeviceInfo();
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
if(count((array)$this->_deviceInfo) > 0) {
|
2009-07-15 21:31:25 +02:00
|
|
|
$devInfo = $state->getClientDeviceInfo();
|
|
|
|
if (is_array($devInfo['dataStore'])
|
|
|
|
&& $devInfo['softwareVersion'] == $this->_deviceInfo['softwareVersion']) {
|
|
|
|
// merge with existing information
|
|
|
|
$devInfo['dataStore'] =
|
|
|
|
array_merge($devInfo['dataStore'],
|
|
|
|
$this->_deviceInfo['dataStore']);
|
|
|
|
} else {
|
|
|
|
// new device
|
|
|
|
$devInfo = $this->_deviceInfo;
|
|
|
|
}
|
|
|
|
#Horde::logMessage("SyncML: Put DeviceInfo:\n" . print_r($this->_deviceInfo, true), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
$state->setClientDeviceInfo($devInfo);
|
2006-08-15 16:42:13 +02:00
|
|
|
$state->writeClientDeviceInfo();
|
|
|
|
}
|
|
|
|
}
|
2009-07-15 21:31:25 +02:00
|
|
|
|
2006-08-15 16:42:13 +02:00
|
|
|
return $status->output($currentCmdID, $output);
|
|
|
|
}
|
|
|
|
|
|
|
|
function startElement($uri, $element, $attrs) {
|
2009-07-15 21:31:25 +02:00
|
|
|
#Horde::logMessage("SyncML: startElement[" . count($this->_stack) . "] $uri $element", __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
|
|
|
switch (count($this->_stack)) {
|
|
|
|
case 4:
|
|
|
|
switch ($element) {
|
|
|
|
case 'DataStore':
|
|
|
|
$this->_properties = array();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
switch ($element) {
|
|
|
|
case 'Property':
|
|
|
|
unset($this->_PropName);
|
|
|
|
$this->_PropSize = -1;
|
|
|
|
$this->_PropNoTruncate = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2006-08-15 16:42:13 +02:00
|
|
|
parent::startElement($uri, $element, $attrs);
|
|
|
|
}
|
2005-06-19 21:00:58 +02:00
|
|
|
|
|
|
|
}
|