diff --git a/phpgwapi/inc/horde/Horde/RPC.php b/phpgwapi/inc/horde/Horde/RPC.php index ed0c56f5b5..0be53fa29b 100644 --- a/phpgwapi/inc/horde/Horde/RPC.php +++ b/phpgwapi/inc/horde/Horde/RPC.php @@ -7,22 +7,24 @@ * - Introspection documentation and method signatures. * * EXAMPLE: + * * $response = Horde_RPC::request('xmlrpc', - * '/horde/rpc.php', 'www.example.com', 80, + * 'http://localhost:80/horde/rpc.php' * 'contacts.search', * array(array('jan'), array('localsql'), * array('name', 'email')), - * Auth::getAuth(), Auth::getCredential('password')); + * array('user' => Auth::getAuth(), + * 'pass' => Auth::getCredential('password'))); + * * - * $Horde: framework/RPC/RPC.php,v 1.7 2004/09/08 09:07:25 jan Exp $ + * $Horde: framework/RPC/RPC.php,v 1.14 2006/01/01 21:10:10 jan Exp $ * - * Copyright 2002-2004 Jan Schneider + * Copyright 2002-2006 Jan Schneider * * 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 Jan Schneider - * @version $Revision$ * @since Horde 3.0 * @package Horde_RPC */ @@ -32,7 +34,7 @@ class Horde_RPC { * Whether we need an authorized user or not. * * @access protected - * @var boolean $_authorize. + * @var boolean */ var $_authorize = true; @@ -113,9 +115,9 @@ class Horde_RPC { /** * Sends an RPC request to the server and returns the result. * - * @param string The raw request string. + * @param string The raw request string. * - * @return string The XML encoded response from the server. + * @return string The XML encoded response from the server. */ function getResponse($request) { @@ -137,14 +139,14 @@ class Horde_RPC { * * This statically called method is actually the RPC client. * - * @param string $driver The protocol driver to use. Currently 'soap' and - * 'xmlrpc' are available. + * @param string $driver The protocol driver to use. Currently 'soap' + * and 'xmlrpc' are available. * @param string $url The path to the RPC server on the called host. * @param string $method The method to call. - * @param array $params (optional) A hash containing any necessary - * parameters for the method call. - * @param $options Optional associative array of parameters depending on - * the selected protocol driver. + * @param array $params A hash containing any necessary parameters for + * the method call. + * @param $options Associative array of parameters depending on + * the selected protocol driver. * * @return mixed The returned result from the method or a PEAR * error object on failure. @@ -177,21 +179,15 @@ class Horde_RPC { * Attempts to return a concrete RPC server instance based on * $driver. * - * @access public + * @param mixed $driver The type of concrete RPC subclass to return. If + * $driver is an array, then we will look in + * $driver[0]/lib/RPC/ for the subclass + * implementation named $driver[1].php. + * @param array $params A hash containing any additional configuration or + * connection parameters a subclass might need. * - * @param mixed $driver The type of concrete RPC subclass to - * return. This is based on the protocol - * driver ($driver). The code is dynamically - * included. If $driver is an array, then - * we will look in $driver[0]/lib/RPC/ - * for the subclass implementation named - * $driver[1].php. - * @param optional array $params A hash containing any additional - * configuration or connection parameters - * a subclass might need. - * - * @return object Horde_RPC The newly created concrete Horde_RPC server - * instance, or a PEAR_Error on an error. + * @return Horde_RPC The newly created concrete Horde_RPC server instance, + * or a PEAR_Error on an error. */ function &factory($driver, $params = null) { @@ -210,11 +206,13 @@ class Horde_RPC { } $class = 'Horde_RPC_' . $driver; if (class_exists($class)) { - return $ret = &new $class($params); + $rpc = &new $class($params); } else { require_once 'PEAR.php'; - return PEAR::raiseError('Class definition of ' . $class . ' not found.'); + $rpc = PEAR::raiseError('Class definition of ' . $class . ' not found.'); } + + return $rpc; } /** @@ -228,19 +226,12 @@ class Horde_RPC { * * This method must be invoked as: $var = &Horde_RPC::singleton() * - * @access public + * @param string $driver The type of concrete RPC subclass to return. + * @param array $params A hash containing any additional configuration or + * connection parameters a subclass might need. * - * @param string $driver The type of concrete RPC subclass to - * return. This is based on the protocol - * driver ($driver). The code is dynamically - * included. - * @param optional array $params A hash containing any additional - * configuration or connection parameters a - * subclass might need. - * - * @return object Horde_RPC The concrete Horde_RPC server reference, or a - * PEAR_Error - * on an error. + * @return Horde_RPC The concrete Horde_RPC server reference, or a + * PEAR_Error on an error. */ function &singleton($driver, $params = null) { diff --git a/phpgwapi/inc/horde/Horde/RPC/syncml.php b/phpgwapi/inc/horde/Horde/RPC/syncml.php index 58689db194..db3921949c 100644 --- a/phpgwapi/inc/horde/Horde/RPC/syncml.php +++ b/phpgwapi/inc/horde/Horde/RPC/syncml.php @@ -1,25 +1,24 @@ , Anthony Mills + * Copyright 2003-2006 Chuck Hagenbuch + * Copyright 2003-2006 Anthony Mills * * 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 * @author Anthony Mills - * @version $Revision$ * @since Horde 3.0 * @package Horde_RPC */ @@ -27,28 +26,33 @@ class Horde_RPC_syncml extends Horde_RPC { /** * Output ContentHandler used to output XML events. - * @var object $_output + * + * @var object */ var $_output; /** - * @var integer $_xmlStack + * @var integer */ var $_xmlStack = 0; /** * Debug directory, if set will store copies of all packets. + * + * @var string */ - var $_debugDir = '/var/www/html/syncdebug/'; + var $_debugDir = '/tmp/sync'; /** * Default character set. Only supports UTF-8(ASCII?). + * + * @var string */ var $_charset = 'UTF-8'; /** - * SyncML handles authentication internally, so bypass the RPC - * framework auth check by just returning true here. + * SyncML handles authentication internally, so bypass the RPC framework + * auth check by just returning true here. */ function authorize() { @@ -60,80 +64,57 @@ class Horde_RPC_syncml extends Horde_RPC { * * @param string $request The raw request string. * - * @return string The XML encoded response from the server. + * @return string The XML encoded response from the server. */ function getResponse($request) { - // 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. + /* 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. */ ob_start(); - if(isset($GLOBALS['config_syncml']['syncml_debug_dir'])) - { - $this->_debugDir = $GLOBALS['config_syncml']['syncml_debug_dir']; - } - // Very useful for debugging. Logs XML packets to - // $this->_debugDir. + /* Very useful for debugging. Logs WBXML packets to + * $this->_debugDir. */ if (!empty($this->_debugDir) && is_dir($this->_debugDir)) { - $today = date('Y-m-d'); - $deviceName = str_replace('/','',$_SERVER["HTTP_USER_AGENT"]); - if(!is_dir($this->_debugDir .'/'. $today)) - { - mkdir($this->_debugDir .'/'. $today); - } - - $debugDir = $this->_debugDir .'/'. $today .'/'. $deviceName; - if(!is_dir($debugDir)) - { - mkdir($debugDir); - } - - $packetNum = @intval(file_get_contents($debugDir . '/syncml.packetnum')); + $packetNum = @intval(file_get_contents($this->_debugDir . '/syncml.packetnum')); if (!isset($packetNum)) { $packetNum = 0; } - $f = @fopen($debugDir . '/syncml_client_' . $packetNum . '.xml', 'wb'); + $f = @fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.xml', 'wb'); if ($f) { fwrite($f, $request); fclose($f); } } - // $this->_output can be already set by a subclass. - // The subclass can use it's own ContentHandler and bypass - // this classes use of the ContentHandler. In this case - // no output is return from this method, instead the output - // comes from the subclasses ContentHandler - // We may need to add this code back when we get to the content - //if (!isset($this->_output)) { - include_once 'XML/WBXML/ContentHandler.php'; - $this->_output = &new XML_WBXML_ContentHandler(); - //} + require_once 'XML/WBXML/ContentHandler.php'; + $this->_output = &new XML_WBXML_ContentHandler(); + $this->_parse($request); $response = $this->_output->getOutput(); - // Very useful for debugging. + /* Very useful for debugging. */ if (!empty($this->_debugDir) && is_dir($this->_debugDir)) { - $f = @fopen($debugDir . '/syncml_server_' . $packetNum . '.xml', 'wb'); + $f = @fopen($this->_debugDir . '/syncml_server_' . $packetNum . '.xml', 'wb'); if ($f) { fwrite($f, $response); fclose($f); } - $fp = @fopen($debugDir . '/syncml.packetnum', 'w'); + $fp = @fopen($this->_debugDir . '/syncml.packetnum', 'w'); if ($fp) { fwrite($fp, ++$packetNum); fclose($fp); } } - // Clear the output buffer that we started above, and log - // anything that came up for later debugging. + /* Clear the output buffer that we started above, and log anything + * that came up for later debugging. */ $errorLogging = ob_get_clean(); if (!empty($errorLogging)) { - Horde::logMessage($errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG); + Horde::logMessage('SyncML: caught output=' . + $errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG); } return $response; @@ -141,7 +122,15 @@ class Horde_RPC_syncml extends Horde_RPC { function _parse($xml) { - // Create the XML parser and set method references. + /* try to extract charset from XML text */ + if(preg_match('/^\s*<\?xml[^>]*encoding\s*=\s*"([^"]*)"/i', + $xml, $m)) { + $this->_charset = $m[1]; + } + NLS::setCharset($this->_charset); + String::setDefaultCharset($this->_charset); + + /* Create the XML parser and set method references. */ $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); @@ -187,7 +176,7 @@ class Horde_RPC_syncml extends Horde_RPC { } /** - * Get the Content-Type of the response. + * Returns the Content-Type of the response. * * @return string The MIME Content-Type of the RPC response. */ @@ -198,7 +187,6 @@ class Horde_RPC_syncml extends Horde_RPC { function startElement($uri, $element, $attrs) { - $this->_xmlStack++; switch ($this->_xmlStack) { @@ -239,8 +227,8 @@ class Horde_RPC_syncml extends Horde_RPC { case 2: // Either or if ($element == 'SyncHdr') { - // Then we get the state from SyncMLHdr, and create a - // new SyncMLBody. + // Then we get the state from SyncMLHdr, and create a new + // SyncMLBody. $this->_contentHandler->endElement($uri, $element); unset($this->_contentHandler); diff --git a/phpgwapi/inc/horde/Horde/RPC/syncml_wbxml.php b/phpgwapi/inc/horde/Horde/RPC/syncml_wbxml.php index 088ff193ce..1cf5920b17 100644 --- a/phpgwapi/inc/horde/Horde/RPC/syncml_wbxml.php +++ b/phpgwapi/inc/horde/Horde/RPC/syncml_wbxml.php @@ -1,23 +1,23 @@ , Anthony Mills + * Copyright 2003-2006 Chuck Hagenbuch + * Copyright 2003-2006 Anthony Mills * * 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 * @author Anthony Mills - * @version $Revision$ * @since Horde 3.0 * @package Horde_RPC */ @@ -28,81 +28,75 @@ class Horde_RPC_syncml_wbxml extends Horde_RPC_syncml { * * @param string $request The raw request string. * - * @return string The WBXML encoded response from the server (binary). + * @return string The WBXML encoded response from the server (binary). */ function getResponse($request) { - // 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. + /* 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. */ ob_start(); - if(isset($GLOBALS['config_syncml']['syncml_debug_dir'])) - { - $this->_debugDir = $GLOBALS['config_syncml']['syncml_debug_dir']; - } - // Very useful for debugging. Logs WBXML packets to - // $this->_debugDir. + /* Very useful for debugging. Logs WBXML packets to + * $this->_debugDir. */ if (!empty($this->_debugDir) && is_dir($this->_debugDir)) { - $today = date('Y-m-d'); - $deviceName = str_replace('/','',$_SERVER["HTTP_USER_AGENT"]); - if(!is_dir($this->_debugDir .'/'. $today)) - { - mkdir($this->_debugDir .'/'. $today); - } - - $debugDir = $this->_debugDir .'/'. $today .'/'. $deviceName; - if(!is_dir($debugDir)) - { - mkdir($debugDir); - } - - $packetNum = @intval(file_get_contents($debugDir . '/syncml_wbxml.packetnum')); + $packetNum = @intval(file_get_contents($this->_debugDir . '/syncml.packetnum')); if (!isset($packetNum)) { $packetNum = 0; } - $fp = fopen($debugDir . '/syncml_client_' . $packetNum . '.wbxml', 'wb'); + $fp = fopen($this->_debugDir . '/syncml_client_' . $packetNum . '.wbxml', 'wb'); fwrite($fp, $request); fclose($fp); } - + + $decoder = &new XML_WBXML_Decoder(); - $xmlinput = $decoder->decode($request); - if (is_a($xmlinput, 'PEAR_Error')) { - return ''; + $this->_output = &new XML_WBXML_Encoder(); + + $decoder->setContentHandler($this); + + $r = $decoder->decode($request); + if (is_a($r, 'PEAR_Error')) { + Horde::logMessage('SyncML: ' . + $r->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR); } + $this->_output->setVersion($decoder->getVersion()); + $this->_output->setCharset($decoder->getCharsetStr()); + $response = $this->_output->getOutput(); - $xmloutput = parent::getResponse($xmlinput); - - $encoder = &new XML_WBXML_Encoder(); - $encoder->setVersion($decoder->getVersion()); - $encoder->setCharset($decoder->getCharsetStr()); - $response = $encoder->encode($xmloutput); + if (is_a($response, 'PEAR_Error')) { + Horde::logMessage($response, __FILE__, __LINE__, PEAR_LOG_ERR); + $response = $response->getMessage(); + } if (!empty($this->_debugDir) && is_dir($this->_debugDir)) { - $fp = fopen($debugDir . '/syncml_server_' . $packetNum . '.wbxml', 'wb'); + $fp = fopen($this->_debugDir . '/syncml_server_' . $packetNum . '.wbxml', 'wb'); fwrite($fp, $response); fclose($fp); - $fp = fopen($debugDir . '/syncml_wbxml.packetnum', 'w'); - fwrite($fp, ++$packetNum); - fclose($fp); + $fp = @fopen($this->_debugDir . '/syncml.packetnum', 'w'); + if ($fp) { + fwrite($fp, ++$packetNum); + fclose($fp); + } + } - // Clear the output buffer that we started above, and log - // anything that came up for later debugging. + /* Clear the output buffer that we started above, and log anything + * that came up for later debugging. */ $errorLogging = ob_get_clean(); if (!empty($errorLogging)) { - Horde::logMessage($errorLogging, __FILE__, __LINE__, PEAR_LOG_DEBUG); + Horde::logMessage('SyncML: caught output=' . $errorLogging, + __FILE__, __LINE__, PEAR_LOG_DEBUG); } return $response; } /** - * Get the Content-Type of the response. + * Returns the Content-Type of the response. * * @return string The MIME Content-Type of the RPC response. */ diff --git a/phpgwapi/inc/horde/Horde/SyncML.php b/phpgwapi/inc/horde/Horde/SyncML.php index 5083391bc3..2cf34a1483 100644 --- a/phpgwapi/inc/horde/Horde/SyncML.php +++ b/phpgwapi/inc/horde/Horde/SyncML.php @@ -477,7 +477,8 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { if ($element != 'Status' && $element != 'Map' && $element != 'Final') { // We've got to do something! This can't be the last // packet. - $this->_actionCommands = true; + $this->_actionCommands = true; + Horde::logMessage("SyncML: found action commands <$element> " . $this->_actionCommands, __FILE__, __LINE__, PEAR_LOG_INFO); } switch($element) @@ -490,6 +491,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); break; } break; @@ -567,11 +569,13 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { $this->_output->characters($this->_currentCmdID); $this->_currentCmdID++; $this->_output->endElement($state->getURI(), 'CmdID'); + $this->_output->startElement($state->getURI(), 'Meta', $attrs); - $this->_output->startElement($state->getURI(), 'Type', $attrs); + $this->_output->startElement($state->getURIMeta(), 'Type', $attrs); $this->_output->characters('application/vnd.syncml-devinf+xml'); - $this->_output->endElement($state->getURI(), 'Type'); + $this->_output->endElement($state->getURIMeta(), 'Type'); $this->_output->endElement($state->getURI(), 'Meta'); + $this->_output->startElement($state->getURI(), 'Item', $attrs); $this->_output->startElement($state->getURI(), 'Target', $attrs); $this->_output->startElement($state->getURI(), 'LocURI', $attrs); @@ -579,6 +583,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { $this->_output->endElement($state->getURI(), 'LocURI'); $this->_output->endElement($state->getURI(), 'Target'); $this->_output->endElement($state->getURI(), 'Item'); + $this->_output->endElement($state->getURI(), 'Get'); } } @@ -590,6 +595,7 @@ class Horde_SyncML_SyncMLBody extends Horde_SyncML_ContentHandler { 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); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Get.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Get.php index 7788c5a2e5..710110340a 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Get.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Get.php @@ -4,44 +4,6 @@ include_once 'Horde/SyncML/State.php'; include_once 'Horde/SyncML/Command.php'; include_once 'Horde/SyncML/Command/Results.php'; -define('DEFAULT_DEFINF_10', '1.0The Horde Framework4711workstation./contactstext/x-vcard2.1text/x-vcard2.11234567./calendartext/x-vcalendar2.0text/x-vcalendar1.0text/x-vcalendar2.0text/x-vcalendar1.01234567text/x-vcalendarBEGINVCALENDARVEVENTVTODODTSTARTDTENDDTSTAMPSEQUENCEENDVCALENDARVEVENTVTODOUIDSUMMARYVERSION1.0AALARMCATEGORIESCLASSDALARMEXDATERESOURCESSTATUSATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTIONDUELAST-MODIFIEDLOCATIONPRIORITYRELATED-TORRULETRANSPURLtext/calendarBEGINVCALENDARVEVENTVTODOVALARMDTSTARTDTENDDTSTAMPSEQUENCEENDVCALENDARVEVENTVTODOVALARMUIDSUMMARYVERSION2.0CATEGORIESCLASSDALARMEXDATERESOURCESSTATUSATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTIONDUELAST-MODIFIEDLOCATIONPRIORITYRELATED-TOTRANSPURLRRULECOMMMENTACTIONTRIGGERDURATIONREPEATtext/x-vcardBEGINVCARDENDVCARDVERSION2.1ENCODINGVALUECHARSETFNNNAMENICKNAMEPHOTOBDAYADRLABELTELEMAILMAILERTZGEOTITLEROLELOGOAGENTORGCATEGORIESNOTEPRODIDREVSORT-STRINGSOUNDURLUIDCLASSKEY'); -define('DEFAULT_DEFINF_11', '1.1The Horde Framework4711workstation./contactstext/x-vcard2.1text/x-vcard2.11234567./calendartext/x-vcalendar2.0text/x-vcalendar1.0text/x-vcalendar2.0text/x-vcalendar1.01234567text/x-vcalendarBEGINVCALENDARVEVENTVTODODTSTARTDTENDDTSTAMPSEQUENCEENDVCALENDARVEVENTVTODOUIDSUMMARYVERSION1.0AALARMCATEGORIESCLASSDALARMEXDATERESOURCESSTATUSATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTIONDUELAST-MODIFIEDLOCATIONPRIORITYRELATED-TORRULETRANSPURLtext/calendarBEGINVCALENDARVEVENTVTODOVALARMDTSTARTDTENDDTSTAMPSEQUENCEENDVCALENDARVEVENTVTODOVALARMUIDSUMMARYVERSION2.0CATEGORIESCLASSDALARMEXDATERESOURCESSTATUSATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTIONDUELAST-MODIFIEDLOCATIONPRIORITYRELATED-TOTRANSPURLRRULECOMMMENTACTIONTRIGGERDURATIONREPEATtext/x-vcardBEGINVCARDENDVCARDVERSION2.1ENCODINGVALUECHARSETFNNNAMENICKNAMEPHOTOBDAYADRLABELTELEMAILMAILERTZGEOTITLEROLELOGOAGENTORGCATEGORIESNOTEPRODIDREVSORT-STRINGSOUNDURLUIDCLASSKEY'); -#define('DEFAULT_DEFINF', '1.0The Horde Framework4711'. -#'workstationcontactstext/x-vcard2.1'. -#'text/x-vcard2.1127'. -#''. -# -#'calendartext/x-vcalendar2.0'. -#'text/x-vcalendar1.0text/x-vcalendar2.0'. -#'text/x-vcalendar1.017'. -# -#'text/x-vcalendarBEGINVCALENDARVEVENT'. -#'VTODODTSTARTDTENDDTSTAMPSEQUENCE'. -#'ENDVCALENDARVEVENTVTODOUID'. -#'SUMMARYVERSION1.0AALARMCATEGORIES', -#'CLASSDALARMEXDATERESOURCESSTATUS', -#'ATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTION'. -#'DUELAST-MODIFIEDLOCATIONPRIORITY'. -#'RELATED-TORRULETRANSPURL'. -#'text/calendarBEGINVCALENDARVEVENTVTODO'. -#'VALARMDTSTARTDTENDDTSTAMPSEQUENCE'. -#'ENDVCALENDARVEVENTVTODOVALARM'. -#'UIDSUMMARYVERSION2.0CATEGORIES'. -#'CLASSDALARMEXDATERESOURCESSTATUS'. -#'ATTACHATTENDEEDCREATEDCOMPLETEDDESCRIPTION'. -#'DUELAST-MODIFIEDLOCATIONPRIORITY'. -#'RELATED-TOTRANSPURLRRULECOMMMENT'. -#'ACTIONTRIGGERDURATIONREPEAT'. -# -#'text/x-vcardBEGINVCARDENDVCARD'. -#'VERSION2.1ENCODINGVALUECHARSET'. -#'FNNNAMENICKNAMEPHOTO'. -#'BDAYADRLABELTELEMAIL'. -#'MAILERTZGEOTITLEROLE'. -#'LOGOAGENTORGCATEGORIESNOTE'. -#'PRODIDREVSORT-STRINGSOUNDURL'. -#'UIDCLASSKEY'); - /** * The Horde_SyncML_Command_Get class. * @@ -70,32 +32,151 @@ class Horde_SyncML_Command_Get extends Horde_SyncML_Command { $status->setCmdRef($this->_cmdID); $status->setTargetRef($ref); $currentCmdID = $status->output($currentCmdID, $output); - Horde::logMessage('SyncML: end output ref: '.$ref, __FILE__, __LINE__, PEAR_LOG_DEBUG); - // Currently DEVINF seems to be ok only for SyncML 1.0. But - // this is used by P800/P900 and these seem to require it: - if ($state->isAuthorized() && $state->getVersion() == 0) { - $results = &new Horde_SyncML_Command_Results(); - $results->setCmdRef($this->_cmdID); - $results->setType("application/vnd.syncml-devinf+xml"); - $results->setlocSourceURI($ref); - $results->setData(DEFAULT_DEFINF_10); + if ($state->isAuthorized()) { + $attrs = array(); + $output->startElement($state->getURI(), 'Results', $attrs); - $currentCmdID = $results->output($currentCmdID, $output); - } - elseif($state->isAuthorized() && $state->getVersion() == 1) - { - $results = &new Horde_SyncML_Command_Results(); - $results->setCmdRef($this->_cmdID); - $results->setType("application/vnd.syncml-devinf+xml"); - $results->setlocSourceURI($ref); - $results->setData(DEFAULT_DEFINF_11); + $output->startElement($state->getURI(), 'CmdID', $attrs); + $chars = $currentCmdID; + $output->characters($chars); + $output->endElement($state->getURI(), 'CmdID'); - $currentCmdID = $results->output($currentCmdID, $output); - + $output->startElement($state->getURI(), 'MsgRef', $attrs); + $chars = $state->getMsgID(); + $output->characters($chars); + $output->endElement($state->getURI(), 'MsgRef'); + + $output->startElement($state->getURI(), 'CmdRef', $attrs); + $chars = $this->_cmdID; + $output->characters($chars); + $output->endElement($state->getURI(), 'CmdRef'); + + $output->startElement($state->getURI(), 'Meta', $attrs); + $output->startElement($state->getURIMeta(), 'Type', $attrs); + if (is_a($output, 'XML_WBXML_Encoder')) { + $output->characters(MIME_SYNCML_DEVICE_INFO_WBXML); + } else { + $output->characters(MIME_SYNCML_DEVICE_INFO_XML); + } + + $output->endElement($state->getURIMeta(), 'Type'); + $output->endElement($state->getURI(), 'Meta'); + + $output->startElement($state->getURI(), 'Item', $attrs); + $output->startElement($state->getURI(), 'Source', $attrs); + $output->startElement($state->getURI(), 'LocURI', $attrs); + $output->characters($ref); + $output->endElement($state->getURI(), 'LocURI'); + $output->endElement($state->getURI(), 'Source'); + + $output->startElement($state->getURI(), 'Data', $attrs); + + $output->startElement($state->getURIDevInf() , 'DevInf', $attrs); + $output->startElement($state->getURIDevInf() , 'VerDTD', $attrs); + $output->characters(($state->getVersion() == 0) ? '1.0' : '1.1'); + $output->endElement($state->getURIDevInf() , 'VerDTD', $attrs); + $output->startElement($state->getURIDevInf() , 'Man', $attrs); + $output->characters('www.egroupware.org'); + $output->endElement($state->getURIDevInf() , 'Man', $attrs); + $output->startElement($state->getURIDevInf() , 'DevID', $attrs); + $output->characters($_SERVER['HTTP_HOST']); + $output->endElement($state->getURIDevInf() , 'DevID', $attrs); + $output->startElement($state->getURIDevInf() , 'DevTyp', $attrs); + $output->characters('server'); + $output->endElement($state->getURIDevInf() , 'DevTyp', $attrs); + $this->_writeDataStore('notes', 'text/x-vnote', '1.1', $output, + array('text/plain' => '1.0')); + $this->_writeDataStore('contacts', 'text/x-vcard', '2.1', $output); + $this->_writeDataStore('tasks', 'text/x-vcalendar', '1.0', $output); + $this->_writeDataStore('calendar', 'text/x-vcalendar', '1.0', $output); + $output->endElement($state->getURIDevInf() , 'DevInf', $attrs); + + $output->endElement($state->getURI(), 'Data'); + $output->endElement($state->getURI(), 'Item'); + $output->endElement($state->getURI(), 'Results'); + + $currentCmdID++; } return $currentCmdID; } + /** + * Writes DevInf data for one DataStore. + * + * @param string $sourceref: data for SourceRef element. + * @param string $mimetype: data for <(R|T)x-Pref><CTType> + * @param string $version: data for <(R|T)x-Pref><VerCT> + * @param string &$output contenthandler that will received the output. + * @param array $additionaltypes: array of additional types for Tx and Rx; + * format array('text/vcard' => '2.0') + */ + function _writeDataStore($sourceref, $mimetype, $version, &$output, + $additionaltypes = false) + { + $attrs = array(); + + $state = &$_SESSION['SyncML.state']; + + $output->startElement($state->getURIDevInf() , 'DataStore', $attrs); + $output->startElement($state->getURIDevInf() , 'SourceRef', $attrs); + $output->characters($sourceref); + $output->endElement($state->getURIDevInf() , 'SourceRef', $attrs); + + $output->startElement($state->getURIDevInf() , 'Rx-Pref', $attrs); + $output->startElement($state->getURIDevInf() , 'CTType', $attrs); + $output->characters($mimetype); + $output->endElement($state->getURIDevInf() , 'CTType', $attrs); + $output->startElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->characters($version); + $output->endElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->endElement($state->getURIDevInf() , 'Rx-Pref', $attrs); + + if (is_array($additionaltypes)) { + foreach ($additionaltypes as $ct => $ctver){ + $output->startElement($state->getURIDevInf() , 'Rx', $attrs); + $output->startElement($state->getURIDevInf() , 'CTType', $attrs); + $output->characters($ct); + $output->endElement($state->getURIDevInf() , 'CTType', $attrs); + $output->startElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->characters($ctver); + $output->endElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->endElement($state->getURIDevInf() , 'Rx', $attrs); + } + } + + $output->startElement($state->getURIDevInf() , 'Tx-Pref', $attrs); + $output->startElement($state->getURIDevInf() , 'CTType', $attrs); + $output->characters($mimetype); + $output->endElement($state->getURIDevInf() , 'CTType', $attrs); + $output->startElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->characters($version); + $output->endElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->endElement($state->getURIDevInf() , 'Tx-Pref', $attrs); + + if (is_array($additionaltypes)) { + foreach ($additionaltypes as $ct => $ctver){ + $output->startElement($state->getURIDevInf() , 'Tx', $attrs); + $output->startElement($state->getURIDevInf() , 'CTType', $attrs); + $output->characters($ct); + $output->endElement($state->getURIDevInf() , 'CTType', $attrs); + $output->startElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->characters($ctver); + $output->endElement($state->getURIDevInf() , 'VerCT', $attrs); + $output->endElement($state->getURIDevInf() , 'Tx', $attrs); + } + } + + $output->startElement($state->getURIDevInf() , 'SyncCap', $attrs); + $output->startElement($state->getURIDevInf() , 'SyncType', $attrs); + $output->characters('1'); + $output->endElement($state->getURIDevInf() , 'SyncType', $attrs); + $output->startElement($state->getURIDevInf() , 'SyncType', $attrs); + $output->characters('2'); + $output->endElement($state->getURIDevInf() , 'SyncType', $attrs); + $output->endElement($state->getURIDevInf() , 'SyncCap', $attrs); + $output->endElement($state->getURIDevInf() , 'DataStore', $attrs); + } + } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php index 41410bedb0..c3abf081fb 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Status.php @@ -143,8 +143,8 @@ class Horde_SyncML_Command_Status extends Horde_SyncML_Command { $output->startElement($state->getURI(), 'Item', $attrs); $output->startElement($state->getURI(), 'Data', $attrs); - // $metainfuri = $state->getURIMeta(); - $metainfuri = $state->getURI(); // debug by FOU + $metainfuri = $state->getURIMeta(); + // $metainfuri = $state->getURI(); // debug by FOU $output->startElement($metainfuri, 'Anchor', $attrs); diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php index 5e785730d8..2f294a91e2 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync.php @@ -142,23 +142,14 @@ class Horde_SyncML_Command_Sync extends Horde_Syncml_Command { break; } - #Horde::logMessage('SyncML: ending sync to client '.$targets[0], __FILE__, __LINE__, PEAR_LOG_DEBUG); + # // no syncs left if($state->getTargets() === FALSE) $state->setSyncStatus(SERVER_SYNC_FINNISHED); + Horde::logMessage('SyncML: syncStatus(server_sync_finnished) '. $state->getSyncStatus, __FILE__, __LINE__, PEAR_LOG_DEBUG); ############################# } -# elseif($state->getSyncStatus() == CLIENT_SYNC_STARTED) -# { -# Horde::logMessage('SyncML: client alert '.$state->_currentSourceURI, __FILE__, __LINE__, PEAR_LOG_DEBUG); -# Horde::logMessage('SyncML: client alert '.$state->_currentTargetURI, __FILE__, __LINE__, PEAR_LOG_DEBUG); -# Horde::logMessage('SyncML: client alert '.$state->_currentTargetURIParameters, __FILE__, __LINE__, PEAR_LOG_DEBUG); -# $alert = &new Horde_SyncML_Command_Alert(ALERT_NEXT_MESSAGE); -# $alert->setSourceLocURI($state->_currentSourceURI); -# $alert->setTargetLocURI((isset($state->_currentTargetURIParameters) ? $state->_currentTargetURI.'?/'.$state->_currentTargetURIParameters : $state->_currentTargetURI)); -# $currentCmdID = $alert->output($currentCmdID, $output); -# } return $currentCmdID; } diff --git a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php index 3723015038..e45da9fd85 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php +++ b/phpgwapi/inc/horde/Horde/SyncML/Command/Sync/ContentSyncElement.php @@ -127,7 +127,8 @@ class Horde_SyncML_Command_Sync_ContentSyncElement extends Horde_SyncML_Command_ } if (isset($this->_content)) { $output->startElement($state->getURI(), 'Data', $attrs); - $chars = '_content.']]>'; + #$chars = '_content.']]>'; + $chars = $this->_content; $output->characters($chars); $output->endElement($state->getURI(), 'Data'); } diff --git a/phpgwapi/inc/horde/Horde/SyncML/State.php b/phpgwapi/inc/horde/Horde/SyncML/State.php index f985faa069..b4a888cd6b 100644 --- a/phpgwapi/inc/horde/Horde/SyncML/State.php +++ b/phpgwapi/inc/horde/Horde/SyncML/State.php @@ -289,6 +289,16 @@ class Horde_SyncML_State { { return $this->_msgID; } + + function setWBXML($wbxml) + { + $this->_wbxml = $wbxml; + } + + function isWBXML() + { + return !empty($this->_wbxml); + } function &getSyncStatus() { @@ -370,9 +380,11 @@ class Horde_SyncML_State { if ($version == 0) { $this->_uri = NAME_SPACE_URI_SYNCML; $this->_uriMeta = NAME_SPACE_URI_METINF; + $this->_uriDevInf = NAME_SPACE_URI_DEVINF; } else { $this->_uri = NAME_SPACE_URI_SYNCML_1_1; $this->_uriMeta = NAME_SPACE_URI_METINF_1_1; + $this->_uriDevInf = NAME_SPACE_URI_DEVINF_1_1; } } @@ -408,7 +420,7 @@ class Horde_SyncML_State { // store sessionID in a variable, because ->verify maybe resets that value $sessionID = session_id(); if(!$GLOBALS['phpgw']->session->verify($sessionID, 'staticsyncmlkp3')) - Horde::logMessage('SyncML_EGW: egw session('.$sessionID.') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); + Horde::logMessage('SyncML_EGW: egw session('.$sessionID. ') not verified ' , __FILE__, __LINE__, PEAR_LOG_DEBUG); } return $this->_isAuthorized; @@ -448,14 +460,28 @@ class Horde_SyncML_State { function getURI() { - return $this->_uri; + /* + * The non WBXML devices (notably P900 and Sync4j seem to get confused + * by a element. They require + * just . So don't use an ns for non wbxml devices. + */ +# if ($this->isWBXML()) { + return $this->_uri; +# } else { +# return ''; +# } } - function getURIMeta() { return $this->_uriMeta; } + function getURIDevInf() + { + return $this->_uriDevInf; + } + + /** * Converts a Horde GUID (like * kronolith:0d1b415fc124d3427722e95f0e926b75) to a client ID as diff --git a/phpgwapi/inc/horde/XML/WBXML.php b/phpgwapi/inc/horde/XML/WBXML.php index 8ead275272..382d0bb18b 100644 --- a/phpgwapi/inc/horde/XML/WBXML.php +++ b/phpgwapi/inc/horde/XML/WBXML.php @@ -63,12 +63,12 @@ define('CHARSET_UTF_16LE', 'UTF-16LE'); define('CHARSET_UTF_16', 'UTF-16'); /** - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * $Horde: framework/XML_WBXML/WBXML.php,v 1.14 2005/01/03 13:09:24 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML.php,v 1.18 2006/01/01 21:10:25 jan Exp $ * * @package XML_WBXML */ @@ -104,35 +104,25 @@ class XML_WBXML { $bytes3 = 128 | XML_WBXML::getBits(3, $i); $bytes4 = 128 | XML_WBXML::getBits(4, $i); - $out .= chr($bytes4); - $out .= chr($bytes3); - $out .= chr($bytes2); - $out .= chr($bytes1); - $out .= chr($bytes0); + $out .= chr($bytes4) . chr($bytes3) . chr($bytes2) . chr($bytes1) . chr($bytes0); } elseif ($i > 2097151) { $bytes0 = 0 | XML_WBXML::getBits(0, $i); $bytes1 = 128 | XML_WBXML::getBits(1, $i); $bytes2 = 128 | XML_WBXML::getBits(2, $i); $bytes3 = 128 | XML_WBXML::getBits(3, $i); - $out .= chr($bytes3); - $out .= chr($bytes2); - $out .= chr($bytes1); - $out .= chr($bytes0); + $out .= chr($bytes3) . chr($bytes2) . chr($bytes1) . chr($bytes0); } elseif ($i > 16383) { $bytes0 = 0 | XML_WBXML::getBits(0, $i); $bytes1 = 128 | XML_WBXML::getBits(1, $i); $bytes2 = 128 | XML_WBXML::getBits(2, $i); - $out .= chr($bytes2); - $out .= chr($bytes1); - $out .= chr($bytes0); + $out .= chr($bytes2) . chr($bytes1) . chr($bytes0); } elseif ($i > 127) { $bytes0 = 0 | XML_WBXML::getBits(0, $i); $bytes1 = 128 | XML_WBXML::getBits(1, $i); - $out .= chr($bytes1); - $out .= chr($bytes0); + $out .= chr($bytes1) . chr($bytes0); } else { $bytes0 = 0 | XML_WBXML::getBits(0, $i); @@ -166,7 +156,6 @@ class XML_WBXML { { /** * ADD CHAPTER - * @var array $_DPIString */ $DPIString = array(2 => DPI_DTD_WML_1_0, 3 => DPI_DTD_WTA_1_0, @@ -184,9 +173,9 @@ class XML_WBXML { // Not all SyncML clients know this, so we // should use the string table. // 0xFD1 => DPI_DTD_SYNCML_1_1, - // 0xFD2 => DPI_DTD_DEVINF_1_1, + 4051 => DPI_DTD_SYNCML_1_1, + 4052 => DPI_DTD_DEVINF_1_1, ); - return isset($DPIString[$i]) ? $DPIString[$i] : null; } @@ -194,7 +183,6 @@ class XML_WBXML { { /** * ADD CHAPTER - * @var array $_DPIInt */ $DPIInt = array(DPI_DTD_WML_1_0 => 2, DPI_DTD_WTA_1_0 => 3, @@ -228,7 +216,6 @@ class XML_WBXML { { /** * From http://www.iana.org/assignments/character-sets - * @var array $_charsetString */ $charsetString = array(3 => 'US-ASCII', 4 => 'ISO-8859-1', @@ -252,7 +239,6 @@ class XML_WBXML { { /** * From http://www.iana.org/assignments/character-sets - * @var array $_charsetInt */ $charsetInt = array('US-ASCII' => 3, 'ISO-8859-1' => 4, diff --git a/phpgwapi/inc/horde/XML/WBXML/ContentHandler.php b/phpgwapi/inc/horde/XML/WBXML/ContentHandler.php index 7ee64da239..86337cd9b1 100644 --- a/phpgwapi/inc/horde/XML/WBXML/ContentHandler.php +++ b/phpgwapi/inc/horde/XML/WBXML/ContentHandler.php @@ -1,8 +1,8 @@ + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -33,7 +33,6 @@ class XML_WBXML_ContentHandler { function XML_WBXML_ContentHandler() { $this->_currentUri = &new XML_WBXML_LifoQueue(); - $this->_output = ''; } function raiseError($error) @@ -67,13 +66,18 @@ class XML_WBXML_ContentHandler { return $this->_output; } + function getOutputSize() + { + return strlen($this->_output); + } + function startElement($uri, $element, $attrs) { $this->_output .= '<' . $element; $currentUri = $this->_currentUri->top(); - if ((!$currentUri) || ($currentUri != $uri)) { + if (((!$currentUri) || ($currentUri != $uri)) && $uri) { $this->_output .= ' xmlns="' . $uri . '"'; } @@ -130,7 +134,7 @@ class XML_WBXML_LifoQueue { function push($obj) { - array_push($this->_queue, $obj); + $this->_queue[] = $obj; } function pop() diff --git a/phpgwapi/inc/horde/XML/WBXML/DTD.php b/phpgwapi/inc/horde/XML/WBXML/DTD.php index e9f6bddccf..880c3dec00 100644 --- a/phpgwapi/inc/horde/XML/WBXML/DTD.php +++ b/phpgwapi/inc/horde/XML/WBXML/DTD.php @@ -1,11 +1,11 @@ + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. diff --git a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncML.php b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncML.php index 1b3c8e22f8..6f2edfa703 100644 --- a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncML.php +++ b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncML.php @@ -3,12 +3,12 @@ include_once 'XML/WBXML/DTD.php'; /** - * $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.7 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/DTD/SyncML.php,v 1.11 2006/01/01 21:10:26 jan Exp $ * * From Binary XML Content Format Specification Version 1.3, 25 July 2001 * found at http://www.wapforum.org * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -19,62 +19,66 @@ class XML_WBXML_DTD_SyncML extends XML_WBXML_DTD { function init() { - $this->setTag(5, 'Add'); // 0x05 - $this->setTag(6, 'Alert'); // 0x06 - $this->setTag(7, 'Archive'); // 0x07 - $this->setTag(8, 'Atomic'); // 0x08 - $this->setTag(9, 'Chal'); // 0x09 - $this->setTag(10, 'Cmd'); // 0x0A - $this->setTag(11, 'CmdID'); // 0x0B - $this->setTag(12, 'CmdRef'); // 0x0C - $this->setTag(13, 'Copy'); // 0x0D - $this->setTag(14, 'Cred'); // 0x0E - $this->setTag(15, 'Data'); // 0x0F + /* this code table has been extracted from libwbxml + * (see http://libwbxml.aymerick.com/) by using + * + * grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c + * | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g' + */ - $this->setTag(16, 'Delete'); // 0x10 - $this->setTag(17, 'Exec'); // 0x11 - $this->setTag(18, 'Final'); // 0x12 - $this->setTag(19, 'Get'); // 0x13 - $this->setTag(20, 'Item'); // 0x14 - $this->setTag(21, 'Lang'); // 0x15 - $this->setTag(22, 'LocName'); // 0x16 - $this->setTag(23, 'LocURI'); // 0x17 - $this->setTag(24, 'Map'); // 0x18 - $this->setTag(25, 'MapItem'); // 0x19 - $this->setTag(26, 'Meta'); // 0x1A - $this->setTag(27, 'MsgID'); // 0x1B - $this->setTag(28, 'MsgRef'); // 0x1C - $this->setTag(29, 'NoRssp'); // 0x1D - $this->setTag(30, 'NoResults'); // 0x1E - $this->setTag(31, 'Put'); // 0x1F - - $this->setTag(32, 'Replace'); // 0x10 - $this->setTag(33, 'RespURI'); // 0x21 - $this->setTag(34, 'Results'); // 0x22 - $this->setTag(35, 'Search'); // 0x23 - $this->setTag(36, 'Sequence'); // 0x24 - $this->setTag(37, 'SessionID'); // 0x25 - $this->setTag(38, 'SftDel'); // 0x26 - $this->setTag(39, 'Source'); // 0x27 - $this->setTag(40, 'SourceRef'); // 0x28 - $this->setTag(41, 'Status'); // 0x29 - $this->setTag(42, 'Sync'); // 0x2A - $this->setTag(43, 'SyncBody'); // 0x2B - $this->setTag(44, 'SyncHdr'); // 0x2C - $this->setTag(45, 'SyncML'); // 0x2D - $this->setTag(46, 'Target'); // 0x2E - $this->setTag(47, 'TargetRef'); // 0x2F - - $this->setTag(48, 'Reserved for future use.'); // 0x30 - $this->setTag(49, 'VerDTD'); // 0x31 - $this->setTag(50, 'VerProto'); // 0x32 - $this->setTag(51, 'NumberOfChanged'); // 0x33 - $this->setTag(52, 'MoreData'); // 0x34 + $this->setTag(0x05, "Add"); // 0x00 + $this->setTag(0x06, "Alert"); // 0x00 + $this->setTag(0x07, "Archive"); // 0x00 + $this->setTag(0x08, "Atomic"); // 0x00 + $this->setTag(0x09, "Chal"); // 0x00 + $this->setTag(0x0a, "Cmd"); // 0x00 + $this->setTag(0x0b, "CmdID"); // 0x00 + $this->setTag(0x0c, "CmdRef"); // 0x00 + $this->setTag(0x0d, "Copy"); // 0x00 + $this->setTag(0x0e, "Cred"); // 0x00 + $this->setTag(0x0f, "Data"); // 0x00 + $this->setTag(0x10, "Delete"); // 0x00 + $this->setTag(0x11, "Exec"); // 0x00 + $this->setTag(0x12, "Final"); // 0x00 + $this->setTag(0x13, "Get"); // 0x00 + $this->setTag(0x14, "Item"); // 0x00 + $this->setTag(0x15, "Lang"); // 0x00 + $this->setTag(0x16, "LocName"); // 0x00 + $this->setTag(0x17, "LocURI"); // 0x00 + $this->setTag(0x18, "Map"); // 0x00 + $this->setTag(0x19, "MapItem"); // 0x00 + $this->setTag(0x1a, "Meta"); // 0x00 + $this->setTag(0x1b, "MsgID"); // 0x00 + $this->setTag(0x1c, "MsgRef"); // 0x00 + $this->setTag(0x1d, "NoResp"); // 0x00 + $this->setTag(0x1e, "NoResults"); // 0x00 + $this->setTag(0x1f, "Put"); // 0x00 + $this->setTag(0x20, "Replace"); // 0x00 + $this->setTag(0x21, "RespURI"); // 0x00 + $this->setTag(0x22, "Results"); // 0x00 + $this->setTag(0x23, "Search"); // 0x00 + $this->setTag(0x24, "Sequence"); // 0x00 + $this->setTag(0x25, "SessionID"); // 0x00 + $this->setTag(0x26, "SftDel"); // 0x00 + $this->setTag(0x27, "Source"); // 0x00 + $this->setTag(0x28, "SourceRef"); // 0x00 + $this->setTag(0x29, "Status"); // 0x00 + $this->setTag(0x2a, "Sync"); // 0x00 + $this->setTag(0x2b, "SyncBody"); // 0x00 + $this->setTag(0x2c, "SyncHdr"); // 0x00 + $this->setTag(0x2d, "SyncML"); // 0x00 + $this->setTag(0x2e, "Target"); // 0x00 + $this->setTag(0x2f, "TargetRef"); // 0x00 + $this->setTag(0x30, "Reserved for future use"); // 0x00 + $this->setTag(0x31, "VerDTD"); // 0x00 + $this->setTag(0x32, "VerProto"); // 0x00 + $this->setTag(0x33, "NumberOfChanged"); // 0x00 + $this->setTag(0x34, "MoreData"); // 0x00 if ($this->version == 0) { - $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml'); + $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0'); $this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf'); - $this->setURI('syncml:syncml'); + $this->setURI('syncml:syncml1.0'); } else { $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1'); $this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1'); diff --git a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLDevInf.php b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLDevInf.php index fa7f84041e..076236b4ce 100644 --- a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLDevInf.php +++ b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLDevInf.php @@ -3,9 +3,9 @@ include_once 'XML/WBXML/DTD.php'; /** - * $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.5 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLDevInf.php,v 1.11 2006/01/01 21:10:26 jan Exp $ * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * From Binary XML Content Format Specification Version 1.3, 25 July 2001 * found at http://www.wapforum.org @@ -19,51 +19,58 @@ class XML_WBXML_DTD_SyncMLDevInf extends XML_WBXML_DTD { function init() { - $this->setTag(5, 'CTCap'); // 0x05 - $this->setTag(6, 'CTType'); // 0x06 - $this->setTag(7, 'DataStore'); // 0x07 - $this->setTag(8, 'DataType'); // 0x08 - $this->setTag(9, 'DevID'); // 0x09 - $this->setTag(10, 'DevInf'); // 0x0A - $this->setTag(11, 'DevTyp'); // 0x0B - $this->setTag(12, 'DisplayName'); // 0x0C - $this->setTag(13, 'DSMem'); // 0x0D - $this->setTag(14, 'Ext'); // 0x0E - $this->setTag(15, 'FwV'); // 0x0F - $this->setTag(16, 'HwV'); // 0x10 - $this->setTag(17, 'Man'); // 0x11 - $this->setTag(18, 'MaxGUIDSize'); // 0x12 - $this->setTag(19, 'MaxID'); // 0x13 - $this->setTag(20, 'MaxMem'); // 0x14 - $this->setTag(21, 'Mod'); // 0x15 - $this->setTag(22, 'OEM'); // 0x15 - $this->setTag(23, 'ParamName'); // 0x17 - $this->setTag(24, 'PropName'); // 0x18 - $this->setTag(25, 'Rx'); // 0x19 - $this->setTag(26, 'Rx-Pref'); // 0x1A - $this->setTag(27, 'SharedMem'); // 0x1B - $this->setTag(28, 'Size'); // 0x1C - $this->setTag(29, 'SourceRef'); // 0x1D - $this->setTag(30, 'SwV'); // 0x1E - $this->setTag(31, 'SyncCap'); // 0x1F - $this->setTag(32, 'SyncType'); // 0x20 - $this->setTag(33, 'Tx'); // 0x21 - $this->setTag(34, 'Tx-Pref'); // 0x22 - $this->setTag(35, 'ValEnum'); // 0x23 - $this->setTag(36, 'VerCT'); // 0x24 - $this->setTag(37, 'VerDTD'); // 0x25 - $this->setTag(38, 'Xnam'); // 0x26 - $this->setTag(39, 'Xval'); // 0x27 - $this->setTag(40, 'UTC'); // 0x28 - $this->setTag(41, 'SupportNumberOfChanges'); // 0x29 - $this->setTag(42, 'SupportLargeObjs'); // 0x2A + /* this code table has been extracted from libwbxml + * (see http://libwbxml.aymerick.com/) by using + * + * grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c + * | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g' + */ + + $this->setTag(0x05, "CTCap"); // 0x00 + $this->setTag(0x06, "CTType"); // 0x00 + $this->setTag(0x07, "DataStore"); // 0x00 + $this->setTag(0x08, "DataType"); // 0x00 + $this->setTag(0x09, "DevID"); // 0x00 + $this->setTag(0x0a, "DevInf"); // 0x00 + $this->setTag(0x0b, "DevTyp"); // 0x00 + $this->setTag(0x0c, "DisplayName"); // 0x00 + $this->setTag(0x0d, "DSMem"); // 0x00 + $this->setTag(0x0e, "Ext"); // 0x00 + $this->setTag(0x0f, "FwV"); // 0x00 + $this->setTag(0x10, "HwV"); // 0x00 + $this->setTag(0x11, "Man"); // 0x00 + $this->setTag(0x12, "MaxGUIDSize"); // 0x00 + $this->setTag(0x13, "MaxID"); // 0x00 + $this->setTag(0x14, "MaxMem"); // 0x00 + $this->setTag(0x15, "Mod"); // 0x00 + $this->setTag(0x16, "OEM"); // 0x00 + $this->setTag(0x17, "ParamName"); // 0x00 + $this->setTag(0x18, "PropName"); // 0x00 + $this->setTag(0x19, "Rx"); // 0x00 + $this->setTag(0x1a, "Rx-Pref"); // 0x00 + $this->setTag(0x1b, "SharedMem"); // 0x00 + $this->setTag(0x1c, "Size"); // 0x00 + $this->setTag(0x1d, "SourceRef"); // 0x00 + $this->setTag(0x1e, "SwV"); // 0x00 + $this->setTag(0x1f, "SyncCap"); // 0x00 + $this->setTag(0x20, "SyncType"); // 0x00 + $this->setTag(0x21, "Tx"); // 0x00 + $this->setTag(0x22, "Tx-Pref"); // 0x00 + $this->setTag(0x23, "ValEnum"); // 0x00 + $this->setTag(0x24, "VerCT"); // 0x00 + $this->setTag(0x25, "VerDTD"); // 0x00 + $this->setTag(0x26, "XNam"); // 0x00 + $this->setTag(0x27, "XVal"); // 0x00 + $this->setTag(0x28, "UTC"); // 0x00 + $this->setTag(0x29, "SupportNumberOfChanges"); // 0x00 + $this->setTag(0x2a, "SupportLargeObjs"); // 0x00 if ($this->version == 0) { $this->setCodePage(0, '-//SYNCML//DTD DevInf 1.0//EN', 'syncml:devinf'); - $this->setURI('sync:devinf'); + $this->setURI('syncml:devinf'); } else { $this->setCodePage(0, '-//SYNCML//DTD DevInf 1.1//EN', 'syncml:devinf1.1'); - $this->setURI('sync:devinf1.1'); + $this->setURI('syncml:devinf1.1'); } } diff --git a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLMetInf.php b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLMetInf.php index a93471ce94..84010187cd 100644 --- a/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLMetInf.php +++ b/phpgwapi/inc/horde/XML/WBXML/DTD/SyncMLMetInf.php @@ -3,9 +3,9 @@ include_once 'XML/WBXML/DTD.php'; /** - * $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.5 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/DTD/SyncMLMetInf.php,v 1.9 2006/01/01 21:10:26 jan Exp $ * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * From Binary XML Content Format Specification Version 1.3, 25 July 2001 * found at http://www.wapforum.org @@ -19,32 +19,40 @@ class XML_WBXML_DTD_SyncMLMetInf extends XML_WBXML_DTD { function init() { - $this->setTag(5, 'Anchor'); // 0x05 - $this->setTag(6, 'EMI'); // 0x06 - $this->setTag(7, 'Format'); // 0x07 - $this->setTag(8, 'FreeID'); // 0x08 - $this->setTag(9, 'FreeMem'); // 0x09 - $this->setTag(10, 'Last'); // 0x0A - $this->setTag(11, 'Mark'); // 0x0B - $this->setTag(12, 'MaxMsgSize'); // 0x0C - $this->setTag(13, 'Mem'); // 0x0D - $this->setTag(14, 'MetInf'); // 0x0E - $this->setTag(15, 'Next'); // 0x0F - $this->setTag(16, 'NextNonce'); // 0x10 - $this->setTag(17, 'SharedMem'); // 0x11 - $this->setTag(18, 'Size'); // 0x12 - $this->setTag(19, 'Type'); // 0x13 - $this->setTag(20, 'Version'); // 0x14 - $this->setTag(21, 'MaxObjSize'); // 0x15 + /* this code table has been extracted from libwbxml + * (see http://libwbxml.aymerick.com/) by using + * + * grep '\"[^\"]*\", *0x.., 0x.. },' wbxml_tables.c + * | sed -e 's#^.*\"\([^\"]*\)\", *\(0x..\), \(0x..\) },.*$# \$this->setTag\(\3, \"\1\"\); // \2#g' + */ + + $this->setTag(0x05, "Anchor"); // 0x01 + $this->setTag(0x06, "EMI"); // 0x01 + $this->setTag(0x07, "Format"); // 0x01 + $this->setTag(0x08, "FreeID"); // 0x01 + $this->setTag(0x09, "FreeMem"); // 0x01 + $this->setTag(0x0a, "Last"); // 0x01 + $this->setTag(0x0b, "Mark"); // 0x01 + $this->setTag(0x0c, "MaxMsgSize"); // 0x01 + $this->setTag(0x15, "MaxObjSize"); // 0x01 + $this->setTag(0x0d, "Mem"); // 0x01 + $this->setTag(0x0e, "MetInf"); // 0x01 + $this->setTag(0x0f, "Next"); // 0x01 + $this->setTag(0x10, "NextNonce"); // 0x01 + $this->setTag(0x11, "SharedMem"); // 0x01 + $this->setTag(0x12, "Size"); // 0x01 + $this->setTag(0x13, "Type"); // 0x01 + $this->setTag(0x14, "Version"); // 0x01 if ($this->version == 0) { - $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml'); + $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.0//EN', 'syncml:SYNCML1.0'); $this->setCodePage(1, '-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf'); $this->setURI('syncml:metinf'); } else { $this->setCodePage(0, '-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1'); $this->setCodePage(1, '-//SYNCML//DTD MetInf 1.1//EN', 'syncml:metinf1.1'); $this->setURI('syncml:metinf1.1'); + //$this->setURI('syncml:metinf'); // for some funny reason, libwbxml produces no :metinf1.1 here } } diff --git a/phpgwapi/inc/horde/XML/WBXML/DTDManager.php b/phpgwapi/inc/horde/XML/WBXML/DTDManager.php index a855034033..1f57e28195 100644 --- a/phpgwapi/inc/horde/XML/WBXML/DTDManager.php +++ b/phpgwapi/inc/horde/XML/WBXML/DTDManager.php @@ -5,9 +5,9 @@ include_once 'XML/WBXML/DTD/SyncMLMetInf.php'; include_once 'XML/WBXML/DTD/SyncMLDevInf.php'; /** - * $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.4 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/DTDManager.php,v 1.7 2006/01/01 21:10:25 jan Exp $ * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -24,7 +24,7 @@ class XML_WBXML_DTDManager { function XML_WBXML_DTDManager() { - $this->registerDTD('-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml', new XML_WBXML_DTD_SyncML(0)); + $this->registerDTD('-//SYNCML//DTD SyncML 1.0//EN', 'syncml:syncml1.0', new XML_WBXML_DTD_SyncML(0)); $this->registerDTD('-//SYNCML//DTD SyncML 1.1//EN', 'syncml:syncml1.1', new XML_WBXML_DTD_SyncML(1)); $this->registerDTD('-//SYNCML//DTD MetInf 1.0//EN', 'syncml:metinf', new XML_WBXML_DTD_SyncMLMetInf(0)); @@ -50,7 +50,7 @@ class XML_WBXML_DTDManager { $dtd->setDPI($publicIdentifier); $this->_strDTD[$publicIdentifier] = $dtd; - $this->_strDTDURI[$uri] = $dtd; + $this->_strDTDURI[strtolower($uri)] = $dtd; } } diff --git a/phpgwapi/inc/horde/XML/WBXML/Decoder.php b/phpgwapi/inc/horde/XML/WBXML/Decoder.php index fd99b0aba1..aeb4aacc48 100644 --- a/phpgwapi/inc/horde/XML/WBXML/Decoder.php +++ b/phpgwapi/inc/horde/XML/WBXML/Decoder.php @@ -5,9 +5,9 @@ include_once 'XML/WBXML/DTDManager.php'; include_once 'XML/WBXML/ContentHandler.php'; /** - * $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.23 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/Decoder.php,v 1.36 2006/01/01 21:10:25 jan Exp $ * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -54,40 +54,39 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { var $_isAttribute; var $_isData = false; + var $_error = false; + /** * The DTD Manager. - * @var object XML_WBXML_DTDManager $dtdManager + * + * @var XML_WBXML_DTDManager */ var $_dtdManager; /** * The string position. - * @var integer $_strpos + * + * @var integer */ var $_strpos; - /** - * Use wbxml2xml from libwbxml. - * @var string $_wbxml2xml - */ - var $_wbxml2xml = '/usr/bin/wbxml2xml'; - - /** - * Arguments to pass to wbxml2xml. - * @var string $_wbxml2xml_args - */ - var $_wbxml2xml_args = '-o - -'; - /** * Constructor. */ function XML_WBXML_Decoder() { - if (empty($this->_wbxml2xml) || !is_executable($this->_wbxml2xml)) { - $this->_dtdManager = &new XML_WBXML_DTDManager(); - } + $this->_dtdManager = &new XML_WBXML_DTDManager(); } + /** + * Sets the contentHandler that will receive the output of the + * decoding. + * + * @param XML_WBXML_ContentHandler $ch The contentHandler + */ + function setContentHandler(&$ch) { + $this->_ch = &$ch; + } /** * Return one byte from the input stream. * @@ -100,91 +99,95 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { /** * Takes a WBXML input document and returns decoded XML. + * However the preferred and more effecient method is to + * use decode() rather than decodeToString() and have an + * appropriate contentHandler deal with the decoded data. * * @param string $wbxml The WBXML document to decode. * * @return string The decoded XML document. */ + function decodeToString($wbxml) + { + $this->_ch = &new XML_WBXML_ContentHandler(); + + $r = $this->decode($wbxml); + if (is_a($r, 'PEAR_Error')) { + return $r; + } + return $this->_ch->getOutput(); + } + + /** + * Takes a WBXML input document and decodes it. + * Decoding result is directly passed to the contentHandler. + * A contenthandler must be set using setContentHandler + * prior to invocation of this method + * + * @param string $wbxml The WBXML document to decode. + * + * @return mixed True on success or PEAR_Error. + */ function decode($wbxml) { - // Figure out if we're going to use wbxml2xml to do the - // conversion, or do it all in PHP code. - if (!empty($this->_wbxml2xml) && is_executable($this->_wbxml2xml)) { - $descriptorspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); + $this->_error = false; // reset state - $wbxml2xml = proc_open($this->_wbxml2xml . ' ' . $this->_wbxml2xml_args, - $descriptorspec, $pipes); - if (is_resource($wbxml2xml)) { - fwrite($pipes[0], $wbxml); - fclose($pipes[0]); + $this->_strpos = 0; - // Grab the output of wbxml2xml. - $xml = ''; - while (!feof($pipes[1])) { - $xml .= fread($pipes[1], 8192); - } - fclose($pipes[1]); - - $rv = proc_close($wbxml2xml); - - return $xml; - } else { - return PEAR::raiseError('wbxml2xml failed'); - } - } else { - $this->_strpos = 0; - - // Get Version Number from Section 5.4 - // version = u_int8 - // currently 1, 2 or 3 - $this->_wbxmlVersion = $this->getVersionNumber($wbxml); - - // Get Document Public Idetifier from Section 5.5 - // publicid = mb_u_int32 | (zero index) - // zero = u_int8 - // Containing the value zero (0) - // The actual DPI is determined after the String Table is read. - $dpiStruct = $this->getDocumentPublicIdentifier($wbxml); - - // Get Charset from 5.6 - // charset = mb_u_int32 - $this->_charset = $this->getCharset($wbxml); - - // Get String Table from 5.7 - // strb1 = length *byte - $this->_stringTable = $this->getStringTable($wbxml, $this->_charset); - - // Get Document Public Idetifier from Section 5.5. - $this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'], - $dpiStruct['dpiNumber'], - $this->_stringTable); - - // Now the real fun begins. - // From Sections 5.2 and 5.8 - - // Default content handler. - $this->_ch = &new XML_WBXML_ContentHandler(); - - // Default content handler. - $this->_dtdManager = &new XML_WBXML_DTDManager(); - - // Get the starting DTD. - $this->_tagDTD = $this->_dtdManager->getInstance($this->_dpi); - if (!$this->_tagDTD) { - return $this->raiseError('No DTD found for ' . $this->_dpi); - } - - $this->_attributeDTD = $this->_tagDTD; - - while ($this->_strpos < strlen($wbxml)) { - $this->_decode($wbxml); - } - - return $this->_ch->getOutput(); + if (empty($this->_ch)) { + return $this->raiseError('No Contenthandler defined.'); } + + // Get Version Number from Section 5.4 + // version = u_int8 + // currently 1, 2 or 3 + $this->_wbxmlVersion = $this->getVersionNumber($wbxml); + + // Get Document Public Idetifier from Section 5.5 + // publicid = mb_u_int32 | (zero index) + // zero = u_int8 + // Containing the value zero (0) + // The actual DPI is determined after the String Table is read. + $dpiStruct = $this->getDocumentPublicIdentifier($wbxml); + + // Get Charset from 5.6 + // charset = mb_u_int32 + $this->_charset = $this->getCharset($wbxml); + + // Get String Table from 5.7 + // strb1 = length *byte + $this->retrieveStringTable($wbxml); + + // Get Document Public Idetifier from Section 5.5. + $this->_dpi = $this->getDocumentPublicIdentifierImpl($dpiStruct['dpiType'], + $dpiStruct['dpiNumber'], + $this->_stringTable); + + // Now the real fun begins. + // From Sections 5.2 and 5.8 + + + // Default content handler. + $this->_dtdManager = &new XML_WBXML_DTDManager(); + + // Get the starting DTD. + $this->_tagDTD = $this->_dtdManager->getInstance($this->_dpi); + + if (!$this->_tagDTD) { + return $this->raiseError('No DTD found for ' + . $this->_dpi . '/' + . $dpiStruct['dpiNumber']); + } + + $this->_attributeDTD = $this->_tagDTD; +print "starting at: ".$this->_strpos."\n"; + while (empty($this->_error) && $this->_strpos < strlen($wbxml)) { + $this->_decode($wbxml); + } + if (!empty($this->_error)) { + return $this->_error; + } + return true; } function getVersionNumber($input) @@ -194,28 +197,22 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { function getDocumentPublicIdentifier($input) { - // 'dpiType' 'dpiNumber' - $dpistruct = array(); - $i = XML_WBXML::MBUInt32ToInt($input, $this->_strpos); - if ($i == 0) { - $dpiStruct['dpiType'] = 2; - $dpiStruct['dpiNumber'] = $this->getByte($input); + return array('dpiType' => 2, + 'dpiNumber' => $this->getByte($input)); } else { - $dpiStruct['dpiType'] = 1; - $dpiStruct['dpiNumber'] = $i; + return array('dpiType' => 1, + 'dpiNumber' => $i); } - - return $dpiStruct; } - function getDocumentPublicIdentifierImpl($dpiType, $dpiNumber, $st) + function getDocumentPublicIdentifierImpl($dpiType, $dpiNumber) { if ($dpiType == 1) { return XML_WBXML::getDPIString($dpiNumber); } else { - return isset($st[$dpiNumber]) ? $st[$dpiNumber] : null; + return $this->getStringTableEntry($dpiNumber); } } @@ -228,43 +225,56 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { function getCharset($input) { $cs = XML_WBXML::MBUInt32ToInt($input, $this->_strpos); - return $charset = XML_WBXML::getCharsetString($cs); + return XML_WBXML::getCharsetString($cs); } /** - * @TODO needs to be fixed. Does this still really need to be - * fixed? + * Retrieves the string table. + * The string table consists of an mb_u_int32 length + * and then length bytes forming the table. + * References to the string table refer to the + * starting position of the (null terminated) + * string in this table. */ - function getStringTable($input, $cs) + function retrieveStringTable($input) { - $stringTable = array(); $size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos); + $this->_stringTable = substr($input, $this->_strpos, $size); + $this->_strpos += $size; + // print "stringtable($size):" . $this->_stringTable ."\n"; + } - // A hack to make it work with arrays. - // How/why is this necessary? - $str = 'j'; + function getStringTableEntry($index) + { + if ($index >= strlen($this->_stringTable)) { + $this->_error = + $this->_ch->raiseError('Invalid offset ' . $index + . ' value encountered around position ' + . $this->_strpos + . '. Broken wbxml?'); + return ''; + } - $numstr = 0; - $start = 0; - $j = 0; - for ($i = 0; $i < $size; $i++ ) { - /* May need to fix the null detector for more than single - * byte charsets like ASCII, UTF-8, etc. */ - $ch = $input[$this->_strpos++]; - if (ord($ch) == 0) { - $stringTable[$numstr++] = $str; - $str = '#'; - $start = $i + 1; - } else { - $str[$j++] = $ch; + // copy of method termstr but without modification of this->_strpos + + $str = '#'; // must start with nonempty string to allow array access + + $i = 0; + $ch = $this->_stringTable[$index++]; + if (ord($ch) == 0) { + return ''; // don't return '#' + } + + while (ord($ch) != 0) { + $str[$i++] = $ch; + if ($index >= strlen($this->_stringTable)) { + break; } + $ch = $this->_stringTable[$index++]; } - - if ($start < $size) { - $stringTable[$numstr++] = $str; - } - - return $stringTable; + // print "string table entry: $str\n"; + return $str; + } function _decode($input) @@ -272,16 +282,20 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { $token = $this->getByte($input); $str = ''; + #print "position: " . $this->_strpos . " token: " . $token . " str10: " . substr($input, $this->_strpos, 10) . "\n"; // @todo: remove debug output + switch ($token) { case XML_WBXML_GLOBAL_TOKEN_STR_I: // Section 5.8.4.1 $str = $this->termstr($input); $this->_ch->characters($str); + // print "str:$str\n"; // @TODO Remove debug code break; case XML_WBXML_GLOBAL_TOKEN_STR_T: // Section 5.8.4.1 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($intput)]; + $x = XML_WBXML::MBUInt32ToInt($input, $this->_strpos); + $str = $this->getStringTableEntry($x); $this->_ch->characters($str); break; @@ -297,7 +311,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { case XML_WBXML_GLOBAL_TOKEN_EXT_T_1: case XML_WBXML_GLOBAL_TOKEN_EXT_T_2: // Section 5.8.4.2 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($intput)]; + $str = $this->getStringTableEnty(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); $this->_ch->characters($str); break; @@ -319,40 +333,65 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { case XML_WBXML_GLOBAL_TOKEN_PI: // Section 5.8.4.4 - // throw new IOException("WBXML global token processing instruction(PI, " + token + ") is unsupported!"); + // throw new IOException + // die("WBXML global token processing instruction(PI, " + token + ") is unsupported!\n"); break; case XML_WBXML_GLOBAL_TOKEN_LITERAL: // Section 5.8.4.5 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, false, false); break; case XML_WBXML_GLOBAL_TOKEN_LITERAL_A: // Section 5.8.4.5 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, true, false); break; case XML_WBXML_GLOBAL_TOKEN_LITERAL_AC: // Section 5.8.4.5 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $string, true, true); break; case XML_WBXML_GLOBAL_TOKEN_LITERAL_C: // Section 5.8.4.5 - $str = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $str = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); $this->parseTag($input, $str, false, true); break; case XML_WBXML_GLOBAL_TOKEN_OPAQUE: // Section 5.8.4.6 $size = XML_WBXML::MBUInt32ToInt($input, $this->_strpos); - $b = substr($input, $this->_strpos, $this->_strpos + $size); + // print "opaque of size $size\n"; // @todo remove debug + $b = substr($input, $this->_strpos, $size); $this->_strpos += $size; - $this->_ch->opaque($b); + // opaque data inside a element may or may not be + // a nested wbxml document (for example devinf data). + // We find out by checking the first byte of the data: if it's + // 1, 2 or 3 we expect it to be the version number of a wbxml + // document and thus start a new wbxml decoder instance on it. + + if ($this->_isData && ord($b) <= 10) { + $decoder = &new XML_WBXML_Decoder(true); + $decoder->setContentHandler($this->_ch); + $s = $decoder->decode($b); + // /* // @todo: FIXME currently we can't decode Nokia + // DevInf data. So ignore error for the time beeing. + if (is_a($s, 'PEAR_Error')) { + $this->_error = $s; + return; + } + // */ + // $this->_ch->characters($s); + } else { + /* normal opaque behaviour: just copy the raw data: */ + $this->_ch->characters( $b); + } + + // old approach to deal with opaque data inside ContentHandler: // FIXME Opaque is used by SYNCML. Opaque data that depends on the context // if (contentHandler instanceof OpaqueContentHandler) { // ((OpaqueContentHandler)contentHandler).opaque(b); @@ -363,8 +402,6 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { // contentHandler.characters(chars, 0, chars.length); // } - // This can cause some problems. We may have to use a - // event based decoder. break; case XML_WBXML_GLOBAL_TOKEN_END: @@ -375,6 +412,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { case XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE: // Section 5.8.4.7.2 $codePage = $this->getByte($input); + // print "switch to codepage $codePage\n"; // @todo: remove debug code $this->switchElementCodePage($codePage); break; @@ -386,11 +424,16 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { $realToken = $token & 0x3F; $str = $this->getTag($realToken); + // print "element:$str\n"; // @TODO Remove debug code $this->parseTag($input, $str, $hasAttributes, $hasContent); if ($realToken == 0x0f) { - // FIXME Don't remember this one. + // store if we're inside a Data tag. This may contain + // an additional enclosed wbxml document on which we have + // to run a seperate encoder $this->_isData = true; + } else { + $this->_isData = false; } break; } @@ -422,10 +465,6 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { $tag = 'Unknown'; } - if ($tag == 'Data') { - $this->_isData = false; - } - $this->_ch->endElement($this->getCurrentURI(), $tag); return $tag; @@ -453,7 +492,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { 'value' => $value); } - $attr = $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $attr = $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); break; // Value specified. @@ -468,7 +507,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { case XML_WBXML_GLOBAL_TOKEN_EXT_T_1: case XML_WBXML_GLOBAL_TOKEN_EXT_T_2: // Section 5.8.4.2 - $value .= $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $value .= $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); break; case XML_WBXML_GLOBAL_TOKEN_EXT_0: @@ -490,7 +529,7 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { case XML_WBXML_GLOBAL_TOKEN_STR_T: // Section 5.8.4.1 - $value .= $this->_stringTable[XML_WBXML::MBUInt32ToInt($input, $this->_strpos)]; + $value .= $this->getStringTableEntry(XML_WBXML::MBUInt32ToInt($input, $this->_strpos)); break; case XML_WBXML_GLOBAL_TOKEN_OPAQUE: @@ -600,13 +639,16 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { } /** - * @TODO FIXME reads a null terminated string. + * Reads a null terminated string. */ function termstr($input) { - $str = '#'; + $str = '#'; // must start with nonempty string to allow array access $i = 0; $ch = $input[$this->_strpos++]; + if (ord($ch) == 0) { + return ''; // don't return '#' + } while (ord($ch) != 0) { $str[$i++] = $ch; $ch = $input[$this->_strpos++]; @@ -616,3 +658,4 @@ class XML_WBXML_Decoder extends XML_WBXML_ContentHandler { } } + diff --git a/phpgwapi/inc/horde/XML/WBXML/Encoder.php b/phpgwapi/inc/horde/XML/WBXML/Encoder.php index 2fa11ba183..729c360f6c 100644 --- a/phpgwapi/inc/horde/XML/WBXML/Encoder.php +++ b/phpgwapi/inc/horde/XML/WBXML/Encoder.php @@ -6,9 +6,9 @@ include_once 'XML/WBXML/DTDManager.php'; include_once 'Horde/String.php'; /** - * $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.27 2005/01/03 13:09:25 jan Exp $ + * $Horde: framework/XML_WBXML/WBXML/Encoder.php,v 1.39 2006/01/01 21:10:25 jan Exp $ * - * Copyright 2003-2005 Anthony Mills + * Copyright 2003-2006 Anthony Mills * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. @@ -36,105 +36,59 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { var $_currentURI; - var $_subParser; + var $_subParser = null; var $_subParserStack = 0; - - /** - * These will store the startElement params to see if we should - * call startElementImp or startEndElementImp. - */ - var $_storeURI; - var $_storeName; - var $_storeAttributes; - + /** * The XML parser. - * @var resource $_parser + * + * @var resource */ var $_parser; /** * The DTD Manager. - * @var object XML_WBXML_DTDManager $dtdManager + * + * @var XML_WBXML_DTDManager */ var $_dtdManager; - var $_indent = 0; - - /** - * Use wbxml2xml from libwbxml. - * @var string $_xml2wbxml - */ - var $_xml2wbxml = '/usr/bin/xml2wbxml'; - - /** - * Arguments to pass to xml2wbxml. - * @var string $_xml2wbxml_args - */ - var $_xml2wbxml_args = '-k -n -v 1.2 -o - -'; - /** * Constructor. */ function XML_WBXML_Encoder() { - if (empty($this->_xml2wbxml) || !is_executable($this->_xml2wbxml)) { - $this->_stringTable = &new XML_WBXML_HashTable(); - $this->_dtdManager = &new XML_WBXML_DTDManager(); - } + $this->_dtdManager = &new XML_WBXML_DTDManager(); + $this->_stringTable = &new XML_WBXML_HashTable(); } /** - * Take the input $xml and turn it into WBXML. + * Take the input $xml and turn it into WBXML. This is _not_ the + * intended way of using this class. It is derived from + * Contenthandler and one should use it as a ContentHandler and + * produce the XML-structure with startElement(), endElement(), + * and characters(). */ function encode($xml) { - if (!empty($this->_xml2wbxml) && is_executable($this->_xml2wbxml)) { - $descriptorspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); + // Create the XML parser and set method references. + $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, ''); - $xml2wbxml = proc_open($this->_xml2wbxml . ' ' . $this->_xml2wbxml_args, - $descriptorspec, $pipes); - if (is_resource($xml2wbxml)) { - fwrite($pipes[0], $xml); - fclose($pipes[0]); - - // Grab the output of xml2wbxml. - $wbxml = ''; - while (!feof($pipes[1])) { - $wbxml .= fread($pipes[1], 8192); - } - fclose($pipes[1]); - - $rv = proc_close($xml2wbxml); - - return $wbxml; - } else { - return PEAR::raiseError('xml2wbxml failed'); - } - } else { - // Create the XML parser and set method references. - $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_default_handler($this->_parser, 'defaultHandler'); - 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); - - return $this->_output; + 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); + + return $this->_output; } /** @@ -142,6 +96,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { */ function writeHeader($uri) { + error_log("getInstanceURI($uri)"); $this->_dtd = &$this->_dtdManager->getInstanceURI($uri); $dpiString = $this->_dtd->getDPI(); @@ -256,57 +211,25 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { return array($uri, $name); } - /** - * Has no content, 64. - */ - function startEndElementImp($uri, $name, $attributes) - { - if (!$this->_hasWrittenHeader) { - $this->writeHeader($uri); - } - - $this->writeTag($name, $attributes, false, $this->_charset); - } - - function startElementImp($uri, $name, $attributes) - { - if (!$this->_hasWrittenHeader) { - $this->writeHeader($uri); - } - - if ($this->_currentURI != $uri) { - $this->changecodepage($uri); - - $this->_currentURI != $uri; - } - - $this->writeTag($name, $attributes, true, $this->_charset); - } - - function writeStartElement($isEnd) - { - if ($this->_storeName != null) { - if ($isEnd) { - $this->startEndElementImp($this->_storeURI, $this->_storeName, $this->_storeAttributes); - } else { - $this->startElementImp($this->_storeURI, $this->_storeName, $this->_storeAttributes); - } - - $this->_storeURI = null; - $this->_storeName = null; - $this->_storeAttributes = null; - } - } - function startElement($uri, $name, $attributes) { + error_log("startElement::: <$name>"); +# error_log(" subparser is:: ".$this->_subParser); if ($this->_subParser == null) { - $this->writeStartElement(false); - $this->_storeURI = $uri; - $this->_storeName = $name; - $this->_storeAttributes = $attributes; + if (!$this->_hasWrittenHeader) { + $this->writeHeader($uri); + } + if ($this->_currentURI != $uri) { + $this->changecodepage($uri); + } + if ($this->_subParser == null) { + $this->writeTag($name, $attributes, true, $this->_charset); + } else { + $this->_subParser->startElement($uri,$name, $attributes); + } } else { $this->_subParserStack++; + $this->_subParser->startElement($uri,$name,$attributes); } } @@ -320,8 +243,6 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { function opaque($bytes) { if ($this->_subParser == null) { - $this->writeStartElement(false); - $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE); XML_WBXML::intToMBUInt32($this->_output, count($bytes)); $this->_output .= $bytes; @@ -331,12 +252,11 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { function characters($chars) { $chars = trim($chars); + error_log("characters ::: ".$chars); if (strlen($chars)) { /* We definitely don't want any whitespace. */ if ($this->_subParser == null) { - $this->writeStartElement(false); - $i = $this->_stringTable->get($chars); if ($i != null) { $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_T); @@ -345,6 +265,8 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_STR_I); $this->writeString($chars, $this->_charset); } + } else { + $this->_subParser->characters($chars); } } } @@ -354,17 +276,15 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { $this->characters($chars); } - function defaultHandler($parser, $data) - { - } - function writeTag($name, $attrs, $hasContent, $cs) { + if ($attrs != null && !count($attrs)) { $attrs = null; } $t = $this->_dtd->toTagInt($name); +# error_log("writeTag ::: -> $name $t"); if ($t == -1) { $i = $this->_stringTable->get($name); if ($i == null) { @@ -394,7 +314,7 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { } } - if ($attrs != null) { + if ($attrs != null && is_array($attrs) && count($attrs) > 0 ) { $this->writeAttributes($attrs, $cs); } } @@ -435,13 +355,23 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { function endElement($uri, $name) { + error_log("endElement ::: "); +# error_log(" subparser is: ".$this->_subParser); if ($this->_subParser == null) { - $this->writeStartElement(false); $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_END); +# error_log(" _output is: ".strlen($this->_output)); } else { + $this->_subParser->endElement($uri, $name); $this->_subParserStack--; + if ($this->_subParserStack == 0) { - unset($this->_subParser); + $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE); + + XML_WBXML::intToMBUInt32($this->_output, + strlen($this->_subParser->getOutput())); + $this->_output .= $this->_subParser->getOutput(); + + $this->_subParser = null; } } } @@ -454,33 +384,37 @@ class XML_WBXML_Encoder extends XML_WBXML_ContentHandler { function changecodepage($uri) { +# error_log("changecodepage::: $uri"); + // @todo: this is a hack! + if (!preg_match('/1\.1$/', $uri)) { + $uri .= '1.1'; + } $cp = $this->_dtd->toCodePageURI($uri); - +# error_log("--- \$cp:: $cp"); if (strlen($cp)) { $this->_dtd = &$this->_dtdManager->getInstanceURI($uri); $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_SWITCH_PAGE); $this->_output .= chr($cp); + $this->_currentURI = $uri; + } else { - $this->_output .= chr(XML_WBXML_GLOBAL_TOKEN_OPAQUE); - - $this->_subParser = &new XML_WBXML_Encoder($this->_output); - $this->startElement($this->_storeURI, $this->_storeName, $this->_storeAttributes); - - $this->_subParserStack = 2; - - $this->_storeURI = null; - $this->_storeName = null; - $this->_storeAttributes = null; + $this->_subParser = &new XML_WBXML_Encoder(true); + $this->_subParserStack = 1; } } /** * Getter for property output. */ - function getOutput($output) + function getOutput() { return $this->_output; } + function getOutputSize() + { + return strlen($this->_output); + } + }