From c5a5f989a9bf91927e6bb627f9f789800ce02fad Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Fri, 01 Feb 2013 09:24:33 -0500
Subject: [PATCH] Allow to list contact groups in (paged) list (yet incomplete)

---
 program/lib/Roundcube/rcube_ldap.php  |   32 ++++++++++++++-
 program/steps/addressbook/func.inc    |   36 +++++++++++++++---
 program/localization/en_US/labels.inc |    1 
 config/main.inc.php.dist              |    1 
 skins/larry/addressbook.css           |   11 +++++
 program/js/app.js                     |   16 ++++++-
 6 files changed, 85 insertions(+), 12 deletions(-)

diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index b113b41..d4246a0 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -680,6 +680,7 @@
     'object_classes' => array("top", "groupOfNames"),
     'member_attr'  => 'member',   // name of the member attribute, e.g. uniqueMember
     'name_attr'    => 'cn',       // attribute to be used as group name
+    'member_filter' => '(objectclass=*)',  // optional filter to use when querying for group members
   ),
 );
 */
diff --git a/program/js/app.js b/program/js/app.js
index dbb65ee..0445004 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -322,7 +322,7 @@
           this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups);
 
         this.enable_command('add', 'import', this.env.writable_source);
-        this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true);
+        this.enable_command('list', 'listgroup', 'pushgroup', 'listsearch', 'advanced-search', true);
 
         if (this.gui_objects.contactslist) {
           this.contact_list = new rcube_list_widget(this.gui_objects.contactslist,
@@ -1080,6 +1080,8 @@
         }
         break;
 
+      case 'pushgroup':
+        // TODO: so some magic stuff here
       case 'listgroup':
         this.reset_qsearch();
         this.list_contacts(props.source, props.id);
@@ -4151,6 +4153,7 @@
 
   this.list_contacts_clear = function()
   {
+    this.contact_list.data = {};
     this.contact_list.clear(true);
     this.show_contentframe(false);
     this.enable_command('delete', false);
@@ -4160,7 +4163,12 @@
   // load contact record
   this.load_contact = function(cid, action, framed)
   {
-    var win, url = {}, target = window;
+    var win, url = {}, target = window,
+      rec = this.contact_list.data[cid];
+
+    if (rec && rec.type == 'group') {
+      alert('group ' + cid)
+    }
 
     if (win = this.get_frame_window(this.env.contentframe)) {
       url._framed = 1;
@@ -4311,7 +4319,7 @@
   };
 
   // add row to contacts list
-  this.add_contact_row = function(cid, cols, classes)
+  this.add_contact_row = function(cid, cols, classes, data)
   {
     if (!this.gui_objects.contactslist)
       return false;
@@ -4333,6 +4341,8 @@
       row.appendChild(col);
     }
 
+    // store data in list member
+    list.data[cid] = data;
     list.insert_row(row);
 
     this.enable_command('export', list.rowcount > 0);
diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php
index a2dd163..80b85d4 100644
--- a/program/lib/Roundcube/rcube_ldap.php
+++ b/program/lib/Roundcube/rcube_ldap.php
@@ -657,6 +657,21 @@
         if (empty($entry[$attr]))
             return $group_members;
 
+        // add group record to cache if it isn't yet there
+        $group_id = self::dn_encode($dn);
+        $group_cache = $this->cache->get('groups');
+        if (!$group_cache[$group_id]) {
+            $name_attr = $this->prop['groups']['name_attr'];
+            $group_name = is_array($ldap_data[$i][$name_attr]) ? $ldap_data[$i][$name_attr][0] : $ldap_data[$i][$name_attr];
+
+            $group_cache[$group_id]['ID'] = $group_id;
+            $group_cache[$group_id]['dn'] = $dn;
+            $group_cache[$group_id]['name'] = $group_name;
+            $group_cache[$group_id]['member_attr'] = $this->get_group_member_attr($entry[$i]['objectclass']);
+
+            $this->cache->set('groups', $group_cache);
+        }
+
         // read these attributes for all members
         $attrib = $count ? array('dn') : array_values($this->fieldmap);
         $attrib[] = 'objectClass';
@@ -664,12 +679,14 @@
         $attrib[] = 'uniqueMember';
         $attrib[] = 'memberURL';
 
+        $filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)';
+
         for ($i=0; $i < $entry[$attr]['count']; $i++)
         {
             if (empty($entry[$attr][$i]))
                 continue;
 
-            $result = @ldap_read($this->conn, $entry[$attr][$i], '(objectclass=*)',
+            $result = @ldap_read($this->conn, $entry[$attr][$i], $filter,
                 $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']);
 
             $members = @ldap_get_entries($this->conn, $result);
@@ -1522,10 +1539,19 @@
      */
     private function _ldap2result($rec)
     {
-        $out = array();
+        $out = array('_type' => 'person');
 
         if ($rec['dn'])
             $out[$this->primary_key] = self::dn_encode($rec['dn']);
+
+        // determine record type
+        if (array_intersect(array('groupofuniquenames','kolabgroupofuniquenames'), (array)$rec['objectclass'])) {
+            $out['_type'] = 'group';
+            $out['readonly'] = true;
+            if ($this->fieldmap['groupname']) {
+                $this->fieldmap['name'] = $this->fieldmap['groupname'];
+            }
+        }
 
         foreach ($this->fieldmap as $rf => $lf)
         {
@@ -1780,7 +1806,7 @@
         for ($i=0; $i < $group_count; $i++)
         {
             $group_name = is_array($ldap_data[$i][$name_attr]) ? $ldap_data[$i][$name_attr][0] : $ldap_data[$i][$name_attr];
-            $group_id = self::dn_encode($group_name);
+            $group_id = self::dn_encode($ldap_data[$i]['dn']);
             $groups[$group_id]['ID'] = $group_id;
             $groups[$group_id]['dn'] = $ldap_data[$i]['dn'];
             $groups[$group_id]['name'] = $group_name;
diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc
index a0b6e6a..2fce96c 100644
--- a/program/localization/en_US/labels.inc
+++ b/program/localization/en_US/labels.inc
@@ -350,6 +350,7 @@
 
 $labels['group'] = 'Group';
 $labels['groups'] = 'Groups';
+$labels['listgroup'] = 'List group members';
 $labels['personaladrbook'] = 'Personal Addresses';
 
 $labels['searchsave'] = 'Save search';
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 80631cd..f921c8c 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -310,7 +310,7 @@
     global $CONTACTS, $OUTPUT;
 
     // define list of cols to be displayed
-    $a_show_cols = array('name');
+    $a_show_cols = array('name','action');
 
     // add id to message list table if not specified
     if (!strlen($attrib['id']))
@@ -339,27 +339,51 @@
         return;
 
     // define list of cols to be displayed
-    $a_show_cols = array('name');
+    $a_show_cols = array('name','action');
 
     while ($row = $result->next()) {
+        $row['CID'] = $row['ID'];
+        $source_id = $OUTPUT->get_env('source');
         $a_row_cols = array();
-        $classes = array('person');  // org records will follow some day
+        $classes = array($row['_type'] ? $row['_type'] : 'person');
 
         // build contact ID with source ID
         if (isset($row['sourceid'])) {
             $row['ID'] = $row['ID'].'-'.$row['sourceid'];
+            $source_id = $row['sourceid'];
         }
 
         // format each col
         foreach ($a_show_cols as $col) {
-            $val = $col == 'name' ? rcube_addressbook::compose_list_name($row) : $row[$col];
-            $a_row_cols[$col] = Q($val);
+            $val = '';
+            switch ($col) {
+                case 'name':
+                    $val = Q(rcube_addressbook::compose_list_name($row));
+                    break;
+
+                case 'action':
+                    if ($row['_type'] == 'group') {
+                        $val = html::a(array(
+                            'href' => '#list',
+                            'rel' => $row['ID'],
+                            'title' => rcube_label('listgroup'),
+                            'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this)", JS_OBJECT_NAME, $source_id, $row['CID']),
+                        ), '&raquo;');
+                    }
+                    break;
+
+                default:
+                    $val = Q($row[$col]);
+                    break;
+            }
+
+            $a_row_cols[$col] = $val;
         }
 
         if ($row['readonly'])
             $classes[] = 'readonly';
 
-        $OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols, join(' ', $classes));
+        $OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols, join(' ', $classes), $row);
     }
 }
 
diff --git a/skins/larry/addressbook.css b/skins/larry/addressbook.css
index ff39514..bd2b05b 100644
--- a/skins/larry/addressbook.css
+++ b/skins/larry/addressbook.css
@@ -141,6 +141,17 @@
 	font-weight: bold;
 }
 
+#contacts-table .group td.name {
+	background-position: 6px -1555px;
+}
+
+#contacts-table .group.selected td.name,
+#contacts-table .group.unfocused td.name {
+	background-position: 6px -1579px;
+	font-weight: bold;
+}
+
+
 #contact-frame {
 	position: absolute;
 	top: 0;

--
Gitblit v1.9.1