2005-06-19 21:00:58 +02:00
|
|
|
<?php
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
require_once 'Horde/SyncML.php';
|
|
|
|
#require_once 'Horde/SyncML/State.php';
|
|
|
|
require_once 'Horde/SyncML/State_egw.php';
|
|
|
|
require_once 'Horde/SyncML/Command/Status.php';
|
2005-06-19 21:00:58 +02:00
|
|
|
|
|
|
|
/**
|
2006-01-11 06:42:07 +01:00
|
|
|
* The Horde_RPC_syncml class provides a SyncML implementation of the Horde
|
|
|
|
* RPC system.
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
2006-01-11 06:42:07 +01:00
|
|
|
* $Horde: framework/RPC/RPC/syncml.php,v 1.27 2006/01/01 21:10:11 jan Exp $
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
2006-01-11 06:42:07 +01:00
|
|
|
* Copyright 2003-2006 Chuck Hagenbuch <chuck@horde.org>
|
|
|
|
* Copyright 2003-2006 Anthony Mills <amills@pyramid6.com>
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
|
|
|
* 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 Chuck Hagenbuch <chuck@horde.org>
|
|
|
|
* @author Anthony Mills <amills@pyramid6.com>
|
|
|
|
* @since Horde 3.0
|
|
|
|
* @package Horde_RPC
|
|
|
|
*/
|
|
|
|
class Horde_RPC_syncml extends Horde_RPC {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Output ContentHandler used to output XML events.
|
2006-01-11 06:42:07 +01:00
|
|
|
*
|
|
|
|
* @var object
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
|
|
|
var $_output;
|
|
|
|
|
|
|
|
/**
|
2006-01-11 06:42:07 +01:00
|
|
|
* @var integer
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
|
|
|
var $_xmlStack = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Debug directory, if set will store copies of all packets.
|
2006-01-11 06:42:07 +01:00
|
|
|
*
|
|
|
|
* @var string
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
2006-01-11 06:42:07 +01:00
|
|
|
var $_debugDir = '/tmp/sync';
|
2005-06-19 21:00:58 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Default character set. Only supports UTF-8(ASCII?).
|
2006-01-11 06:42:07 +01:00
|
|
|
*
|
|
|
|
* @var string
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
|
|
|
var $_charset = 'UTF-8';
|
|
|
|
|
|
|
|
/**
|
2006-01-11 06:42:07 +01:00
|
|
|
* SyncML handles authentication internally, so bypass the RPC framework
|
|
|
|
* auth check by just returning true here.
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
|
|
|
function authorize()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends an RPC request to the server and returns the result.
|
|
|
|
*
|
|
|
|
* @param string $request The raw request string.
|
|
|
|
*
|
2006-01-11 06:42:07 +01:00
|
|
|
* @return string The XML encoded response from the server.
|
2005-06-19 21:00:58 +02:00
|
|
|
*/
|
|
|
|
function getResponse($request)
|
|
|
|
{
|
2006-01-11 06:42:07 +01:00
|
|
|
/* Catch any errors/warnings/notices that may get thrown while
|
|
|
|
* processing. Don't want to let anything go to the client that's not
|
|
|
|
* part of the valid response. */
|
2005-06-19 21:00:58 +02:00
|
|
|
ob_start();
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
/* Very useful for debugging. Logs WBXML packets to
|
|
|
|
* $this->_debugDir. */
|
2005-06-19 21:00:58 +02:00
|
|
|
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
2006-01-11 06:42:07 +01:00
|
|
|
$packetNum = @intval(file_get_contents($this->_debugDir . '/syncml.packetnum'));
|
2005-06-19 21:00:58 +02:00
|
|
|
if (!isset($packetNum)) {
|
|
|
|
$packetNum = 0;
|
|
|
|
}
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
$f = @fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.xml', 'wb');
|
2005-06-19 21:00:58 +02:00
|
|
|
if ($f) {
|
|
|
|
fwrite($f, $request);
|
|
|
|
fclose($f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
require_once 'XML/WBXML/ContentHandler.php';
|
|
|
|
$this->_output = &new XML_WBXML_ContentHandler();
|
|
|
|
|
2005-06-19 21:00:58 +02:00
|
|
|
$this->_parse($request);
|
|
|
|
$response = $this->_output->getOutput();
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
/* Very useful for debugging. */
|
2005-06-19 21:00:58 +02:00
|
|
|
if (!empty($this->_debugDir) && is_dir($this->_debugDir)) {
|
2006-01-11 06:42:07 +01:00
|
|
|
$f = @fopen($this->_debugDir . '/syncml_server_' . $packetNum . '.xml', 'wb');
|
2005-06-19 21:00:58 +02:00
|
|
|
if ($f) {
|
|
|
|
fwrite($f, $response);
|
|
|
|
fclose($f);
|
|
|
|
}
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
$fp = @fopen($this->_debugDir . '/syncml.packetnum', 'w');
|
2005-06-19 21:00:58 +02:00
|
|
|
if ($fp) {
|
|
|
|
fwrite($fp, ++$packetNum);
|
|
|
|
fclose($fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-11 06:42:07 +01:00
|
|
|
/* Clear the output buffer that we started above, and log anything
|
|
|
|
* that came up for later debugging. */
|
2005-06-19 21:00:58 +02:00
|
|
|
$errorLogging = ob_get_clean();
|
|
|
|
if (!empty($errorLogging)) {
|
2006-01-11 06:42:07 +01:00
|
|
|
Horde::logMessage('SyncML: caught output=' .
|
|
|
|
$errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
2005-06-19 21:00:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
function _parse($xml)
|
|
|
|
{
|
2006-01-11 06:42:07 +01:00
|
|
|
/* try to extract charset from XML text */
|
|
|
|
if(preg_match('/^\s*<\?xml[^>]*encoding\s*=\s*"([^"]*)"/i',
|
|
|
|
$xml, $m)) {
|
|
|
|
$this->_charset = $m[1];
|
|
|
|
}
|
2006-03-21 14:49:13 +01:00
|
|
|
#NLS::setCharset($this->_charset);
|
|
|
|
#String::setDefaultCharset($this->_charset);
|
2006-01-11 06:42:07 +01:00
|
|
|
|
|
|
|
/* Create the XML parser and set method references. */
|
2005-06-19 21:00:58 +02:00
|
|
|
$this->_parser = xml_parser_create_ns($this->_charset);
|
|
|
|
xml_set_object($this->_parser, $this);
|
|
|
|
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
|
|
|
|
xml_set_element_handler($this->_parser, '_startElement', '_endElement');
|
|
|
|
xml_set_character_data_handler($this->_parser, '_characters');
|
|
|
|
xml_set_processing_instruction_handler($this->_parser, '');
|
|
|
|
xml_set_external_entity_ref_handler($this->_parser, '');
|
|
|
|
|
|
|
|
if (!xml_parse($this->_parser, $xml)) {
|
|
|
|
return $this->raiseError(sprintf('XML error: %s at line %d',
|
|
|
|
xml_error_string(xml_get_error_code($this->_parser)),
|
|
|
|
xml_get_current_line_number($this->_parser)));
|
|
|
|
}
|
|
|
|
|
|
|
|
xml_parser_free($this->_parser);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _startElement($parser, $tag, $attributes)
|
|
|
|
{
|
|
|
|
list($uri, $name) = $this->_splitURI($tag);
|
|
|
|
|
|
|
|
$this->startElement($uri, $name, $attributes);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _characters($parser, $chars)
|
|
|
|
{
|
|
|
|
$this->characters($chars);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _endElement($parser, $tag)
|
|
|
|
{
|
|
|
|
list($uri, $name) = $this->_splitURI($tag);
|
|
|
|
|
|
|
|
$this->endElement($uri, $name);
|
|
|
|
}
|
|
|
|
|
|
|
|
function _splitURI($tag)
|
|
|
|
{
|
|
|
|
$parts = explode(':', $tag);
|
|
|
|
$name = array_pop($parts);
|
|
|
|
$uri = implode(':', $parts);
|
|
|
|
return array($uri, $name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-01-11 06:42:07 +01:00
|
|
|
* Returns the Content-Type of the response.
|
2005-06-19 21:00:58 +02:00
|
|
|
*
|
|
|
|
* @return string The MIME Content-Type of the RPC response.
|
|
|
|
*/
|
|
|
|
function getResponseContentType()
|
|
|
|
{
|
|
|
|
return 'application/vnd.syncml+xml';
|
|
|
|
}
|
|
|
|
|
|
|
|
function startElement($uri, $element, $attrs)
|
|
|
|
{
|
|
|
|
$this->_xmlStack++;
|
|
|
|
|
|
|
|
switch ($this->_xmlStack) {
|
|
|
|
case 1:
|
|
|
|
// <SyncML>
|
|
|
|
// Defined in SyncML Representation Protocol, version 1.1 5.2.1
|
|
|
|
$this->_output->startElement($uri, $element, $attrs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
// Either <SyncML><SyncHdr> or <SyncML><SyncBody>
|
|
|
|
if (!isset($this->_contentHandler)) {
|
|
|
|
// If not defined then create SyncHdr.
|
|
|
|
$this->_contentHandler = &new Horde_SyncML_SyncmlHdr();
|
|
|
|
$this->_contentHandler->setOutput($this->_output);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->_contentHandler->startElement($uri, $element, $attrs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (isset($this->_contentHandler)) {
|
|
|
|
$this->_contentHandler->startElement($uri, $element, $attrs);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function endElement($uri, $element)
|
|
|
|
{
|
|
|
|
switch ($this->_xmlStack) {
|
|
|
|
case 1:
|
|
|
|
// </SyncML>
|
|
|
|
// Defined in SyncML Representation Protocol, version 1.1 5.2.1
|
|
|
|
$this->_output->endElement($uri, $element);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
// Either </SyncHdr></SyncML> or </SyncBody></SyncML>
|
|
|
|
if ($element == 'SyncHdr') {
|
2006-01-11 06:42:07 +01:00
|
|
|
// Then we get the state from SyncMLHdr, and create a new
|
|
|
|
// SyncMLBody.
|
2005-06-19 21:00:58 +02:00
|
|
|
$this->_contentHandler->endElement($uri, $element);
|
|
|
|
|
|
|
|
unset($this->_contentHandler);
|
|
|
|
|
|
|
|
$this->_contentHandler = &new Horde_SyncML_SyncmlBody();
|
|
|
|
$this->_contentHandler->setOutput($this->_output);
|
|
|
|
} else {
|
|
|
|
// No longer used.
|
|
|
|
$this->_contentHandler->endElement($uri, $element);
|
|
|
|
unset($this->_contentHandler);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// </*></SyncHdr></SyncML> or </*></SyncBody></SyncML>
|
|
|
|
if (isset($this->_contentHandler)) {
|
|
|
|
$this->_contentHandler->endElement($uri, $element);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($this->_chars)) {
|
|
|
|
unset($this->_chars);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->_xmlStack--;
|
|
|
|
}
|
|
|
|
|
|
|
|
function characters($str)
|
|
|
|
{
|
|
|
|
if (isset($this->_contentHandler)) {
|
|
|
|
$this->_contentHandler->characters($str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function raiseError($str)
|
|
|
|
{
|
|
|
|
return Horde::logMessage($str, __FILE__, __LINE__, PEAR_LOG_ERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|