Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F9785900
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/plugins/kolab_config/kolab_config.php b/plugins/kolab_config/kolab_config.php
new file mode 100644
index 00000000..03aa3864
--- /dev/null
+++ b/plugins/kolab_config/kolab_config.php
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * Kolab configuration storage.
+ *
+ * Plugin to use Kolab server as a configuration storage. Provides an API to handle
+ * configuration according to http://wiki.kolab.org/KEP:9.
+ *
+ * Copyright (C) 2011, Kolab Systems AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * @author Machniak Aleksander <machniak@kolabsys.com>
+ *
+ */
+class kolab_config extends rcube_plugin
+{
+ public $task = 'utils';
+
+ private $config;
+ private $enabled;
+
+ /**
+ * Required startup method of a Roundcube plugin
+ */
+ public function init()
+ {
+ $rcmail = rcmail::get_instance();
+
+ // Register spellchecker dictionary handlers
+ if (strtolower($rcmail->config->get('spellcheck_dictionary')) != 'shared') {
+ $this->add_hook('spell_dictionary_save', array($this, 'dictionary_save'));
+ $this->add_hook('spell_dictionary_get', array($this, 'dictionary_get'));
+ }
+/*
+ // Register addressbook saved searches handlers
+ $this->add_hook('saved_search_create', array($this, 'saved_search_create'));
+ $this->add_hook('saved_search_delete', array($this, 'saved_search_delete'));
+ $this->add_hook('saved_search_list', array($this, 'saved_search_list'));
+ $this->add_hook('saved_search_get', array($this, 'saved_search_get'));
+*/
+ }
+
+ /**
+ * Initializes config object and dependencies
+ */
+ private function load()
+ {
+ if ($this->config)
+ return;
+
+ $this->require_plugin('kolab_folders');
+
+ // load dependencies
+ require_once 'Horde/Util.php';
+ require_once 'Horde/Kolab/Format.php';
+ require_once 'Horde/Kolab/Format/XML.php';
+ require_once $this->home . '/lib/configuration.php';
+ require_once $this->home . '/lib/kolab_configuration.php';
+
+ String::setDefaultCharset('UTF-8');
+
+ $this->config = new kolab_configuration();
+
+ // check if configuration folder exist
+ if (strlen($this->config->dir)) {
+ $this->enabled = true;
+ }
+ }
+
+ /**
+ * Saves spellcheck dictionary.
+ *
+ * @param array $args Hook arguments
+ *
+ * @return array Hook arguments
+ */
+ public function dictionary_save($args)
+ {
+ $this->load();
+
+ if (!$this->enabled) {
+ return $args;
+ }
+
+ $lang = $args['language'];
+ $dict = $this->dict;
+
+ $dict['type'] = 'dictionary';
+ $dict['language'] = $args['language'];
+ $dict['e'] = $args['dictionary'];
+
+ if (empty($dict['e'])) {
+ // Delete the object
+ $this->config->del($dict);
+ }
+ else {
+ // Update the object
+ $this->config->set($dict);
+ }
+
+ $args['abort'] = true;
+
+ return $args;
+ }
+
+ /**
+ * Returns spellcheck dictionary.
+ *
+ * @param array $args Hook arguments
+ *
+ * @return array Hook arguments
+ */
+ public function dictionary_get($args)
+ {
+ $this->load();
+
+ if (!$this->enabled) {
+ return $args;
+ }
+
+ $lang = $args['language'];
+ $this->dict = $this->config->get('dictionary.'.$lang);
+
+ if (!empty($this->dict)) {
+ $args['dictionary'] = $this->dict['e'];
+ }
+
+ $args['abort'] = true;
+
+ return $args;
+ }
+}
diff --git a/plugins/kolab_config/lib/configuration.php b/plugins/kolab_config/lib/configuration.php
new file mode 100644
index 00000000..e8c127fb
--- /dev/null
+++ b/plugins/kolab_config/lib/configuration.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * Kolab XML handler for configuration (KEP:9).
+ *
+ * Copyright (C) 2011 Kolab Systems AG
+ *
+ * @author Aleksander Machniak <machniak@kolabsys.com>
+ */
+class Horde_Kolab_Format_XML_configuration extends Horde_Kolab_Format_XML {
+ /**
+ * Specific data fields for the configuration object
+ *
+ * @var Kolab
+ */
+ var $_fields_specific;
+
+ var $_root_version = 2.1;
+
+ /**
+ * Constructor
+ */
+ function Horde_Kolab_Format_XML_configuration($params = array())
+ {
+ $this->_root_name = 'configuration';
+
+ // Specific configuration fields, in kolab format specification order
+ $this->_fields_specific = array(
+ 'application' => array (
+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
+ ),
+ 'type' => array(
+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
+ ),
+ );
+
+ // Dictionary fields
+ if (!empty($params['subtype']) && preg_match('/^dictionary.*/', $params['subtype'])) {
+ $this->_fields_specific = array_merge($this->_fields_specific, array(
+ 'language' => array (
+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
+ ),
+ 'e' => array(
+ 'type' => HORDE_KOLAB_XML_TYPE_MULTIPLE,
+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
+ 'array' => array(
+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
+ ),
+ ),
+ ));
+ }
+
+ parent::Horde_Kolab_Format_XML($params);
+
+ unset($this->_fields_basic['body']);
+ unset($this->_fields_basic['categories']);
+ unset($this->_fields_basic['sensitivity']);
+ }
+}
diff --git a/plugins/kolab_config/lib/kolab_configuration.php b/plugins/kolab_config/lib/kolab_configuration.php
new file mode 100644
index 00000000..9fc4b7b4
--- /dev/null
+++ b/plugins/kolab_config/lib/kolab_configuration.php
@@ -0,0 +1,232 @@
+<?php
+
+/**
+ * Kolab configuration storage handler.
+ *
+ * Copyright (C) 2011, Kolab Systems AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * @author Machniak Aleksander <machniak@kolabsys.com>
+ */
+class kolab_configuration
+{
+ public $dir;
+ private $rc;
+ private $imap_data = array();
+
+ /**
+ * Class constructor. Establishes IMAP connection.
+ */
+ public function __construct()
+ {
+ $this->rc = rcmail::get_instance();
+
+ // Connect to IMAP
+ $this->rc->imap_connect();
+
+ // Get default configuration directory
+ // @TODO: handle many config directories, according to KEP:9
+ $dirs = $this->rc->imap->list_unsubscribed('', '*', 'configuration');
+ $this->dir = array_shift($dirs);
+ }
+
+ /**
+ * Returns configuration object
+ *
+ * @param string $type Configuration object type
+ *
+ * @return array Configuration object
+ */
+ public function get($type)
+ {
+ // If config folder exists
+ if (isset($this->dir[0])) {
+ // search by object type
+ // @TODO: configuration folders shouldn't be big, consider
+ // caching of all objects, then if we extend cache with object type
+ // column we could simply search in cache.
+ // @TODO: handle many config directories, according to KEP:9
+ $ctype = 'application/x-vnd.kolab.configuration' . ($type ? '.'.$type : '');
+ $search = 'HEADER X-Kolab-Type ' . $ctype;
+
+ $this->set_imap_props();
+ $this->rc->imap->search($this->dir, $search, 'US-ASCII', 'date');
+
+ $list = $this->rc->imap->list_headers($this->dir, 1, 'date', 'DESC');
+ $this->reset_imap_props();
+
+ foreach ($list as $idx => $obj) {
+ // @TODO: maybe we could skip parsing the message structure and
+ // get second part's body directly
+ $msg = new rcube_message($obj->uid);
+ $xml = null;
+
+ // get XML part
+ foreach ((array)$msg->attachments as $part) {
+ if ($part->mimetype == 'application/xml') {
+ if (!$part->body)
+ $part->body = $msg->get_part_content($part->mime_id);
+ $xml = $part->body;
+ break;
+ }
+ }
+
+ // that shouldn't happen
+ if ($xml === null) {
+ continue;
+ }
+
+ // Load XML object parser
+ $handler = Horde_Kolab_Format::factory('XML', 'configuration', array('subtype' => $type));
+ if (is_object($handler) && is_a($handler, 'PEAR_Error')) {
+ return null;
+ }
+
+ // XML-to-array
+ $object = $handler->load($xml);
+
+ if (is_object($object) && is_a($object, 'PEAR_Error')) {
+ return null;
+ }
+
+ $object['mailbox'] = $this->dir;
+ $object['msguid'] = $obj->uid;
+
+ return $object;
+ }
+ }
+ }
+
+ /**
+ * Saves configuration object
+ *
+ * @param array $object Configuration object
+ *
+ * @return bool True on success, False on failre
+ */
+ public function set($object)
+ {
+ $object['uid'] = md5(uniqid(mt_rand(), true));
+ $raw_msg = $this->build_message($object);
+
+ if ($raw_msg && isset($this->dir[0])) {
+ $result = $this->rc->imap->save_message($this->dir, $raw_msg, '', false);
+ }
+
+ // delete old message
+ if ($result && !empty($object['msguid'])) {
+ $this->rc->imap->delete_message($object['msguid'], $object['mailbox']);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Deletes configuration object
+ *
+ * @param array $object Configuration object
+ *
+ * @return bool True on success, False on failre
+ */
+ public function del($object)
+ {
+ if (!empty($object['msguid'])) {
+ return $this->rc->imap->delete_message($object['msguid'], $object['mailbox']);
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets some rcube_imap settings before searching for config objects
+ */
+ private function set_imap_props()
+ {
+ // Save old settings
+ $this->imap_data = array(
+ 'skip_deleted' => $skip_deleted,
+ 'page_size' => $page_size,
+ 'list_page' => $list_page,
+ 'threading' => $threading,
+ );
+
+ // Configure for configuration folder
+ $this->rc->imap->skip_deleted = true;
+ $this->rc->imap->threading = false;
+ $this->rc->imap->page_size = 100;
+ $this->rc->imap->list_page = 1;
+ }
+
+ /**
+ * Resets rcube_imap settings after searching for config objects
+ */
+ private function reset_imap_props()
+ {
+ // Reset to old settings
+ foreach ($this->imap_data as $key => $val) {
+ $this->rc->imap->$key = $val;
+ }
+ // reset saved search
+ $this->rc->imap->search_set = null;
+ }
+
+ /**
+ * Creates source of the configuration object message
+ */
+ private function build_message($object)
+ {
+ $MAIL_MIME = new Mail_mime("\r\n");
+
+ $name = 'configuration';
+
+ if (!empty($object['type'])) {
+ $name .= '.' . $object['type'];
+ if ($object['type'] == 'dictionary' && !empty($object['language'])) {
+ $name .= '.' . $object['language'];
+ }
+ }
+
+ $handler = Horde_Kolab_Format::factory('XML', 'configuration',
+ array('subtype' => $object['type']));
+
+ if (is_object($handler) && is_a($handler, 'PEAR_Error')) {
+ return false;
+ }
+
+ $xml = $handler->save($object);
+
+ if (is_object($xml) && is_a($xml, 'PEAR_Error')) {
+ return false;
+ }
+
+ if ($ident = $this->rc->user->get_identity()) {
+ $headers['From'] = $ident['email'];
+ $headers['To'] = $ident['email'];
+ }
+ $headers['Date'] = date('r');
+ $headers['X-Kolab-Type'] = 'application/x-vnd.kolab.'.$name;
+ $headers['Subject'] = $object['uid'];
+ $headers['Message-ID'] = rcmail_gen_message_id();
+ $headers['User-Agent'] = $this->rc->config->get('useragent');
+
+ $MAIL_MIME->headers($headers);
+ $MAIL_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');
+
+ $MAIL_MIME->addAttachment($xml,
+ 'application/xml',
+ $name . '.xml',
+ false, '8bit', 'attachment', RCMAIL_CHARSET, '', '',
+ $this->rc->config->get('mime_param_folding') ? 'quoted-printable' : null,
+ $this->rc->config->get('mime_param_folding') == 2 ? 'quoted-printable' : null,
+ '', RCMAIL_CHARSET
+ );
+
+ return $MAIL_MIME->getMessage();
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Aug 17, 11:59 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1261716
Default Alt Text
(13 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment