diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php index 23246d32..bedee440 100644 --- a/plugins/libkolab/lib/kolab_format.php +++ b/plugins/libkolab/lib/kolab_format.php @@ -31,38 +31,59 @@ abstract class kolab_format public /*abstract*/ $CTYPE; + protected /*abstract*/ $objclass; protected /*abstract*/ $read_func; protected /*abstract*/ $write_func; protected $obj; protected $data; protected $xmldata; + protected $xmlobject; protected $loaded = false; + protected $version = 3.0; - const VERSION = '3.0'; const KTYPE_PREFIX = 'application/x-vnd.kolab.'; + const PRODUCT_ID = 'Roundcube-libkolab-0.9'; /** - * Factory method to instantiate a kolab_format object of the given type + * Factory method to instantiate a kolab_format object of the given type and version * * @param string Object type to instantiate * @param string Cached xml data to initialize with + * @param float Format version * @return object kolab_format */ - public static function factory($type, $xmldata = null) + public static function factory($type, $xmldata = null, $version = 3.0) { if (!isset(self::$timezone)) self::$timezone = new DateTimeZone('UTC'); + if (!self::supports($version)) + return PEAR::raiseError("No support for Kolab format version " . $version); + $type = preg_replace('/configuration\.[a-z.]+$/', 'configuration', $type); $suffix = preg_replace('/[^a-z]+/', '', $type); $classname = 'kolab_format_' . $suffix; if (class_exists($classname)) - return new $classname($xmldata); + return new $classname($xmldata, $version); return PEAR::raiseError("Failed to load Kolab Format wrapper for type " . $type); } + /** + * Determine support for the given format version + * + * @param float Format version to check + * @return boolean True if supported, False otherwise + */ + public static function supports($version) + { + if ($version == 2.0) + return class_exists('kolabobject'); + // default is version 3 + return class_exists('kolabformat'); + } + /** * Convert the given date/time value into a cDateTime object * @@ -184,6 +205,23 @@ abstract class kolab_format return preg_replace('/dictionary.[a-z.]+$/', 'dictionary', substr($x_kolab_type, strlen(self::KTYPE_PREFIX))); } + + /** + * Default constructor of all kolab_format_* objects + */ + public function __construct($xmldata = null, $version = null) + { + $this->obj = new $this->objclass; + $this->xmldata = $xmldata; + + if ($version) + $this->version = $version; + + // use libkolab module if available + if (class_exists('kolabobject')) + $this->xmlobject = new XMLObject(); + } + /** * Check for format errors after calling kolabformat::write*() * @@ -245,6 +283,39 @@ abstract class kolab_format } } + /** + * Get constant value for libkolab's version parameter + * + * @param float Version value to convert + * @return int Constant value of either kolabobject::KolabV2 or kolabobject::KolabV3 or false if kolabobject module isn't available + */ + protected function libversion($v = null) + { + if (class_exists('kolabobject')) { + $version = $v ?: $this->version; + if ($version <= 2.0) + return kolabobject::KolabV2; + else + return kolabobject::KolabV3; + } + + return false; + } + + /** + * Determine the correct libkolab(xml) wrapper function for the given call + * depending on the available PHP modules + */ + protected function libfunc($func) + { + if (is_array($func) || strpos($func, '::')) + return $func; + else if (class_exists('kolabobject')) + return array($this->xmlobject, $func); + else + return 'kolabformat::' . $func; + } + /** * Direct getter for object properties */ @@ -257,22 +328,29 @@ abstract class kolab_format * Load Kolab object data from the given XML block * * @param string XML data + * @return boolean True on success, False on failure */ public function load($xml) { - $this->obj = call_user_func($this->read_func, $xml, false); + $r = call_user_func($this->libfunc($this->read_func), $xml, $this->libversion()); + if (is_resource($r)) + $this->obj = new $this->objclass($r); + else if (is_a($r, $this->objclass)) + $this->obj = $r; + $this->loaded = !$this->format_errors(); } /** * Write object data to XML format * + * @param float Format version to write * @return string XML data */ - public function write() + public function write($version = null) { $this->init(); - $this->xmldata = call_user_func($this->write_func, $this->obj); + $this->xmldata = call_user_func($this->libfunc($this->write_func), $this->obj, $this->libversion($version), self::PRODUCT_ID); if (!$this->format_errors()) $this->update_uid(); diff --git a/plugins/libkolab/lib/kolab_format_configuration.php b/plugins/libkolab/lib/kolab_format_configuration.php index 974fc453..1bb919d3 100644 --- a/plugins/libkolab/lib/kolab_format_configuration.php +++ b/plugins/libkolab/lib/kolab_format_configuration.php @@ -26,6 +26,7 @@ class kolab_format_configuration extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.configuration'; + protected $objclass = 'Configuration'; protected $read_func = 'kolabformat::readConfiguration'; protected $write_func = 'kolabformat::writeConfiguration'; @@ -35,12 +36,6 @@ class kolab_format_configuration extends kolab_format ); - function __construct($xmldata = null) - { - $this->obj = new Configuration; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php index ffef059d..bae5fa33 100644 --- a/plugins/libkolab/lib/kolab_format_contact.php +++ b/plugins/libkolab/lib/kolab_format_contact.php @@ -26,8 +26,9 @@ class kolab_format_contact extends kolab_format { public $CTYPE = 'application/vcard+xml'; - protected $read_func = 'kolabformat::readContact'; - protected $write_func = 'kolabformat::writeContact'; + protected $objclass = 'Contact'; + protected $read_func = 'readContact'; + protected $write_func = 'writeContact'; public static $fulltext_cols = array('name', 'firstname', 'surname', 'middlename', 'email'); @@ -106,10 +107,9 @@ class kolab_format_contact extends kolab_format /** * Default constructor */ - function __construct($xmldata = null) + function __construct($xmldata = null, $version = 3.0) { - $this->obj = new Contact; - $this->xmldata = $xmldata; + parent::__construct($xmldata, $version); // complete phone types $this->phonetypes['homefax'] |= Telephone::Home; diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php index fcb94c14..6def48fd 100644 --- a/plugins/libkolab/lib/kolab_format_distributionlist.php +++ b/plugins/libkolab/lib/kolab_format_distributionlist.php @@ -26,16 +26,11 @@ class kolab_format_distributionlist extends kolab_format { public $CTYPE = 'application/vcard+xml'; - protected $read_func = 'kolabformat::readDistlist'; - protected $write_func = 'kolabformat::writeDistlist'; + protected $objclass = 'DistList'; + protected $read_func = 'readDistlist'; + protected $write_func = 'writeDistlist'; - function __construct($xmldata = null) - { - $this->obj = new DistList; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php index 4e790f2b..b2cb87b9 100644 --- a/plugins/libkolab/lib/kolab_format_event.php +++ b/plugins/libkolab/lib/kolab_format_event.php @@ -24,8 +24,9 @@ class kolab_format_event extends kolab_format_xcal { - protected $read_func = 'kolabformat::readEvent'; - protected $write_func = 'kolabformat::writeEvent'; + protected $objclass = 'Event'; + protected $read_func = 'readEvent'; + protected $write_func = 'writeEvent'; private $kolab2_rolemap = array( 'required' => 'REQ-PARTICIPANT', @@ -43,24 +44,15 @@ class kolab_format_event extends kolab_format_xcal /** - * Default constructor + * Clones into an instance of libcalendaring's extended EventCal class + * + * @return mixed EventCal object or false on failure */ - function __construct($xmldata = null) + public function to_libcal() { - $this->obj = new Event; - $this->xmldata = $xmldata; + return class_exists('kolabcalendaring') ? new EventCal($this->obj) : false; } - /** - * Clones into an instance of libcalendaring's extended EventCal class - * - * @return mixed EventCal object or false on failure - */ - public function to_libcal() - { - return class_exists('kolabcalendaring') ? new EventCal($this->obj) : false; - } - /** * Set event properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_journal.php b/plugins/libkolab/lib/kolab_format_journal.php index 5869af09..0e1b4743 100644 --- a/plugins/libkolab/lib/kolab_format_journal.php +++ b/plugins/libkolab/lib/kolab_format_journal.php @@ -26,16 +26,11 @@ class kolab_format_journal extends kolab_format { public $CTYPE = 'application/calendar+xml'; - protected $read_func = 'kolabformat::readJournal'; - protected $write_func = 'kolabformat::writeJournal'; + protected $objclass = 'Journal'; + protected $read_func = 'readJournal'; + protected $write_func = 'writeJournal'; - function __construct($xmldata = null) - { - $this->obj = new Journal; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_note.php b/plugins/libkolab/lib/kolab_format_note.php index 1c88a8bb..482a3e8f 100644 --- a/plugins/libkolab/lib/kolab_format_note.php +++ b/plugins/libkolab/lib/kolab_format_note.php @@ -26,16 +26,11 @@ class kolab_format_note extends kolab_format { public $CTYPE = 'application/x-vnd.kolab.note'; - protected $read_func = 'kolabformat::readNote'; - protected $write_func = 'kolabformat::writeNote'; + protected $objclass = 'Note'; + protected $read_func = 'readNote'; + protected $write_func = 'writeNote'; - function __construct($xmldata = null) - { - $this->obj = new Note; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_format_task.php b/plugins/libkolab/lib/kolab_format_task.php index 2a7a629f..425f5e06 100644 --- a/plugins/libkolab/lib/kolab_format_task.php +++ b/plugins/libkolab/lib/kolab_format_task.php @@ -24,16 +24,11 @@ class kolab_format_task extends kolab_format_xcal { - protected $read_func = 'kolabformat::readTodo'; - protected $write_func = 'kolabformat::writeTodo'; + protected $objclass = 'Todo'; + protected $read_func = 'readTodo'; + protected $write_func = 'writeTodo'; - function __construct($xmldata = null) - { - $this->obj = new Todo; - $this->xmldata = $xmldata; - } - /** * Set properties to the kolabformat object * diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php index 12419340..ac7de34b 100644 --- a/plugins/libkolab/lib/kolab_storage.php +++ b/plugins/libkolab/lib/kolab_storage.php @@ -31,6 +31,7 @@ class kolab_storage const SERVERSIDE_SUBSCRIPTION = 0; const CLIENTSIDE_SUBSCRIPTION = 1; + public static $version = 3.0; public static $last_error; private static $ready = false; @@ -49,6 +50,7 @@ class kolab_storage $rcmail = rcube::get_instance(); self::$config = $rcmail->config; + self::$version = $rcmail->config->get('kolab_format_version', self::$version); self::$imap = $rcmail->get_storage(); self::$ready = class_exists('kolabformat') && (self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2')); diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php index 08bf6690..e92a6fae 100644 --- a/plugins/libkolab/lib/kolab_storage_folder.php +++ b/plugins/libkolab/lib/kolab_storage_folder.php @@ -466,39 +466,27 @@ class kolab_storage_folder return false; } - $format = kolab_format::factory($object_type); - - if (is_a($format, 'PEAR_Error')) - return false; - // check kolab format version - $mime_version = $headers->others['x-kolab-mime-version']; - if (empty($mime_version)) { + $format_version = $headers->others['x-kolab-mime-version']; + if (empty($format_version)) { list($xmltype, $subtype) = explode('.', $object_type); $xmlhead = substr($xml, 0, 512); // detect old Kolab 2.0 format if (strpos($xmlhead, '<' . $xmltype) !== false && strpos($xmlhead, 'xmlns=') === false) - $mime_version = 2.0; + $format_version = 2.0; else - $mime_version = 3.0; // assume 3.0 + $format_version = 3.0; // assume 3.0 } - if ($mime_version <= 2.0) { - // read Kolab 2.0 format - $handler = class_exists('Horde_Kolab_Format') ? Horde_Kolab_Format::factory('XML', $xmltype, array('subtype' => $subtype)) : null; - if (!is_object($handler) || is_a($handler, 'PEAR_Error')) { - return false; - } + // get Kolab format handler for the given type + $format = kolab_format::factory($object_type, $format_version); - // XML-to-array - $object = $handler->load($xml); - $format->fromkolab2($object); - } - else { - // load Kolab 3 format using libkolabxml - $format->load($xml); - } + if (is_a($format, 'PEAR_Error')) + return false; + + // load Kolab object from XML part + $format->load($xml); if ($format->is_valid()) { $object = $format->to_array(); @@ -696,13 +684,13 @@ class kolab_storage_folder // create new kolab_format instance if (!$format) - $format = kolab_format::factory($type); + $format = kolab_format::factory($type, kolab_storage::$version); if (PEAR::isError($format)) return false; $format->set($object); - $xml = $format->write(); + $xml = $format->write(kolab_storage::$version); $object['uid'] = $format->uid; // read UID from format $object['_formatobj'] = $format; @@ -721,7 +709,7 @@ class kolab_storage_folder } $headers['Date'] = date('r'); $headers['X-Kolab-Type'] = kolab_format::KTYPE_PREFIX . $type; - $headers['X-Kolab-Mime-Version'] = kolab_format::VERSION; + $headers['X-Kolab-Mime-Version'] = kolab_storage::$version; $headers['Subject'] = $object['uid']; // $headers['Message-ID'] = $rcmail->gen_message_id(); $headers['User-Agent'] = $rcmail->config->get('useragent');