Page MenuHomePhorge

No OneTemporary

Size
39 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/libkolab/lib/kolab_format.php b/plugins/libkolab/lib/kolab_format.php
new file mode 100644
index 00000000..8681fb77
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_format.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * Kolab format model class wrapping libkolabxml bindings
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+abstract class kolab_format
+{
+ public static $timezone;
+
+ /**
+ * Factory method to instantiate a kolab_format object of the given type
+ */
+ public static function factory($type)
+ {
+ if (!isset(self::$timezone))
+ self::$timezone = new DateTimeZone('UTC');
+
+ $suffix = preg_replace('/[^a-z]+/', '', $type);
+ $classname = 'kolab_format_' . $suffix;
+ if (class_exists($classname))
+ return new $classname();
+
+ return PEAR::raiseError(sprintf("Failed to load Kolab Format wrapper for type %s", $type));
+ }
+
+ /**
+ * Generate random UID for Kolab objects
+ *
+ * @return string MD5 hash with a unique value
+ */
+ public static function generate_uid()
+ {
+ return md5(uniqid(mt_rand(), true));
+ }
+
+ /**
+ * Convert the given date/time value into a c_DateTime object
+ *
+ * @param mixed Date/Time value either as unix timestamp, date string or PHP DateTime object
+ * @param DateTimeZone The timezone the date/time is in. Use global default if empty
+ * @param boolean True of the given date has no time component
+ * @return c_DateTime The libkolabxml date/time object or null on error
+ */
+ public static function getDateTime($datetime, $tz = null, $dateonly = false)
+ {
+ if (!$tz) $tz = self::$timezone;
+ $result = null;
+
+ if (is_numeric($datetime))
+ $datetime = new DateTime('@'.$datetime, $tz);
+ else if (is_string($datetime))
+ $datetime = new DateTime($datetime, $tz);
+
+ if (is_a($datetime, 'DateTime')) {
+ $result = new KolabDateTime();
+ $result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j'), 0, 0, 0);
+
+ if (!$dateonly)
+ $result->setTime($datetime->format('G'), $datetime->format('i'), $datetime->format('s'));
+ if ($tz)
+ $result->setTimezone($tz->getName());
+ }
+
+ return $result;
+ }
+
+ /**
+ * Convert a libkolabxml vector to a PHP array
+ *
+ * @param object vector Object
+ * @return array Indexed array contaning vector elements
+ */
+ public static function vector2array($vec)
+ {
+ $arr = array();
+ for ($i=0; $i < $vec->size(); $i++)
+ $arr[] = $vec->get($i);
+ return $arr;
+ }
+
+ /**
+ * Load Kolab object data from the given XML block
+ *
+ * @param string XML data
+ */
+ abstract public function load($xml);
+
+ /**
+ * Set properties to the kolabformat object
+ *
+ * @param array Object data as hash array
+ */
+ abstract public function set(&$object);
+
+ /**
+ *
+ */
+ abstract public function is_valid();
+
+ /**
+ * Write object data to XML format
+ *
+ * @return string XML data
+ */
+ abstract public function write();
+
+ /**
+ * Convert the Kolab object into a hash array data structure
+ *
+ * @return array Kolab object data as hash array
+ */
+ abstract public function to_array();
+
+}
diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php
new file mode 100644
index 00000000..918355f8
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_format_contact.php
@@ -0,0 +1,244 @@
+<?php
+
+
+class kolab_format_contact extends kolab_format
+{
+ public $CTYPE = 'application/vcard+xml';
+
+ private $data;
+ private $obj;
+
+ // old Kolab 2 format field map
+ private $kolab2_fieldmap = array(
+ // kolab => roundcube
+ 'full-name' => 'name',
+ 'given-name' => 'firstname',
+ 'middle-names' => 'middlename',
+ 'last-name' => 'surname',
+ 'prefix' => 'prefix',
+ 'suffix' => 'suffix',
+ 'nick-name' => 'nickname',
+ 'organization' => 'organization',
+ 'department' => 'department',
+ 'job-title' => 'jobtitle',
+ 'initials' => 'initials',
+ 'birthday' => 'birthday',
+ 'anniversary' => 'anniversary',
+ 'phone' => 'phone',
+ 'im-address' => 'im',
+ 'web-page' => 'website',
+ 'office-location' => 'officelocation',
+ 'profession' => 'profession',
+ 'manager-name' => 'manager',
+ 'assistant' => 'assistant',
+ 'spouse-name' => 'spouse',
+ 'children' => 'children',
+ 'body' => 'notes',
+ 'pgp-publickey' => 'pgppublickey',
+ 'free-busy-url' => 'freebusyurl',
+ 'gender' => 'gender',
+ );
+
+ function __construct()
+ {
+ $this->obj = new Contact;
+ }
+
+ /**
+ * Load Contact object data from the given XML block
+ *
+ * @param string XML data
+ */
+ public function load($xml)
+ {
+ $this->obj = kolabformat::readContact($xml, false);
+ }
+
+ /**
+ * Write Contact object data to XML format
+ *
+ * @return string XML data
+ */
+ public function write()
+ {
+ return kolabformat::writeContact($this->obj);
+ }
+
+ /**
+ * Set contact properties to the kolabformat object
+ *
+ * @param array Contact data as hash array
+ */
+ public function set(&$object)
+ {
+ // set some automatic values if missing
+ if (empty($object['uid']))
+ $object['uid'] = self::generate_uid();
+
+ if (false && !$this->obj->created()) {
+ if (!empty($object['created']))
+ $object['created'] = new DateTime('now', self::$timezone);
+ $this->obj->setCreated(self::getDateTime($object['created']));
+ }
+
+ // do the hard work of setting object values
+ $this->obj->setUid($object['uid']);
+
+ $nc = new NameComponents;
+ // surname
+ $sn = new vectors();
+ $sn->push($object['surname']);
+ $nc->setSurnames($sn);
+ // firstname
+ $gn = new vectors();
+ $gn->push($object['firstname']);
+ $nc->setGiven($gn);
+ // middle name
+ $mn = new vectors();
+ if ($object['middlename'])
+ $mn->push($object['middlename']);
+ $nc->setAdditional($mn);
+ // prefix
+ $px = new vectors();
+ if ($object['prefix'])
+ $px->push($object['prefix']);
+ $nc->setPrefixes($px);
+ // suffix
+ $sx = new vectors();
+ if ($object['suffix'])
+ $sx->push($object['suffix']);
+ $nc->setSuffixes($sx);
+
+ $this->obj->setNameComponents($nc);
+ $this->obj->setName($object['name']);
+
+ // email addresses
+ $emails = new vectors;
+ foreach ($object['email'] as $em)
+ $emails->push($em);
+ $this->obj->setEmailAddresses($emails);
+
+ // addresses
+ $adrs = new vectoraddress;
+ foreach ($object['address'] as $address) {
+ $adr = new Address;
+ $adr->setTypes($address['type'] == 'work' ? Address::Work : Address::Home);
+ if ($address['street'])
+ $adr->setStreet($address['street']);
+ if ($address['locality'])
+ $adr->setLocality($address['locality']);
+ if ($address['code'])
+ $adr->setCode($address['code']);
+ if ($address['region'])
+ $adr->setRegion($address['region']);
+ if ($address['country'])
+ $adr->setCountry($address['country']);
+
+ $adrs->push($adr);
+ }
+ $this->obj->setAddresses($adrs);
+
+ // cache this data
+ $this->data = $object;
+ }
+
+ /**
+ *
+ */
+ public function is_valid()
+ {
+ return $this->data || (is_object($this->obj) && true /*$this->obj->isValid()*/);
+ }
+
+
+ /**
+ * Convert the Contact object into a hash array data structure
+ *
+ * @return array Contact data as hash array
+ */
+ public function to_array()
+ {
+ // return cached result
+ if (!empty($this->data))
+ return $this->data;
+
+ // TODO: read object properties into local data object
+ $object = array(
+ 'uid' => $this->obj->uid(),
+ # 'changed' => $this->obj->lastModified(),
+ 'name' => $this->obj->name(),
+ );
+
+ $nc = $this->obj->nameComponents();
+ $object['surname'] = join(' ', self::vector2array($nc->surnames()));
+ $object['firstname'] = join(' ', self::vector2array($nc->given()));
+ $object['middlename'] = join(' ', self::vector2array($nc->additional()));
+ $object['prefix'] = join(' ', self::vector2array($nc->prefixes()));
+ $object['suffix'] = join(' ', self::vector2array($nc->suffixes()));
+
+ $object['email'] = self::vector2array($this->obj->emailAddresses());
+
+ $addresses = $this->obj->addresses();
+ for ($i=0; $i < $addresses->size(); $i++) {
+ $adr = $addresses->get($i);
+ $object['address'][] = array(
+ 'type' => $adr->types() == Address::Work ? 'work' : 'home',
+ 'street' => $adr->street(),
+ 'code' => $adr->code(),
+ 'locality' => $adr->locality(),
+ 'region' => $adr->region(),
+ 'country' => $adr->country()
+ );
+ }
+
+ $this->data = $object;
+ return $this->data;
+ }
+
+ /**
+ * Load data from old Kolab2 format
+ */
+ public function fromkolab2($record)
+ {
+ $object = array(
+ 'uid' => $record['uid'],
+ 'email' => array(),
+ 'phone' => array(),
+ );
+
+ foreach ($this->kolab2_fieldmap as $kolab => $rcube) {
+ if (is_array($record[$kolab]) || strlen($record[$kolab]))
+ $object[$rcube] = $record[$kolab];
+ }
+
+ if (isset($record['gender']))
+ $object['gender'] = $this->gender_map[$record['gender']];
+
+ foreach ((array)$record['email'] as $i => $email)
+ $object['email'][] = $email['smtp-address'];
+
+ if (!$record['email'] && $record['emails'])
+ $object['email'] = preg_split('/,\s*/', $record['emails']);
+
+ if (is_array($record['address'])) {
+ foreach ($record['address'] as $i => $adr) {
+ $object['address'][] = array(
+ 'type' => $adr['type'],
+ 'street' => $adr['street'],
+ 'locality' => $adr['locality'],
+ 'code' => $adr['postal-code'],
+ 'region' => $adr['region'],
+ 'country' => $adr['country'],
+ );
+ }
+ }
+
+ // photo is stored as separate attachment
+ if ($record['picture'] && ($att = $record['_attachments'][$record['picture']])) {
+ $object['photo'] = $att['content'] ? $att['content'] : $this->contactstorage->getAttachment($att['key']);
+ }
+
+ // remove empty fields
+ $this->data = array_filter($object);
+ }
+}
diff --git a/plugins/libkolab/lib/kolab_format_distributionlist.php b/plugins/libkolab/lib/kolab_format_distributionlist.php
new file mode 100644
index 00000000..a1f5891b
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_format_distributionlist.php
@@ -0,0 +1,126 @@
+<?php
+
+
+class kolab_format_distributionlist extends kolab_format
+{
+ public $CTYPE = 'application/vcard+xml';
+
+ private $data;
+ private $obj;
+
+ function __construct()
+ {
+ $obj = new DistList;
+ }
+
+ /**
+ * Load Kolab object data from the given XML block
+ *
+ * @param string XML data
+ */
+ public function load($xml)
+ {
+ $this->obj = kolabformat::readDistlist($xml, false);
+ }
+
+ /**
+ * Write object data to XML format
+ *
+ * @return string XML data
+ */
+ public function write()
+ {
+ return kolabformat::writeDistlist($this->obj);
+ }
+
+ public function set(&$object)
+ {
+ // TODO: do the hard work of setting object values
+ }
+
+ public function is_valid()
+ {
+ return $this->data || (is_object($this->obj) && true /*$this->obj->isValid()*/);
+ }
+
+ /**
+ * Load data from old Kolab2 format
+ */
+ public function fromkolab2($record)
+ {
+ $object = array(
+ 'uid' => $record['uid'],
+ 'changed' => $record['last-modification-date'],
+ 'name' => $record['last-name'],
+ 'member' => array(),
+ );
+
+ foreach ($record['member'] as $member) {
+ $object['member'][] = array(
+ 'mailto' => $member['smtp-address'],
+ 'name' => $member['display-name'],
+ 'uid' => $member['uid'],
+ );
+ }
+
+ $this->data = $object;
+ }
+
+ /**
+ * Convert the Distlist object into a hash array data structure
+ *
+ * @return array Distribution list data as hash array
+ */
+ public function to_array()
+ {
+ // return cached result
+ if (!empty($this->data))
+ return $this->data;
+
+ // read object properties
+ $object = array(
+ 'uid' => $this->obj->uid(),
+# 'changed' => $this->obj->lastModified(),
+ 'name' => $this->obj->name(),
+ 'member' => array(),
+ );
+
+ $members = $this->obj->members();
+ for ($i=0; $i < $members->size(); $i++) {
+ $adr = self::decode_member($members->get($i));
+ if ($adr[0]['mailto'])
+ $object['member'][] = array(
+ 'mailto' => $adr[0]['mailto'],
+ 'name' => $adr[0]['name'],
+ 'uid' => '????',
+ );
+ }
+
+ return $this->data;
+ }
+
+ /**
+ * Compose a valid Mailto URL according to RFC 822
+ *
+ * @param string E-mail address
+ * @param string Person name
+ * @return string Formatted string
+ */
+ public static function format_member($email, $name = '')
+ {
+ // let Roundcube internals do the job
+ return 'mailto:' . format_email_recipient($email, $name);
+ }
+
+ /**
+ * Split a mailto: url into a structured member component
+ *
+ * @param string RFC 822 mailto: string
+ * @return array Hash array with member properties
+ */
+ public static function decode_member($str)
+ {
+ $adr = rcube_mime::decode_address_list(preg_replace('/^mailto:/', '', $str));
+ return $adr[0];
+ }
+}
diff --git a/plugins/libkolab/lib/kolab_format_event.php b/plugins/libkolab/lib/kolab_format_event.php
new file mode 100644
index 00000000..d8ab2764
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_format_event.php
@@ -0,0 +1,46 @@
+<?php
+
+
+class kolab_format_event extends kolab_format
+{
+ public $CTYPE = 'application/calendar+xml';
+
+ private $data;
+ private $obj;
+
+ function __construct()
+ {
+ $obj = new Event;
+ }
+
+ public function load($xml)
+ {
+ $this->obj = kolabformat::readEvent($xml, false);
+ }
+
+ public function write()
+ {
+ return kolabformat::writeEvent($this->obj);
+ }
+
+ public function set(&$object)
+ {
+ // TODO: do the hard work of setting object values
+ }
+
+ public function is_valid()
+ {
+ return is_object($this->obj) && $this->obj->isValid();
+ }
+
+ public function fromkolab2($object)
+ {
+ $this->data = $object;
+ }
+
+ public function to_array()
+ {
+ // TODO: read object properties
+ return $this->data;
+ }
+}
diff --git a/plugins/libkolab/lib/kolab_storage.php b/plugins/libkolab/lib/kolab_storage.php
new file mode 100644
index 00000000..ec93213f
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_storage.php
@@ -0,0 +1,206 @@
+<?php
+
+/**
+ * Kolab storage class providing static methods to access groupware objects on a Kolab server.
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+class kolab_storage
+{
+ const CTYPE_KEY = '/shared/vendor/kolab/folder-type';
+
+ public static $last_error;
+
+ private static $ready = false;
+ private static $config;
+ private static $cache;
+ private static $imap;
+
+
+ /**
+ * Setup the environment needed by the libs
+ */
+ public static function setup()
+ {
+ if (self::$ready)
+ return;
+
+ $rcmail = rcmail::get_instance();
+ self::$config = $rcmail->config;
+ self::$imap = $rcmail->get_storage();
+ self::$ready = class_exists('kolabformat') && $rcmail->storage_connect() &&
+ (self::$imap->get_capability('METADATA') || self::$imap->get_capability('ANNOTATEMORE') || self::$imap->get_capability('ANNOTATEMORE2'));
+
+ if (self::$ready) {
+ // set imap options
+ self::$imap->set_options(array(
+ 'skip_deleted' => true,
+ 'threading' => false,
+ ));
+ self::$imap->set_pagesize(9999);
+ }
+ }
+
+
+ /**
+ * Get a list of storage folders for the given data type
+ *
+ * @param string Data type to list folders for (contact,event,task,note)
+ *
+ * @return array List of Kolab_Folder objects (folder names in UTF7-IMAP)
+ */
+ public static function get_folders($type)
+ {
+ self::setup();
+ $folders = array();
+
+ if (self::$ready) {
+ foreach ((array)self::$imap->list_folders('', '*', $type) as $foldername) {
+ $folders[$foldername] = new kolab_storage_folder($foldername, self::$imap);
+ }
+ }
+
+ return $folders;
+ }
+
+
+ /**
+ * Getter for a specific storage folder
+ *
+ * @param string IMAP folder to access (UTF7-IMAP)
+ * @return object Kolab_Folder The folder object
+ */
+ public static function get_folder($folder)
+ {
+ self::setup();
+ return self::$ready ? new kolab_storage_folder($folder, null, self::$imap) : null;
+ }
+
+
+ /**
+ *
+ */
+ public static function get_freebusy_server()
+ {
+ return unslashify(self::$config->get('kolab_freebusy_server', 'https://' . $_SESSION['imap_host'] . '/freebusy'));
+ }
+
+
+ /**
+ * Compose an URL to query the free/busy status for the given user
+ */
+ public static function get_freebusy_url($email)
+ {
+ return self::get_freebusy_server() . '/' . $email . '.ifb';
+ }
+
+
+ /**
+ * Creates folder ID from folder name
+ *
+ * @param string $folder Folder name (UTF7-IMAP)
+ *
+ * @return string Folder ID string
+ */
+ public static function folder_id($folder)
+ {
+ return asciiwords(strtr($folder, '/.-', '___'));
+ }
+
+
+ /**
+ * Getter for human-readable name of Kolab object (folder)
+ * See http://wiki.kolab.org/UI-Concepts/Folder-Listing for reference
+ *
+ * @param string $folder IMAP folder name (UTF7-IMAP)
+ * @param string $folder_ns Will be set to namespace name of the folder
+ *
+ * @return string Name of the folder-object
+ */
+ public static function object_name($folder, &$folder_ns=null)
+ {
+ self::setup();
+
+ $found = false;
+ $namespace = self::$imap->get_namespace();
+
+ if (!empty($namespace['shared'])) {
+ foreach ($namespace['shared'] as $ns) {
+ if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
+ $prefix = '';
+ $folder = substr($folder, strlen($ns[0]));
+ $delim = $ns[1];
+ $found = true;
+ $folder_ns = 'shared';
+ break;
+ }
+ }
+ }
+ if (!$found && !empty($namespace['other'])) {
+ foreach ($namespace['other'] as $ns) {
+ if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
+ // remove namespace prefix
+ $folder = substr($folder, strlen($ns[0]));
+ $delim = $ns[1];
+ // get username
+ $pos = strpos($folder, $delim);
+ if ($pos) {
+ $prefix = '('.substr($folder, 0, $pos).') ';
+ $folder = substr($folder, $pos+1);
+ }
+ else {
+ $prefix = '('.$folder.')';
+ $folder = '';
+ }
+ $found = true;
+ $folder_ns = 'other';
+ break;
+ }
+ }
+ }
+ if (!$found && !empty($namespace['personal'])) {
+ foreach ($namespace['personal'] as $ns) {
+ if (strlen($ns[0]) && strpos($folder, $ns[0]) === 0) {
+ // remove namespace prefix
+ $folder = substr($folder, strlen($ns[0]));
+ $prefix = '';
+ $delim = $ns[1];
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ if (empty($delim))
+ $delim = self::$imap->get_hierarchy_delimiter();
+
+ $folder = rcube_charset::convert($folder, 'UTF7-IMAP');
+ $folder = str_replace($delim, ' &raquo; ', $folder);
+
+ if ($prefix)
+ $folder = $prefix . ' ' . $folder;
+
+ if (!$folder_ns)
+ $folder_ns = 'personal';
+
+ return $folder;
+ }
+
+}
diff --git a/plugins/libkolab/lib/kolab_storage_folder.php b/plugins/libkolab/lib/kolab_storage_folder.php
new file mode 100644
index 00000000..0c15be74
--- /dev/null
+++ b/plugins/libkolab/lib/kolab_storage_folder.php
@@ -0,0 +1,498 @@
+<?php
+
+/**
+ * The kolab_storage_folder class represents an IMAP folder on the Kolab server.
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+class kolab_storage_folder
+{
+ const KTYPE_PREFIX = 'application/x-vnd.kolab.';
+
+ /**
+ * The folder name.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * The type of this folder.
+ *
+ * @var string
+ */
+ public $type;
+
+ private $type_annotation;
+ private $subpath;
+ private $imap;
+ private $info;
+ private $owner;
+ private $uid2msg = array();
+
+
+ /**
+ * Default constructor
+ */
+ function __construct($name, $imap = null)
+ {
+ $this->name = $name;
+ $this->imap = is_object($imap) ? $imap : rcmail::get_instance()->get_storage();
+ $this->imap->set_folder($this->name);
+
+ $metadata = $this->imap->get_metadata($this->name, array(kolab_storage::CTYPE_KEY));
+ $this->type_annotation = $metadata[$this->name][kolab_storage::CTYPE_KEY];
+ $this->type = reset(explode('.', $this->type_annotation));
+ }
+
+
+ /**
+ *
+ */
+ private function get_folder_info()
+ {
+ if (!isset($this->info))
+ $this->info = $this->imap->folder_info($this->name);
+
+ return $this->info;
+ }
+
+
+ /**
+ * Returns the owner of the folder.
+ *
+ * @return string The owner of this folder.
+ */
+ public function get_owner()
+ {
+ // return cached value
+ if (isset($this->owner))
+ return $this->owner;
+
+ $info = $this->get_folder_info();
+ $rcmail = rcmail::get_instance();
+
+ switch ($info['namespace']) {
+ case 'personal':
+ $this->owner = $rcmail->user->get_username();
+ break;
+
+ case 'shared':
+ $this->owner = 'anonymous';
+ break;
+
+ default:
+ $owner = '';
+ list($prefix, $user) = explode($this->imap->get_hierarchy_delimiter(), $info['name']);
+ if (strpos($user, '@') === false) {
+ $domain = strstr($rcmail->user->get_username(), '@');
+ if (!empty($domain))
+ $user .= $domain;
+ }
+ $this->owner = $user;
+ break;
+ }
+
+ return $this->owner;
+ }
+
+
+ /**
+ * Getter for the name of the namespace to which the IMAP folder belongs
+ *
+ * @return string Name of the namespace (personal, other, shared)
+ */
+ public function get_namespace()
+ {
+ return $this->imap->folder_namespace($this->name);
+ }
+
+
+ /**
+ * Get IMAP ACL information for this folder
+ *
+ * @return string Permissions as string
+ */
+ function get_acl()
+ {
+ return join('', (array)$this->imap->get_acl($this->name));
+ }
+
+
+ /**
+ * List all Kolab objects of the given type
+ *
+ * @param string $type Object type (e.g. contact, event, todo, journal, note, configuration)
+ * @return array List of Kolab data objects (each represented as hash array)
+ */
+ function get_objects($type = null)
+ {
+ if (!$type) $type = $this->type;
+
+ // search by object type
+ $ctype = self::KTYPE_PREFIX . $type;
+ $search = 'HEADER X-Kolab-Type ' . $ctype;
+
+ $index = $this->imap->search_once($this->name, $search);
+ $results = array();
+
+ // fetch all messages from IMAP
+ foreach ($index->get() as $msguid) {
+ if ($object = $this->read_object($msguid, $type)) {
+ $results[] = $object;
+ $this->uid2msg[$object['uid']] = $msguid;
+ }
+ }
+
+ // TODO: write $this->uid2msg to cache
+
+ return $results;
+ }
+
+
+ /**
+ * Getter for a single Kolab object, identified by its UID
+ *
+ * @param string Object UID
+ * @return array The Kolab object represented as hash array
+ */
+ public function get_object($uid)
+ {
+ $msguid = $this->uid2msguid($uid);
+ if ($msguid && ($object = $this->read_object($msguid)))
+ return $object;
+
+ return array('uid' => $uid);
+ }
+
+
+ /**
+ * Fetch a Kolab object attachment which is stored in a separate part
+ * of the mail MIME message that represents the Kolab record.
+ *
+ * @param string Object's UID
+ * @param string The attachment key stored in the Kolab XML
+ * @return mixed The attachment content as binary string
+ */
+ public function get_attachment($uid, $key)
+ {
+ // TODO: implement this
+
+ if ($msguid = $this->uid2msguid($uid)) {
+ $message = new rcube_message($msguid);
+ }
+
+ return null;
+ }
+
+
+ /**
+ *
+ */
+ private function read_object($msguid, $type = null)
+ {
+ if (!$type) $type = $this->type;
+ $ctype= self::KTYPE_PREFIX . $type;
+
+ $this->imap->set_folder($this->name);
+ $message = new rcube_message($msguid);
+
+ // get XML part
+ foreach ((array)$message->attachments as $part) {
+ if ($part->mimetype == $ctype || preg_match('!application/([a-z]+\+)?xml!', $part->mimetype)) {
+ $xml = $part->body ? $part->body : $message->get_part_content($part->mime_id);
+ break;
+ }
+ }
+
+ if (!$xml) {
+ raise_error(array(
+ 'code' => 600,
+ 'type' => 'php',
+ 'file' => __FILE__,
+ 'line' => __LINE__,
+ 'message' => "Could not find Kolab data part in message " . $this->name . ':' . $uid,
+ ), true);
+ return false;
+ }
+
+ $format = kolab_format::factory($type);
+
+ // check kolab format version
+ if (strpos($xml, '<' . $type) !== false) {
+ // old Kolab 2.0 format detected
+ $handler = Horde_Kolab_Format::factory('XML', $type);
+ if (is_object($handler) && is_a($handler, 'PEAR_Error')) {
+ continue;
+ }
+
+ // XML-to-array
+ $object = $handler->load($xml);
+ $format->fromkolab2($object);
+ }
+ else {
+ // load Kolab 3 format using libkolabxml
+ $format->load($xml);
+ }
+
+ if ($format->is_valid()) {
+ $object = $format->to_array();
+ $object['_msguid'] = $msguid;
+ $object['_mailbox'] = $this->name;
+ return $object;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Save an object in this folder.
+ *
+ * @param array $object The array that holds the data of the object.
+ * @param string $type The type of the kolab object.
+ * @param string $uid The UID of the old object if it existed before
+ * @return boolean True on success, false on error
+ */
+ public function save(&$object, $type, $uid = null)
+ {
+ if (!$type)
+ $type = $this->type;
+
+ if ($raw_msg = $this->build_message($object, $type)) {
+ $result = $this->imap->save_message($this->name, $raw_msg, '', false);
+
+ // delete old message
+ if ($result && !empty($object['_msguid']) && !empty($object['_mailbox'])) {
+ $this->imap->delete_message($object['_msguid'], $object['_mailbox']);
+ }
+ else if ($result && $uid && ($msguid = $this->uid2msguid($uid))) {
+ $this->imap->delete_message($msguid, $this->name);
+ }
+
+ // TODO: update cache with new UID
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * Delete the specified object from this folder.
+ *
+ * @param array $object The Kolab object to delete
+ * @param boolean $trigger Should the folder be triggered?
+ * @param boolean $expunge Should the folder be expunged?
+ *
+ * @return boolean True if successful, false on error
+ */
+ function delete($object, $trigger = true, $expunge = true)
+ {
+ if (!empty($object['_msguid'])) {
+ return $this->imap->delete_message($object['_msguid'], $this->name);
+ }
+
+ return false;
+ }
+
+
+ /**
+ *
+ */
+ public function delete_all()
+ {
+ return $this->imap->clear_folder($this->name);
+ }
+
+
+ /**
+ * Resolve an object UID into an IMAP message UID
+ */
+ private function uid2msguid($uid)
+ {
+ if (!isset($this->uid2msg[$uid])) {
+ // use IMAP SEARCH to get the right message
+ $index = $this->imap->search_once($this->name, 'HEADER SUBJECT ' . $uid);
+ $results = $index->get();
+ $this->uid2msg[$uid] = $results[0];
+
+ // TODO: cache this lookup
+ }
+
+ return $this->uid2msg[$uid];
+ }
+
+
+ /**
+ * Creates source of the configuration object message
+ */
+ private function build_message(&$object, $type)
+ {
+ $format = kolab_format::factory($type);
+ $format->set($object);
+ $xml = $format->write();
+
+ if (!$format->is_valid()) {
+ return false;
+ }
+
+ $mime = new Mail_mime("\r\n");
+ $rcmail = rcmail::get_instance();
+ $headers = array();
+
+ if ($ident = $rcmail->user->get_identity()) {
+ $headers['From'] = $ident['email'];
+ $headers['To'] = $ident['email'];
+ }
+ $headers['Date'] = date('r');
+ $headers['X-Kolab-Type'] = self::KTYPE_PREFIX . $type;
+ $headers['Subject'] = $object['uid'];
+// $headers['Message-ID'] = rcmail_gen_message_id();
+ $headers['User-Agent'] = $rcmail->config->get('useragent');
+
+ $mime->headers($headers);
+ $mime->setTXTBody('This is a Kolab Groupware object. '
+ . 'To view this object you will need an email client that understands the Kolab Groupware format. '
+ . "For a list of such email clients please visit http://www.kolab.org/kolab2-clients.html\n\n");
+
+ $mime->addAttachment($xml,
+ $format->CTYPE,
+ 'kolab.xml',
+ false, '8bit', 'attachment', RCMAIL_CHARSET, '', '',
+ $rcmail->config->get('mime_param_folding') ? 'quoted-printable' : null,
+ $rcmail->config->get('mime_param_folding') == 2 ? 'quoted-printable' : null,
+ '', RCMAIL_CHARSET
+ );
+
+ return $mime->getMessage();
+ }
+
+
+ /**
+ * Triggers any required updates after changes within the
+ * folder. This is currently only required for handling free/busy
+ * information with Kolab.
+ *
+ * @return boolean|PEAR_Error True if successfull.
+ */
+ public function trigger()
+ {
+ $owner = $this->get_owner();
+
+ switch($this->type) {
+ case 'event':
+ $url = sprintf('%s/trigger/%s/%s.pfb', kolab_storage::get_freebusy_server(), $owner, $this->subpath);
+ break;
+
+ default:
+ return true;
+ }
+
+ $result = $this->trigger_url($url);
+ if (is_a($result, 'PEAR_Error')) {
+ return PEAR::raiseError(sprintf("Failed triggering folder %s. Error was: %s"),
+ $this->name, $result->getMessage());
+ }
+ return $result;
+ }
+
+ /**
+ * Triggers a URL.
+ *
+ * @param string $url The URL to be triggered.
+ * @return boolean|PEAR_Error True if successfull.
+ */
+ private function trigger_url($url)
+ {
+ // TBD.
+ return PEAR::raiseError("Feature not implemented.");
+ }
+
+
+ /* Legacy methods to keep compatibility with the old Horde Kolab_Storage classes */
+
+ /**
+ * Compatibility method
+ */
+ public function getOwner()
+ {
+ console("Call to deprecated method kolab_storage_folder::getOwner()");
+ return $this->get_owner();
+ }
+
+ /**
+ * Get IMAP ACL information for this folder
+ */
+ public function getMyRights()
+ {
+ return $this->get_acl();
+ }
+
+ /**
+ * NOP to stay compatible with the formerly used Horde classes
+ */
+ public function getData()
+ {
+ return $this;
+ }
+
+ /**
+ * List all Kolab objects of the given type
+ */
+ public function getObjects($type = null)
+ {
+ return $this->get_objects($type);
+ }
+
+ /**
+ * Getter for a single Kolab object, identified by its UID
+ */
+ public function getObject($uid)
+ {
+ return $this->get_object($uid);
+ }
+
+ /**
+ *
+ */
+ public function getAttachment($key)
+ {
+ PEAR::raiseError("Call to deprecated method not returning anything.");
+ return null;
+ }
+
+ /**
+ * Alias function of delete()
+ */
+ public function deleteMessage($id, $trigger = true, $expunge = true)
+ {
+ return $this->delete(array('_msguid' => $id), $trigger, $expunge);
+ }
+
+ /**
+ *
+ */
+ public function deleteAll()
+ {
+ return $this->delete_all();
+ }
+
+
+}
+
diff --git a/plugins/libkolab/libkolab.php b/plugins/libkolab/libkolab.php
new file mode 100644
index 00000000..9092f463
--- /dev/null
+++ b/plugins/libkolab/libkolab.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Kolab core library
+ *
+ * Plugin to setup a basic environment for the interaction with a Kolab server.
+ * Other Kolab-related plugins will depend on it and can use the library classes
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+class libkolab extends rcube_plugin
+{
+ /**
+ * Required startup method of a Roundcube plugin
+ */
+ public function init()
+ {
+ // load local config
+ $this->load_config();
+
+ // extend include path to load bundled lib classes
+ $include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path');
+ set_include_path($include_path);
+
+ $rcmail = rcmail::get_instance();
+ kolab_format::$timezone = new DateTimeZone($rcmail->config->get('timezone', 'GMT'));
+
+ // load (old) dependencies
+ require_once 'Horde/Util.php';
+ require_once 'Horde/Kolab/Format.php';
+ require_once 'Horde/Kolab/Format/XML.php';
+ require_once 'Horde/Kolab/Format/XML/contact.php';
+ require_once 'Horde/Kolab/Format/XML/event.php';
+
+ String::setDefaultCharset('UTF-8');
+ }
+
+
+}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Aug 17, 10:33 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1261675
Default Alt Text
(39 KB)

Event Timeline