From 8fb04bee97aa6ae0b4a9faac0a4c0d2d27e1f64e Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Thu, 06 Oct 2011 15:36:04 -0400
Subject: [PATCH] Read group members according to objectClass of group records; support groupOfUrls; cache groups listing for better performance

---
 program/include/rcube_ldap.php |  113 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 84 insertions(+), 29 deletions(-)

diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index 97b0e7e..55c8c15 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -53,8 +53,9 @@
 
     private $base_dn = '';
     private $groups_base_dn = '';
-    private $group_cache = array();
+    private $group_url = null;
     private $group_members = array();
+    private $cache;
 
     private $vlv_active = false;
     private $vlv_count = 0;
@@ -130,6 +131,11 @@
         $this->sort_col    = is_array($p['sort']) ? $p['sort'][0] : $p['sort'];
         $this->debug       = $debug;
         $this->mail_domain = $mail_domain;
+
+        // initialize cache
+        $rcmail = rcmail::get_instance();
+        $this->cache = $rcmail->get_cache('LDAP.' . asciiwords($this->prop['name']), 'db', 600);
+        $this->cache->expunge();
 
         $this->_connect();
     }
@@ -435,7 +441,8 @@
      */
     function list_records($cols=null, $subset=0)
     {
-        if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id) {
+        if ($this->prop['searchonly'] && empty($this->filter) && !$this->group_id)
+        {
             $this->result = new rcube_result_set(0);
             $this->result->searchonly = true;
             return $this->result;
@@ -446,6 +453,18 @@
         {
             $filter = $this->prop['filter'];
             $this->set_search_set($filter);
+        }
+
+        // query URL is given by the selected group
+        if ($this->group_id && $this->group_url)
+        {
+            // extract components from url
+            if (preg_match('!ldap:///([^\?]+)\?\?(\w+)\?(.*)$!', $this->group_url, $m))
+            {
+                $this->base_dn = $m[1];
+                $this->prop['scope'] = $m[2];
+                $this->filter = $m[3];
+            }
         }
 
         // exec LDAP search if no result resource is stored
@@ -472,7 +491,7 @@
             $entries = ldap_get_entries($this->conn, $this->ldap_result);
 
             // filtering for group members
-            if ($this->groups and $this->group_id)
+            if ($this->groups && $this->group_id && !$this->group_url)
             {
                 $count = 0;
                 $members = array();
@@ -1087,10 +1106,10 @@
     {
         if ($group_id)
         {
-            if (!$this->group_cache)
-                $this->list_groups();
+            if (!($group_cache = $this->cache->get('groups')))
+                $group_cache = $this->list_groups();
 
-            $cache_members = $this->group_cache[$group_id]['members'];
+            $cache_members = $group_cache[$group_id]['members'];
 
             $members = array();
             for ($i=0; $i<$cache_members["count"]; $i++)
@@ -1099,10 +1118,15 @@
                     $members[self::dn_encode($cache_members[$i])] = 1;
             }
             $this->group_members = $members;
+            $this->group_url = $group_cache[$group_id]['member_url'];
             $this->group_id = $group_id;
         }
         else
+        {
             $this->group_id = 0;
+            $this->group_url = null;
+            $this->group_members = array();
+        }
     }
 
     /**
@@ -1122,7 +1146,7 @@
 
         $this->_debug("C: Search [$filter][dn: $base_dn]");
 
-        $res = @ldap_search($this->conn, $base_dn, $filter, array($name_attr, $this->prop['member_attr']));
+        $res = @ldap_search($this->conn, $base_dn, $filter);
         if ($res === false)
         {
             $this->_debug("S: ".ldap_error($this->conn));
@@ -1142,12 +1166,39 @@
                 $group_id = self::dn_encode($group_name);
                 $groups[$group_id]['ID'] = $group_id;
                 $groups[$group_id]['name'] = $group_name;
-                $groups[$group_id]['members'] = $ldap_data[$i][$this->prop['member_attr']];
+
+                // default behavior: check members attribute
+                if ($this->prop['member_attr']) {
+                    $groups[$group_id]['members'] = $ldap_data[$i][$this->prop['member_attr']];
+                    $groups[$group_id]['member_attr'] = $this->prop['member_attr'];
+                }
+
+                // check objectClass attributes of group and act accordingly
+                for ($j=0; $j < $ldap_data[$i]['objectclass']['count']; $j++) {
+                    switch (strtolower($ldap_data[$i]['objectclass'][$j])) {
+                        case 'groupofnames':
+                            $groups[$group_id]['members'] = $ldap_data[$i]['members'];
+                            $groups[$group_id]['member_attr'] = 'member';
+                            break;
+
+                        case 'groupofuniquenames':
+                            $groups[$group_id]['members'] = $ldap_data[$i]['uniqueMember'];
+                            $groups[$group_id]['member_attr'] = 'uniqueMember';
+                            break;
+
+                        case 'groupofurls':
+                            $groups[$group_id]['member_url'] = $ldap_data[$i]['memberurl'][0];
+                            break;
+                    }
+                }
+
                 $group_sortnames[] = strtolower($group_name);
             }
         }
         array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups);
-        $this->group_cache = $groups;
+
+        // cache this
+        $this->cache->set('groups', $groups);
 
         return $groups;
     }
@@ -1160,9 +1211,6 @@
      */
     function create_group($group_name)
     {
-        if (!$this->group_cache)
-            $this->list_groups();
-
         $base_dn = $this->groups_base_dn;
         $new_dn = "cn=$group_name,$base_dn";
         $new_gid = self::dn_encode($group_name);
@@ -1171,7 +1219,6 @@
         $new_entry = array(
             'objectClass' => $this->prop['groups']['object_classes'],
             $name_attr => $group_name,
-            $this->prop['member_attr'] => '',
         );
 
         $this->_debug("C: Add [dn: $new_dn]: ".print_r($new_entry, true));
@@ -1185,6 +1232,7 @@
         }
 
         $this->_debug("S: OK");
+        $this->cache->remove('groups');
 
         return array('id' => $new_gid, 'name' => $group_name);
     }
@@ -1197,11 +1245,11 @@
      */
     function delete_group($group_id)
     {
-        if (!$this->group_cache)
-            $this->list_groups();
+        if (!($group_cache = $this->cache->get('groups')))
+            $group_cache = $this->list_groups();
 
         $base_dn = $this->groups_base_dn;
-        $group_name = $this->group_cache[$group_id]['name'];
+        $group_name = $group_cache[$group_id]['name'];
         $del_dn = "cn=$group_name,$base_dn";
 
         $this->_debug("C: Delete [dn: $del_dn]");
@@ -1215,6 +1263,7 @@
         }
 
         $this->_debug("S: OK");
+        $this->cache->remove('groups');
 
         return true;
     }
@@ -1229,11 +1278,11 @@
      */
     function rename_group($group_id, $new_name, &$new_gid)
     {
-        if (!$this->group_cache)
-            $this->list_groups();
+        if (!($group_cache = $this->cache->get('groups')))
+            $group_cache = $this->list_groups();
 
         $base_dn = $this->groups_base_dn;
-        $group_name = $this->group_cache[$group_id]['name'];
+        $group_name = $group_cache[$group_id]['name'];
         $old_dn = "cn=$group_name,$base_dn";
         $new_rdn = "cn=$new_name";
         $new_gid = self::dn_encode($new_name);
@@ -1249,6 +1298,7 @@
         }
 
         $this->_debug("S: OK");
+        $this->cache->remove('groups');
 
         return $new_name;
     }
@@ -1262,12 +1312,12 @@
      */
     function add_to_group($group_id, $contact_ids)
     {
-        if (!$this->group_cache)
-            $this->list_groups();
+        if (!($group_cache = $this->cache->get('groups')))
+            $group_cache = $this->list_groups();
 
         $base_dn     = $this->groups_base_dn;
-        $group_name  = $this->group_cache[$group_id]['name'];
-        $member_attr = $this->prop['member_attr'];
+        $group_name  = $group_cache[$group_id]['name'];
+        $member_attr = $group_cache[$group_id]['member_attr'];
         $group_dn    = "cn=$group_name,$base_dn";
 
         $new_attrs = array();
@@ -1285,6 +1335,7 @@
         }
 
         $this->_debug("S: OK");
+        $this->cache->remove('groups');
 
         return count($new_attrs['member']);
     }
@@ -1298,12 +1349,12 @@
      */
     function remove_from_group($group_id, $contact_ids)
     {
-        if (!$this->group_cache)
-            $this->list_groups();
+        if (!($group_cache = $this->cache->get('groups')))
+            $group_cache = $this->list_groups();
 
         $base_dn     = $this->groups_base_dn;
-        $group_name  = $this->group_cache[$group_id]['name'];
-        $member_attr = $this->prop['member_attr'];
+        $group_name  = $group_cache[$group_id]['name'];
+        $member_attr = $group_cache[$group_id]['member_attr'];
         $group_dn    = "cn=$group_name,$base_dn";
 
         $del_attrs = array();
@@ -1321,6 +1372,7 @@
         }
 
         $this->_debug("S: OK");
+        $this->cache->remove('groups');
 
         return count($del_attrs['member']);
     }
@@ -1340,9 +1392,12 @@
 
         $base_dn     = $this->groups_base_dn;
         $contact_dn  = self::dn_decode($contact_id);
-        $member_attr = $this->prop['member_attr'];
         $name_attr   = $this->prop['groups']['name_attr'];
-        $filter      = strtr("($member_attr=$contact_dn)", array('\\' => '\\\\'));
+        $member_attr = $this->prop['member_attr'];
+        $add_filter  = '';
+        if ($member_attr != 'member' && $member_attr != 'uniqueMember')
+            $add_filter = "($member_attr=$contact_dn)";
+        $filter = strtr("(|(member=$contact_dn)(uniqueMember=$contact_dn)$add_filter)", array('\\' => '\\\\'));
 
         $this->_debug("C: Search [$filter][dn: $base_dn]");
 

--
Gitblit v1.9.1