16 commits - bin/disable-all-console-messages bin/enable-all-console-messages .gitignore lib/api lib/Auth lib/Auth.php lib/client lib/functions.php lib/kolab_api_controller.php lib/kolab_api_service.php lib/kolab_client_api.php lib/kolab_client_task.php lib/kolab_recipient_policy.php lib/locale public_html/js

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Tue May 22 18:39:18 CEST 2012


 .gitignore                                   |    2 
 bin/disable-all-console-messages             |    4 
 bin/enable-all-console-messages              |    4 
 lib/Auth.php                                 |   48 ++
 lib/Auth/LDAP.php                            |  487 +++++++++++++++++++--------
 lib/api/kolab_api_service_domain.php         |   30 +
 lib/api/kolab_api_service_domains.php        |    2 
 lib/api/kolab_api_service_form_value.php     |  180 +++++++++
 lib/api/kolab_api_service_resource.php       |  185 ++++++++++
 lib/api/kolab_api_service_resource_types.php |   64 +++
 lib/api/kolab_api_service_resources.php      |  147 ++++++++
 lib/api/kolab_api_service_user.php           |    8 
 lib/client/kolab_client_task_domain.php      |   71 +--
 lib/client/kolab_client_task_group.php       |    4 
 lib/client/kolab_client_task_role.php        |    2 
 lib/client/kolab_client_task_user.php        |    2 
 lib/functions.php                            |    2 
 lib/kolab_api_controller.php                 |   30 -
 lib/kolab_api_service.php                    |   26 -
 lib/kolab_client_api.php                     |    4 
 lib/kolab_client_task.php                    |   33 +
 lib/kolab_recipient_policy.php               |   16 
 lib/locale/en_US.php                         |    7 
 public_html/js/kolab_admin.js                |   40 ++
 24 files changed, 1180 insertions(+), 218 deletions(-)

New commits:
commit 29b36b76446ecd798a73648763ba590122bf2ac3
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:38:49 2012 +0100

    Add use of the default locale to the normalization functions

diff --git a/lib/kolab_recipient_policy.php b/lib/kolab_recipient_policy.php
index 54f79d2..10179d8 100644
--- a/lib/kolab_recipient_policy.php
+++ b/lib/kolab_recipient_policy.php
@@ -44,6 +44,12 @@ class kolab_recipient_policy {
         foreach ($groupdata as $key => $value) {
             if (isset($groupdata['preferredlanguage'])) {
                 setlocale(LC_ALL, $groupdata['preferredlanguage']);
+            } else {
+                $conf = Conf::get_instance();
+                $locale = $conf->get('default_locale');
+                if (!empty($locale)) {
+                    setlocale(LC_ALL, $locale);
+                }
             }
 
             if (!is_array($groupdata[$key])) {
@@ -73,6 +79,12 @@ class kolab_recipient_policy {
 
             if (isset($userdata['preferredlanguage'])) {
                 setlocale(LC_ALL, $userdata['preferredlanguage']);
+            } else {
+                $conf = Conf::get_instance();
+                $locale = $conf->get('default_locale');
+                if (!empty($locale)) {
+                    setlocale(LC_ALL, $locale);
+                }
             }
 
             if (!is_array($userdata[$_key])) {


commit 68479de37f1b32eb0b3cd6f081e8d53923a9ac60
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:37:44 2012 +0100

    Add resources to the API controller

diff --git a/lib/kolab_api_controller.php b/lib/kolab_api_controller.php
index e3a5640..cd5782c 100644
--- a/lib/kolab_api_controller.php
+++ b/lib/kolab_api_controller.php
@@ -56,16 +56,19 @@ class kolab_api_controller
         }
 
         // TODO: register services based on config or whatsoever
-        $this->add_service('domain', 'kolab_api_service_domain');
-        $this->add_service('domains', 'kolab_api_service_domains');
-        $this->add_service('form_value', 'kolab_api_service_form_value');
-        $this->add_service('group_types', 'kolab_api_service_group_types');
-        $this->add_service('group', 'kolab_api_service_group');
-        $this->add_service('groups', 'kolab_api_service_groups');
-        $this->add_service('roles', 'kolab_api_service_roles');
-        $this->add_service('user_types', 'kolab_api_service_user_types');
-        $this->add_service('user', 'kolab_api_service_user');
-        $this->add_service('users', 'kolab_api_service_users');
+        $this->add_service('domain',            'kolab_api_service_domain');
+        $this->add_service('domains',           'kolab_api_service_domains');
+        $this->add_service('form_value',        'kolab_api_service_form_value');
+        $this->add_service('group_types',       'kolab_api_service_group_types');
+        $this->add_service('group',             'kolab_api_service_group');
+        $this->add_service('groups',            'kolab_api_service_groups');
+        $this->add_service('resource_types',    'kolab_api_service_resource_types');
+        $this->add_service('resource',          'kolab_api_service_resource');
+        $this->add_service('resources',         'kolab_api_service_resources');
+        $this->add_service('roles',             'kolab_api_service_roles');
+        $this->add_service('user_types',        'kolab_api_service_user_types');
+        $this->add_service('user',              'kolab_api_service_user');
+        $this->add_service('users',             'kolab_api_service_users');
     }
 
     /**


commit 2a8ca12da53edb731b893b61bbcc0aad81396e7c
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:37:01 2012 +0100

    Add 'resource' as a valid type

diff --git a/lib/kolab_api_service.php b/lib/kolab_api_service.php
index 8c9dbde..18e6e82 100644
--- a/lib/kolab_api_service.php
+++ b/lib/kolab_api_service.php
@@ -59,7 +59,7 @@ abstract class kolab_api_service
      */
     protected function object_type_attributes($object_name, $type_id, $required = true)
     {
-        $supported = array('domain', 'group', 'role', 'user');
+        $supported = array('domain', 'group', 'resource', 'role', 'user');
         if (!$object_name || !in_array($object_name, $supported)) {
             return array();
         }
@@ -165,11 +165,12 @@ abstract class kolab_api_service
      */
     protected function object_types($object_name)
     {
-        $supported = array('group', 'user');
+        $supported = array('group', 'resource', 'user');
         if (!$object_name || !in_array($object_name, $supported)) {
             return array();
         }
 
+
         if (!empty($this->cache['object_types']) && !empty($this->cache['object_types'][$object_name])) {
             return $this->cache['object_types'][$object_name];
         }
@@ -198,7 +199,12 @@ abstract class kolab_api_service
             }
         }
 
+        //console("Object types for " . $object_name, $object_types);
+
+//         return $object_types;
+
         return $this->cache['object_types'][$object_name] = $object_types;
+
     }
 
     /**


commit 521b6a5d90eba76fb7ea43754915ae0793b77349
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:34:58 2012 +0100

    Add the form_value functions for resource management

diff --git a/lib/api/kolab_api_service_form_value.php b/lib/api/kolab_api_service_form_value.php
index 3bc008d..a737277 100644
--- a/lib/api/kolab_api_service_form_value.php
+++ b/lib/api/kolab_api_service_form_value.php
@@ -184,15 +184,20 @@ class kolab_api_service_form_value extends kolab_api_service
             return $result;
         }
 
-        $method_name = 'list_options_' . strtolower($attr_name);
 
-        //console($method_name);
+        $method_name = 'list_options_' . strtolower($attr_name) . '_' . strtolower($postdata['object_type']);
 
         if (!method_exists($this, $method_name)) {
-            return $result;
+            //console("Method $method_name doesn't exist");
+
+            $method_name = 'list_options_' . strtolower($attr_name);
+
+            if (!method_exists($this, $method_name)) {
+                return $result;
+            }
         }
 
-        //console("Still here");
+        //console($method_name);
 
         $result['list'] = $this->{$method_name}($postdata, $attribs);
 
@@ -221,6 +226,46 @@ class kolab_api_service_form_value extends kolab_api_service
         }
     }
 
+    private function generate_cn_resource($postdata, $attribs = array())
+    {
+        if (isset($attribs['auto_form_fields']) && isset($attribs['auto_form_fields']['cn'])) {
+            // Use Data Please
+            foreach ($attribs['auto_form_fields']['cn']['data'] as $key) {
+                if (!isset($postdata[$key])) {
+                    throw new Exception("Key not set: " . $key, 12356);
+                }
+            }
+
+            $auth = Auth::get_instance($_SESSION['user']->get_domain());
+            $conf = Conf::get_instance();
+
+            $unique_attr = $conf->get('unique_attribute');
+            if (!$unique_attr) {
+                $unique_attr = 'nsuniqueid';
+            }
+
+            $cn = $postdata['cn'];
+
+            $x = 2;
+            while (($resource_found = $auth->resource_find_by_attribute(array('cn' => $cn)))) {
+                if (!empty($postdata['id'])) {
+                    $resource_found_dn = key($resource_found);
+                    $resource_found_unique_attr = $auth->get_attribute($resource_found_dn, $unique_attr);
+                    //console("resource with mail $mail found", $resource_found_unique_attr);
+                    if ($resource_found_unique_attr == $postdata['id']) {
+                        //console("that's us.");
+                        break;
+                    }
+                }
+
+                $cn = $postdata['cn'] . ' #' . $x;
+                $x++;
+            }
+
+            return $cn;
+        }
+    }
+
     private function generate_displayname($postdata, $attribs = array())
     {
         if (isset($attribs['auto_form_fields']) && isset($attribs['auto_form_fields']['displayname'])) {
@@ -314,6 +359,24 @@ class kolab_api_service_form_value extends kolab_api_service
         }
     }
 
+    private function generate_kolabtargetfolder_resource($postdata, $attribs = array())
+    {
+        if (isset($attribs['auto_form_fields']) && isset($attribs['auto_form_fields']['kolabtargetfolder'])) {
+            // Use Data Please
+            foreach ($attribs['auto_form_fields']['kolabtargetfolder']['data'] as $key) {
+                if (!isset($postdata[$key])) {
+                    throw new Exception("Key not set: " . $key, 12356);
+                }
+            }
+
+            // TODO: Detect or from config
+            $imap_hierarchysep = '/';
+            $cn = $this->generate_cn_resource($postdata, $attribs);
+
+            return 'shared' . $imap_hierarchysep . 'Resources' . $imap_hierarchysep . $cn . '@' . $_SESSION['user']->get_domain();
+        }
+    }
+
     private function generate_mail($postdata, $attribs = array())
     {
         return $this->generate_primary_mail($postdata, $attribs);
@@ -324,6 +387,61 @@ class kolab_api_service_form_value extends kolab_api_service
         return $this->generate_primary_mail_group($postdata, $attribs);
     }
 
+    private function generate_mail_resource($postdata, $attribs = array())
+    {
+        $db = SQL::get_instance();
+        $result = $db->fetch_assoc($db->query("SELECT `key` FROM `resource_types` WHERE id = ?", $postdata['type_id']));
+
+        $object_type_key = $result['key'];
+
+        if (isset($attribs['auto_form_fields']) && isset($attribs['auto_form_fields']['mail'])) {
+            // Use Data Please
+            foreach ($attribs['auto_form_fields']['mail']['data'] as $key) {
+                if (!isset($postdata[$key])) {
+                    throw new Exception("Key not set: " . $key, 12356);
+                }
+            }
+
+            $resourcedata = kolab_recipient_policy::normalize_groupdata($postdata);
+            console("normalized resource data", $resourcedata);
+
+            // TODO: Normalize $postdata
+            $mail_local = 'resource-' . $object_type_key . '-' . strtolower($resourcedata['cn']);
+            $mail_domain = $_SESSION['user']->get_domain();
+            $mail = $mail_local . '@' . $mail_domain;
+
+            $orig_mail = $mail;
+
+            $auth = Auth::get_instance($_SESSION['user']->get_domain());
+            $conf = Conf::get_instance();
+
+            $unique_attr = $conf->get('unique_attribute');
+            if (!$unique_attr) {
+                $unique_attr = 'nsuniqueid';
+            }
+
+            $x = 2;
+            while (($resource_found = $auth->resource_find_by_attribute(array('mail' => $mail)))) {
+                if (!empty($postdata['id'])) {
+                    $resource_found_dn = key($resource_found);
+                    $resource_found_unique_attr = $auth->get_attribute($resource_found_dn, $unique_attr);
+                    //console("resource with mail $mail found", $resource_found_unique_attr);
+                    if ($resource_found_unique_attr == $postdata['id']) {
+                        //console("that's us.");
+                        break;
+                    }
+                }
+
+                $mail = $mail_local . '-' . $x . '@' . $mail_domain;
+                $x++;
+            }
+
+            return $mail;
+
+
+        }
+    }
+
     private function generate_mailalternateaddress($postdata, $attribs = array())
     {
         return $this->generate_secondary_mail($postdata, $attribs);
@@ -614,6 +732,11 @@ class kolab_api_service_form_value extends kolab_api_service
         return $this->_list_options_members($postdata, $attribs);
     }
 
+    private function list_options_uniquemember_resource($postdata, $attribs = array())
+    {
+        return $this->_list_options_resources($postdata, $attribs);
+    }
+
     private function select_options_c($postdata, $attribs = array())
     {
         return $this->_select_options_from_db('c');
@@ -750,6 +873,49 @@ class kolab_api_service_form_value extends kolab_api_service
         return $list;
     }
 
+    private function _list_options_resources($postdata, $attribs = array())
+    {
+        // return specified records only, by exact DN attributes
+        if (!empty($postdata['list'])) {
+            $data['search'] = array(
+                'entrydn' => array(
+                    'value' => $postdata['list'],
+                    'type'  => 'exact',
+                ),
+            );
+        }
+        // return records with specified string
+        else {
+            $keyword = array('value' => $postdata['search']);
+            $data['page_size'] = 15;
+            $data['search']    = array(
+                'cn'          => $keyword,
+            );
+        }
+
+        $data['attributes'] = array('cn');
+
+        console("api/form_value._list_options_resources() searching with data", $data);
+
+        $service = $this->controller->get_service('resources');
+        $result  = $service->resources_list(null, $data);
+        $list    = $result['list'];
+
+        // convert to key=>value array
+        foreach ($list as $idx => $value) {
+            if (!empty($value['displayname'])) {
+                $list[$idx] = $value['displayname'];
+            } elseif (!empty($value['cn'])) {
+                $list[$idx] = $value['cn'];
+            } else {
+                //console("No display name or cn for $idx");
+            }
+
+        }
+
+        return $list;
+    }
+
     private function _highest_of_two($one, $two) {
         if ($one > $two) {
             return $one;


commit d7d3fc63dd354e8d67d83240ae756179b9b2293c
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:34:16 2012 +0100

    Add the necessary Auth and Auth/LDAP functions for resource management

diff --git a/lib/Auth.php b/lib/Auth.php
index b7ec376..5176933 100644
--- a/lib/Auth.php
+++ b/lib/Auth.php
@@ -306,6 +306,19 @@ class Auth {
         return $groups;
     }
 
+    public function list_resources($domain = NULL, $attributes = array(), $search = array(), $params = array())
+    {
+        $this->connect($domain);
+        if ($domain === NULL) {
+            $domain = $this->conf->get('primary_domain');
+        }
+
+        $resources = $this->_auth[$domain]->list_resources($attributes, $search, $params);
+
+        return $resources;
+    }
+
+
     public function list_roles($domain = NULL, $attributes = array(), $search = array(), $params = array())
     {
         $this->connect($domain);
@@ -340,6 +353,36 @@ class Auth {
         }
     }
 
+    public function resource_add($attributes, $typeid = null)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_add($attributes, $typeid);
+    }
+
+    public function resource_edit($resource, $attributes, $typeid = null)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_edit($resource, $attributes, $typeid);
+    }
+
+    public function resource_delete($subject)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_delete($subject);
+    }
+
+    public function resource_find_by_attribute($attribute)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_find_by_attribute($attribute);
+    }
+
+    public function resource_info($resourcedata)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_info($resourcedata);
+    }
+
+    public function resource_members_list($resourcedata, $recurse = true)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->resource_members_list($resourcedata, $recurse);
+    }
+
     public function search()
     {
         $this->connect($domain);
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
index 30657e8..f30f38a 100644
--- a/lib/Auth/LDAP.php
+++ b/lib/Auth/LDAP.php
@@ -661,6 +661,37 @@ class LDAP
         return $users;
     }
 
+    public function list_resources($attributes = array(), $search = array(), $params = array())
+    {
+        if (!empty($params['sort_by'])) {
+            if (is_array($params['sort_by'])) {
+                foreach ($params['sort_by'] as $attrib) {
+                    if (!in_array($attrib, $attributes)) {
+                        $attributes[] = $attrib;
+                    }
+                }
+            } else {
+                if (!in_array($params['sort_by'], $attributes)) {
+                    $attributes[] = $params['sort_by'];
+                }
+            }
+        }
+
+        $resources = $this->resources_list($attributes, $search);
+        $resources = self::normalize_result($resources);
+
+        if (!empty($params['sort_by'])) {
+            $this->sort_result_key = $params['sort_by'];
+            uasort($resources, array($this, 'sort_result'));
+
+            if ($params['sort_order'] == 'DESC') {
+                $resources = array_reverse($resources, true);
+            }
+        }
+
+        return $resources;
+    }
+
     public function list_roles($attributes = array(), $search = array(), $params = array())
     {
         if (!empty($params['sort_by'])) {
@@ -684,6 +715,105 @@ class LDAP
         return $roles;
     }
 
+    public function resource_add($attrs, $typeid = null)
+    {
+        if ($typeid == null) {
+            $type_str = 'resource';
+        }
+        else {
+            $db   = SQL::get_instance();
+            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM resource_types WHERE id = ?", $typeid));
+            $type_str = $_key['key'];
+        }
+
+        // Check if the resource_type has a specific base DN specified.
+        $base_dn = $this->conf->get($type_str . "_resource_base_dn");
+        // If not, take the regular user_base_dn
+        if (!$base_dn)
+            $base_dn = $this->conf->get("resource_base_dn");
+
+        // TODO: The rdn is configurable as well.
+        // Use [$type_str . "_"]user_rdn_attr
+        $dn = "cn=" . $attrs['cn'] . "," . $base_dn;
+
+        return $this->_add($dn, $attrs);
+    }
+
+    public function resource_delete($resource)
+    {
+        $resource_dn = $this->entry_dn($resource);
+
+        if (!$resource_dn) {
+            return false;
+        }
+
+        return $this->_delete($resource_dn);
+    }
+
+    public function resource_edit($resource, $attributes, $typeid = null)
+    {
+/*
+        // Get the type "key" string for the next few settings.
+        if ($typeid == null) {
+            $type_str = 'resource';
+        }
+        else {
+            $db   = SQL::get_instance();
+            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM resource_types WHERE id = ?", $typeid));
+            $type_str = $_key['key'];
+        }
+*/
+        // Group identifier
+        $unique_attr = $this->unique_attribute();
+        $attributes[$unique_attr] = $resource;
+
+        // Now that values have been re-generated where necessary, compare
+        // the new resource attributes to the original resource attributes.
+        $_resource = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr]));
+
+        if (!$_resource) {
+            //console("Could not find resource");
+            return false;
+        }
+
+        $_resource_dn = key($_resource);
+        $_resource = $this->resource_info($_resource_dn, array_keys($attributes));
+
+        // We should start throwing stuff over the fence here.
+        return $this->modify_entry($_resource_dn, $_resource[$_resource_dn], $attributes);
+    }
+
+    public function resource_find_by_attribute($attribute)
+    {
+        return $this->entry_find_by_attribute($attribute);
+    }
+
+    /**
+     * Resource attributes
+     *
+     *
+     */
+    public function resource_info($resource, $attributes = array('*'))
+    {
+        $resource_dn = $this->entry_dn($resource);
+
+        if (!$resource_dn)
+            return false;
+
+        return self::normalize_result($this->_search($resource_dn, '(objectclass=*)', $attributes));
+    }
+
+    public function resource_members_list($resource, $recurse = true)
+    {
+        $resource_dn = $this->entry_dn($resource);
+
+        if (!$resource_dn) {
+            return false;
+        }
+
+        return $this->_list_resource_members($resource_dn, null, $recurse);
+    }
+
     public function user_add($attrs, $typeid = null)
     {
         if ($typeid == null) {
@@ -1390,6 +1520,32 @@ class LDAP
         return $result['']['supportedcontrol'];
     }
 
+    private function resources_list($attributes = array(), $search = array())
+    {
+        $conf = Conf::get_instance();
+
+        $base_dn = $conf->get('resource_base_dn');
+
+        if (!$base_dn)
+            $base_dn = "ou=Resources," . $conf->get('base_dn');
+
+        $filter  = $conf->get('resource_filter');
+        if (!$filter)
+            $filter = '(objectclass=*)';
+
+        if (empty($attributes) || !is_array($attributes)) {
+            $attributes = array('*');
+        }
+
+        if ($s_filter = $this->_search_filter($search)) {
+            // join search filter with objectClass filter
+            $filter = '(&' . $filter . $s_filter . ')';
+        }
+
+        return $this->_search($base_dn, $filter, $attributes);
+    }
+
+
     private function users_list($attributes = array(), $search = array())
     {
         $conf = Conf::get_instance();
@@ -1781,10 +1937,12 @@ class LDAP
         }
 
         if (($entries = ldap_get_entries($this->conn, $search_results)) == false) {
-            //message("Could not get the results of the search: " . $this->_errstr());
+            console("Could not get the results of the search: " . $this->_errstr());
             return false;
         }
 
+        //console("__search() entries:", $entries);
+
         return $entries;
     }
 


commit b159286587c07a9f580db92fbc34a528044c2b42
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 22 17:33:38 2012 +0100

    Add the API side of resource management

diff --git a/lib/api/kolab_api_service_resource.php b/lib/api/kolab_api_service_resource.php
new file mode 100644
index 0000000..9cd3304
--- /dev/null
+++ b/lib/api/kolab_api_service_resource.php
@@ -0,0 +1,185 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | 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/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Service providing resource data management
+ */
+class kolab_api_service_resource extends kolab_api_service
+{
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        //console("kolab_api_service_group::capabilities");
+
+        $auth = Auth::get_instance();
+
+        $effective_rights = $auth->list_rights('resource');
+
+        //console("effective_rights", $effective_rights);
+
+        $rights = array();
+
+        if (in_array('add', $effective_rights['entryLevelRights'])) {
+            $rights['add'] = "w";
+        }
+
+        if (in_array('delete', $effective_rights['entryLevelRights'])) {
+            $rights['delete'] = "w";
+        }
+
+        if (in_array('modrdn', $effective_rights['entryLevelRights'])) {
+            $rights['edit'] = "w";
+        }
+
+        if (in_array('read', $effective_rights['entryLevelRights'])) {
+            $rights['find'] = "r";
+            $rights['find_by_any_attribute'] = "r";
+            $rights['find_by_attribute'] = "r";
+            $rights['find_by_attributes'] = "r";
+            $rights['info'] = "r";
+        }
+
+        $rights['effective_rights'] = "r";
+
+        return $rights;
+    }
+
+    /**
+     * Create resource.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array|bool User attributes or False on error.
+     */
+    public function resource_add($getdata, $postdata)
+    {
+        //console("resource_add()", $postdata);
+
+        $resource_attributes = $this->parse_input_attributes('resource', $postdata);
+
+        //console("resource_add()", $resource_attributes);
+
+        // TODO: The cn needs to be unique
+        $auth = Auth::get_instance();
+        $result = $auth->resource_add($resource_attributes, $postdata['type_id']);
+
+        if ($result) {
+            return $resource_attributes;
+        }
+
+        return false;
+    }
+
+    /**
+     * Detete resource.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return bool True on success, False on failure
+     */
+    public function resource_delete($getdata, $postdata)
+    {
+        //console("resource_delete()", $getdata, $postdata);
+        if (!isset($postdata['resource'])) {
+            return false;
+        }
+
+        // TODO: Input validation
+        $auth   = Auth::get_instance();
+        $result = $auth->resource_delete($postdata['resource']);
+
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+    }
+
+    public function resource_edit($getdata, $postdata)
+    {
+        //console("\$postdata to resource_edit()", $postdata);
+
+        $resource_attributes = $this->parse_input_attributes('resource', $postdata);
+
+        //console("\$resource_attributes as result from parse_input_attributes", $resource_attributes);
+
+        $resource            = $postdata['id'];
+
+        $auth   = Auth::get_instance();
+        $result = $auth->resource_edit($resource, $resource_attributes, $postdata['type_id']);
+
+        // Return the $mod_array
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+
+    }
+
+    public function resource_effective_rights($getdata, $postdata)
+    {
+        $auth = Auth::get_instance();
+        $effective_rights = $auth->list_rights($getdata['resource']);
+        return $effective_rights;
+    }
+
+    /**
+     * User information.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array|bool User attributes, False on error
+     */
+    public function resource_info($getdata, $postdata)
+    {
+        if (!isset($getdata['resource'])) {
+            return false;
+        }
+
+        $auth   = Auth::get_instance();
+        $result = $auth->resource_info($getdata['resource']);
+
+        // normalize result
+        $result = $this->parse_result_attributes('resource', $result);
+
+        //console($result);
+
+        if ($result) {
+            return $result;
+        }
+
+        return false;
+    }
+}
diff --git a/lib/api/kolab_api_service_resource_types.php b/lib/api/kolab_api_service_resource_types.php
new file mode 100644
index 0000000..69d13ea
--- /dev/null
+++ b/lib/api/kolab_api_service_resource_types.php
@@ -0,0 +1,64 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | 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/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ *
+ */
+class kolab_api_service_resource_types extends kolab_api_service
+{
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        return array(
+            'list' => 'r',
+        );
+    }
+
+    /**
+     * User types listing.
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array List result with 'list' and 'count' items
+     */
+    public function resource_types_list($get, $post)
+    {
+        $resource_types = $this->object_types('resource');
+
+        //console("api/resource_types_list()", $resource_types);
+
+        return array(
+            'list'  => $resource_types,
+            'count' => count($resource_types),
+        );
+    }
+}
diff --git a/lib/api/kolab_api_service_resources.php b/lib/api/kolab_api_service_resources.php
new file mode 100644
index 0000000..6bcc7e3
--- /dev/null
+++ b/lib/api/kolab_api_service_resources.php
@@ -0,0 +1,147 @@
+<?php
+/*
+ +--------------------------------------------------------------------------+
+ | This file is part of the Kolab Web Admin Panel                           |
+ |                                                                          |
+ | Copyright (C) 2011-2012, Kolab Systems AG                                |
+ |                                                                          |
+ | 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/>      |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com>                      |
+ | Author: Jeroen van Meeuwen <vanmeeuwen at kolabsys.com>                     |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * Service providing resources listing
+ */
+class kolab_api_service_resources extends kolab_api_service
+{
+    public $list_attribs = array(
+        'alias',
+        'cn',
+        'entrydn',
+        'mail',
+        'objectclass',
+    );
+
+
+    /**
+     * Returns service capabilities.
+     *
+     * @param string $domain Domain name
+     *
+     * @return array Capabilities list
+     */
+    public function capabilities($domain)
+    {
+        return array(
+            'list' => 'r',
+        );
+    }
+
+    /**
+     * Users listing (with searching).
+     *
+     * @param array $get   GET parameters
+     * @param array $post  POST parameters
+     *
+     * @return array List result with 'list' and 'count' items
+     */
+    public function resources_list($get, $post)
+    {
+        $auth = Auth::get_instance();
+
+        // returned attributes
+        if (!empty($post['attributes']) && is_array($post['attributes'])) {
+            // get only supported attributes
+            $attributes = array_intersect($this->list_attribs, $post['attributes']);
+            // need to fix array keys
+            $attributes = array_values($attributes);
+        }
+        if (empty($attributes)) {
+            $attributes = (array)$this->list_attribs[0];
+        }
+
+        $search = array();
+        $params = array();
+
+        // searching
+        if (!empty($post['search']) && is_array($post['search'])) {
+            $params = $post['search'];
+
+            foreach ($params as $idx => $param) {
+                // get only supported attributes
+                if (!in_array($idx, $this->list_attribs)) {
+                    unset($params[$idx]);
+                    continue;
+                }
+
+                // search string
+                if (empty($param['value'])) {
+                    unset($params[$idx]);
+                    continue;
+                }
+            }
+
+            $search['params'] = $params;
+            if (!empty($post['search_operator'])) {
+                $search['operator'] = $post['search_operator'];
+            }
+        }
+
+        if (!empty($post['sort_by'])) {
+            if (is_array($post['sort_by'])) {
+                $params['sort_by'] = Array();
+                foreach ($post['sort_by'] as $attrib) {
+                    if (in_array($attrib, $this->list_attribs)) {
+                        $params['sort_by'][] = $attrib;
+                    }
+                }
+            } else {
+                // check if sort attribute is supported
+                if (in_array($post['sort_by'], $this->list_attribs)) {
+                    $params['sort_by'] = $post['sort_by'];
+                }
+            }
+        }
+
+        if (!empty($post['sort_order'])) {
+            $params['sort_order'] = $post['sort_order'] == 'DESC' ? 'DESC' : 'ASC';
+        }
+
+        $resources = $auth->list_resources(null, $attributes, $search, $params);
+        $count = count($resources);
+
+        // pagination
+        if (!empty($post['page_size']) && $count) {
+            $size   = (int) $post['page_size'];
+            $page   = !empty($post['page']) ? $post['page'] : 1;
+            $page   = max(1, (int) $page);
+            $offset = ($page - 1) * $size;
+
+            $resources = array_slice($resources, $offset, $size, true);
+        }
+
+        $result = array(
+            'list'  => $resources,
+            'count' => $count,
+        );
+
+        //console($result);
+
+        return $result;
+    }
+
+}


commit c5d2e4bf2db36c8f2af69cadac5c61a6aad7dcbf
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri May 18 10:48:33 2012 +0100

    Add scripts to enable and disable all console messages

diff --git a/bin/disable-all-console-messages b/bin/disable-all-console-messages
new file mode 100755
index 0000000..4af5f3b
--- /dev/null
+++ b/bin/disable-all-console-messages
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+sed -r -i -e 's|^(\s*)console|\1//console|g' `find . -type f -name "*.php"`
+
diff --git a/bin/enable-all-console-messages b/bin/enable-all-console-messages
new file mode 100755
index 0000000..d5640d5
--- /dev/null
+++ b/bin/enable-all-console-messages
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+sed -r -i -e 's|^(\s*)//console|\1console|g' `find . -type f -name "*.php"`
+


commit 57d2c5b4f1338f2f56bc46be22a43718ce1de179
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Fri May 18 10:46:11 2012 +0100

    Add .gitignore file

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9b26e6f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+cache/*.php
+logs/*


commit f8239e2e98e816639a135773b46eeb9e166c8cd1
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 10:25:21 2012 +0100

    Update standard domain type description

diff --git a/lib/client/kolab_client_task_domain.php b/lib/client/kolab_client_task_domain.php
index eaf5d92..b8eba82 100644
--- a/lib/client/kolab_client_task_domain.php
+++ b/lib/client/kolab_client_task_domain.php
@@ -287,7 +287,7 @@ class kolab_client_task_domain extends kolab_client_task
         $result = array(
                 1 => array(
                         'key' => 'standard',
-                        'name' => 'standard domain name space',
+                        'name' => 'Standard domain',
                         'description' => 'A standard domain name space',
                         'attributes' => array(
                                 'auto_form_fields' => array(),
@@ -306,7 +306,7 @@ class kolab_client_task_domain extends kolab_client_task
                                             ),
                                     ),
                             ),
-                    )
+                    ),
             );
         //console("domain_types() \$result", $result);
         return $result;


commit ffe21f242320ea991e5c9f47327d86c16a4fc459
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:57:31 2012 +0100

    Disable console() calls

diff --git a/lib/api/kolab_api_service_domains.php b/lib/api/kolab_api_service_domains.php
index 479d292..439e865 100644
--- a/lib/api/kolab_api_service_domains.php
+++ b/lib/api/kolab_api_service_domains.php
@@ -56,7 +56,7 @@ class kolab_api_service_domains extends kolab_api_service
         $auth = Auth::get_instance();
 
         $domains = $auth->list_domains();
-        console($domains);
+        //console($domains);
         $count   = count($domains);
 
         // pagination
diff --git a/lib/api/kolab_api_service_form_value.php b/lib/api/kolab_api_service_form_value.php
index 8af2f8f..3bc008d 100644
--- a/lib/api/kolab_api_service_form_value.php
+++ b/lib/api/kolab_api_service_form_value.php
@@ -442,7 +442,7 @@ class kolab_api_service_form_value extends kolab_api_service
                 setlocale(LC_ALL, $postdata['preferredlanguage']);
             }
 /*            else {
-                console("No locale specified...!");
+                //console("No locale specified...!");
             }
 */
 
@@ -454,7 +454,7 @@ class kolab_api_service_form_value extends kolab_api_service
 
             $auth = Auth::get_instance($_SESSION['user']->get_domain());
             $conf = Conf::get_instance();
-            
+
             $unique_attr = $conf->get('unique_attribute');
             if (!$unique_attr) {
                 $unique_attr = 'nsuniqueid';
@@ -739,7 +739,7 @@ class kolab_api_service_form_value extends kolab_api_service
             } elseif (!empty($value['cn'])) {
                 $list[$idx] = $value['cn'];
             } else {
-                console("No display name or cn for $idx");
+                //console("No display name or cn for $idx");
             }
 
             if (!empty($value['mail'])) {
diff --git a/lib/api/kolab_api_service_user.php b/lib/api/kolab_api_service_user.php
index 8352ae0..f9adbac 100644
--- a/lib/api/kolab_api_service_user.php
+++ b/lib/api/kolab_api_service_user.php
@@ -82,11 +82,11 @@ class kolab_api_service_user extends kolab_api_service
      */
     public function user_add($getdata, $postdata)
     {
-        console("user_add()", $postdata);
+        //console("user_add()", $postdata);
 
-        $user_attributes = $this->parse_input_attributes('user', $postdata); 
+        $user_attributes = $this->parse_input_attributes('user', $postdata);
 
-        console("user_add()", $user_attributes);
+        //console("user_add()", $user_attributes);
 
         $auth = Auth::get_instance();
         $result = $auth->user_add($user_attributes, $postdata['type_id']);
@@ -171,7 +171,7 @@ class kolab_api_service_user extends kolab_api_service
         $result = $auth->user_info($getdata['user']);
 
         // normalize result
-        $result = $this->parse_result_attributes('user', $result); 
+        $result = $this->parse_result_attributes('user', $result);
 
         if ($result) {
             return $result;
diff --git a/lib/client/kolab_client_task_group.php b/lib/client/kolab_client_task_group.php
index 097e150..0c6e3d0 100644
--- a/lib/client/kolab_client_task_group.php
+++ b/lib/client/kolab_client_task_group.php
@@ -271,7 +271,7 @@ class kolab_client_task_group extends kolab_client_task
             } elseif (!empty($value['cn'])) {
                 $list[$idx] = $value['cn'];
             } else {
-                console("No display name or cn for $idx");
+                //console("No display name or cn for $idx");
             }
 
             if (!empty($value['mail'])) {
@@ -298,7 +298,7 @@ class kolab_client_task_group extends kolab_client_task
             }
         }
 
-        console($_SESSION['group_types']);
+        //console($_SESSION['group_types']);
 
         return $_SESSION['group_types'];
     }
diff --git a/lib/client/kolab_client_task_role.php b/lib/client/kolab_client_task_role.php
index 431d9e0..d012abd 100644
--- a/lib/client/kolab_client_task_role.php
+++ b/lib/client/kolab_client_task_role.php
@@ -271,7 +271,7 @@ class kolab_client_task_role extends kolab_client_task
             } elseif (!empty($value['cn'])) {
                 $list[$idx] = $value['cn'];
             } else {
-                console("No display name or cn for $idx");
+                //console("No display name or cn for $idx");
             }
 
             if (!empty($value['mail'])) {
diff --git a/lib/client/kolab_client_task_user.php b/lib/client/kolab_client_task_user.php
index 5287006..f21a041 100644
--- a/lib/client/kolab_client_task_user.php
+++ b/lib/client/kolab_client_task_user.php
@@ -262,6 +262,8 @@ class kolab_client_task_user extends kolab_client_task
         // Prepare fields
         list($fields, $types, $type) = $this->form_prepare('user', $data, array('userpassword2'));
 
+        //console("Result from form_prepare", $fields, $types, $type);
+
         $add_mode  = empty($data['id']);
         $accttypes = array();
 
diff --git a/lib/functions.php b/lib/functions.php
index 4183454..9761358 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -127,7 +127,7 @@ function timer($time = null, $label = '')
 {
     $now = microtime(true);
     if ($time) {
-        console(($label ? $label.' ' : '') . sprintf('%.4f', $now - $time));
+        //console(($label ? $label.' ' : '') . sprintf('%.4f', $now - $time));
     }
     return $now;
 }
diff --git a/lib/kolab_api_controller.php b/lib/kolab_api_controller.php
index 5fbe099..e3a5640 100644
--- a/lib/kolab_api_controller.php
+++ b/lib/kolab_api_controller.php
@@ -133,7 +133,7 @@ class kolab_api_controller
         $method  = $this->request['method'];
         $postdata = @json_decode($postdata, true);
 
-        console("Calling method " . $method . " on service " . $service);
+        //console("Calling method " . $method . " on service " . $service);
 
         // validate user session
         if ($service != 'system' || $method != 'authenticate') {
@@ -181,7 +181,7 @@ class kolab_api_controller
         $method  = $this->request['method'];
         $url     = rtrim($url, '/') . '/' . $service . '.' . $method;
 
-        console("Proxying " . $url);
+        //console("Proxying " . $url);
 
         $request = new HTTP_Request2();
         $url     = new Net_URL2($url);
@@ -297,7 +297,9 @@ class kolab_api_controller
      */
     private function capabilities()
     {
+        //console("system.capabilities called");
         $auth = Auth::get_instance();
+
         $this->domains = $auth->list_domains();
 
         $result = array();
@@ -305,6 +307,7 @@ class kolab_api_controller
         // Should we have no permissions to list domain name spaces,
         // we should always return our own.
         if (count($this->domains) < 1) {
+            //console("As there is but one domain, we insert our own");
             $this->domains[] = $_SESSION['user']->get_domain();
         }
 
diff --git a/lib/kolab_api_service.php b/lib/kolab_api_service.php
index 54687a9..8c9dbde 100644
--- a/lib/kolab_api_service.php
+++ b/lib/kolab_api_service.php
@@ -76,15 +76,12 @@ abstract class kolab_api_service
 
         if (empty($object_types[$type_id])) {
             if ($object_name == 'domain') {
-                return array(
+                $result = array(
                         'auto_form_fields' => array(),
                         'form_fields' => array(
                                 'associateddomain' => array(
                                         'type' => 'list'
                                     ),
-                                'o' => array(
-                                        'optional' => 'true',
-                                    ),
                             ),
                         'fields' => array(
                                 'objectclass' => array(
@@ -94,6 +91,10 @@ abstract class kolab_api_service
                             ),
                     );
 
+                //console("object_type_attributes('domain', $type_id);", $result);
+
+                return $result;
+
             } else {
                 throw new Exception($this->controller->translate($object_name . '.invalidtypeid'), 35);
             }
@@ -142,8 +143,8 @@ abstract class kolab_api_service
             $commonalities = count($object_class) - $differences;
             $elem_score    = $differences > 0 ? ($commonalities / $differences) : $commonalities;
 
-//            console("\$object_class not in \$ref_class (" . $elem['key'] . "): " . implode(", ", $_object_class));
-//            console("\$ref_class not in \$object_class (" . $elem['key'] . "): " . implode(", ", $_ref_class));
+            //console("\$object_class not in \$ref_class (" . $elem['key'] . "): " . implode(", ", $_object_class));
+            //console("\$ref_class not in \$object_class (" . $elem['key'] . "): " . implode(", ", $_ref_class));
             //console("Score for $object_name type " . $elem['name'] . ": " . $elem_score . "(" . $commonalities . "/" . $differences . ")");
 
             if ($elem_score > $type_score) {
@@ -210,6 +211,8 @@ abstract class kolab_api_service
      */
     protected function parse_result_attributes($object_name, $attrs = array())
     {
+        //console("parse_result_attributes($object_name, \$attrs = ", $attrs);
+
         if (empty($attrs) || !is_array($attrs)) {
             return $attrs;
         }
@@ -282,6 +285,7 @@ abstract class kolab_api_service
         $type_attrs   = $this->object_type_attributes($object_name, $attribs['type_id']);
 
         //console("parse_input_attributes", $type_attrs);
+        //console("called with \$attribs", $attribs);
 
         $form_service = $this->controller->get_service('form_value');
         $result       = array();
diff --git a/lib/kolab_client_api.php b/lib/kolab_client_api.php
index 96188a2..359fe73 100644
--- a/lib/kolab_client_api.php
+++ b/lib/kolab_client_api.php
@@ -150,7 +150,7 @@ class kolab_client_api
 
         $this->request->setMethod(HTTP_Request2::METHOD_GET);
 
-        console("GET", $url);
+        //console("GET", $url);
 
         return $this->get_response($url);
     }
@@ -171,7 +171,7 @@ class kolab_client_api
         $this->request->setMethod(HTTP_Request2::METHOD_POST);
         $this->request->setBody(@json_encode($post));
 
-        console("POST", $url, $post);
+        //console("POST", $url, $post);
 
         return $this->get_response($url);
     }
diff --git a/lib/kolab_client_task.php b/lib/kolab_client_task.php
index 4bcc56b..652cfa2 100644
--- a/lib/kolab_client_task.php
+++ b/lib/kolab_client_task.php
@@ -457,7 +457,7 @@ class kolab_client_task
 
         $capabilities = $this->capabilities();
 
-        //console($capabilities);
+        //console("Capabilities", $capabilities);
 
         foreach ($this->menu as $idx => $label) {
             //console("$task: $task, idx: $idx, label: $label");
@@ -515,6 +515,8 @@ class kolab_client_task
             $_SESSION['user_types'] = $list;
         }
 
+        //console("user_types() \$list", $list);
+
         return $list;
     }
 
@@ -557,6 +559,8 @@ class kolab_client_task
             $result = $this->api->post('system.capabilities');
             $list   = $result->get('list');
 
+            //console("Capabilities obtained from the API", $list);
+
             if (is_array($list)) {
                 $_SESSION['capabilities'] = $list;
             }
@@ -741,6 +745,9 @@ class kolab_client_task
     protected function form_prepare($name, &$data, $extra_fields = array())
     {
         $types        = (array) $this->{$name . '_types'}();
+
+        //console("form_prepare types", $types);
+
         $form_id      = $attribs['id'];
         $add_mode     = empty($data['id']);
 
@@ -979,13 +986,24 @@ class kolab_client_task
      */
     protected function form_create($name, $attribs, $sections, $fields, $fields_map, $data, $add_mode)
     {
+        //console("Creating form for $name");
+
+        //console("Assign fields to sections", $fields);
         // Assign sections to fields
         foreach ($fields as $idx => $field) {
             if (!$field['section']) {
                 $fields[$idx]['section'] = isset($fields_map[$idx]) ? $fields_map[$idx] : 'other';
+                //console("Assigned field $idx to section " . $fields[$idx]['section']);
+/*
+            } else {
+                $fields[$idx]['section'] = 'other';
+                //console("Assigned field $idx to section " . $fields[$idx]['section']);
+*/
             }
         }
 
+        //console("Using fields_map", $fields_map);
+
         // Sort
         foreach ($fields_map as $idx => $val) {
             if (array_key_exists($idx, $fields)) {
@@ -1000,13 +1018,19 @@ class kolab_client_task
             $fields_map = array_merge($fields_map, $fields);
         }
 
+        //console("Using attribs", $attribs);
+
         $form = new kolab_form($attribs);
         $assoc_fields = array();
         $req_fields   = array();
         $writeable    = 0;
 
         $auto_fields = $this->output->get_env('auto_fields');
-        //console("\$auto_fields", $auto_fields);
+
+        //console("form_create() \$attribs", $attribs);
+        //console("form_create() \$auto_fields", $auto_fields);
+
+        //console("Going to walk through sections", $sections);
 
         // Parse elements and add them to the form object
         foreach ($sections as $section_idx => $section) {
@@ -1026,6 +1050,9 @@ class kolab_client_task
                 $field['section']     = $section_idx;
 
                 if (empty($field['value']) && !empty($data[$idx])) {
+
+                    //console("Using data value", $data[$idx], "for value of field $idx");
+
                     $field['value'] = $data[$idx];
 
                     // Convert data for the list field with autocompletion
@@ -1090,6 +1117,8 @@ class kolab_client_task
                     }
                 }
 
+                //console("Adding field to form", $field);
+
                 $form->add_element($field);
             }
         }
diff --git a/lib/kolab_recipient_policy.php b/lib/kolab_recipient_policy.php
index 6667631..54f79d2 100644
--- a/lib/kolab_recipient_policy.php
+++ b/lib/kolab_recipient_policy.php
@@ -157,7 +157,7 @@ class kolab_recipient_policy {
                         );
                 }
             } else {
-                console("Key " . $substrings[1][$x] . " does not exist in \$userdata");
+                //console("Key " . $substrings[1][$x] . " does not exist in \$userdata");
             }
         }
 
@@ -209,7 +209,7 @@ class kolab_recipient_policy {
                     if (array_key_exists($substrings[1][$x], $userdata)) {
                         $userdata[$substrings[1][$x]] = substr($userdata[$substrings[1][$x]], $substrings[2][$x], $substrings[3][$x]);
                     } else {
-                        console("Key " . $substrings[1][$x] . " does not exist in \$userdata");
+                        //console("Key " . $substrings[1][$x] . " does not exist in \$userdata");
                     }
 
                     $rule = preg_replace(


commit f8b2322a55c7cf725c5cf45d47c568ca2cee0c80
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:54:49 2012 +0100

    Prepare for domain management functionality
    Disable console() calls

diff --git a/lib/client/kolab_client_task_domain.php b/lib/client/kolab_client_task_domain.php
index 408f342..eaf5d92 100644
--- a/lib/client/kolab_client_task_domain.php
+++ b/lib/client/kolab_client_task_domain.php
@@ -128,7 +128,7 @@ class kolab_client_task_domain extends kolab_client_task
         // table body
         if (!empty($result)) {
             foreach ($result as $idx => $item) {
-                console($idx);
+                //console($idx);
                 if (!is_array($item) || empty($item['associateddomain'])) {
                     continue;
                 }
@@ -170,7 +170,7 @@ class kolab_client_task_domain extends kolab_client_task
     }
 
     /**
-     * Group information (form) action.
+     * Domain information (form) action.
      */
     public function action_info()
     {
@@ -189,7 +189,7 @@ class kolab_client_task_domain extends kolab_client_task
     }
 
     /**
-     * Groups adding (form) action.
+     * Domain adding (form) action.
      */
     public function action_add()
     {
@@ -200,7 +200,7 @@ class kolab_client_task_domain extends kolab_client_task
     }
 
     /**
-     * Group edit/add form.
+     * Domain edit/add form.
      */
     private function domain_form($attribs, $data = array())
     {
@@ -221,9 +221,13 @@ class kolab_client_task_domain extends kolab_client_task
             'associateddomain'  => 'system',
         );
 
+        //console("domain_form() \$data", $data);
+
         // Prepare fields
         list($fields, $types, $type) = $this->form_prepare('domain', $data);
 
+        //console("Result from form_prepare", $fields, $types, $type);
+
         $add_mode  = empty($data['id']);
         $accttypes = array();
 
@@ -231,7 +235,7 @@ class kolab_client_task_domain extends kolab_client_task
             $accttypes[$idx] = array('value' => $idx, 'content' => $elem['name']);
         }
 
-        // Add user type id selector
+        // Add domain type id selector
         $fields['type_id'] = array(
             'section'  => 'system',
             'type'     => kolab_form::INPUT_SELECT,
@@ -251,9 +255,9 @@ class kolab_client_task_domain extends kolab_client_task
         }
         // Edit mode
         else {
-            $title = $data['cn'];
+            $title = $data['primary_domain'];
 
-            // Add user type name
+            // Add domain type name
             $fields['type_id_name'] = array(
                 'label'    => 'domain.type_id',
                 'section'  => 'system',
@@ -264,6 +268,8 @@ class kolab_client_task_domain extends kolab_client_task
         // Create form object and populate with fields
         $form = $this->form_create('domain', $attribs, $sections, $fields, $fields_map, $data, $add_mode);
 
+        //console("domain_form() \$form", $form);
+
         $form->set_title(kolab_html::escape($title));
 
         $this->output->add_translation('domain.add.success', 'domain.edit.success', 'domain.delete.success');
@@ -271,26 +277,6 @@ class kolab_client_task_domain extends kolab_client_task
         return $form->output();
     }
 
-    private function parse_members($list)
-    {
-        // convert to key=>value array, see kolab_api_service_form_value::list_options_uniquemember()
-        foreach ($list as $idx => $value) {
-            if (!empty($value['displayname'])) {
-                $list[$idx] = $value['displayname'];
-            } elseif (!empty($value['cn'])) {
-                $list[$idx] = $value['cn'];
-            } else {
-                console("No display name or cn for $idx");
-            }
-
-            if (!empty($value['mail'])) {
-                $list[$idx] .= ' <' . $value['mail'] . '>';
-            }
-        }
-
-        return $list;
-    }
-
     /**
      * Returns list of domain types.
      *
@@ -298,19 +284,32 @@ class kolab_client_task_domain extends kolab_client_task
      */
     public function domain_types()
     {
-        return array(
-                array(
+        $result = array(
+                1 => array(
                         'key' => 'standard',
                         'name' => 'standard domain name space',
                         'description' => 'A standard domain name space',
                         'attributes' => array(
-                                'associateddomain' => array(),
-                                'inetdomainbasedn' => array(
-                                        'optional' => true
-                                    )
-                            )
+                                'auto_form_fields' => array(),
+                                'form_fields' => array(
+                                        'associateddomain' => array(
+                                                'type' => 'list',
+                                            ),
+                                        'inetdomainbasedn' => array(
+                                                'optional' => 'true',
+                                            ),
+                                    ),
+                                'fields' => array(
+                                        'objectclass' => array(
+                                                'top',
+                                                'domainrelatedobject',
+                                            ),
+                                    ),
+                            ),
                     )
             );
+        //console("domain_types() \$result", $result);
+        return $result;
     }
 
     /**


commit 040881dfc1ab5ada3b7a3f8257bef36e0ffb6c37
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:54:04 2012 +0100

    Add service method domain_edit()
    Disable console() calls

diff --git a/lib/api/kolab_api_service_domain.php b/lib/api/kolab_api_service_domain.php
index aced3d5..e00de8f 100644
--- a/lib/api/kolab_api_service_domain.php
+++ b/lib/api/kolab_api_service_domain.php
@@ -40,6 +40,8 @@ class kolab_api_service_domain extends kolab_api_service
     {
         return array(
             'add' => 'w',
+            'edit' => 'w',
+            'delete' => 'w'
         );
     }
 
@@ -57,12 +59,30 @@ class kolab_api_service_domain extends kolab_api_service
         $auth->domain_add($postdata['domain'], $postdata['parent']);
     }
 
+    public function domain_edit($getdata, $postdata)
+    {
+        //console("domain_edit \$postdata", $postdata);
+
+        $domain_attributes  = $this->parse_input_attributes('domain', $postdata);
+        $domain             = $postdata['id'];
+
+        $auth   = Auth::get_instance();
+        $result = $auth->domain_edit($postdata['id'], $domain_attributes, $postdata['type_id']);
+
+        // @TODO: return unique attribute or all attributes as domain_add()
+        if ($result) {
+            return true;
+        }
+
+        return false;
+    }
+
     public function domain_effective_rights($getdata, $postdata)
     {
         $auth = Auth::get_instance();
         $conf = Conf::get_instance();
 
-        console($getdata);
+        //console($getdata);
 
         if (!empty($getdata['domain'])) {
             $entry_dn = $getdata['domain'];
@@ -73,7 +93,7 @@ class kolab_api_service_domain extends kolab_api_service
                     array($unique_attr => $entry_dn)
                 );
 
-            console($domain);
+            //console($domain);
 
             if (!empty($domain)) {
                 $entry_dn = key($domain);
@@ -84,13 +104,13 @@ class kolab_api_service_domain extends kolab_api_service
             $entry_dn = $conf->get('ldap', 'domain_base_dn');
         }
 
-        console("API/domain.effective_rights(); Using entry_dn: " . $entry_dn);
+        //console("API/domain.effective_rights(); Using entry_dn: " . $entry_dn);
 
         // TODO: Fix searching the correct base_dn... Perhaps find the entry
         // first.
         $effective_rights = $auth->list_rights($entry_dn);
 
-        console($effective_rights);
+        //console($effective_rights);
         return $effective_rights;
     }
 
@@ -114,7 +134,7 @@ class kolab_api_service_domain extends kolab_api_service
         // normalize result
         $result = $this->parse_result_attributes('domain', $result);
 
-        console("API/domain.info() \$result:", $result);
+        //console("API/domain.info() \$result:", $result);
 
         if ($result) {
             return $result;


commit 11dd3c65019cdc4a32ff12e4265b88d36060c4d7
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:48:29 2012 +0100

    Add function domain_edit()
    Disable console messages
    Re-order functions alphabetically
    Escape setting/unsetting 'ou' attribute if not set in modify_entry()
    Look at old (non)array values vs. new (non)array values to find which attribute values need deleting.

diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
index b5c9f3f..30657e8 100644
--- a/lib/Auth/LDAP.php
+++ b/lib/Auth/LDAP.php
@@ -303,6 +303,28 @@ class LDAP
         }
     }
 
+    public function domain_edit($domain, $attributes, $typeid = null)
+    {
+        // Domain identifier
+        $unique_attr = $this->unique_attribute();
+        $attributes[$unique_attr] = $domain;
+
+        // Now that values have been re-generated where necessary, compare
+        // the new domain attributes to the original domain attributes.
+        $_domain = $this->domain_find_by_attribute(array($unique_attr => $attributes[$unique_attr]));
+
+        if (!$_domain) {
+            //console("Could not find domain");
+            return false;
+        }
+
+        $_domain_dn = key($_domain);
+        $_domain = $this->domain_info($_domain_dn, array_keys($attributes));
+
+        // We should start throwing stuff over the fence here.
+        return $this->modify_entry($_domain_dn, $_domain[$_domain_dn], $attributes);
+    }
+
     public function domain_find_by_attribute($attribute)
     {
         $conf = Conf::get_instance();
@@ -330,7 +352,7 @@ class LDAP
             return false;
         }
 
-        console("domain_info() result:", $result);
+        //console("domain_info() result:", $result);
 
         return $result;
     }
@@ -363,7 +385,7 @@ class LDAP
             $entry_dn = $conf->get("base_dn");
         }
 
-        console("effective_rights for $subject resolves to $entry_dn");
+        //console("effective_rights for $subject resolves to $entry_dn");
 
         $moz_ldapsearch = "/usr/lib64/mozldap/ldapsearch";
         if (!is_file($moz_ldapsearch)) {
@@ -398,11 +420,11 @@ class LDAP
                 '"*"',
             );
 
-        console("Executing command " . implode(' ', $command));
+        //console("Executing command " . implode(' ', $command));
 
         exec(implode(' ', $command), $output, $return_code);
 
-        console("Output", $output, "Return code: " . $return_code);
+        //console("Output", $output, "Return code: " . $return_code);
 
         $lines = array();
         foreach ($output as $line_num => $line) {
@@ -437,6 +459,28 @@ class LDAP
         return $attributes;
     }
 
+    public function find_user_groups($member_dn)
+    {
+        error_log(__FILE__ . "(" . __LINE__ . "): " .  $member_dn);
+
+        $groups = array();
+
+        $root_dn = $this->domain_root_dn($this->domain);
+
+        // TODO: Do not query for both, it's either one or the other
+        $entries = $this->_search($root_dn, "(|" .
+                "(&(objectclass=groupofnames)(member=$member_dn))" .
+                "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" .
+            ")");
+
+        $entries = self::normalize_result($entries);
+
+        foreach ($entries as $entry_dn => $entry_attributes) {
+            $groups[] = $entry_dn;
+        }
+
+        return $groups;
+    }
 
     public function get_attribute($subject_dn, $attribute)
     {
@@ -460,6 +504,101 @@ class LDAP
         return false;
     }
 
+    public function group_add($attrs, $typeid = null)
+    {
+        if ($typeid == null) {
+            $type_str = 'group';
+        }
+        else {
+            $db   = SQL::get_instance();
+            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid));
+            $type_str = $_key['key'];
+        }
+
+        // Check if the group_type has a specific base DN specified.
+        $base_dn = $this->conf->get($type_str . "_group_base_dn");
+        // If not, take the regular user_base_dn
+        if (!$base_dn)
+            $base_dn = $this->conf->get("group_base_dn");
+
+        // TODO: The rdn is configurable as well.
+        // Use [$type_str . "_"]user_rdn_attr
+        $dn = "cn=" . $attrs['cn'] . "," . $base_dn;
+
+        return $this->_add($dn, $attrs);
+    }
+
+    public function group_delete($group)
+    {
+        $group_dn = $this->entry_dn($group);
+
+        if (!$group_dn) {
+            return false;
+        }
+
+        return $this->_delete($group_dn);
+    }
+
+    public function group_edit($group, $attributes, $typeid = null)
+    {
+/*
+        // Get the type "key" string for the next few settings.
+        if ($typeid == null) {
+            $type_str = 'group';
+        }
+        else {
+            $db   = SQL::get_instance();
+            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid));
+            $type_str = $_key['key'];
+        }
+*/
+        // Group identifier
+        $unique_attr = $this->unique_attribute();
+        $attributes[$unique_attr] = $group;
+
+        // Now that values have been re-generated where necessary, compare
+        // the new group attributes to the original group attributes.
+        $_group = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr]));
+
+        if (!$_group) {
+            //console("Could not find group");
+            return false;
+        }
+
+        $_group_dn = key($_group);
+        $_group = $this->group_info($_group_dn, array_keys($attributes));
+
+        // We should start throwing stuff over the fence here.
+        return $this->modify_entry($_group_dn, $_group[$_group_dn], $attributes);
+    }
+
+    public function group_find_by_attribute($attribute)
+    {
+        return $this->entry_find_by_attribute($attribute);
+    }
+
+    public function group_info($group, $attributes = array('*'))
+    {
+        $group_dn = $this->entry_dn($group);
+
+        if (!$group_dn) {
+            return false;
+        }
+
+        return self::normalize_result($this->_search($group_dn, '(objectclass=*)', $attributes));
+    }
+
+    public function group_members_list($group, $recurse = true)
+    {
+        $group_dn = $this->entry_dn($group);
+
+        if (!$group_dn) {
+            return false;
+        }
+
+        return $this->_list_group_members($group_dn, null, $recurse);
+    }
+
     public function list_domains()
     {
         $domains = $this->domains_list();
@@ -577,7 +716,7 @@ class LDAP
             $base_dn = $attrs['ou'];
         }
 
-        console("Base DN now: $base_dn");
+        //console("Base DN now: $base_dn");
 
         // TODO: The rdn is configurable as well.
         // Use [$type_str . "_"]user_rdn_attr
@@ -651,124 +790,6 @@ class LDAP
         return $this->entry_find_by_attribute($attribute);
     }
 
-    public function find_user_groups($member_dn)
-    {
-        error_log(__FILE__ . "(" . __LINE__ . "): " .  $member_dn);
-
-        $groups = array();
-
-        $root_dn = $this->domain_root_dn($this->domain);
-
-        // TODO: Do not query for both, it's either one or the other
-        $entries = $this->_search($root_dn, "(|" .
-                "(&(objectclass=groupofnames)(member=$member_dn))" .
-                "(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" .
-            ")");
-
-        $entries = self::normalize_result($entries);
-
-        foreach ($entries as $entry_dn => $entry_attributes) {
-            $groups[] = $entry_dn;
-        }
-
-        return $groups;
-    }
-
-    public function group_add($attrs, $typeid = null)
-    {
-        if ($typeid == null) {
-            $type_str = 'group';
-        }
-        else {
-            $db   = SQL::get_instance();
-            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid));
-            $type_str = $_key['key'];
-        }
-
-        // Check if the group_type has a specific base DN specified.
-        $base_dn = $this->conf->get($type_str . "_group_base_dn");
-        // If not, take the regular user_base_dn
-        if (!$base_dn)
-            $base_dn = $this->conf->get("group_base_dn");
-
-        // TODO: The rdn is configurable as well.
-        // Use [$type_str . "_"]user_rdn_attr
-        $dn = "cn=" . $attrs['cn'] . "," . $base_dn;
-
-        return $this->_add($dn, $attrs);
-    }
-
-    public function group_edit($group, $attributes, $typeid = null)
-    {
-/*
-        // Get the type "key" string for the next few settings.
-        if ($typeid == null) {
-            $type_str = 'group';
-        }
-        else {
-            $db   = SQL::get_instance();
-            $_key = $db->fetch_assoc($db->query("SELECT `key` FROM group_types WHERE id = ?", $typeid));
-            $type_str = $_key['key'];
-        }
-*/
-        // Group identifier
-        $unique_attr = $this->unique_attribute();
-        $attributes[$unique_attr] = $group;
-
-        // Now that values have been re-generated where necessary, compare
-        // the new group attributes to the original group attributes.
-        $_group = $this->entry_find_by_attribute(array($unique_attr => $attributes[$unique_attr]));
-
-        if (!$_group) {
-            //console("Could not find group");
-            return false;
-        }
-
-        $_group_dn = key($_group);
-        $_group = $this->group_info($_group_dn, array_keys($attributes));
-
-        // We should start throwing stuff over the fence here.
-        return $this->modify_entry($_group_dn, $_group[$_group_dn], $attributes);
-    }
-
-    public function group_delete($group)
-    {
-        $group_dn = $this->entry_dn($group);
-
-        if (!$group_dn) {
-            return false;
-        }
-
-        return $this->_delete($group_dn);
-    }
-
-    public function group_info($group, $attributes = array('*'))
-    {
-        $group_dn = $this->entry_dn($group);
-
-        if (!$group_dn) {
-            return false;
-        }
-
-        return self::normalize_result($this->_search($group_dn, '(objectclass=*)', $attributes));
-    }
-
-    public function group_members_list($group, $recurse = true)
-    {
-        $group_dn = $this->entry_dn($group);
-
-        if (!$group_dn) {
-            return false;
-        }
-
-        return $this->_list_group_members($group_dn, null, $recurse);
-    }
-
-    public function group_find_by_attribute($attribute)
-    {
-        return $this->entry_find_by_attribute($attribute);
-    }
-
     /*
         Translate a domain name into it's corresponding root dn.
     */
@@ -1057,10 +1078,15 @@ class LDAP
             );
 
         // This is me cheating. Remove this special attribute.
-        $old_ou = $old_attrs['ou'];
-        $new_ou = $new_attrs['ou'];
-        unset($old_attrs['ou']);
-        unset($new_attrs['ou']);
+        if (array_key_exists('ou', $old_attrs) || array_key_exists('ou', $new_attrs)) {
+            $old_ou = $old_attrs['ou'];
+            $new_ou = $new_attrs['ou'];
+            unset($old_attrs['ou']);
+            unset($new_attrs['ou']);
+        } else {
+            $old_ou = null;
+            $new_ou = null;
+        }
 
         // Compare each attribute value of the old attrs with the corresponding value
         // in the new attrs, if any.
@@ -1084,28 +1110,59 @@ class LDAP
                         if (is_array($old_attrs[$attr])) {
                             if (!is_array($new_attrs[$attr])) {
                                 if (in_array($new_attrs[$attr], $old_attrs[$attr])) {
-                                    // TODO: Need to remove all $old_attrs[$attr] values not equal to $new_attrs[$attr]
-                                    if ($new_attrs[$attr] !== $old_attrs[$attr][0]) {
-                                        // TODO: Also need to rename the entry
+                                    // TODO: Need to remove all $old_attrs[$attr] values not equal to $new_attrs[$attr], and not equal to the current $rdn_attr value [0]
+
+                                    //console("old attrs. is array, new attrs. is not array. new attr. exists in old attrs.");
+
+                                    $rdn_attr_value = array_shift($old_attrs[$attr]);
+                                    $_attr_to_remove = array();
+
+                                    foreach ($old_attrs[$attr] as $value) {
+                                        if (strtolower($value) != strtolower($new_attrs[$attr])) {
+                                            $_attr_to_remove[] = $value;
+                                        }
                                     }
+
+                                    //console("Adding to delete attribute $attr values:" . implode(', ', $_attr_to_remove));
+
+                                    $mod_array['delete'][$attr] = $_attr_to_remove;
+
+                                    if (strtolower($new_attrs[$attr]) !== strtolower($rdn_attr_value)) {
+                                        //console("new attrs is not the same as the old rdn value, issuing a rename");
+                                        $mod_array['rename']['dn'] = $subject_dn;
+                                        $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0];
+                                    }
+
                                 } else {
-                                    // TODO: Both replace attribute value and rename.
+                                    //console("new attrs is not the same as any of the old rdn value, issuing a full rename");
+                                    $mod_array['rename']['dn'] = $subject_dn;
+                                    $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr];
                                 }
                             } else {
                                 // TODO: See if the rdn attr. value is still in $new_attrs[$attr]
+                                if (in_array($old_attrs[$attr][0], $new_attrs[$attr])) {
+                                    //console("Simply replacing attr $attr as rnd attr value is preserved.");
+                                    $mod_array['replace'][$attr] = $new_attrs[$attr];
+                                } else {
+                                    // TODO: This fails.
+                                    $mod_array['rename']['dn'] = $subject_dn;
+                                    $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr][0];
+                                    $mod_array['delete'][$attr] = $old_attrs[$attr][0];
+                                }
                             }
                         } else {
                             if (!is_array($new_attrs[$attr])) {
-                                // TODO: Do something here
+                                //console("Renaming " . $old_attrs[$attr] . " to " . $new_attrs[$attr]);
+                                $mod_array['rename']['dn'] = $subject_dn;
+                                $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr];
                             } else {
+                                //console("Adding to replace");
                                 // An additional attribute value is being supplied. Just replace and continue.
                                 $mod_array['replace'][$attr] = $new_attrs[$attr];
                                 continue;
                             }
                         }
 
-                        $mod_array['rename']['dn'] = $subject_dn;
-                        $mod_array['rename']['new_rdn'] = $rdn_attr . '=' . $new_attrs[$attr];
                     } else {
                         if (empty($new_attrs[$attr])) {
                             switch ($attr) {
@@ -1166,7 +1223,7 @@ class LDAP
             $old_ou = implode(',', $subject_dn_components);
         }
 
-        if (!(strtolower($old_ou) === strtolower($new_ou))) {
+        if (!(empty($old_ou) || empty($new_ou)) && !(strtolower($old_ou) === strtolower($new_ou))) {
             $mod_array['rename']['new_parent'] = $new_ou;
             if (empty($mod_array['rename']['dn']) || empty($mod_array['rename']['new_rdn'])) {
                 $mod_array['rename']['dn'] = $subject_dn;
@@ -1188,6 +1245,8 @@ class LDAP
     {
         $this->_bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
 
+        //console($attributes);
+
         // Opportunities to set false include failed ldap commands.
         $result = true;
 
@@ -1222,7 +1281,7 @@ class LDAP
         }
 
         if (!$result) {
-            console("Failed to replace the following attributes on subject " . $subject_dn, $attributes['replace']);
+            //console("Failed to replace the following attributes on subject " . $subject_dn, $attributes['replace']);
             return false;
         }
 
@@ -1231,7 +1290,7 @@ class LDAP
         }
 
         if (!$result) {
-            console("Failed to delete the following attributes", $attributes['del']);
+            //console("Failed to delete the following attributes", $attributes['del']);
             return false;
         }
 
@@ -1241,7 +1300,7 @@ class LDAP
         }
 
         if (!$result) {
-            console("Failed to add the following attributes", $attributes['add']);
+            //console("Failed to add the following attributes", $attributes['add']);
             return false;
         }
 
@@ -1508,8 +1567,8 @@ class LDAP
         // Always bind with the session credentials
         $this->_bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
 
-        console("Entry DN", $entry_dn);
-        console("Attributes", $attributes);
+        //console("Entry DN", $entry_dn);
+        //console("Attributes", $attributes);
 
         foreach ($attributes as $attr_name => $attr_value) {
             if (empty($attr_value)) {


commit 841fe7cec659356dac237077ccabc8c32a6a7b6d
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:45:07 2012 +0100

    Add additional translations for domain management feature

diff --git a/lib/locale/en_US.php b/lib/locale/en_US.php
index 3721ad1..ee5dca9 100644
--- a/lib/locale/en_US.php
+++ b/lib/locale/en_US.php
@@ -10,8 +10,15 @@ $LANG['delete.button'] = 'Delete';
 $LANG['deleting'] = 'Deleting data...';
 
 $LANG['domain.add'] = 'Add Domain';
+$LANG['domain.add.success'] = 'Added domain';
+$LANG['domain.associateddomain'] = 'Domain name(s)';
+$LANG['domain.edit'] = 'Edit domain';
+$LANG['domain.edit.success'] = 'Domain updated';
+$LANG['domain.inetdomainbasedn'] = 'Custom Root DN(s)';
 $LANG['domain.list'] = 'Domains List';
 $LANG['domain.list.records'] = '$1 to $2 of $3';
+$LANG['domain.o'] = 'Organization';
+$LANG['domain.other'] = 'Other';
 $LANG['domain.system'] = 'System';
 $LANG['domain.type_id'] = 'Standard Domain';
 


commit e9fd8d40704b929387a4fcffe7b4fec542969b2b
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue May 15 09:30:45 2012 +0100

    Add function domain_edit()

diff --git a/lib/Auth.php b/lib/Auth.php
index b4cda69..b7ec376 100644
--- a/lib/Auth.php
+++ b/lib/Auth.php
@@ -210,6 +210,11 @@ class Auth {
         return $this->_auth[$_SESSION['user']->get_domain()]->domain_add($domain, $parent_domain);
     }
 
+    public function domain_edit($domain, $attributes, $typeid = null)
+    {
+        return $this->_auth[$_SESSION['user']->get_domain()]->domain_edit($domain, $attributes, $typeid);
+    }
+
     public function domain_find_by_attribute($attribute)
     {
         return $this->_auth[$_SESSION['user']->get_domain()]->domain_find_by_attribute($attribute);


commit 7caf5ed306604ae5a9ca3355c1b266bad51248d6
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Mon May 14 17:25:56 2012 +0100

    Add domain_save + corresponding response handlers

diff --git a/public_html/js/kolab_admin.js b/public_html/js/kolab_admin.js
index bdc0780..84f5384 100644
--- a/public_html/js/kolab_admin.js
+++ b/public_html/js/kolab_admin.js
@@ -1043,6 +1043,46 @@ function kolab_admin()
     this.http_post('domain.info', {id: id});
   };
 
+  this.domain_save = function(reload, section)
+  {
+    var data = this.serialize_form('#'+this.env.form_id),
+      action = data.id ? 'edit' : 'add';
+
+    if (reload) {
+      data.section = section;
+      this.http_post('domain.' + action, {data: data});
+      return;
+    }
+
+    this.form_error_clear();
+
+    if (!this.check_required_fields(data)) {
+      this.display_message('form.required.empty', 'error');
+      return;
+    }
+
+    this.set_busy(true, 'saving');
+    this.api_post('domain.' + action, data, 'domain_' + action + '_response');
+  };
+
+  this.domain_add_response = function(response)
+  {
+    if (!this.api_response(response))
+      return;
+
+    this.display_message('domain.add.success');
+    this.command('domain.list', {page: this.env.list_page});
+  };
+
+  this.domain_edit_response = function(response)
+  {
+    if (!this.api_response(response))
+      return;
+
+    this.display_message('domain.edit.success');
+    this.command('domain.list', {page: this.env.list_page});
+  };
+
   this.user_info = function(id)
   {
     this.http_post('user.info', {id: id});





More information about the commits mailing list