summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthomasb <thomasb@208e9e7b-5314-0410-a742-e7e81cd9613c>2010-10-25 17:32:58 +0000
committerthomasb <thomasb@208e9e7b-5314-0410-a742-e7e81cd9613c>2010-10-25 17:32:58 +0000
commitf7f0624c07eb4e13a0e777f1f0a0fe740463538e (patch)
tree83bb6e22e54141622ec5dce9cd24633556459f02
parent20d07a78a8dbb49df6c94ddbdb45b19cad27039a (diff)
Work-in-progress Kolab address book plugin
git-svn-id: https://svn.roundcube.net/trunk@4134 208e9e7b-5314-0410-a742-e7e81cd9613c
-rw-r--r--plugins/kolab_addressbook/README.txt32
-rw-r--r--plugins/kolab_addressbook/config.inc.php.dist8
-rw-r--r--plugins/kolab_addressbook/kolab_addressbook.php32
-rw-r--r--plugins/kolab_addressbook/lib/rcube_kolab.php39
-rw-r--r--plugins/kolab_addressbook/rcube_kolab_contacts.php176
5 files changed, 253 insertions, 34 deletions
diff --git a/plugins/kolab_addressbook/README.txt b/plugins/kolab_addressbook/README.txt
new file mode 100644
index 000000000..87537c0b8
--- /dev/null
+++ b/plugins/kolab_addressbook/README.txt
@@ -0,0 +1,32 @@
+Kolab Integration Plugin README
+-------------------------------
+
+This plugin relies on classes from the Horde project. In order to have all
+the required files available you need to install the following packages from
+Horde:
+ Horde_Framework
+ Kolab_Format
+ Kolab_Storage
+ Horde_NLS
+ Horde_DOM
+
+This is best done using PEAR. Make sure that the local PEAR directory is in
+the PHP isntall path and execute the following commands to install the
+required packages:
+
+pear channel-discover pear.horde.org
+
+pear install horde/Horde_Framework
+pear install horde/Horde_DOM
+pear install horde/Horde_NLS
+pear install horde/Horde_Share
+pear install horde/Log
+pear install horde/Kolab_Format
+pear install horde/Kolab_Storage
+
+
+Configuration
+-------------
+
+Rename the config.inc.php.dist to config.inc.php within this plugin directory
+and add the corresponding values for your local Kolab server.
diff --git a/plugins/kolab_addressbook/config.inc.php.dist b/plugins/kolab_addressbook/config.inc.php.dist
new file mode 100644
index 000000000..b6ac25a4d
--- /dev/null
+++ b/plugins/kolab_addressbook/config.inc.php.dist
@@ -0,0 +1,8 @@
+<?php
+
+// Sample configuration for Kolab LDAP binding used by Kolab_Storage
+$rcmail_config['kolab']['ldap']['basedn'] = 'dc=kolabserver,dc=local';
+$rcmail_config['kolab']['ldap']['phpdn'] = 'cn=nobody,cn=internal,dc=kolabserver,dc=local';
+$rcmail_config['kolab']['ldap']['phppw'] = '<ldap-pwd-goes-here>';
+
+?>
diff --git a/plugins/kolab_addressbook/kolab_addressbook.php b/plugins/kolab_addressbook/kolab_addressbook.php
index 0e29c2ebb..9c8383e3d 100644
--- a/plugins/kolab_addressbook/kolab_addressbook.php
+++ b/plugins/kolab_addressbook/kolab_addressbook.php
@@ -17,23 +17,31 @@ require_once(dirname(__FILE__) . '/rcube_kolab_contacts.php');
class kolab_addressbook extends rcube_plugin
{
private $abook_id = 'kolab';
+ private $abook;
/**
* Required startup method of a Roundcube plugin
*/
public function init()
{
+ // load local config
+ $this->load_config();
+
$this->add_hook('addressbooks_list', array($this, 'address_sources'));
$this->add_hook('addressbook_get', array($this, 'get_address_book'));
+ $this->add_hook('imap_init', array($this, 'imap_init'));
// use this address book for autocompletion queries
- // (maybe this should be configurable by the user?)
$config = rcmail::get_instance()->config;
$sources = (array) $config->get('autocomplete_addressbooks', array('sql'));
if (!in_array($this->abook_id, $sources)) {
$sources[] = $this->abook_id;
$config->set('autocomplete_addressbooks', $sources);
}
+
+ // extend include path to load bundled Horde classes
+ $include_path = $this->home . '/lib' . PATH_SEPARATOR . ini_get('include_path');
+ set_include_path($include_path);
}
/**
@@ -47,10 +55,10 @@ class kolab_addressbook extends rcube_plugin
*/
public function address_sources($p)
{
- // could be changed to a factory call
- $abook = new rcube_kolab_contacts;
+ // get single instance (for now)
+ $abook = rcube_kolab_contacts::singleton();
- // maybe here we add more than one item.
+ // maybe here we'll add more than one item
$p['sources'][$this->abook_id] = array(
'id' => $this->abook_id,
'name' => 'Kolab',
@@ -60,16 +68,26 @@ class kolab_addressbook extends rcube_plugin
return $p;
}
+
/**
- *
+ * Getter for the rcube_addressbook instance
*/
public function get_address_book($p)
{
if ($p['id'] === $this->abook_id) {
- $p['instance'] = new rcube_kolab_contacts;
+ $p['instance'] = rcube_kolab_contacts::singleton();
}
-
+
return $p;
}
+
+ /**
+ * Make sure the X-Kolab-Type headers are also fetched when listing messages
+ */
+ function imap_init($p)
+ {
+ $p['fetch_headers'] = strtoupper('X-Kolab-Type');
+ return $p;
+ }
}
diff --git a/plugins/kolab_addressbook/lib/rcube_kolab.php b/plugins/kolab_addressbook/lib/rcube_kolab.php
index e3588f8f5..44c37a68f 100644
--- a/plugins/kolab_addressbook/lib/rcube_kolab.php
+++ b/plugins/kolab_addressbook/lib/rcube_kolab.php
@@ -1,5 +1,11 @@
<?php
+require_once 'Horde/Kolab/Format/XML.php';
+require_once 'Horde/Kolab/Storage/List.php';
+require_once 'Horde/Auth.php';
+require_once 'Horde/Auth/kolab.php';
+require_once 'Horde/Perms.php';
+
/**
* Glue class to handle access to the Kolab data using the Kolab_* classes
* from the Horde project.
@@ -8,24 +14,39 @@
*/
class rcube_kolab
{
+ private static $horde_auth;
+
/**
* Setup the environment needed by the Kolab_* classes to access Kolab data
*/
public static function setup()
{
+ global $conf;
+
+ // setup already done
+ if (self::$horde_auth)
+ return;
+
$rcmail = rcmail::get_instance();
- // if we need IMAP access through Roundcube IMAP class
- // $rcmail->imap_init();
-
- // get some config settings for the IMAP connection
- $imap_auth_method = $rcmail->config->get('imap_auth_type', 'check');
- $imap_delimiter = isset($_SESSION['imap_delimiter']) ? $_SESSION['imap_delimiter'] : $rcmail->config->get('imap_delimiter');
-
- // this is how we get the current IMAP authentication credentials:
- // $_SESSION['imap_host'], $_SESSION['username'], $rcmail->decrypt($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']
+ // load ldap credentials from local config
+ $conf['kolab'] = $rcmail->config->get('kolab');
+ $conf['kolab']['ldap']['server'] = 'ldap://' . $_SESSION['imap_host'] . ':389';
+ $conf['kolab']['imap']['server'] = $_SESSION['imap_host'];
+ $conf['kolab']['imap']['port'] = $_SESSION['imap_port'];
+ // pass the current IMAP authentication credentials to the Horde auth system
+ self::$horde_auth = Auth::singleton('kolab');
+ if (self::$horde_auth->authenticate($_SESSION['username'], array('password' => ($pwd = $rcmail->decrypt($_SESSION['password']))), false)) {
+ $_SESSION['__auth'] = array(
+ 'authenticated' => true,
+ 'userId' => $_SESSION['username'],
+ 'timestamp' => time(),
+ 'remote_addr' => $_SERVER['REMOTE_ADDR'],
+ );
+ Auth::setCredential('password', $pwd);
+ }
}
diff --git a/plugins/kolab_addressbook/rcube_kolab_contacts.php b/plugins/kolab_addressbook/rcube_kolab_contacts.php
index d209cce63..476202e33 100644
--- a/plugins/kolab_addressbook/rcube_kolab_contacts.php
+++ b/plugins/kolab_addressbook/rcube_kolab_contacts.php
@@ -1,7 +1,5 @@
<?php
-require_once(dirname(__FILE__) . '/lib/rcube_kolab.php');
-
/**
* Backend class for a custom address book
@@ -18,8 +16,29 @@ class rcube_kolab_contacts extends rcube_addressbook
public $readonly = true;
public $groups = true;
+ private static $instance;
+
+ private $_gid;
+ private $_imap;
+ private $_kolab;
+ private $_folder;
+ private $_data;
+ private $_groups;
+ private $_uid2index;
private $filter;
private $result;
+ private $imap_folder = 'INBOX/Contacts';
+
+
+ /**
+ * Singleton getter
+ */
+ public static function singleton()
+ {
+ if (!self::$instance)
+ self::$instance = new rcube_kolab_contacts;
+ return self::$instance;
+ }
public function __construct()
@@ -27,9 +46,36 @@ class rcube_kolab_contacts extends rcube_addressbook
// setup Kolab backend
rcube_kolab::setup();
- // $this->share = Kolab_Storage::getShare();
+ // fetch objects from Cotnacts folder
+ $this->_kolab = Kolab_List::singleton();
+ $this->_folder = $this->_kolab->getFolder($this->imap_folder);
+ $this->_storage = $this->_folder->getData();
+ $this->_objects = $this->_storage->getObjects();
+
+ // dump objects to log/console
+ console($this->_objects);
+
+ // TEMPORARY SOLUTION: use Roundcube's IMAP connection to fetch data
+ $rcmail = rcmail::get_instance();
+ $rcmail->imap_connect();
+ $this->_imap = $rcmail->imap;
+
+ $folders = $this->_imap->list_unsubscribed();
- $this->ready = true;
+ if (in_array($this->imap_folder, $folders)) {
+ $this->_imap->set_pagesize(9999);
+ $this->_imap->set_mailbox($this->imap_folder);
+ $this->ready = true;
+ }
+ }
+
+
+ /**
+ * Setter for the current group
+ */
+ function set_group($gid)
+ {
+ $this->_gid = $gid;
}
@@ -72,10 +118,11 @@ class rcube_kolab_contacts extends rcube_addressbook
*/
function list_groups($search = null)
{
- return array(
- #array('ID' => 'testgroup1', 'name' => "Testgroup"),
- #array('ID' => 'testgroup2', 'name' => "Sample Group"),
- );
+ $this->_fetch_data();
+ $groups = array();
+ foreach ($this->_groups as $group)
+ $groups[] = array('ID' => $group['ID'], 'name' => $group['last-name']);
+ return $groups;
}
/**
@@ -87,13 +134,76 @@ class rcube_kolab_contacts extends rcube_addressbook
*/
public function list_records($cols=null, $subset=0)
{
- $this->result = $this->count();
+ if ($this->_gid) {
+ $data = $this->_fetch_data();
+ $this->result = $this->count();
+
+ foreach ((array)$this->_groups[$this->_gid]['member'] as $member) {
+ $this->result->add($data->records[$this->_uid2index[$member['uid']]]);
+ }
+ }
+ else
+ $this->result = $this->_fetch_data();
- // Just return a sample contact record for now
- $this->result->add(array('ID' => '111', 'name' => "Kolab Contact", 'firstname' => "Kolab", 'surname' => "Contact", 'email' => "example@kolab.org"));
-
return $this->result;
}
+
+
+ /**
+ * Simply fetch all records and store them in a result_set object
+ */
+ private function _fetch_data()
+ {
+ if ($this->_data)
+ return $this->_data;
+
+ $this->_data = new rcube_result_set(0, ($this->list_page-1) * $this->page_size);
+ $this->_groups = $this->_uid2index = array();
+
+ $xml_contact = Horde_Kolab_Format_XML::factory('contact');
+ $xml_list = Horde_Kolab_Format_XML::factory('distributionlist');
+
+ $index = 0;
+ $headers = $this->_imap->list_headers();
+ foreach ($headers as $header) {
+ if ($type = $header->others['x-kolab-type']) {
+ if ($type == 'application/x-vnd.kolab.contact')
+ $loader = $xml_contact;
+ else if ($type == 'application/x-vnd.kolab.distribution-list')
+ $loader = $xml_list;
+ else
+ continue;
+
+ $record = $loader->load($this->_imap->get_message_part($header->uid, '2'));
+ if (PEAR::isError($record)) {
+ raise_error(array(
+ 'code' => 600, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Failed to load XML data from IMAP record:" . $record->getMessage()),
+ true, false);
+ }
+ else if ($type == 'application/x-vnd.kolab.contact') {
+ $this->_data->add(array(
+ 'ID' => md5($record['uid']),
+ 'name' => $record['full-name'],
+ 'firstname' => $record['given-name'],
+ 'surname' => $record['last-name'],
+ 'email' => $record['emails'],
+ ));
+ $this->_data->count++;
+ $this->_uid2index[$record['uid']] = $index++;
+ }
+ else if ($type == 'application/x-vnd.kolab.distribution-list') {
+ $record['ID'] = md5($record['uid']);
+ foreach ($record['member'] as $i => $member)
+ $record['member'][$i]['ID'] = md5($member['uid']);
+ $this->_groups[$record['ID']] = $record;
+ }
+ }
+ }
+
+ return $this->_data;
+ }
/**
@@ -118,7 +228,9 @@ class rcube_kolab_contacts extends rcube_addressbook
*/
public function count()
{
- return new rcube_result_set(1, ($this->list_page-1) * $this->page_size);
+ $this->_fetch_data();
+ $count = $this->_gid ? count($this->_groups[$this->_gid]['member']) : $this->_data->count;
+ return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
}
@@ -141,15 +253,43 @@ class rcube_kolab_contacts extends rcube_addressbook
*/
public function get_record($id, $assoc=false)
{
- $this->list_records();
- $first = $this->result->first();
- $sql_arr = $first['ID'] == $id ? $first : null;
-
- return $assoc && $sql_arr ? $sql_arr : $this->result;
+ $list = $this->_fetch_data();
+ $rec = $list->first();
+ do {
+ if ($rec['ID'] == $id)
+ break;
+ }
+ while ($rec = $list->next());
+
+ $this->result = new rcube_result_set(1);
+ $this->result->add($rec);
+
+ return $assoc ? $rec : $this->result;
}
/**
+ * Get group assignments of a specific contact record
+ *
+ * @param mixed Record identifier
+ * @return array List of assigned groups as ID=>Name pairs
+ */
+ function get_record_groups($id)
+ {
+ $out = array();
+
+ foreach ($this->_groups as $gid => $group) {
+ foreach ($group['member'] as $member) {
+ if ($member['ID'] == $id)
+ $out[$gid] = $group['last-name'];
+ }
+ }
+
+ return $out;
+ }
+
+
+ /**
* Close connection to source
* Called on script shutdown
*/