From: Gunnar Wrobel
Date: Sun, 30 Aug 2009 21:17:37 +0000 (+0200)
Subject: Further cleanup for Horde 4. Renamed XML classes to Xml. Some tests still failing...
X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=fc5a4a8abd16bcafeefec01bade6d115cd51d861;p=horde.git
Further cleanup for Horde 4. Renamed XML classes to Xml. Some tests still failing though.
---
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format.php b/framework/Kolab_Format/lib/Horde/Kolab/Format.php
index 37dc3f47b..06e422213 100644
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format.php
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format.php
@@ -54,7 +54,7 @@ abstract class Horde_Kolab_Format
static public function &factory($format_type = '', $object_type = '',
$params = null)
{
- $class = 'Horde_Kolab_Format_' . $format_type;
+ $class = 'Horde_Kolab_Format_' . ucfirst(strtolower($format_type));
if (class_exists($class)) {
$driver = call_user_func(array($class, 'factory'), $object_type,
$params);
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML.php
deleted file mode 100644
index 269cb9b0d..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML.php
+++ /dev/null
@@ -1,1420 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML to array hash converter.
- *
- * For implementing a new format type you will have to inherit this
- * class and provide a _load/_save function.
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML
-{
-
- /**
- * Defines a XML value that should get a default value if missing
- */
- const PRODUCT_ID = 'Horde::Kolab';
-
- /**
- * Defines a XML value that should get a default value if missing
- */
- const VALUE_DEFAULT = 0;
-
- /**
- * Defines a XML value that may be missing
- */
- const VALUE_MAYBE_MISSING = 1;
-
- /**
- * Defines a XML value that may not be missing
- */
- const VALUE_NOT_EMPTY = 2;
-
- /**
- * Defines a XML value that will be calculated by its own function
- */
- const VALUE_CALCULATED = 3;
-
- /**
- * Defines a XML value as string type
- */
- const TYPE_STRING = 0;
-
- /**
- * Defines a XML value as integer type
- */
- const TYPE_INTEGER = 1;
-
- /**
- * Defines a XML value as boolean type
- */
- const TYPE_BOOLEAN = 2;
-
- /**
- * Defines a XML value as date type
- */
- const TYPE_DATE = 3;
-
- /**
- * Defines a XML value as datetime type
- */
- const TYPE_DATETIME = 4;
-
- /**
- * Defines a XML value as date or datetime type
- */
- const TYPE_DATE_OR_DATETIME = 5;
-
- /**
- * Defines a XML value as color type
- */
- const TYPE_COLOR = 6;
-
- /**
- * Defines a XML value as composite value type
- */
- const TYPE_COMPOSITE = 7;
-
- /**
- * Defines a XML value as array type
- */
- const TYPE_MULTIPLE = 8;
-
- /**
- * Requested version of the data array to return
- *
- * @var int
- */
- protected $_version = 1;
-
- /**
- * The name of the resulting document.
- *
- * @var string
- */
- protected $_name = 'kolab.xml';
-
- /**
- * The XML document this driver works with.
- *
- * @var Horde_DOM_Document
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public $_xmldoc = null;
-
- /**
- * The name of the root element.
- *
- * @var string
- */
- protected $_root_name = 'kolab';
-
- /**
- * Kolab format version of the root element.
- *
- * @var string
- */
- protected $_root_version = '1.0';
-
- /**
- * Basic fields in any Kolab object
- *
- * @var array
- */
- protected $_fields_basic;
-
- /**
- * Automatically create categories if they are missing?
- *
- * @var boolean
- */
- protected $_create_categories = true;
-
- /**
- * Fields for a simple person
- *
- * @var array
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public $_fields_simple_person = array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'display-name' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'smtp-address' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'uid' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- ),
- );
-
- /**
- * Fields for an attendee
- *
- * @var array
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public $_fields_attendee = array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_DEFAULT,
- 'default' => array(),
- 'array' => array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'display-name' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'smtp-address' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'status' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 'none',
- ),
- 'request-response' => array(
- 'type' => self::TYPE_BOOLEAN,
- 'value' => self::VALUE_DEFAULT,
- 'default' => true,
- ),
- 'role' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 'required',
- ),
- ),
- ),
- );
-
- /**
- * Fields for a recurrence
- *
- * @var array
- */
- protected $_fields_recurrence = array(
- // Attribute on root node: cycle
- // Attribute on root node: type
- 'interval' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'day' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- 'daynumber' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'month' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- // Attribute on range: type
- 'range' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'exclusion' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- 'complete' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- );
-
- /**
- * Constructor
- *
- * @param array $params Any additional options
- */
- public function __construct($params = null)
- {
- if (is_array($params) && isset($params['version'])) {
- $this->_version = $params['version'];
- } else {
- $this->_version = 1;
- }
-
- /* Generic fields, in kolab format specification order */
- $this->_fields_basic = array(
- 'uid' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_NOT_EMPTY,
- ),
- 'body' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'categories' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'creation-date' => array(
- 'type' => self::TYPE_DATETIME,
- 'value' => self::VALUE_CALCULATED,
- 'load' => 'CreationDate',
- 'save' => 'CreationDate',
- ),
- 'last-modification-date' => array(
- 'type' => self::TYPE_DATETIME,
- 'value' => self::VALUE_CALCULATED,
- 'load' => 'ModificationDate',
- 'save' => 'ModificationDate',
- ),
- 'sensitivity' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 'public',
- ),
- 'inline-attachment' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- 'link-attachment' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- 'product-id' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_CALCULATED,
- 'load' => 'ProductId',
- 'save' => 'ProductId',
- ),
- );
- }
-
- /**
- * Attempts to return a concrete Horde_Kolab_Format_XML instance.
- * based on $object_type.
- *
- * @param string $object_type The object type that should be handled.
- * @param array $params Any additional parameters.
- *
- * @return Horde_Kolab_Format_XML The newly created concrete
- * Horde_Kolab_Format_XML instance.
- *
- * @throws Horde_Exception If the class for the object type could
- * not be loaded.
- */
- public function &factory($object_type = '', $params = null)
- {
- $object_type = ucfirst(str_replace('-', '', $object_type));
- $class = 'Horde_Kolab_Format_XML_' . $object_type;
-
- if (class_exists($class)) {
- $driver = &new $class($params);
- } else {
- throw new Horde_Exception(sprintf(_("Failed to load Kolab XML driver %s"),
- $object_type));
- }
-
- return $driver;
- }
-
- /**
- * Return the name of the resulting document.
- *
- * @return string The name that may be used as filename.
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * Return the mime type of the resulting document.
- *
- * @return string The mime type of the result.
- */
- public function getMimeType()
- {
- return 'application/x-vnd.kolab.' . $this->_root_name;
- }
-
- /**
- * Return the disposition of the resulting document.
- *
- * @return string The disportion of this document.
- */
- public function getDisposition()
- {
- return 'attachment';
- }
-
- /**
- * Load an object based on the given XML string.
- *
- * @todo Check encoding of the returned array. It seems to be ISO-8859-1 at
- * the moment and UTF-8 would seem more appropriate.
- *
- * @param string $xmltext The XML of the message as string.
- *
- * @return array The data array representing the object.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- public function load(&$xmltext)
- {
- try {
- $this->_parseXml($xmltext);
- } catch (DOMException $e) {
- /**
- * If the first call does not return successfully this might mean we
- * got an attachment with broken encoding. There are some Kolab
- * client versions in the wild that might have done that. So the
- * next section starts a second attempt by guessing the encoding and
- * trying again.
- */
- if (strcasecmp(mb_detect_encoding($xmltext,
- 'UTF-8, ISO-8859-1'), 'UTF-8') !== 0) {
- $xmltext = mb_convert_encoding($xmltext, 'UTF-8', 'ISO-8859-1');
- }
- $this->_parseXml($xmltext);
- }
- if (empty($this->_xmldoc)) {
- return false;
- }
-
- if (!$this->_xmldoc->hasChildNodes()) {
- throw new Horde_Exception(_("No or unreadable content in Kolab XML object"));
- }
-
- // fresh object data
- $object = array();
-
- $result = $this->_loadArray($this->_xmldoc->childNodes, $this->_fields_basic);
- $object = array_merge($object, $result);
- $this->_loadMultipleCategories($object);
-
- $result = $this->_load($this->_xmldoc->childNodes);
- $object = array_merge($object, $result);
-
- // uid is vital
- if (!isset($object['uid'])) {
- throw new Horde_Exception(_("UID not found in Kolab XML object"));
- }
-
- return $object;
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array $children An array of XML nodes.
- *
- * @return array The data array representing the object.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- if (!empty($this->_fields_specific)) {
- return $this->_loadArray($children, $this->_fields_specific);
- } else {
- return array();
- }
- }
-
- /**
- * Load an array with data from the XML nodes.
- *
- * @param array $object The resulting data array.
- * @param array $children An array of XML nodes.
- * @param array $fields The fields to populate in the object array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _loadArray(&$children, $fields)
- {
- $object = array();
-
- // basic fields below the root node
- foreach($fields as $field => $params) {
- $result = $this->_getXmlData($children, $field, $params);
- if (isset($result)) {
- $object[$field] = $result;
- }
- }
- return $object;
- }
-
- /**
- * Get the text content of the named data node among the specified
- * children.
- *
- * @param array &$children The children to search.
- * @param string $name The name of the node to return.
- * @param array $params Parameters for the data conversion.
- *
- * @return string The content of the specified node or an empty
- * string.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public function _getXmlData(&$children, $name, $params)
- {
- if ($params['type'] == self::TYPE_MULTIPLE) {
- $result = array();
- foreach($children as $child) {
- if ($child->nodeType == XML_ELEMENT_NODE && $child->tagName == $name) {
- $value = $this->_getXmlData(array($child), $name,
- $params['array']);
- $result[] = $value;
- }
- }
- return $result;
- }
-
- $value = null;
- $missing = false;
-
- // identify the child node
- $child = $this->_findNode($children, $name);
-
- // Handle empty values
- if (!$child) {
- if ($params['value'] == self::VALUE_MAYBE_MISSING) {
- // 'MAYBE_MISSING' means we should return null
- return null;
- } elseif ($params['value'] == self::VALUE_NOT_EMPTY) {
- // May not be empty. Return an error
- throw new Horde_Exception(sprintf(_("Data value for %s is empty in Kolab XML object!"),
- $name));
- } elseif ($params['value'] == self::VALUE_DEFAULT) {
- // Return the default
- return $params['default'];
- } elseif ($params['value'] == self::VALUE_CALCULATED) {
- $missing = true;
- }
- }
-
- // Do we need to calculate the value?
- if ($params['value'] == self::VALUE_CALCULATED && isset($params['load'])) {
- if (method_exists($this, '_load' . $params['load'])) {
- $value = call_user_func(array($this, '_load' . $params['load']),
- $child, $missing);
- } else {
- throw new Horde_Exception(sprintf("Kolab XML: Missing function %s!",
- $params['load']));
- }
- } elseif ($params['type'] == self::TYPE_COMPOSITE) {
- return $this->_loadArray($child->childNodes, $params['array']);
- } else {
- return $this->_loadDefault($child, $params);
- }
-
- // Nothing specified. Return the value as it is.
- return $value;
- }
-
- /**
- * Parse the XML string. The root node is returned on success.
- *
- * @param string $xmltext The XML of the message as string.
- *
- * @return NULL
- *
- * @throws Horde_Exception If parsing the XML data failed.
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public function _parseXml(&$xmltext)
- {
- $this->_xmldoc = new DOMDocument();
- $this->_xmldoc->preserveWhiteSpace = false;
- $this->_xmldoc->formatOutput = true;
- $this->_xmldoc->loadXML($xmltext);
- }
-
- /**
- * Convert the data to a XML string.
- *
- * @param array $attributes The data array representing the note.
- *
- * @return string The data as XML string.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- public function save($object)
- {
- $root = $this->_prepareSave();
-
- $this->_saveMultipleCategories($object);
- $this->_saveArray($root, $object, $this->_fields_basic);
- $this->_save($root, $object);
-
- return $this->_xmldoc->saveXML();
- }
-
- /**
- * Save the specific XML values.
- *
- * @param array &$root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save(&$root, $object)
- {
- if (!empty($this->_fields_specific)) {
- $this->_saveArray($root, $object, $this->_fields_specific);
- }
- return true;
- }
-
- /**
- * Creates a new XML document if necessary.
- *
- * @param string $xmltext The XML of the message as string.
- *
- * @return Horde_DOM_Node The root node of the document.
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public function &_prepareSave()
- {
- if (empty($this->_xmldoc)) {
- // create new XML
- $this->_xmldoc = new DOMDocument();
- $this->_xmldoc->preserveWhiteSpace = false;
- $this->_xmldoc->formatOutput = true;
- $root = $this->_xmldoc->createElement($this->_root_name);
- $root = $this->_xmldoc->appendChild($root);
- $root->setAttribute('version', $this->_root_version);
- }
- return $this->_xmldoc;
- }
-
- /**
- * Save a data array to XML nodes.
- *
- * @param array $root The XML document root.
- * @param array $object The data array.
- * @param array $fields The fields to write into the XML object.
- * @param boolean $append Should the nodes be appended?
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _saveArray($root, $object, $fields, $append = false)
- {
- // basic fields below the root node
- foreach($fields as $field => $params) {
- $this->_updateNode($root, $object, $field, $params, $append);
- }
- return true;
- }
-
- /**
- * Update the specified node.
- *
- * @param Horde_DOM_Node $parent_node The parent node of the node that
- * should be updated.
- * @param array $attributes The data array that holds all
- * attribute values.
- * @param string $name The name of the the attribute
- * to be updated.
- * @param array $params Parameters for saving the node
- * @param boolean $append Should the node be appended?
- *
- * @return Horde_DOM_Node The new/updated child node.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- *
- * @todo Make protected (fix the XmlTest for that)
- */
- public function _updateNode($parent_node, $attributes, $name, $params,
- $append = false)
- {
- $value = null;
- $missing = false;
-
- // Handle empty values
- if (!isset($attributes[$name])) {
- // Do we have information if this may be empty?
- if ($params['value'] == self::VALUE_DEFAULT) {
- // Use the default
- $value = $params['default'];
- } elseif ($params['value'] == self::VALUE_NOT_EMPTY) {
- // May not be empty. Return an error
- throw new Horde_Exception(sprintf(_("Data value for %s is empty in Kolab XML object!"),
- $name));
- } elseif ($params['value'] == self::VALUE_MAYBE_MISSING) {
- /**
- * 'MAYBE_MISSING' means we should not create an XML
- * node here
- */
- $this->_removeNodes($parent_node, $name);
- return false;
- } elseif ($params['value'] == self::VALUE_CALCULATED) {
- $missing = true;
- }
- } else {
- $value = $attributes[$name];
- }
-
- if ($params['value'] == self::VALUE_CALCULATED) {
- // Calculate the value
- if (method_exists($this, '_save' . $params['save'])) {
- return call_user_func(array($this, '_save' . $params['save']),
- $parent_node, $name, $value, $missing);
- } else {
- throw new Horde_Exception(sprintf("Kolab XML: Missing function %s!",
- $params['save']));
- }
- } elseif ($params['type'] == self::TYPE_COMPOSITE) {
- // Possibly remove the old node first
- if (!$append) {
- $this->_removeNodes($parent_node, $name);
- }
-
- // Create a new complex node
- $composite_node = $this->_xmldoc->createElement($name);
- $composite_node = $parent_node->appendChild($composite_node);
- return $this->_saveArray($composite_node, $value, $params['array']);
- } elseif ($params['type'] == self::TYPE_MULTIPLE) {
- // Remove the old nodes first
- $this->_removeNodes($parent_node, $name);
-
- // Add the new nodes
- foreach($value as $add_node) {
- $this->_saveArray($parent_node,
- array($name => $add_node),
- array($name => $params['array']),
- true);
- }
- return true;
- } else {
- return $this->_saveDefault($parent_node, $name, $value, $params,
- $append);
- }
- }
-
- /**
- * Create a text node.
- *
- * @param Horde_DOM_Node $parent The parent of the new node.
- * @param string $name The name of the child node to create.
- * @param string $value The value of the child node to create.
- *
- * @return Horde_DOM_Node The new node.
- */
- protected function _createTextNode($parent, $name, $value)
- {
- $value = Horde_String::convertCharset($value, Horde_Nls::getCharset(), 'utf-8');
-
- $node = $this->_xmldoc->createElement($name);
-
- $node = $parent->appendChild($node);
-
- // content
- $text = $this->_xmldoc->createTextNode($value);
- $text = $node->appendChild($text);
-
- return $node;
- }
-
- /**
- * Return the named node among a list of nodes.
- *
- * @param array %$nodes The list of nodes.
- * @param string $name The name of the node to return.
- *
- * @return mixed The named Horde_DOM_Node or false if no node was found.
- */
- protected function _findNode(&$nodes, $name)
- {
- foreach($nodes as $node) {
- if ($node->nodeType == XML_ELEMENT_NODE && $node->tagName == $name) {
- return $node;
- }
- }
- return false;
- }
-
- /**
- * Retrieve a named child from a named parent if it has the given
- * value.
- *
- * @param array $nodes The list of nodes.
- * @param string $parent_name The name of the parent node.
- * @param string $child_name The name of the child node.
- * @param string $value The value of the child node
- *
- * @return mixed The specified Horde_DOM_Node or false if no node was found.
- */
- protected function _findNodeByChildData($nodes, $parent_name, $child_name,
- $value)
- {
- foreach($nodes as $node)
- {
- if ($node->nodeType == XML_ELEMENT_NODE && $node->tagName == $parent_name) {
- $children = $node->childNodes;
- foreach ($children as $child)
- if ($child->nodeType == XML_ELEMENT_NODE
- && $child->tagName == $child_name
- && $child->textContent == $value) {
- return $node;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Retrieve the content of a Horde_DOM_Node.
- *
- * @param Horde_DOM_Node $nodes The node that should be read.
- *
- * @return string The content of the node.
- */
- protected function _getNodeContent($node)
- {
- return Horde_String::convertCharset($node->textContent, 'utf-8');
- }
-
-
- /**
- * Create a new named node on a parent node.
- *
- * @param Horde_DOM_Node $parent The parent node.
- * @param string $name The name of the new child node.
- *
- * @return Horde_DOM_Node The new child node.
- */
- protected function _createChildNode($parent, $name)
- {
- $node = $this->_xmldoc->createElement($name);
- $node = $parent->appendChild($node);
-
- return $node;
- }
-
- /**
- * Remove named nodes from a parent node.
- *
- * @param Horde_DOM_Node $parent The parent node.
- * @param string $name The name of the children to be removed.
- */
- protected function _removeNodes($parent_node, $name)
- {
- while ($old_node = $this->_findNode($parent_node->childNodes, $name)) {
- $parent_node->removeChild($old_node);
- }
- }
-
- /**
- * Create a new named node on a parent node if it is not already
- * present in the given children.
- *
- * @param Horde_DOM_Node $parent The parent node.
- * @param array $children The children that might already
- * contain the node.
- * @param string $name The name of the new child node.
- *
- * @return Horde_DOM_Node The new or already existing child node.
- */
- protected function _createOrFindChildNode($parent, $children, $name)
- {
- // look for existing node
- $old_node = $this->_findNode($children, $name);
- if ($old_node !== false) {
- return $old_node;
- }
-
- // create new parent node
- return $this->_createChildNode($parent, $name);
- }
-
- /**
- * Load the different XML types.
- *
- * @param string $node The node to load the data from
- * @param array $params Parameters for loading the value
- *
- * @return string The loaded value.
- *
- * @throws Horde_Exception If converting the data from XML failed.
- */
- protected function _loadDefault($node, $params)
- {
- $content = $this->_getNodeContent($node);
-
- switch($params['type']) {
- case self::TYPE_DATE:
- return Horde_Kolab_Format_Date::decodeDate($content);
-
- case self::TYPE_DATETIME:
- return Horde_Kolab_Format_Date::decodeDateTime($content);
-
- case self::TYPE_DATE_OR_DATETIME:
- return Horde_Kolab_Format_Date::decodeDateOrDateTime($content);
-
- case self::TYPE_INTEGER:
- return (int) $content;
-
- case self::TYPE_BOOLEAN:
- return (bool) $content;
-
- default:
- // Strings and colors are returned as they are
- return $content;
- }
- }
-
- /**
- * Save a data array as a XML node attached to the given parent node.
- *
- * @param Horde_DOM_Node $parent_node The parent node to attach
- * the child to
- * @param string $name The name of the node
- * @param mixed $value The value to store
- * @param boolean $missing Has the value been missing?
- * @param boolean $append Should the node be appended?
- *
- * @return Horde_DOM_Node The new child node.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _saveDefault($parent_node, $name, $value, $params,
- $append = false)
- {
- if (!$append) {
- $this->_removeNodes($parent_node, $name);
- }
-
- switch ($params['type']) {
- case self::TYPE_DATE:
- $value = Horde_Kolab_Format_Date::encodeDate($value);
- break;
-
- case self::TYPE_DATETIME:
- case self::TYPE_DATE_OR_DATETIME:
- $value = Horde_Kolab_Format_Date::encodeDateTime($value);
- break;
-
- case self::TYPE_INTEGER:
- $value = (string) $value;
- break;
-
- case self::TYPE_BOOLEAN:
- if ($value) {
- $value = 'true';
- } else {
- $value = 'false';
- }
-
- break;
- }
-
- // create the node
- return $this->_createTextNode($parent_node, $name, $value);
- }
-
- /**
- * Handle loading of categories. Preserve multiple categories in a hidden
- * object field. Optionally creates categories unknown to the Horde user.
- *
- * @param array $object Array of strings, containing the 'categories' field.
- *
- * @return NULL
- */
- protected function _loadMultipleCategories(&$object)
- {
- global $prefs;
-
- if (empty($object['categories'])) {
- return;
- }
-
- // Create horde category if needed
- @include_once 'Horde/Prefs/CategoryManager.php';
- if ($this->_create_categories
- && class_exists('Prefs_CategoryManager')
- && isset($prefs) && is_a($prefs, 'Prefs')) {
- $cManager = new Prefs_CategoryManager();
- $horde_categories = $cManager->get();
- } else {
- $cManager = null;
- $horde_categories = null;
- }
-
- $kolab_categories = explode (',', $object['categories']);
-
- $primary_category = '';
- foreach ($kolab_categories as $kolab_category) {
- $kolab_category = trim($kolab_category);
-
- $valid_category = true;
- if ($cManager &&
- array_search($kolab_category, $horde_categories) === false) {
- // Unknown category -> Add
- if ($cManager->add($kolab_category) === false) {
- // categories might be locked
- $valid_category = false;
- }
- }
-
- // First valid category becomes primary category
- if ($valid_category && empty($primary_category)) {
- $primary_category = $kolab_category;
- }
- }
-
- // Backup multiple categories
- if (count($kolab_categories) > 1) {
- $object['_categories_all'] = $object['categories'];
- $object['_categories_primary'] = $primary_category;
- }
- // Make default category visible to Horde
- $object['categories'] = $primary_category;
- }
-
- /**
- * Preserve multiple categories on save if "categories" didn't change.
- * The name "categories" currently refers to one primary category.
- *
- * @param array $object Array of strings, containing the 'categories' field.
- *
- * @return NULL
- */
- protected function _saveMultipleCategories(&$object)
- {
- // Check for multiple categories.
- if (!isset($object['_categories_all'])
- || !isset($object['_categories_primary'])
- || !isset($object['categories']))
- {
- return;
- }
-
- // Preserve multiple categories if "categories" didn't change
- if ($object['_categories_primary'] == $object['categories']) {
- $object['categories'] = $object['_categories_all'];
- }
- }
-
- /**
- * Load the object creation date.
- *
- * @param Horde_DOM_Node $node The original node if set.
- * @param boolean $missing Has the node been missing?
- *
- * @return string The creation date.
- *
- * @throws Horde_Exception If converting the data from XML failed.
- */
- protected function _loadCreationDate($node, $missing)
- {
- if ($missing) {
- // Be gentle and accept a missing creation date.
- return time();
- }
- return $this->_loadDefault($node,
- array('type' => self::TYPE_DATETIME));
- }
-
- /**
- * Save the object creation date.
- *
- * @param Horde_DOM_Node $parent_node The parent node to attach the child
- * to.
- * @param string $name The name of the node.
- * @param mixed $value The value to store.
- * @param boolean $missing Has the value been missing?
- *
- * @return Horde_DOM_Node The new child node.
- */
- protected function _saveCreationDate($parent_node, $name, $value, $missing)
- {
- // Only create the creation date if it has not been set before
- if ($missing) {
- $value = time();
- }
- return $this->_saveDefault($parent_node,
- $name,
- $value,
- array('type' => self::TYPE_DATETIME));
- }
-
- /**
- * Load the object modification date.
- *
- * @param Horde_DOM_Node $node The original node if set.
- * @param boolean $missing Has the node been missing?
- *
- * @return string The last modification date.
- */
- protected function _loadModificationDate($node, $missing)
- {
- if ($missing) {
- // Be gentle and accept a missing modification date.
- return time();
- }
- return $this->_loadDefault($node,
- array('type' => self::TYPE_DATETIME));
- }
-
- /**
- * Save the object modification date.
- *
- * @param Horde_DOM_Node $parent_node The parent node to attach
- * the child to.
- * @param string $name The name of the node.
- * @param mixed $value The value to store.
- * @param boolean $missing Has the value been missing?
- *
- * @return Horde_DOM_Node The new child node.
- */
- protected function _saveModificationDate($parent_node, $name, $value, $missing)
- {
- // Always store now as modification date
- return $this->_saveDefault($parent_node,
- $name,
- time(),
- array('type' => self::TYPE_DATETIME));
- }
-
- /**
- * Load the name of the last client that modified this object
- *
- * @param Horde_DOM_Node $node The original node if set.
- * @param boolean $missing Has the node been missing?
- *
- * @return string The last modification date.
- */
- protected function _loadProductId($node, $missing)
- {
- if ($missing) {
- // Be gentle and accept a missing product id
- return '';
- }
- return $this->_getNodeContent($node);
- }
-
- /**
- * Save the name of the last client that modified this object.
- *
- * @param Horde_DOM_Node $parent_node The parent node to attach
- * the child to.
- * @param string $name The name of the node.
- * @param mixed $value The value to store.
- * @param boolean $missing Has the value been missing?
- *
- * @return Horde_DOM_Node The new child node.
- */
- protected function _saveProductId($parent_node, $name, $value, $missing)
- {
- // Always store now as modification date
- return $this->_saveDefault($parent_node,
- $name,
- self::PRODUCT_ID,
- array('type' => self::TYPE_STRING));
- }
-
- /**
- * Load recurrence information.
- *
- * @param Horde_DOM_Node $node The original node if set.
- * @param boolean $missing Has the node been missing?
- *
- * @return array The recurrence information.
- *
- * @throws Horde_Exception If converting the data from XML failed.
- */
- protected function _loadRecurrence($node, $missing)
- {
- if ($missing) {
- return null;
- }
-
- // Collect all child nodes
- $children = $node->child_nodes();
-
- $recurrence = $this->_loadArray($children, $this->_fields_recurrence);
-
- // Get the cycle type (must be present)
- $recurrence['cycle'] = $node->get_attribute('cycle');
- // Get the sub type (may be present)
- $recurrence['type'] = $node->get_attribute('type');
-
- // Exclusions.
- if (isset($recurrence['exclusion'])) {
- $exceptions = array();
- foreach($recurrence['exclusion'] as $exclusion) {
- if (!empty($exclusion)) {
- list($year, $month, $mday) = sscanf($exclusion, '%04d-%02d-%02d');
-
- $exceptions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
- }
- }
- $recurrence['exceptions'] = $exceptions;
- }
-
- // Completed dates.
- if (isset($recurrence['complete'])) {
- $completions = array();
- foreach($recurrence['complete'] as $complete) {
- if (!empty($complete)) {
- list($year, $month, $mday) = sscanf($complete, '%04d-%02d-%02d');
-
- $completions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
- }
- }
- $recurrence['completions'] = $completions;
- }
-
- // Range is special
- foreach($children as $child) {
- if ($child->tagname == 'range') {
- $recurrence['range-type'] = $child->get_attribute('type');
- }
- }
-
- if (isset($recurrence['range']) && isset($recurrence['range-type'])
- && $recurrence['range-type'] == 'date') {
- $recurrence['range'] = Horde_Kolab_Format_Date::decodeDate($recurrence['range']);
- }
-
- // Sanity check
- $valid = $this->_validateRecurrence($recurrence);
-
- return $recurrence;
- }
-
- /**
- * Validate recurrence hash information.
- *
- * @param array $recurrence Recurrence hash loaded from XML.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If the recurrence data is invalid.
- */
- protected function _validateRecurrence(&$recurrence)
- {
- if (!isset($recurrence['cycle'])) {
- throw new Horde_Exception('recurrence tag error: cycle attribute missing');
- }
-
- if (!isset($recurrence['interval'])) {
- throw new Horde_Exception('recurrence tag error: interval tag missing');
- }
- $interval = $recurrence['interval'];
- if ($interval < 0) {
- throw new Horde_Exception('recurrence tag error: interval cannot be below zero: '
- . $interval);
- }
-
- if ($recurrence['cycle'] == 'weekly') {
- // Check for
- if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
- throw new Horde_Exception('recurrence tag error: day tag missing for weekly recurrence');
- }
- }
-
- // The code below is only for monthly or yearly recurrences
- if ($recurrence['cycle'] != 'monthly'
- && $recurrence['cycle'] != 'yearly')
- return true;
-
- if (!isset($recurrence['type'])) {
- throw new Horde_Exception('recurrence tag error: type attribute missing');
- }
-
- if (!isset($recurrence['daynumber'])) {
- throw new Horde_Exception('recurrence tag error: daynumber tag missing');
- }
- $daynumber = $recurrence['daynumber'];
- if ($daynumber < 0) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be below zero: '
- . $daynumber);
- }
-
- if ($recurrence['type'] == 'daynumber') {
- if ($recurrence['cycle'] == 'yearly' && $daynumber > 366) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 366 for yearly recurrences: ' . $daynumber);
- } else if ($recurrence['cycle'] == 'monthly' && $daynumber > 31) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 31 for monthly recurrences: ' . $daynumber);
- }
- } else if ($recurrence['type'] == 'weekday') {
- // daynumber is the week of the month
- if ($daynumber > 5) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 5 for type weekday: ' . $daynumber);
- }
-
- // Check for
- if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
- throw new Horde_Exception('recurrence tag error: day tag missing for type weekday');
- }
- }
-
- if (($recurrence['type'] == 'monthday' || $recurrence['type'] == 'yearday')
- && $recurrence['cycle'] == 'monthly')
- {
- throw new Horde_Exception('recurrence tag error: type monthday/yearday is only allowed for yearly recurrences');
- }
-
- if ($recurrence['cycle'] == 'yearly') {
- if ($recurrence['type'] == 'monthday') {
- // daynumber and month
- if (!isset($recurrence['month'])) {
- throw new Horde_Exception('recurrence tag error: month tag missing for type monthday');
- }
- if ($daynumber > 31) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 31 for type monthday: ' . $daynumber);
- }
- } else if ($recurrence['type'] == 'yearday') {
- if ($daynumber > 366) {
- throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 366 for type yearday: ' . $daynumber);
- }
- }
- }
-
- return true;
- }
-
- /**
- * Save recurrence information.
- *
- * @param Horde_DOM_Node $parent_node The parent node to attach
- * the child to.
- * @param string $name The name of the node.
- * @param mixed $value The value to store.
- * @param boolean $missing Has the value been missing?
- *
- * @return Horde_DOM_Node The new child node.
- */
- protected function _saveRecurrence($parent_node, $name, $value, $missing)
- {
- $this->_removeNodes($parent_node, $name);
-
- if (empty($value)) {
- return false;
- }
-
- // Exclusions.
- if (isset($value['exceptions'])) {
- $exclusions = array();
- foreach($value['exceptions'] as $exclusion) {
- if (!empty($exclusion)) {
- list($year, $month, $mday) = sscanf($exclusion, '%04d%02d%02d');
- $exclusions[] = "$year-$month-$mday";
- }
- }
- $value['exclusion'] = $exclusions;
- }
-
- // Completed dates.
- if (isset($value['completions'])) {
- $completions = array();
- foreach($value['completions'] as $complete) {
- if (!empty($complete)) {
- list($year, $month, $mday) = sscanf($complete, '%04d%02d%02d');
- $completions[] = "$year-$month-$mday";
- }
- }
- $value['complete'] = $completions;
- }
-
- if (isset($value['range'])
- && isset($value['range-type']) && $value['range-type'] == 'date') {
- $value['range'] = Horde_Kolab_Format_Date::encodeDate($value['range']);
- }
-
- $r_node = $this->_xmldoc->createElement($name);
- $r_node = $parent_node->appendChild($r_node);
-
- // Save normal fields
- $this->_saveArray($r_node, $value, $this->_fields_recurrence);
-
- // Add attributes
- $r_node->setAttribute('cycle', $value['cycle']);
- if (isset($value['type'])) {
- $r_node->setAttribute('type', $value['type']);
- }
-
- $child = $this->_findNode($r_node->childNodes, 'range');
- if ($child) {
- $child->setAttribute('type', $value['range-type']);
- }
-
- return $r_node;
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Annotation.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Annotation.php
deleted file mode 100644
index 61a14b522..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Annotation.php
+++ /dev/null
@@ -1,106 +0,0 @@
-
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for IMAP folder annotations.
- *
- * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Annotation extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the prefs object
- *
- * @var Kolab
- */
- protected $_fields_specific;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = 'annotations';
-
- /**
- * Specific preferences fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'annotation' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with the object data
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = $this->_loadArray($children, $this->_fields_specific);
-
- $result = array();
- foreach ($object['annotation'] as $annotation) {
- list($key, $value) = split('#', $annotation, 2);
- $result[base64_decode($key)] = base64_decode($value);
- }
-
- return $result;
- }
-
- /**
- * Save the specific XML values.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- $annotations = array();
- foreach ($object as $key => $value) {
- if ($key != 'uid') {
- $annotations['annotation'][] = base64_encode($key) .
- '#' . base64_encode($value);
- }
- }
-
- return $this->_saveArray($root, $annotations, $this->_fields_specific);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Contact.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Contact.php
deleted file mode 100644
index 44f4783a7..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Contact.php
+++ /dev/null
@@ -1,525 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for contact groupware objects
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Contact extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the contact object
- *
- * @var array
- */
- protected $_fields_specific;
-
- /**
- * Structure of the name field
- *
- * @var array
- */
- protected $_fields_name = array(
- 'given-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'middle-names' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'last-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'full-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'initials' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'prefix' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'suffix' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- )
- );
-
- /**
- * Structure of an address field
- *
- * @var array
- */
- protected $_fields_address = array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 'home',
- ),
- 'street' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'locality' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'region' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'postal-code' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'country' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- )
- );
-
- /**
- * Structure of a phone field
- *
- * @var array
- */
- protected $_fields_phone = array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'number' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- );
-
- /**
- * Address types
- *
- * @var array
- */
- protected $_address_types = array(
- 'business',
- 'home',
- 'other',
- );
-
- /**
- * Phone types
- *
- * @var array
- */
- protected $_phone_types = array(
- 'business1',
- 'business2',
- 'businessfax',
- 'callback',
- 'car',
- 'company',
- 'home1',
- 'home2',
- 'homefax',
- 'isdn',
- 'mobile',
- 'pager',
- 'primary',
- 'radio',
- 'telex',
- 'ttytdd',
- 'assistant',
- 'other',
- );
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = "contact";
-
- /** Specific task fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'name' => array (
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => $this->_fields_name,
- ),
- 'free-busy-url' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'organization' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'web-page' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'im-address' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'department' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'office-location' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'profession' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'job-title' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'manager-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'assistant' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'nick-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'spouse-name' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'birthday' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'anniversary' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'picture' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'children' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'gender' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'language' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'address' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => $this->_fields_address,
- ),
- 'email' => array (
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => $this->_fields_simple_person,
- ),
- 'phone' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => $this->_fields_phone,
- ),
- 'preferred-address' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'latitude' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'longitude' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- // Horde specific fields
- 'pgp-publickey' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- // Support for broken clients
- 'website' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'im-adress' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with the object data.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = $this->_loadArray($children, $this->_fields_specific);
-
- // Handle name fields
- if (isset($object['name'])) {
- $object = array_merge($object['name'], $object);
- unset($object['name']);
- }
-
- // Handle email fields
- $emails = array();
- if (isset($object['email'])) {
- foreach ($object['email'] as $email) {
- $smtp_address = $email['smtp-address'];
- if (!empty($smtp_address)) {
- $emails[] = $smtp_address;
- }
- }
- }
- $object['emails'] = implode(', ', $emails);
-
- // Handle phone fields
- if (isset($object['phone'])) {
- foreach ($object['phone'] as $phone) {
- if (isset($phone['number']) &&
- in_array($phone['type'], $this->_phone_types)) {
- $object["phone-" . $phone['type']] = $phone['number'];
- }
- }
- }
-
- // Handle address fields
- if (isset($object['address'])) {
- foreach ($object['address'] as $address) {
- if (in_array($address['type'], $this->_address_types)) {
- foreach ($address as $name => $value) {
- $object["addr-" . $address['type'] . "-" . $name] = $value;
- }
- }
- }
- }
-
- // Handle gender field
- if (isset($object['gender'])) {
- $gender = $object['gender'];
-
- if ($gender == "female") {
- $object['gender'] = 1;
- } else if ($gender == "male") {
- $object['gender'] = 0;
- } else {
- // unspecified gender
- unset($object['gender']);
- }
- }
-
- // Compatibility with broken clients
- $broken_fields = array("website" => "web-page",
- "im-adress" => "im-address");
- foreach ($broken_fields as $broken_field => $real_field) {
- if (!empty($object[$broken_field]) && empty($object[$real_field])) {
- $object[$real_field] = $object[$broken_field];
- }
- unset($object[$broken_field]);
- }
-
- $object['__type'] = 'Object';
-
- return $object;
- }
-
- /**
- * Save the specifc XML values.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- // Handle name fields
- $name = array();
- foreach (array_keys($this->_fields_name) as $key) {
- if (isset($object[$key])) {
- $name[$key] = $object[$key];
- unset($object[$key]);
- }
- }
- $object['name'] = $name;
-
- // Handle email fields
- if (!isset($object['emails'])) {
- $emails = array();
- } else {
- $emails = explode(',', $object['emails']);
- }
-
- if (isset($object['email']) &&
- !in_array($object['email'], $emails)) {
- $emails[] = $object['email'];
- }
-
- $object['email'] = array();
-
- foreach ($emails as $email) {
- $email = trim($email);
- if (!empty($email)) {
- $new_email = array('display-name' => $object['name']['full-name'],
- 'smtp-address' => $email);
-
- $object['email'][] = $new_email;
- }
- }
-
- // Handle phone fields
- if (!isset($object['phone'])) {
- $object['phone'] = array();
- }
- foreach ($this->_phone_types as $type) {
- $key = 'phone-' . $type;
- if (array_key_exists($key, $object)) {
- $new_phone = array('type' => $type,
- 'number' => $object[$key]);
-
- // Update existing phone entry of this type
- $updated = false;
- foreach ($object['phone'] as $index => $phone) {
- if ($phone['type'] == $type) {
- $object['phone'][$index] = $new_phone;
-
- $updated = true;
- break;
- }
- }
- if (!$updated) {
- $object['phone'][] = $new_phone;
- }
- }
- }
-
- // Phone cleanup: remove empty numbers
- foreach ($object['phone'] as $index => $phone) {
- if (empty($phone['number'])) {
- unset($object['phone'][$index]);
- }
- }
-
- // Handle address fields
- if (!isset($object['address'])) {
- $object['address'] = array();
- }
-
- foreach ($this->_address_types as $type) {
- $basekey = 'addr-' . $type . '-';
- $new_address = array('type' => $type);
- foreach (array_keys($this->_fields_address['array']) as $subkey) {
- $key = $basekey . $subkey;
- if (array_key_exists($key, $object)) {
- $new_address[$subkey] = $object[$key];
- }
- }
-
- // Update existing address entry of this type
- $updated = false;
- foreach ($object['address'] as $index => $address) {
- if ($address['type'] == $type) {
- $object['address'][$index] = $new_address;
-
- $updated = true;
- }
- }
- if (!$updated) {
- $object['address'][] = $new_address;
- }
- }
-
- // Address cleanup: remove empty addresses
- foreach ($object['address'] as $index => $address) {
- $all_empty = true;
- foreach ($address as $name => $value) {
- if (!empty($value) && $name != "type") {
- $all_empty = false;
- break;
- }
- }
-
- if ($all_empty) {
- unset($object['address'][$index]);
- }
- }
-
- // Handle gender field
- if (isset($object['gender'])) {
- $gender = $object['gender'];
-
- if ($gender == "0") {
- $object['gender'] = "male";
- } else if ($gender == "1") {
- $object['gender'] = "female";
- } else {
- // unspecified gender
- unset($object['gender']);
- }
- }
-
- // Do the actual saving
- return $this->_saveArray($root, $object, $this->_fields_specific);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Distributionlist.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Distributionlist.php
deleted file mode 100644
index 0e784687e..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Distributionlist.php
+++ /dev/null
@@ -1,113 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for distributionlist groupware objects
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Distributionlist extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the contact object
- *
- * @var array
- */
- protected $_fields_specific;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = "distribution-list";
-
- /** Specific task fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'display-name' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_NOT_EMPTY
- ),
- 'member' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => $this->_fields_simple_person,
- )
- );
-
- parent::__construct();
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with data.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = $this->_loadArray($children, $this->_fields_specific);
-
- // Map the display-name of a kolab dist list to horde's lastname attribute
- if (isset($object['display-name'])) {
- $object['last-name'] = $object['display-name'];
- unset($object['display-name']);
- }
-
- /**
- * The mapping from $object['member'] as stored in XML back to
- * Turba_Objects (contacts) must be performed in the
- * Kolab_IMAP storage driver as we need access to the search
- * facilities of the kolab storage driver.
- */
- $object['__type'] = 'Group';
- return $object;
- }
-
- /**
- * Save the specifc XML values.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- // Map the display-name of a kolab dist list to horde's lastname attribute
- if (isset($object['last-name'])) {
- $object['display-name'] = $object['last-name'];
- unset($object['last-name']);
- }
-
- return $this->_saveArray($root, $object, $this->_fields_specific);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Event.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Event.php
deleted file mode 100644
index 63b5df70c..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Event.php
+++ /dev/null
@@ -1,139 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for event groupware objects.
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Event extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the contact object
- *
- * @var array
- */
- protected $_fields_specific;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = 'event';
-
- /** Specific event fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'summary' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'location' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'organizer' => $this->_fields_simple_person,
- 'start-date' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_NOT_EMPTY,
- ),
- 'alarm' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'recurrence' => array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_CALCULATED,
- 'load' => 'Recurrence',
- 'save' => 'Recurrence',
- ),
- 'attendee' => $this->_fields_attendee,
- 'show-time-as' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'color-label' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'end-date' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_NOT_EMPTY,
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load event XML values and translate start/end date.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with the object data.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = parent::_load($children);
-
- // Translate start/end date including full day events
- if (strlen($object['start-date']) == 10) {
- $object['start-date'] = Horde_Kolab_Format_Date::decodeDate($object['start-date']);
- $object['end-date'] = Horde_Kolab_Format_Date::decodeDate($object['end-date']) + 24*60*60;
- } else {
- $object['start-date'] = Horde_Kolab_Format_Date::decodeDateTime($object['start-date']);
- $object['end-date'] = Horde_Kolab_Format_Date::decodeDateTime($object['end-date']);
- }
-
- return $object;
- }
-
- /**
- * Save event XML values and translate start/end date.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- // Translate start/end date including full day events
- if (!empty($object['_is_all_day'])) {
- $object['start-date'] = Horde_Kolab_Format_Date::encodeDate($object['start-date']);
- $object['end-date'] = Horde_Kolab_Format_Date::encodeDate($object['end-date'] - 24*60*60);
- } else {
- $object['start-date'] = Horde_Kolab_Format_Date::encodeDateTime($object['start-date']);
- $object['end-date'] = Horde_Kolab_Format_Date::encodeDateTime($object['end-date']);
- }
-
- return parent::_save($root, $object);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Hprefs.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Hprefs.php
deleted file mode 100644
index 8f63c715f..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Hprefs.php
+++ /dev/null
@@ -1,119 +0,0 @@
-
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for client preferences.
- *
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Hprefs extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the prefs object
- *
- * @var Kolab
- */
- protected $_fields_specific;
-
- /**
- * Automatically create categories if they are missing?
- *
- * @var boolean
- */
- protected $_create_categories = false;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = 'h-prefs';
-
- /** Specific preferences fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'application' => array (
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'pref' => array(
- 'type' => self::TYPE_MULTIPLE,
- 'value' => self::VALUE_MAYBE_MISSING,
- 'array' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load an object based on the given XML string.
- *
- * @param string &$xmltext The XML of the message as string.
- *
- * @return array The data array representing the object.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- public function load(&$xmltext)
- {
- $object = parent::load($xmltext);
-
- if (empty($object['application'])) {
- if (!empty($object['categories'])) {
- $object['application'] = $object['categories'];
- unset($object['categories']);
- } else {
- throw new Horde_Exception('Preferences XML object is missing an application setting.');
- }
- }
-
- return $object;
- }
-
- /**
- * Convert the data to a XML string.
- *
- * @param array $object The data array representing the note.
- *
- * @return string The data as XML string.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- public function save($object)
- {
- if (empty($object['application'])) {
- if (!empty($object['categories'])) {
- $object['application'] = $object['categories'];
- unset($object['categories']);
- } else {
- throw new Horde_Exception('Preferences XML object is missing an application setting.');
- }
- }
-
- return parent::save($object);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Note.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Note.php
deleted file mode 100644
index c15bb6420..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Note.php
+++ /dev/null
@@ -1,106 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for note groupware objects.
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Note extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the note object
- *
- * @var Kolab
- */
- protected $_fields_specific;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = 'note';
-
- /** Specific note fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'summary' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'background-color' => array(
- 'type' => self::TYPE_COLOR,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '#000000',
- ),
- 'foreground-color' => array(
- 'type' => self::TYPE_COLOR,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '#ffff00',
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with the object data
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = $this->_loadArray($children, $this->_fields_specific);
-
- $object['desc'] = $object['summary'];
- unset($object['summary']);
-
- return $object;
- }
-
- /**
- * Save the specific XML values.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- $object['summary'] = $object['desc'];
- unset($object['desc']);
-
- return $this->_saveArray($root, $object, $this->_fields_specific);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Task.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Task.php
deleted file mode 100644
index 48bb5bf95..000000000
--- a/framework/Kolab_Format/lib/Horde/Kolab/Format/XML/Task.php
+++ /dev/null
@@ -1,199 +0,0 @@
-
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- */
-
-/**
- * Kolab XML handler for task groupware objects.
- *
- * Copyright 2007-2009 Klarälvdalens Datakonsult AB
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- *
- * @category Kolab
- * @package Kolab_Format
- * @author Thomas Jarosch
- * @author Gunnar Wrobel
- * @license http://www.fsf.org/copyleft/lgpl.html LGPL
- * @link http://pear.horde.org/index.php?package=Kolab_Server
- * @since Horde 3.2
- */
-class Horde_Kolab_Format_XML_Task extends Horde_Kolab_Format_XML
-{
- /**
- * Specific data fields for the note object
- *
- * @var array
- */
- protected $_fields_specific;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->_root_name = 'task';
-
- /** Specific task fields, in kolab format specification order
- */
- $this->_fields_specific = array(
- 'summary' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'location' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => '',
- ),
- 'creator' => $this->_fields_simple_person,
- 'organizer' => $this->_fields_simple_person,
- 'start-date' => array(
- 'type' => self::TYPE_DATE_OR_DATETIME,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'alarm' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'recurrence' => array(
- 'type' => self::TYPE_COMPOSITE,
- 'value' => self::VALUE_CALCULATED,
- 'load' => 'Recurrence',
- 'save' => 'Recurrence',
- ),
- 'attendee' => $this->_fields_attendee,
- 'priority' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 3,
- ),
- 'completed' => array(
- 'type' => self::TYPE_INTEGER,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 0,
- ),
- 'status' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_DEFAULT,
- 'default' => 'not-started',
- ),
- 'due-date' => array(
- 'type' => self::TYPE_DATE_OR_DATETIME,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'parent' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- // These are not part of the Kolab specification but it is
- // ok if the client supports additional entries
- 'estimate' => array(
- 'type' => self::TYPE_STRING,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- 'completed_date' => array(
- 'type' => self::TYPE_DATE_OR_DATETIME,
- 'value' => self::VALUE_MAYBE_MISSING,
- ),
- );
-
- parent::__construct();
- }
-
- /**
- * Load the groupware object based on the specifc XML values.
- *
- * @param array &$children An array of XML nodes.
- *
- * @return array Array with data.
- *
- * @throws Horde_Exception If parsing the XML data failed.
- */
- protected function _load(&$children)
- {
- $object = $this->_loadArray($children, $this->_fields_specific);
-
- $object['name'] = $object['summary'];
- unset($object['summary']);
-
- if (empty($object['completed-date'])) {
- $object['completed-date'] = null;
- }
-
- if (empty($object['alarm'])) {
- $object['alarm'] = null;
- }
-
- if (isset($object['due-date'])) {
- $object['due'] = $object['due-date'];
- unset($object['due-date']);
- } else {
- $object['due'] = null;
- }
-
- if (isset($object['start-date'])) {
- $object['start'] = $object['start-date'];
- unset($object['start-date']);
- } else {
- $object['start'] = null;
- }
-
- if (!isset($object['estimate'])) {
- $object['estimate'] = null;
- } else {
- $object['estimate'] = (float) $object['estimate'];
- }
-
- if (!isset($object['parent'])) {
- $object['parent'] = null;
- }
-
- $object['completed'] = (bool) Kolab::percentageToBoolean($object['completed']);
-
- if (isset($object['organizer']) && isset($object['organizer']['smtp-address'])) {
- $object['assignee'] = $object['organizer']['smtp-address'];
- }
-
- return $object;
- }
-
- /**
- * Save the specific XML values.
- *
- * @param array $root The XML document root.
- * @param array $object The resulting data array.
- *
- * @return boolean True on success.
- *
- * @throws Horde_Exception If converting the data to XML failed.
- */
- protected function _save($root, $object)
- {
- $object['summary'] = $object['name'];
- unset($object['name']);
-
- $object['due-date'] = $object['due'];
- unset($object['due']);
-
- $object['start-date'] = $object['start'];
- unset($object['start']);
-
- $object['estimate'] = number_format($object['estimate'], 2);
-
- $object['completed'] = Kolab::BooleanToPercentage($object['completed']);
-
- return $this->_saveArray($root, $object, $this->_fields_specific);
- }
-}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml.php
new file mode 100644
index 000000000..9650af82e
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml.php
@@ -0,0 +1,1421 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML to array hash converter.
+ *
+ * For implementing a new format type you will have to inherit this
+ * class and provide a _load/_save function.
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml
+{
+
+ /**
+ * Defines a XML value that should get a default value if missing
+ */
+ const PRODUCT_ID = 'Horde::Kolab';
+
+ /**
+ * Defines a XML value that should get a default value if missing
+ */
+ const VALUE_DEFAULT = 0;
+
+ /**
+ * Defines a XML value that may be missing
+ */
+ const VALUE_MAYBE_MISSING = 1;
+
+ /**
+ * Defines a XML value that may not be missing
+ */
+ const VALUE_NOT_EMPTY = 2;
+
+ /**
+ * Defines a XML value that will be calculated by its own function
+ */
+ const VALUE_CALCULATED = 3;
+
+ /**
+ * Defines a XML value as string type
+ */
+ const TYPE_STRING = 0;
+
+ /**
+ * Defines a XML value as integer type
+ */
+ const TYPE_INTEGER = 1;
+
+ /**
+ * Defines a XML value as boolean type
+ */
+ const TYPE_BOOLEAN = 2;
+
+ /**
+ * Defines a XML value as date type
+ */
+ const TYPE_DATE = 3;
+
+ /**
+ * Defines a XML value as datetime type
+ */
+ const TYPE_DATETIME = 4;
+
+ /**
+ * Defines a XML value as date or datetime type
+ */
+ const TYPE_DATE_OR_DATETIME = 5;
+
+ /**
+ * Defines a XML value as color type
+ */
+ const TYPE_COLOR = 6;
+
+ /**
+ * Defines a XML value as composite value type
+ */
+ const TYPE_COMPOSITE = 7;
+
+ /**
+ * Defines a XML value as array type
+ */
+ const TYPE_MULTIPLE = 8;
+
+ /**
+ * Requested version of the data array to return
+ *
+ * @var int
+ */
+ protected $_version = 1;
+
+ /**
+ * The name of the resulting document.
+ *
+ * @var string
+ */
+ protected $_name = 'kolab.xml';
+
+ /**
+ * The XML document this driver works with.
+ *
+ * @var Horde_DOM_Document
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public $_xmldoc = null;
+
+ /**
+ * The name of the root element.
+ *
+ * @var string
+ */
+ protected $_root_name = 'kolab';
+
+ /**
+ * Kolab format version of the root element.
+ *
+ * @var string
+ */
+ protected $_root_version = '1.0';
+
+ /**
+ * Basic fields in any Kolab object
+ *
+ * @var array
+ */
+ protected $_fields_basic;
+
+ /**
+ * Automatically create categories if they are missing?
+ *
+ * @var boolean
+ */
+ protected $_create_categories = true;
+
+ /**
+ * Fields for a simple person
+ *
+ * @var array
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public $_fields_simple_person = array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'display-name' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'smtp-address' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'uid' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ ),
+ );
+
+ /**
+ * Fields for an attendee
+ *
+ * @var array
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public $_fields_attendee = array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => array(),
+ 'array' => array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'display-name' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'smtp-address' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'status' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 'none',
+ ),
+ 'request-response' => array(
+ 'type' => self::TYPE_BOOLEAN,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => true,
+ ),
+ 'role' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 'required',
+ ),
+ ),
+ ),
+ );
+
+ /**
+ * Fields for a recurrence
+ *
+ * @var array
+ */
+ protected $_fields_recurrence = array(
+ // Attribute on root node: cycle
+ // Attribute on root node: type
+ 'interval' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'day' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ 'daynumber' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'month' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ // Attribute on range: type
+ 'range' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'exclusion' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ 'complete' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ );
+
+ /**
+ * Constructor
+ *
+ * @param array $params Any additional options
+ */
+ public function __construct($params = null)
+ {
+ if (is_array($params) && isset($params['version'])) {
+ $this->_version = $params['version'];
+ } else {
+ $this->_version = 1;
+ }
+
+ /* Generic fields, in kolab format specification order */
+ $this->_fields_basic = array(
+ 'uid' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_NOT_EMPTY,
+ ),
+ 'body' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'categories' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'creation-date' => array(
+ 'type' => self::TYPE_DATETIME,
+ 'value' => self::VALUE_CALCULATED,
+ 'load' => 'CreationDate',
+ 'save' => 'CreationDate',
+ ),
+ 'last-modification-date' => array(
+ 'type' => self::TYPE_DATETIME,
+ 'value' => self::VALUE_CALCULATED,
+ 'load' => 'ModificationDate',
+ 'save' => 'ModificationDate',
+ ),
+ 'sensitivity' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 'public',
+ ),
+ 'inline-attachment' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ 'link-attachment' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ 'product-id' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_CALCULATED,
+ 'load' => 'ProductId',
+ 'save' => 'ProductId',
+ ),
+ );
+ }
+
+ /**
+ * Attempts to return a concrete Horde_Kolab_Format_Xml instance.
+ * based on $object_type.
+ *
+ * @param string $object_type The object type that should be handled.
+ * @param array $params Any additional parameters.
+ *
+ * @return Horde_Kolab_Format_Xml The newly created concrete
+ * Horde_Kolab_Format_Xml instance.
+ *
+ * @throws Horde_Exception If the class for the object type could
+ * not be loaded.
+ */
+ public function &factory($object_type = '', $params = null)
+ {
+ $object_type = ucfirst(str_replace('-', '', $object_type));
+ $class = 'Horde_Kolab_Format_Xml_' . $object_type;
+
+ if (class_exists($class)) {
+ $driver = &new $class($params);
+ } else {
+ throw new Horde_Exception(sprintf(_("Failed to load Kolab XML driver %s"),
+ $object_type));
+ }
+
+ return $driver;
+ }
+
+ /**
+ * Return the name of the resulting document.
+ *
+ * @return string The name that may be used as filename.
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Return the mime type of the resulting document.
+ *
+ * @return string The mime type of the result.
+ */
+ public function getMimeType()
+ {
+ return 'application/x-vnd.kolab.' . $this->_root_name;
+ }
+
+ /**
+ * Return the disposition of the resulting document.
+ *
+ * @return string The disportion of this document.
+ */
+ public function getDisposition()
+ {
+ return 'attachment';
+ }
+
+ /**
+ * Load an object based on the given XML string.
+ *
+ * @todo Check encoding of the returned array. It seems to be ISO-8859-1 at
+ * the moment and UTF-8 would seem more appropriate.
+ *
+ * @param string $xmltext The XML of the message as string.
+ *
+ * @return array The data array representing the object.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ public function load(&$xmltext)
+ {
+ try {
+ $this->_parseXml($xmltext);
+ } catch (DOMException $e) {
+ /**
+ * If the first call does not return successfully this might mean we
+ * got an attachment with broken encoding. There are some Kolab
+ * client versions in the wild that might have done that. So the
+ * next section starts a second attempt by guessing the encoding and
+ * trying again.
+ */
+ if (strcasecmp(mb_detect_encoding($xmltext,
+ 'UTF-8, ISO-8859-1'), 'UTF-8') !== 0) {
+ $xmltext = mb_convert_encoding($xmltext, 'UTF-8', 'ISO-8859-1');
+ }
+ $this->_parseXml($xmltext);
+ }
+ if (empty($this->_xmldoc)) {
+ return false;
+ }
+
+ if (!$this->_xmldoc->documentElement->hasChildNodes()) {
+ throw new Horde_Exception(_("No or unreadable content in Kolab XML object"));
+ }
+
+ // fresh object data
+ $object = array();
+
+ $result = $this->_loadArray($this->_xmldoc->documentElement->childNodes, $this->_fields_basic);
+ $object = array_merge($object, $result);
+ $this->_loadMultipleCategories($object);
+
+ $result = $this->_load($this->_xmldoc->documentElement->childNodes);
+ $object = array_merge($object, $result);
+
+ // uid is vital
+ if (!isset($object['uid'])) {
+ throw new Horde_Exception(_("UID not found in Kolab XML object"));
+ }
+
+ return $object;
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array $children An array of XML nodes.
+ *
+ * @return array The data array representing the object.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ if (!empty($this->_fields_specific)) {
+ return $this->_loadArray($children, $this->_fields_specific);
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Load an array with data from the XML nodes.
+ *
+ * @param array $object The resulting data array.
+ * @param array $children An array of XML nodes.
+ * @param array $fields The fields to populate in the object array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _loadArray(&$children, $fields)
+ {
+ $object = array();
+
+ // basic fields below the root node
+ foreach($fields as $field => $params) {
+ $result = $this->_getXmlData($children, $field, $params);
+ if (isset($result)) {
+ $object[$field] = $result;
+ }
+ }
+ return $object;
+ }
+
+ /**
+ * Get the text content of the named data node among the specified
+ * children.
+ *
+ * @param array &$children The children to search.
+ * @param string $name The name of the node to return.
+ * @param array $params Parameters for the data conversion.
+ *
+ * @return string The content of the specified node or an empty
+ * string.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public function _getXmlData(&$children, $name, $params)
+ {
+ if ($params['type'] == self::TYPE_MULTIPLE) {
+ $result = array();
+ foreach($children as $child) {
+ if ($child->nodeType == XML_ELEMENT_NODE && $child->tagName == $name) {
+ $child_a = array($child);
+ $value = $this->_getXmlData($child_a, $name,
+ $params['array']);
+ $result[] = $value;
+ }
+ }
+ return $result;
+ }
+
+ $value = null;
+ $missing = false;
+
+ // identify the child node
+ $child = $this->_findNode($children, $name);
+
+ // Handle empty values
+ if (!$child) {
+ if ($params['value'] == self::VALUE_MAYBE_MISSING) {
+ // 'MAYBE_MISSING' means we should return null
+ return null;
+ } elseif ($params['value'] == self::VALUE_NOT_EMPTY) {
+ // May not be empty. Return an error
+ throw new Horde_Exception(sprintf(_("Data value for %s is empty in Kolab XML object!"),
+ $name));
+ } elseif ($params['value'] == self::VALUE_DEFAULT) {
+ // Return the default
+ return $params['default'];
+ } elseif ($params['value'] == self::VALUE_CALCULATED) {
+ $missing = true;
+ }
+ }
+
+ // Do we need to calculate the value?
+ if ($params['value'] == self::VALUE_CALCULATED && isset($params['load'])) {
+ if (method_exists($this, '_load' . $params['load'])) {
+ $value = call_user_func(array($this, '_load' . $params['load']),
+ $child, $missing);
+ } else {
+ throw new Horde_Exception(sprintf("Kolab XML: Missing function %s!",
+ $params['load']));
+ }
+ } elseif ($params['type'] == self::TYPE_COMPOSITE) {
+ return $this->_loadArray($child->childNodes, $params['array']);
+ } else {
+ return $this->_loadDefault($child, $params);
+ }
+
+ // Nothing specified. Return the value as it is.
+ return $value;
+ }
+
+ /**
+ * Parse the XML string. The root node is returned on success.
+ *
+ * @param string $xmltext The XML of the message as string.
+ *
+ * @return NULL
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public function _parseXml(&$xmltext)
+ {
+ $this->_xmldoc = new DOMDocument();
+ $this->_xmldoc->preserveWhiteSpace = false;
+ $this->_xmldoc->formatOutput = true;
+ $this->_xmldoc->loadXML($xmltext);
+ }
+
+ /**
+ * Convert the data to a XML string.
+ *
+ * @param array $attributes The data array representing the note.
+ *
+ * @return string The data as XML string.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ public function save($object)
+ {
+ $root = $this->_prepareSave();
+
+ $this->_saveMultipleCategories($object);
+ $this->_saveArray($root, $object, $this->_fields_basic);
+ $this->_save($root, $object);
+
+ return $this->_xmldoc->saveXML();
+ }
+
+ /**
+ * Save the specific XML values.
+ *
+ * @param array &$root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save(&$root, $object)
+ {
+ if (!empty($this->_fields_specific)) {
+ $this->_saveArray($root, $object, $this->_fields_specific);
+ }
+ return true;
+ }
+
+ /**
+ * Creates a new XML document if necessary.
+ *
+ * @param string $xmltext The XML of the message as string.
+ *
+ * @return Horde_DOM_Node The root node of the document.
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public function &_prepareSave()
+ {
+ if (empty($this->_xmldoc)) {
+ // create new XML
+ $this->_xmldoc = new DOMDocument();
+ $this->_xmldoc->preserveWhiteSpace = false;
+ $this->_xmldoc->formatOutput = true;
+ $root = $this->_xmldoc->createElement($this->_root_name);
+ $this->_xmldoc->appendChild($root);
+ $root->setAttribute('version', $this->_root_version);
+ }
+ return $root;
+ }
+
+ /**
+ * Save a data array to XML nodes.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The data array.
+ * @param array $fields The fields to write into the XML object.
+ * @param boolean $append Should the nodes be appended?
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _saveArray($root, $object, $fields, $append = false)
+ {
+ // basic fields below the root node
+ foreach($fields as $field => $params) {
+ $this->_updateNode($root, $object, $field, $params, $append);
+ }
+ return true;
+ }
+
+ /**
+ * Update the specified node.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node of the node that
+ * should be updated.
+ * @param array $attributes The data array that holds all
+ * attribute values.
+ * @param string $name The name of the the attribute
+ * to be updated.
+ * @param array $params Parameters for saving the node
+ * @param boolean $append Should the node be appended?
+ *
+ * @return Horde_DOM_Node The new/updated child node.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ *
+ * @todo Make protected (fix the XmlTest for that)
+ */
+ public function _updateNode($parent_node, $attributes, $name, $params,
+ $append = false)
+ {
+ $value = null;
+ $missing = false;
+
+ // Handle empty values
+ if (!isset($attributes[$name])) {
+ // Do we have information if this may be empty?
+ if ($params['value'] == self::VALUE_DEFAULT) {
+ // Use the default
+ $value = $params['default'];
+ } elseif ($params['value'] == self::VALUE_NOT_EMPTY) {
+ // May not be empty. Return an error
+ throw new Horde_Exception(sprintf(_("Data value for %s is empty in Kolab XML object!"),
+ $name));
+ } elseif ($params['value'] == self::VALUE_MAYBE_MISSING) {
+ /**
+ * 'MAYBE_MISSING' means we should not create an XML
+ * node here
+ */
+ $this->_removeNodes($parent_node, $name);
+ return false;
+ } elseif ($params['value'] == self::VALUE_CALCULATED) {
+ $missing = true;
+ }
+ } else {
+ $value = $attributes[$name];
+ }
+
+ if ($params['value'] == self::VALUE_CALCULATED) {
+ // Calculate the value
+ if (method_exists($this, '_save' . $params['save'])) {
+ return call_user_func(array($this, '_save' . $params['save']),
+ $parent_node, $name, $value, $missing);
+ } else {
+ throw new Horde_Exception(sprintf("Kolab XML: Missing function %s!",
+ $params['save']));
+ }
+ } elseif ($params['type'] == self::TYPE_COMPOSITE) {
+ // Possibly remove the old node first
+ if (!$append) {
+ $this->_removeNodes($parent_node, $name);
+ }
+
+ // Create a new complex node
+ $composite_node = $this->_xmldoc->createElement($name);
+ $composite_node = $parent_node->appendChild($composite_node);
+ return $this->_saveArray($composite_node, $value, $params['array']);
+ } elseif ($params['type'] == self::TYPE_MULTIPLE) {
+ // Remove the old nodes first
+ $this->_removeNodes($parent_node, $name);
+
+ // Add the new nodes
+ foreach($value as $add_node) {
+ $this->_saveArray($parent_node,
+ array($name => $add_node),
+ array($name => $params['array']),
+ true);
+ }
+ return true;
+ } else {
+ return $this->_saveDefault($parent_node, $name, $value, $params,
+ $append);
+ }
+ }
+
+ /**
+ * Create a text node.
+ *
+ * @param Horde_DOM_Node $parent The parent of the new node.
+ * @param string $name The name of the child node to create.
+ * @param string $value The value of the child node to create.
+ *
+ * @return Horde_DOM_Node The new node.
+ */
+ protected function _createTextNode($parent, $name, $value)
+ {
+ $value = Horde_String::convertCharset($value, Horde_Nls::getCharset(), 'utf-8');
+
+ $node = $this->_xmldoc->createElement($name);
+
+ $node = $parent->appendChild($node);
+
+ // content
+ $text = $this->_xmldoc->createTextNode($value);
+ $text = $node->appendChild($text);
+
+ return $node;
+ }
+
+ /**
+ * Return the named node among a list of nodes.
+ *
+ * @param array %$nodes The list of nodes.
+ * @param string $name The name of the node to return.
+ *
+ * @return mixed The named Horde_DOM_Node or false if no node was found.
+ */
+ protected function _findNode(&$nodes, $name)
+ {
+ foreach($nodes as $node) {
+ if ($node->nodeType == XML_ELEMENT_NODE && $node->tagName == $name) {
+ return $node;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve a named child from a named parent if it has the given
+ * value.
+ *
+ * @param array $nodes The list of nodes.
+ * @param string $parent_name The name of the parent node.
+ * @param string $child_name The name of the child node.
+ * @param string $value The value of the child node
+ *
+ * @return mixed The specified Horde_DOM_Node or false if no node was found.
+ */
+ protected function _findNodeByChildData($nodes, $parent_name, $child_name,
+ $value)
+ {
+ foreach($nodes as $node)
+ {
+ if ($node->nodeType == XML_ELEMENT_NODE && $node->tagName == $parent_name) {
+ $children = $node->childNodes;
+ foreach ($children as $child)
+ if ($child->nodeType == XML_ELEMENT_NODE
+ && $child->tagName == $child_name
+ && $child->textContent == $value) {
+ return $node;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieve the content of a Horde_DOM_Node.
+ *
+ * @param Horde_DOM_Node $nodes The node that should be read.
+ *
+ * @return string The content of the node.
+ */
+ protected function _getNodeContent($node)
+ {
+ return Horde_String::convertCharset($node->textContent, 'utf-8');
+ }
+
+
+ /**
+ * Create a new named node on a parent node.
+ *
+ * @param Horde_DOM_Node $parent The parent node.
+ * @param string $name The name of the new child node.
+ *
+ * @return Horde_DOM_Node The new child node.
+ */
+ protected function _createChildNode($parent, $name)
+ {
+ $node = $this->_xmldoc->createElement($name);
+ $node = $parent->appendChild($node);
+
+ return $node;
+ }
+
+ /**
+ * Remove named nodes from a parent node.
+ *
+ * @param Horde_DOM_Node $parent The parent node.
+ * @param string $name The name of the children to be removed.
+ */
+ protected function _removeNodes($parent_node, $name)
+ {
+ while ($old_node = $this->_findNode($parent_node->childNodes, $name)) {
+ $parent_node->removeChild($old_node);
+ }
+ }
+
+ /**
+ * Create a new named node on a parent node if it is not already
+ * present in the given children.
+ *
+ * @param Horde_DOM_Node $parent The parent node.
+ * @param array $children The children that might already
+ * contain the node.
+ * @param string $name The name of the new child node.
+ *
+ * @return Horde_DOM_Node The new or already existing child node.
+ */
+ protected function _createOrFindChildNode($parent, $children, $name)
+ {
+ // look for existing node
+ $old_node = $this->_findNode($children, $name);
+ if ($old_node !== false) {
+ return $old_node;
+ }
+
+ // create new parent node
+ return $this->_createChildNode($parent, $name);
+ }
+
+ /**
+ * Load the different XML types.
+ *
+ * @param string $node The node to load the data from
+ * @param array $params Parameters for loading the value
+ *
+ * @return string The loaded value.
+ *
+ * @throws Horde_Exception If converting the data from XML failed.
+ */
+ protected function _loadDefault($node, $params)
+ {
+ $content = $this->_getNodeContent($node);
+
+ switch($params['type']) {
+ case self::TYPE_DATE:
+ return Horde_Kolab_Format_Date::decodeDate($content);
+
+ case self::TYPE_DATETIME:
+ return Horde_Kolab_Format_Date::decodeDateTime($content);
+
+ case self::TYPE_DATE_OR_DATETIME:
+ return Horde_Kolab_Format_Date::decodeDateOrDateTime($content);
+
+ case self::TYPE_INTEGER:
+ return (int) $content;
+
+ case self::TYPE_BOOLEAN:
+ return (bool) $content;
+
+ default:
+ // Strings and colors are returned as they are
+ return $content;
+ }
+ }
+
+ /**
+ * Save a data array as a XML node attached to the given parent node.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node to attach
+ * the child to
+ * @param string $name The name of the node
+ * @param mixed $value The value to store
+ * @param boolean $missing Has the value been missing?
+ * @param boolean $append Should the node be appended?
+ *
+ * @return Horde_DOM_Node The new child node.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _saveDefault($parent_node, $name, $value, $params,
+ $append = false)
+ {
+ if (!$append) {
+ $this->_removeNodes($parent_node, $name);
+ }
+
+ switch ($params['type']) {
+ case self::TYPE_DATE:
+ $value = Horde_Kolab_Format_Date::encodeDate($value);
+ break;
+
+ case self::TYPE_DATETIME:
+ case self::TYPE_DATE_OR_DATETIME:
+ $value = Horde_Kolab_Format_Date::encodeDateTime($value);
+ break;
+
+ case self::TYPE_INTEGER:
+ $value = (string) $value;
+ break;
+
+ case self::TYPE_BOOLEAN:
+ if ($value) {
+ $value = 'true';
+ } else {
+ $value = 'false';
+ }
+
+ break;
+ }
+
+ // create the node
+ return $this->_createTextNode($parent_node, $name, $value);
+ }
+
+ /**
+ * Handle loading of categories. Preserve multiple categories in a hidden
+ * object field. Optionally creates categories unknown to the Horde user.
+ *
+ * @param array $object Array of strings, containing the 'categories' field.
+ *
+ * @return NULL
+ */
+ protected function _loadMultipleCategories(&$object)
+ {
+ global $prefs;
+
+ if (empty($object['categories'])) {
+ return;
+ }
+
+ // Create horde category if needed
+ @include_once 'Horde/Prefs/CategoryManager.php';
+ if ($this->_create_categories
+ && class_exists('Prefs_CategoryManager')
+ && isset($prefs) && is_a($prefs, 'Prefs')) {
+ $cManager = new Prefs_CategoryManager();
+ $horde_categories = $cManager->get();
+ } else {
+ $cManager = null;
+ $horde_categories = null;
+ }
+
+ $kolab_categories = explode (',', $object['categories']);
+
+ $primary_category = '';
+ foreach ($kolab_categories as $kolab_category) {
+ $kolab_category = trim($kolab_category);
+
+ $valid_category = true;
+ if ($cManager &&
+ array_search($kolab_category, $horde_categories) === false) {
+ // Unknown category -> Add
+ if ($cManager->add($kolab_category) === false) {
+ // categories might be locked
+ $valid_category = false;
+ }
+ }
+
+ // First valid category becomes primary category
+ if ($valid_category && empty($primary_category)) {
+ $primary_category = $kolab_category;
+ }
+ }
+
+ // Backup multiple categories
+ if (count($kolab_categories) > 1) {
+ $object['_categories_all'] = $object['categories'];
+ $object['_categories_primary'] = $primary_category;
+ }
+ // Make default category visible to Horde
+ $object['categories'] = $primary_category;
+ }
+
+ /**
+ * Preserve multiple categories on save if "categories" didn't change.
+ * The name "categories" currently refers to one primary category.
+ *
+ * @param array $object Array of strings, containing the 'categories' field.
+ *
+ * @return NULL
+ */
+ protected function _saveMultipleCategories(&$object)
+ {
+ // Check for multiple categories.
+ if (!isset($object['_categories_all'])
+ || !isset($object['_categories_primary'])
+ || !isset($object['categories']))
+ {
+ return;
+ }
+
+ // Preserve multiple categories if "categories" didn't change
+ if ($object['_categories_primary'] == $object['categories']) {
+ $object['categories'] = $object['_categories_all'];
+ }
+ }
+
+ /**
+ * Load the object creation date.
+ *
+ * @param Horde_DOM_Node $node The original node if set.
+ * @param boolean $missing Has the node been missing?
+ *
+ * @return string The creation date.
+ *
+ * @throws Horde_Exception If converting the data from XML failed.
+ */
+ protected function _loadCreationDate($node, $missing)
+ {
+ if ($missing) {
+ // Be gentle and accept a missing creation date.
+ return time();
+ }
+ return $this->_loadDefault($node,
+ array('type' => self::TYPE_DATETIME));
+ }
+
+ /**
+ * Save the object creation date.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node to attach the child
+ * to.
+ * @param string $name The name of the node.
+ * @param mixed $value The value to store.
+ * @param boolean $missing Has the value been missing?
+ *
+ * @return Horde_DOM_Node The new child node.
+ */
+ protected function _saveCreationDate($parent_node, $name, $value, $missing)
+ {
+ // Only create the creation date if it has not been set before
+ if ($missing) {
+ $value = time();
+ }
+ return $this->_saveDefault($parent_node,
+ $name,
+ $value,
+ array('type' => self::TYPE_DATETIME));
+ }
+
+ /**
+ * Load the object modification date.
+ *
+ * @param Horde_DOM_Node $node The original node if set.
+ * @param boolean $missing Has the node been missing?
+ *
+ * @return string The last modification date.
+ */
+ protected function _loadModificationDate($node, $missing)
+ {
+ if ($missing) {
+ // Be gentle and accept a missing modification date.
+ return time();
+ }
+ return $this->_loadDefault($node,
+ array('type' => self::TYPE_DATETIME));
+ }
+
+ /**
+ * Save the object modification date.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node to attach
+ * the child to.
+ * @param string $name The name of the node.
+ * @param mixed $value The value to store.
+ * @param boolean $missing Has the value been missing?
+ *
+ * @return Horde_DOM_Node The new child node.
+ */
+ protected function _saveModificationDate($parent_node, $name, $value, $missing)
+ {
+ // Always store now as modification date
+ return $this->_saveDefault($parent_node,
+ $name,
+ time(),
+ array('type' => self::TYPE_DATETIME));
+ }
+
+ /**
+ * Load the name of the last client that modified this object
+ *
+ * @param Horde_DOM_Node $node The original node if set.
+ * @param boolean $missing Has the node been missing?
+ *
+ * @return string The last modification date.
+ */
+ protected function _loadProductId($node, $missing)
+ {
+ if ($missing) {
+ // Be gentle and accept a missing product id
+ return '';
+ }
+ return $this->_getNodeContent($node);
+ }
+
+ /**
+ * Save the name of the last client that modified this object.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node to attach
+ * the child to.
+ * @param string $name The name of the node.
+ * @param mixed $value The value to store.
+ * @param boolean $missing Has the value been missing?
+ *
+ * @return Horde_DOM_Node The new child node.
+ */
+ protected function _saveProductId($parent_node, $name, $value, $missing)
+ {
+ // Always store now as modification date
+ return $this->_saveDefault($parent_node,
+ $name,
+ self::PRODUCT_ID,
+ array('type' => self::TYPE_STRING));
+ }
+
+ /**
+ * Load recurrence information.
+ *
+ * @param Horde_DOM_Node $node The original node if set.
+ * @param boolean $missing Has the node been missing?
+ *
+ * @return array The recurrence information.
+ *
+ * @throws Horde_Exception If converting the data from XML failed.
+ */
+ protected function _loadRecurrence($node, $missing)
+ {
+ if ($missing) {
+ return null;
+ }
+
+ // Collect all child nodes
+ $children = $node->childNodes;
+
+ $recurrence = $this->_loadArray($children, $this->_fields_recurrence);
+
+ // Get the cycle type (must be present)
+ $recurrence['cycle'] = $node->getAttribute('cycle');
+ // Get the sub type (may be present)
+ $recurrence['type'] = $node->getAttribute('type');
+
+ // Exclusions.
+ if (isset($recurrence['exclusion'])) {
+ $exceptions = array();
+ foreach($recurrence['exclusion'] as $exclusion) {
+ if (!empty($exclusion)) {
+ list($year, $month, $mday) = sscanf($exclusion, '%04d-%02d-%02d');
+
+ $exceptions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
+ }
+ }
+ $recurrence['exceptions'] = $exceptions;
+ }
+
+ // Completed dates.
+ if (isset($recurrence['complete'])) {
+ $completions = array();
+ foreach($recurrence['complete'] as $complete) {
+ if (!empty($complete)) {
+ list($year, $month, $mday) = sscanf($complete, '%04d-%02d-%02d');
+
+ $completions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
+ }
+ }
+ $recurrence['completions'] = $completions;
+ }
+
+ // Range is special
+ foreach($children as $child) {
+ if ($child->tagname == 'range') {
+ $recurrence['range-type'] = $child->get_attribute('type');
+ }
+ }
+
+ if (isset($recurrence['range']) && isset($recurrence['range-type'])
+ && $recurrence['range-type'] == 'date') {
+ $recurrence['range'] = Horde_Kolab_Format_Date::decodeDate($recurrence['range']);
+ }
+
+ // Sanity check
+ $valid = $this->_validateRecurrence($recurrence);
+
+ return $recurrence;
+ }
+
+ /**
+ * Validate recurrence hash information.
+ *
+ * @param array $recurrence Recurrence hash loaded from XML.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If the recurrence data is invalid.
+ */
+ protected function _validateRecurrence(&$recurrence)
+ {
+ if (!isset($recurrence['cycle'])) {
+ throw new Horde_Exception('recurrence tag error: cycle attribute missing');
+ }
+
+ if (!isset($recurrence['interval'])) {
+ throw new Horde_Exception('recurrence tag error: interval tag missing');
+ }
+ $interval = $recurrence['interval'];
+ if ($interval < 0) {
+ throw new Horde_Exception('recurrence tag error: interval cannot be below zero: '
+ . $interval);
+ }
+
+ if ($recurrence['cycle'] == 'weekly') {
+ // Check for
+ if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
+ throw new Horde_Exception('recurrence tag error: day tag missing for weekly recurrence');
+ }
+ }
+
+ // The code below is only for monthly or yearly recurrences
+ if ($recurrence['cycle'] != 'monthly'
+ && $recurrence['cycle'] != 'yearly')
+ return true;
+
+ if (!isset($recurrence['type'])) {
+ throw new Horde_Exception('recurrence tag error: type attribute missing');
+ }
+
+ if (!isset($recurrence['daynumber'])) {
+ throw new Horde_Exception('recurrence tag error: daynumber tag missing');
+ }
+ $daynumber = $recurrence['daynumber'];
+ if ($daynumber < 0) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be below zero: '
+ . $daynumber);
+ }
+
+ if ($recurrence['type'] == 'daynumber') {
+ if ($recurrence['cycle'] == 'yearly' && $daynumber > 366) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 366 for yearly recurrences: ' . $daynumber);
+ } else if ($recurrence['cycle'] == 'monthly' && $daynumber > 31) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 31 for monthly recurrences: ' . $daynumber);
+ }
+ } else if ($recurrence['type'] == 'weekday') {
+ // daynumber is the week of the month
+ if ($daynumber > 5) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 5 for type weekday: ' . $daynumber);
+ }
+
+ // Check for
+ if (!isset($recurrence['day']) || count($recurrence['day']) == 0) {
+ throw new Horde_Exception('recurrence tag error: day tag missing for type weekday');
+ }
+ }
+
+ if (($recurrence['type'] == 'monthday' || $recurrence['type'] == 'yearday')
+ && $recurrence['cycle'] == 'monthly')
+ {
+ throw new Horde_Exception('recurrence tag error: type monthday/yearday is only allowed for yearly recurrences');
+ }
+
+ if ($recurrence['cycle'] == 'yearly') {
+ if ($recurrence['type'] == 'monthday') {
+ // daynumber and month
+ if (!isset($recurrence['month'])) {
+ throw new Horde_Exception('recurrence tag error: month tag missing for type monthday');
+ }
+ if ($daynumber > 31) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 31 for type monthday: ' . $daynumber);
+ }
+ } else if ($recurrence['type'] == 'yearday') {
+ if ($daynumber > 366) {
+ throw new Horde_Exception('recurrence tag error: daynumber cannot be larger than 366 for type yearday: ' . $daynumber);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Save recurrence information.
+ *
+ * @param Horde_DOM_Node $parent_node The parent node to attach
+ * the child to.
+ * @param string $name The name of the node.
+ * @param mixed $value The value to store.
+ * @param boolean $missing Has the value been missing?
+ *
+ * @return Horde_DOM_Node The new child node.
+ */
+ protected function _saveRecurrence($parent_node, $name, $value, $missing)
+ {
+ $this->_removeNodes($parent_node, $name);
+
+ if (empty($value)) {
+ return false;
+ }
+
+ // Exclusions.
+ if (isset($value['exceptions'])) {
+ $exclusions = array();
+ foreach($value['exceptions'] as $exclusion) {
+ if (!empty($exclusion)) {
+ list($year, $month, $mday) = sscanf($exclusion, '%04d%02d%02d');
+ $exclusions[] = "$year-$month-$mday";
+ }
+ }
+ $value['exclusion'] = $exclusions;
+ }
+
+ // Completed dates.
+ if (isset($value['completions'])) {
+ $completions = array();
+ foreach($value['completions'] as $complete) {
+ if (!empty($complete)) {
+ list($year, $month, $mday) = sscanf($complete, '%04d%02d%02d');
+ $completions[] = "$year-$month-$mday";
+ }
+ }
+ $value['complete'] = $completions;
+ }
+
+ if (isset($value['range'])
+ && isset($value['range-type']) && $value['range-type'] == 'date') {
+ $value['range'] = Horde_Kolab_Format_Date::encodeDate($value['range']);
+ }
+
+ $r_node = $this->_xmldoc->createElement($name);
+ $r_node = $parent_node->appendChild($r_node);
+
+ // Save normal fields
+ $this->_saveArray($r_node, $value, $this->_fields_recurrence);
+
+ // Add attributes
+ $r_node->setAttribute('cycle', $value['cycle']);
+ if (isset($value['type'])) {
+ $r_node->setAttribute('type', $value['type']);
+ }
+
+ $child = $this->_findNode($r_node->childNodes, 'range');
+ if ($child) {
+ $child->setAttribute('type', $value['range-type']);
+ }
+
+ return $r_node;
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Annotation.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Annotation.php
new file mode 100644
index 000000000..7604cffcf
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Annotation.php
@@ -0,0 +1,106 @@
+
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for IMAP folder annotations.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Annotation extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the prefs object
+ *
+ * @var Kolab
+ */
+ protected $_fields_specific;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = 'annotations';
+
+ /**
+ * Specific preferences fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'annotation' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with the object data
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = $this->_loadArray($children, $this->_fields_specific);
+
+ $result = array();
+ foreach ($object['annotation'] as $annotation) {
+ list($key, $value) = split('#', $annotation, 2);
+ $result[base64_decode($key)] = base64_decode($value);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Save the specific XML values.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ $annotations = array();
+ foreach ($object as $key => $value) {
+ if ($key != 'uid') {
+ $annotations['annotation'][] = base64_encode($key) .
+ '#' . base64_encode($value);
+ }
+ }
+
+ return $this->_saveArray($root, $annotations, $this->_fields_specific);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Contact.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Contact.php
new file mode 100644
index 000000000..ef66f2f58
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Contact.php
@@ -0,0 +1,525 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for contact groupware objects
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Contact extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the contact object
+ *
+ * @var array
+ */
+ protected $_fields_specific;
+
+ /**
+ * Structure of the name field
+ *
+ * @var array
+ */
+ protected $_fields_name = array(
+ 'given-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'middle-names' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'last-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'full-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'initials' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'prefix' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'suffix' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ )
+ );
+
+ /**
+ * Structure of an address field
+ *
+ * @var array
+ */
+ protected $_fields_address = array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 'home',
+ ),
+ 'street' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'locality' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'region' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'postal-code' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'country' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ )
+ );
+
+ /**
+ * Structure of a phone field
+ *
+ * @var array
+ */
+ protected $_fields_phone = array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'number' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ );
+
+ /**
+ * Address types
+ *
+ * @var array
+ */
+ protected $_address_types = array(
+ 'business',
+ 'home',
+ 'other',
+ );
+
+ /**
+ * Phone types
+ *
+ * @var array
+ */
+ protected $_phone_types = array(
+ 'business1',
+ 'business2',
+ 'businessfax',
+ 'callback',
+ 'car',
+ 'company',
+ 'home1',
+ 'home2',
+ 'homefax',
+ 'isdn',
+ 'mobile',
+ 'pager',
+ 'primary',
+ 'radio',
+ 'telex',
+ 'ttytdd',
+ 'assistant',
+ 'other',
+ );
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = "contact";
+
+ /** Specific task fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'name' => array (
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => $this->_fields_name,
+ ),
+ 'free-busy-url' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'organization' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'web-page' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'im-address' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'department' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'office-location' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'profession' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'job-title' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'manager-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'assistant' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'nick-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'spouse-name' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'birthday' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'anniversary' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'picture' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'children' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'gender' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'language' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'address' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => $this->_fields_address,
+ ),
+ 'email' => array (
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => $this->_fields_simple_person,
+ ),
+ 'phone' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => $this->_fields_phone,
+ ),
+ 'preferred-address' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'latitude' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'longitude' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ // Horde specific fields
+ 'pgp-publickey' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ // Support for broken clients
+ 'website' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'im-adress' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with the object data.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = $this->_loadArray($children, $this->_fields_specific);
+
+ // Handle name fields
+ if (isset($object['name'])) {
+ $object = array_merge($object['name'], $object);
+ unset($object['name']);
+ }
+
+ // Handle email fields
+ $emails = array();
+ if (isset($object['email'])) {
+ foreach ($object['email'] as $email) {
+ $smtp_address = $email['smtp-address'];
+ if (!empty($smtp_address)) {
+ $emails[] = $smtp_address;
+ }
+ }
+ }
+ $object['emails'] = implode(', ', $emails);
+
+ // Handle phone fields
+ if (isset($object['phone'])) {
+ foreach ($object['phone'] as $phone) {
+ if (isset($phone['number']) &&
+ in_array($phone['type'], $this->_phone_types)) {
+ $object["phone-" . $phone['type']] = $phone['number'];
+ }
+ }
+ }
+
+ // Handle address fields
+ if (isset($object['address'])) {
+ foreach ($object['address'] as $address) {
+ if (in_array($address['type'], $this->_address_types)) {
+ foreach ($address as $name => $value) {
+ $object["addr-" . $address['type'] . "-" . $name] = $value;
+ }
+ }
+ }
+ }
+
+ // Handle gender field
+ if (isset($object['gender'])) {
+ $gender = $object['gender'];
+
+ if ($gender == "female") {
+ $object['gender'] = 1;
+ } else if ($gender == "male") {
+ $object['gender'] = 0;
+ } else {
+ // unspecified gender
+ unset($object['gender']);
+ }
+ }
+
+ // Compatibility with broken clients
+ $broken_fields = array("website" => "web-page",
+ "im-adress" => "im-address");
+ foreach ($broken_fields as $broken_field => $real_field) {
+ if (!empty($object[$broken_field]) && empty($object[$real_field])) {
+ $object[$real_field] = $object[$broken_field];
+ }
+ unset($object[$broken_field]);
+ }
+
+ $object['__type'] = 'Object';
+
+ return $object;
+ }
+
+ /**
+ * Save the specifc XML values.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ // Handle name fields
+ $name = array();
+ foreach (array_keys($this->_fields_name) as $key) {
+ if (isset($object[$key])) {
+ $name[$key] = $object[$key];
+ unset($object[$key]);
+ }
+ }
+ $object['name'] = $name;
+
+ // Handle email fields
+ if (!isset($object['emails'])) {
+ $emails = array();
+ } else {
+ $emails = explode(',', $object['emails']);
+ }
+
+ if (isset($object['email']) &&
+ !in_array($object['email'], $emails)) {
+ $emails[] = $object['email'];
+ }
+
+ $object['email'] = array();
+
+ foreach ($emails as $email) {
+ $email = trim($email);
+ if (!empty($email)) {
+ $new_email = array('display-name' => $object['name']['full-name'],
+ 'smtp-address' => $email);
+
+ $object['email'][] = $new_email;
+ }
+ }
+
+ // Handle phone fields
+ if (!isset($object['phone'])) {
+ $object['phone'] = array();
+ }
+ foreach ($this->_phone_types as $type) {
+ $key = 'phone-' . $type;
+ if (array_key_exists($key, $object)) {
+ $new_phone = array('type' => $type,
+ 'number' => $object[$key]);
+
+ // Update existing phone entry of this type
+ $updated = false;
+ foreach ($object['phone'] as $index => $phone) {
+ if ($phone['type'] == $type) {
+ $object['phone'][$index] = $new_phone;
+
+ $updated = true;
+ break;
+ }
+ }
+ if (!$updated) {
+ $object['phone'][] = $new_phone;
+ }
+ }
+ }
+
+ // Phone cleanup: remove empty numbers
+ foreach ($object['phone'] as $index => $phone) {
+ if (empty($phone['number'])) {
+ unset($object['phone'][$index]);
+ }
+ }
+
+ // Handle address fields
+ if (!isset($object['address'])) {
+ $object['address'] = array();
+ }
+
+ foreach ($this->_address_types as $type) {
+ $basekey = 'addr-' . $type . '-';
+ $new_address = array('type' => $type);
+ foreach (array_keys($this->_fields_address['array']) as $subkey) {
+ $key = $basekey . $subkey;
+ if (array_key_exists($key, $object)) {
+ $new_address[$subkey] = $object[$key];
+ }
+ }
+
+ // Update existing address entry of this type
+ $updated = false;
+ foreach ($object['address'] as $index => $address) {
+ if ($address['type'] == $type) {
+ $object['address'][$index] = $new_address;
+
+ $updated = true;
+ }
+ }
+ if (!$updated) {
+ $object['address'][] = $new_address;
+ }
+ }
+
+ // Address cleanup: remove empty addresses
+ foreach ($object['address'] as $index => $address) {
+ $all_empty = true;
+ foreach ($address as $name => $value) {
+ if (!empty($value) && $name != "type") {
+ $all_empty = false;
+ break;
+ }
+ }
+
+ if ($all_empty) {
+ unset($object['address'][$index]);
+ }
+ }
+
+ // Handle gender field
+ if (isset($object['gender'])) {
+ $gender = $object['gender'];
+
+ if ($gender == "0") {
+ $object['gender'] = "male";
+ } else if ($gender == "1") {
+ $object['gender'] = "female";
+ } else {
+ // unspecified gender
+ unset($object['gender']);
+ }
+ }
+
+ // Do the actual saving
+ return $this->_saveArray($root, $object, $this->_fields_specific);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Distributionlist.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Distributionlist.php
new file mode 100644
index 000000000..e471953e1
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Distributionlist.php
@@ -0,0 +1,113 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for distributionlist groupware objects
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Distributionlist extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the contact object
+ *
+ * @var array
+ */
+ protected $_fields_specific;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = "distribution-list";
+
+ /** Specific task fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'display-name' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_NOT_EMPTY
+ ),
+ 'member' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => $this->_fields_simple_person,
+ )
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with data.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = $this->_loadArray($children, $this->_fields_specific);
+
+ // Map the display-name of a kolab dist list to horde's lastname attribute
+ if (isset($object['display-name'])) {
+ $object['last-name'] = $object['display-name'];
+ unset($object['display-name']);
+ }
+
+ /**
+ * The mapping from $object['member'] as stored in XML back to
+ * Turba_Objects (contacts) must be performed in the
+ * Kolab_IMAP storage driver as we need access to the search
+ * facilities of the kolab storage driver.
+ */
+ $object['__type'] = 'Group';
+ return $object;
+ }
+
+ /**
+ * Save the specifc XML values.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ // Map the display-name of a kolab dist list to horde's lastname attribute
+ if (isset($object['last-name'])) {
+ $object['display-name'] = $object['last-name'];
+ unset($object['last-name']);
+ }
+
+ return $this->_saveArray($root, $object, $this->_fields_specific);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Event.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Event.php
new file mode 100644
index 000000000..9544ae041
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Event.php
@@ -0,0 +1,139 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for event groupware objects.
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Event extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the contact object
+ *
+ * @var array
+ */
+ protected $_fields_specific;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = 'event';
+
+ /** Specific event fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'summary' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'location' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'organizer' => $this->_fields_simple_person,
+ 'start-date' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_NOT_EMPTY,
+ ),
+ 'alarm' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'recurrence' => array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_CALCULATED,
+ 'load' => 'Recurrence',
+ 'save' => 'Recurrence',
+ ),
+ 'attendee' => $this->_fields_attendee,
+ 'show-time-as' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'color-label' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'end-date' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_NOT_EMPTY,
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load event XML values and translate start/end date.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with the object data.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = parent::_load($children);
+
+ // Translate start/end date including full day events
+ if (strlen($object['start-date']) == 10) {
+ $object['start-date'] = Horde_Kolab_Format_Date::decodeDate($object['start-date']);
+ $object['end-date'] = Horde_Kolab_Format_Date::decodeDate($object['end-date']) + 24*60*60;
+ } else {
+ $object['start-date'] = Horde_Kolab_Format_Date::decodeDateTime($object['start-date']);
+ $object['end-date'] = Horde_Kolab_Format_Date::decodeDateTime($object['end-date']);
+ }
+
+ return $object;
+ }
+
+ /**
+ * Save event XML values and translate start/end date.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ // Translate start/end date including full day events
+ if (!empty($object['_is_all_day'])) {
+ $object['start-date'] = Horde_Kolab_Format_Date::encodeDate($object['start-date']);
+ $object['end-date'] = Horde_Kolab_Format_Date::encodeDate($object['end-date'] - 24*60*60);
+ } else {
+ $object['start-date'] = Horde_Kolab_Format_Date::encodeDateTime($object['start-date']);
+ $object['end-date'] = Horde_Kolab_Format_Date::encodeDateTime($object['end-date']);
+ }
+
+ return parent::_save($root, $object);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Hprefs.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Hprefs.php
new file mode 100644
index 000000000..b7a8eebc9
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Hprefs.php
@@ -0,0 +1,119 @@
+
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for client preferences.
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Hprefs extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the prefs object
+ *
+ * @var Kolab
+ */
+ protected $_fields_specific;
+
+ /**
+ * Automatically create categories if they are missing?
+ *
+ * @var boolean
+ */
+ protected $_create_categories = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = 'h-prefs';
+
+ /** Specific preferences fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'application' => array (
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'pref' => array(
+ 'type' => self::TYPE_MULTIPLE,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ 'array' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load an object based on the given XML string.
+ *
+ * @param string &$xmltext The XML of the message as string.
+ *
+ * @return array The data array representing the object.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ public function load(&$xmltext)
+ {
+ $object = parent::load($xmltext);
+
+ if (empty($object['application'])) {
+ if (!empty($object['categories'])) {
+ $object['application'] = $object['categories'];
+ unset($object['categories']);
+ } else {
+ throw new Horde_Exception('Preferences XML object is missing an application setting.');
+ }
+ }
+
+ return $object;
+ }
+
+ /**
+ * Convert the data to a XML string.
+ *
+ * @param array $object The data array representing the note.
+ *
+ * @return string The data as XML string.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ public function save($object)
+ {
+ if (empty($object['application'])) {
+ if (!empty($object['categories'])) {
+ $object['application'] = $object['categories'];
+ unset($object['categories']);
+ } else {
+ throw new Horde_Exception('Preferences XML object is missing an application setting.');
+ }
+ }
+
+ return parent::save($object);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Note.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Note.php
new file mode 100644
index 000000000..bd12d2116
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Note.php
@@ -0,0 +1,106 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for note groupware objects.
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Note extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the note object
+ *
+ * @var Kolab
+ */
+ protected $_fields_specific;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = 'note';
+
+ /** Specific note fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'summary' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'background-color' => array(
+ 'type' => self::TYPE_COLOR,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '#000000',
+ ),
+ 'foreground-color' => array(
+ 'type' => self::TYPE_COLOR,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '#ffff00',
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with the object data
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = $this->_loadArray($children, $this->_fields_specific);
+
+ $object['desc'] = $object['summary'];
+ unset($object['summary']);
+
+ return $object;
+ }
+
+ /**
+ * Save the specific XML values.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ $object['summary'] = $object['desc'];
+ unset($object['desc']);
+
+ return $this->_saveArray($root, $object, $this->_fields_specific);
+ }
+}
diff --git a/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Task.php b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Task.php
new file mode 100644
index 000000000..5d37389f2
--- /dev/null
+++ b/framework/Kolab_Format/lib/Horde/Kolab/Format/Xml/Task.php
@@ -0,0 +1,199 @@
+
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ */
+
+/**
+ * Kolab XML handler for task groupware objects.
+ *
+ * Copyright 2007-2009 Klarälvdalens Datakonsult AB
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ *
+ * @category Kolab
+ * @package Kolab_Format
+ * @author Thomas Jarosch
+ * @author Gunnar Wrobel
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @link http://pear.horde.org/index.php?package=Kolab_Server
+ * @since Horde 3.2
+ */
+class Horde_Kolab_Format_Xml_Task extends Horde_Kolab_Format_Xml
+{
+ /**
+ * Specific data fields for the note object
+ *
+ * @var array
+ */
+ protected $_fields_specific;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->_root_name = 'task';
+
+ /** Specific task fields, in kolab format specification order
+ */
+ $this->_fields_specific = array(
+ 'summary' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'location' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => '',
+ ),
+ 'creator' => $this->_fields_simple_person,
+ 'organizer' => $this->_fields_simple_person,
+ 'start-date' => array(
+ 'type' => self::TYPE_DATE_OR_DATETIME,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'alarm' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'recurrence' => array(
+ 'type' => self::TYPE_COMPOSITE,
+ 'value' => self::VALUE_CALCULATED,
+ 'load' => 'Recurrence',
+ 'save' => 'Recurrence',
+ ),
+ 'attendee' => $this->_fields_attendee,
+ 'priority' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 3,
+ ),
+ 'completed' => array(
+ 'type' => self::TYPE_INTEGER,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 0,
+ ),
+ 'status' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_DEFAULT,
+ 'default' => 'not-started',
+ ),
+ 'due-date' => array(
+ 'type' => self::TYPE_DATE_OR_DATETIME,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'parent' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ // These are not part of the Kolab specification but it is
+ // ok if the client supports additional entries
+ 'estimate' => array(
+ 'type' => self::TYPE_STRING,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ 'completed_date' => array(
+ 'type' => self::TYPE_DATE_OR_DATETIME,
+ 'value' => self::VALUE_MAYBE_MISSING,
+ ),
+ );
+
+ parent::__construct();
+ }
+
+ /**
+ * Load the groupware object based on the specifc XML values.
+ *
+ * @param array &$children An array of XML nodes.
+ *
+ * @return array Array with data.
+ *
+ * @throws Horde_Exception If parsing the XML data failed.
+ */
+ protected function _load(&$children)
+ {
+ $object = $this->_loadArray($children, $this->_fields_specific);
+
+ $object['name'] = $object['summary'];
+ unset($object['summary']);
+
+ if (empty($object['completed-date'])) {
+ $object['completed-date'] = null;
+ }
+
+ if (empty($object['alarm'])) {
+ $object['alarm'] = null;
+ }
+
+ if (isset($object['due-date'])) {
+ $object['due'] = $object['due-date'];
+ unset($object['due-date']);
+ } else {
+ $object['due'] = null;
+ }
+
+ if (isset($object['start-date'])) {
+ $object['start'] = $object['start-date'];
+ unset($object['start-date']);
+ } else {
+ $object['start'] = null;
+ }
+
+ if (!isset($object['estimate'])) {
+ $object['estimate'] = null;
+ } else {
+ $object['estimate'] = (float) $object['estimate'];
+ }
+
+ if (!isset($object['parent'])) {
+ $object['parent'] = null;
+ }
+
+ $object['completed'] = (bool) Kolab::percentageToBoolean($object['completed']);
+
+ if (isset($object['organizer']) && isset($object['organizer']['smtp-address'])) {
+ $object['assignee'] = $object['organizer']['smtp-address'];
+ }
+
+ return $object;
+ }
+
+ /**
+ * Save the specific XML values.
+ *
+ * @param array $root The XML document root.
+ * @param array $object The resulting data array.
+ *
+ * @return boolean True on success.
+ *
+ * @throws Horde_Exception If converting the data to XML failed.
+ */
+ protected function _save($root, $object)
+ {
+ $object['summary'] = $object['name'];
+ unset($object['name']);
+
+ $object['due-date'] = $object['due'];
+ unset($object['due']);
+
+ $object['start-date'] = $object['start'];
+ unset($object['start']);
+
+ $object['estimate'] = number_format($object['estimate'], 2);
+
+ $object['completed'] = Kolab::BooleanToPercentage($object['completed']);
+
+ return $this->_saveArray($root, $object, $this->_fields_specific);
+ }
+}
diff --git a/framework/Kolab_Format/package.xml b/framework/Kolab_Format/package.xml
index bd98fce45..df33af729 100644
--- a/framework/Kolab_Format/package.xml
+++ b/framework/Kolab_Format/package.xml
@@ -34,7 +34,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
2009-04-02
- 1.0.1
+ 1.0.2
1.0.0
@@ -43,14 +43,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
LGPL
- * Handle parsing errors within the DOM XML extension correctly
- kolab/issue3520 (calendar with certain entries does not display in web client)
- https://www.intevation.de/roundup/kolab/issue3520
- kolab/issue3525 (free/busy regeneration aborts for unparsable events)
- https://www.intevation.de/roundup/kolab/issue3525
- * Accept ISO-8859-1 encoding even if advertised as UTF-8
- kolab/issue3528 (Events with broken encoding should work)
- https://www.intevation.de/roundup/kolab/issue3528
+ * Converted to Horde4/PHP5
+ * Removed Horde_DOM dependency.
@@ -80,8 +74,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
-
-
+
+
@@ -89,7 +83,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
-
+
@@ -127,12 +121,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
1.4.0b1
- Horde_DOM
- pear.horde.org
- 0.1.0
-
-
- Horde_NLS
+ Nls
pear.horde.org
@@ -146,7 +135,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
pear.horde.org
- Horde_Date
+ Date
pear.horde.org
@@ -158,14 +147,14 @@ http://pear.php.net/dtd/package-2.0.xsd">
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -182,6 +171,28 @@ http://pear.php.net/dtd/package-2.0.xsd">
+ 2009-04-02
+
+ 1.0.1
+ 1.0.0
+
+
+ stable
+ stable
+
+ LGPL
+
+ * Handle parsing errors within the DOM XML extension correctly
+ kolab/issue3520 (calendar with certain entries does not display in web client)
+ https://www.intevation.de/roundup/kolab/issue3520
+ kolab/issue3525 (free/busy regeneration aborts for unparsable events)
+ https://www.intevation.de/roundup/kolab/issue3525
+ * Accept ISO-8859-1 encoding even if advertised as UTF-8
+ kolab/issue3528 (Events with broken encoding should work)
+ https://www.intevation.de/roundup/kolab/issue3528
+
+
+
2008-12-12
1.0.0
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/ContactTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/ContactTest.php
index 3648013bb..5cd856786 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/ContactTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/ContactTest.php
@@ -8,14 +8,10 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
+require_once 'Horde/Autoloader.php';
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
-require_once 'Horde/Kolab/Format/XML.php';
-require_once 'Horde/Kolab/Format/XML/Contact.php';
class DummyRegistry {
function get()
@@ -24,7 +20,7 @@ class DummyRegistry {
}
}
-class Horde_Kolab_Format_XML_contact_dummy extends Horde_Kolab_Format_XML_contact
+class Horde_Kolab_Format_Xml_Contact_dummy extends Horde_Kolab_Format_Xml_Contact
{
function _saveCreationDate($parent_node, $name, $value, $missing)
{
@@ -77,7 +73,7 @@ class Horde_Kolab_Format_ContactTest extends PHPUnit_Framework_TestCase
*/
public function testSingleEmail()
{
- $contact = &new Horde_Kolab_Format_XML_contact_dummy();
+ $contact = &new Horde_Kolab_Format_Xml_contact_dummy();
$object = array('uid' => '1',
'full-name' => 'User Name',
'email' => 'user@example.org');
@@ -91,7 +87,7 @@ class Horde_Kolab_Format_ContactTest extends PHPUnit_Framework_TestCase
*/
public function testPGP()
{
- $contact = &new Horde_Kolab_Format_XML_contact_dummy();
+ $contact = &new Horde_Kolab_Format_Xml_contact_dummy();
$object = array('uid' => '1',
'full-name' => 'User Name',
'pgp-publickey' => 'PGP Test Key',
@@ -108,7 +104,7 @@ class Horde_Kolab_Format_ContactTest extends PHPUnit_Framework_TestCase
{
global $prefs;
- $contact = &new Horde_Kolab_Format_XML_contact();
+ $contact = &new Horde_Kolab_Format_Xml_contact();
$xml = file_get_contents(dirname(__FILE__) . '/fixtures/contact_category.xml');
$object = $contact->load($xml);
$this->assertContains('Test', $object['categories']);
@@ -134,7 +130,7 @@ class Horde_Kolab_Format_ContactTest extends PHPUnit_Framework_TestCase
/* Monkey patch to allw the value to be set. */
$prefs->_prefs['categories'] = array('v' => '');
- $contact = &new Horde_Kolab_Format_XML_contact();
+ $contact = &new Horde_Kolab_Format_Xml_contact();
$xml = file_get_contents(dirname(__FILE__) . '/fixtures/contact_category.xml');
$object = $contact->load($xml);
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/EventTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/EventTest.php
index a8fc5c4be..bec51f6b9 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/EventTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/EventTest.php
@@ -8,12 +8,9 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
-
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
+require_once 'Horde/Autoloader.php';
/**
* Test event handling.
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/MimeAttrTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/MimeAttrTest.php
index f2d5535b9..99733e396 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/MimeAttrTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/MimeAttrTest.php
@@ -15,12 +15,9 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
-
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
+require_once 'Horde/Autoloader.php';
/**
* Test Kolab Format MIME attributes
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/PreferencesTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/PreferencesTest.php
index fc50a53e3..b752810ec 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/PreferencesTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/PreferencesTest.php
@@ -8,17 +8,13 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
+require_once 'Horde/Autoloader.php';
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
-require_once 'Horde/Kolab/Format/XML.php';
-require_once 'Horde/Kolab/Format/XML/Hprefs.php';
-class Horde_Kolab_Format_XML_hprefs_dummy extends Horde_Kolab_Format_XML_hprefs
+class Horde_Kolab_Format_Xml_Hprefs_dummy extends Horde_Kolab_Format_Xml_Hprefs
{
function _saveCreationDate($parent_node, $name, $value, $missing)
{
@@ -71,7 +67,7 @@ class Horde_Kolab_Format_PreferencesTest extends PHPUnit_Framework_TestCase
*/
public function testConversionFromOld()
{
- $preferences = &new Horde_Kolab_Format_XML_hprefs_dummy();
+ $preferences = &new Horde_Kolab_Format_Xml_hprefs_dummy();
$xml = file_get_contents(dirname(__FILE__) . '/fixtures/preferences_read_old.xml');
$object = $preferences->load($xml);
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/RecurrenceTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/RecurrenceTest.php
index 0f81ba05a..cefd966b5 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/RecurrenceTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/RecurrenceTest.php
@@ -8,12 +8,9 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
-
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
+require_once 'Horde/Autoloader.php';
/**
* Test recurrence handling
diff --git a/framework/Kolab_Format/test/Horde/Kolab/Format/XmlTest.php b/framework/Kolab_Format/test/Horde/Kolab/Format/XmlTest.php
index b5f23e74f..380c8aca2 100644
--- a/framework/Kolab_Format/test/Horde/Kolab/Format/XmlTest.php
+++ b/framework/Kolab_Format/test/Horde/Kolab/Format/XmlTest.php
@@ -8,13 +8,9 @@
*/
/**
- * We need the unit test framework
+ * The Autoloader allows us to omit "require/include" statements.
*/
-require_once 'PHPUnit/Framework.php';
-
-require_once 'Horde/Nls.php';
-require_once 'Horde/Kolab/Format.php';
-require_once 'Horde/Kolab/Format/XML.php';
+require_once 'Horde/Autoloader.php';
/**
* Test the XML format.
@@ -71,8 +67,7 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
public function testAdd()
{
$xml = &new Horde_Kolab_Format_XML();
- $xml->_prepareSave();
- $root = $xml->_xmldoc;
+ $root = $xml->_prepareSave();
$base = $xml->_xmldoc->saveXML();
// A missing attribute should cause no change if it
@@ -120,9 +115,8 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
*/
public function testNodeOps()
{
- $dxml = new Horde_Kolab_Format_XML_dummy();
- $dxml->_prepareSave();
- $droot = $dxml->_xmldoc;
+ $dxml = new Horde_Kolab_Format_Xml_dummy();
+ $droot = $dxml->_prepareSave();
// Test calculated nodes
$dxml->_updateNode($droot,
@@ -137,9 +131,8 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
'save' => 'Value', 'type' => 0));
$this->assertEquals("\n\n empty2: , missing\n present1: present1\n\n", $dxml->_xmldoc->saveXML());
- $xml = &new Horde_Kolab_Format_XML();
- $xml->_prepareSave();
- $root = $xml->_xmldoc;
+ $xml = &new Horde_Kolab_Format_Xml();
+ $root = $xml->_prepareSave();
$xml->_updateNode($root,
array(),
'empty1',
@@ -229,7 +222,7 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
public function testReleod()
{
// Save an object and reload it
- $xml = new Horde_Kolab_Format_XML();
+ $xml = new Horde_Kolab_Format_Xml();
$result = $xml->save(array('uid'=>'test',
'body' => 'body',
'dummy' => 'hello',
@@ -251,9 +244,8 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
public function testComplex()
{
// Continue with complex values
- $xml = new Horde_Kolab_Format_XML();
- $xml->_prepareSave();
- $root = $xml->_xmldoc;
+ $xml = new Horde_Kolab_Format_Xml();
+ $root = $xml->_prepareSave();
// Test saving a composite value
$xml->_updateNode($root,
@@ -267,7 +259,7 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
'attendee1', $xml->_fields_attendee);
$this->assertEquals("\n\n \n test\n test@example.com\n \n \n \n test\n \n none\n true\n required\n \n \n \n test@example.com\n none\n true\n required\n \n\n", $xml->_xmldoc->saveXML());
- $children = $root->child_nodes();
+ $children = $root->childNodes;
// Load a composite value
$data = $xml->_getXmlData($children,
@@ -301,7 +293,7 @@ class Horde_Kolab_Format_XmlTest extends PHPUnit_Framework_TestCase
* @author Gunnar Wrobel
* @package Kolab_Format
*/
-class Horde_Kolab_Format_XML_dummy extends Horde_Kolab_Format_XML
+class Horde_Kolab_Format_Xml_dummy extends Horde_Kolab_Format_Xml
{
function _saveValue($node, $name, $value, $missing)
{