Code

Updated listing classes
[gosa.git] / gosa-core / include / class_listing.inc
index d2f2ce91193eeb8a65e305293a76e33e63906e45..5f04cdf3171a7afaec3a68837a978771564a0ba6 100644 (file)
 
 class listing {
 
-  var $xmlData;
-  var $entries;
-  var $departments= array();
-  var $departmentBrowser= false;
-  var $departmentRootVisible= false;
-  var $multiSelect= false;
-  var $template;
-  var $headline;
-  var $module;
-  var $base;
-  var $sortDirection= null;
-  var $sortColumn= null;
-  var $sortAttribute;
-  var $sortType;
-  var $numColumns;
-  var $baseMode= false;
-  var $bases= array();
-  var $header= array();
-  var $colprops= array();
-  var $filters= array();
-  var $pid;
-  var $objectTypes= array();
-  var $objectTypeCount= array();
-  var $objectDnMapping= array();
-  var $copyPasteHandler= null;
-  var $snapshotHandler= null;
-  var $exporter= array();
-  var $exportColumns= array();
-  var $useSpan= false;
-  var $height= 0;
-  var $scrollPosition= 0;
-
-
-  function listing($filename)
-  {
-    global $config;
-    global $class_mapping;
+    var $xmlData;
+    var $entries;
+    var $departments= array();
+    var $departmentBrowser= false;
+    var $departmentRootVisible= false;
+    var $multiSelect= false;
+    var $singleSelect= false;
+    var $noAclChecks= false;
+    var $template;
+    var $headline;
+    var $base;
+    var $sortDirection= null;
+    var $sortColumn= null;
+    var $sortAttribute;
+    var $sortType;
+    var $numColumns;
+    var $baseMode= false;
+    var $bases= array();
+    var $header= array();
+    var $colprops= array();
+    var $filters= array();
+    var $filter= null;
+    var $pid;
+    var $objectTypes= array();
+    var $objectTypeCount= array();
+    var $objectDnMapping= array();
+    var $copyPasteHandler= null;
+    var $snapshotHandler= null;
+    var $exporter= array();
+    var $exportColumns= array();
+    var $useSpan= false;
+    var $height= 0;
+    var $scrollPosition= 0;
+    var $baseSelector;
+    var $aclToObjectClass = array();
+
+    function listing($source, $isString = FALSE)
+    {
+        global $config;
+        global $class_mapping;
+
+        // Initialize pid
+        $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE));
+
+        if($isString){
+            if(!$this->loadString($source)){
+                die("Cannot parse $source!");
+            }
+        }else{
+            if (!$this->loadFile($source)) {
+                die("Cannot parse $source!");
+            }
+        }
 
-    // Initialize pid
-    $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE));
+        // Set base for filter
+        if ($this->baseMode) {
+            $this->base= session::global_get("CurrentMainBase");
+            if ($this->base == null) {
+                $this->base= $config->current['BASE'];
+            }
+            $this->refreshBasesList();
+        } else {
+            $this->base= $config->current['BASE'];
+        }
 
-    if (!$this->load($filename)) {
-      die("Cannot parse $filename!");
-    }
+        // Move footer information
+        $this->showFooter= ($config->get_cfg_value("core","listSummary") == "true");
+
+        // Register build in filters
+        $this->registerElementFilter("objectType", "listing::filterObjectType");
+        $this->registerElementFilter("departmentLink", "listing::filterDepartmentLink");
+        $this->registerElementFilter("link", "listing::filterLink");
+        $this->registerElementFilter("actions", "listing::filterActions");
+
+        // Load exporters
+        foreach($class_mapping as $class => $dummy) {
+            if (preg_match('/Exporter$/', $class)) {
+                $info= call_user_func(array($class, "getInfo"));
+                if ($info != null) {
+                    $this->exporter= array_merge($this->exporter, $info);
+                }
+            }
+        }
 
-    // Set base for filter
-    if ($this->baseMode) {
-      $this->base= session::global_get("CurrentMainBase");
-      if ($this->base == null) {
-        $this->base= $config->current['BASE'];
-      }
-      $this->refreshBasesList();
-    } else {
-      $this->base= $config->current['BASE'];
+        // Instanciate base selector
+        $this->baseSelector= new baseSelector($this->bases, $this->base);
     }
 
-    // Move footer information
-    $this->showFooter= ($config->get_cfg_value("listSummary") == "true");
-
-    // Register build in filters
-    $this->registerElementFilter("objectType", "listing::filterObjectType");
-    $this->registerElementFilter("departmentLink", "listing::filterDepartmentLink");
-    $this->registerElementFilter("link", "listing::filterLink");
-    $this->registerElementFilter("actions", "listing::filterActions");
 
-    // Load exporters
-    foreach($class_mapping as $class => $dummy) {
-      if (preg_match('/Exporter$/', $class)) {
-        $info= call_user_func(array($class, "getInfo"));
-        if ($info != null) {
-          $this->exporter= array_merge($this->exporter, $info);
-        }
-      }
+    function setCopyPasteHandler($handler)
+    {
+        $this->copyPasteHandler= &$handler;
     }
-  }
 
 
-  function setCopyPasteHandler($handler)
-  {
-    $this->copyPasteHandler= &$handler;
-  }
+    function setHeight($height)
+    {
+        $this->height= $height;
+    }
 
 
-  function setHeight($height)
-  {
-    $this->height= $height;
-  }
+    function setSnapshotHandler($handler)
+    {
+        $this->snapshotHandler= &$handler;
+    }
 
 
-  function setSnapshotHandler($handler)
-  {
-    $this->snapshotHandler= &$handler;
-  }
+    function getFilter()
+    { 
+        return($this->filter);
+    }  
 
 
-  function setFilter($filter)
-  {
-    $this->filter= &$filter;
-    if ($this->departmentBrowser){
-      $this->departments= $this->getDepartments();
+    function setFilter($filter)
+    {
+        $this->filter= &$filter;
+        if ($this->departmentBrowser){
+            $this->departments= $this->getDepartments();
+        }
+        $this->filter->setBase($this->base);
     }
-    $this->filter->setBase($this->base);
-  }
 
 
-  function registerElementFilter($name, $call)
-  {
-    if (!isset($this->filters[$name])) {
-      $this->filters[$name]= $call;
-      return true;
-    }
+    function registerElementFilter($name, $call)
+    {
+        if (!isset($this->filters[$name])) {
+            $this->filters[$name]= $call;
+            return true;
+        }
 
-    return false;
-  }
+        return false;
+    }
 
+    function loadFile($filename)
+    {
+        return($this->loadString(file_get_contents($filename)));
+    }
 
-  function load($filename)
-  {
-    $contents = file_get_contents($filename);
-    $this->xmlData= xml::xml2array($contents, 1);
+    function loadString($contents)
+    {
+        $this->xmlData= xml::xml2array($contents, 1);
 
-    if (!isset($this->xmlData['list'])) {
-      return false;
-    }
+        if (!isset($this->xmlData['list'])) {
+            return false;
+        }
 
-    $this->xmlData= $this->xmlData["list"];
+        $this->xmlData= $this->xmlData["list"];
 
-    // Load some definition values
-    foreach (array("departmentBrowser", "departmentRootVisible", "multiSelect", "baseMode") as $token) {
-      if (isset($this->xmlData['definition'][$token]) &&
-          $this->xmlData['definition'][$token] == "true"){
-        $this->$token= true;
-      }
-    }
+        // Load some definition values
+        foreach (array("departmentBrowser", "departmentRootVisible", "multiSelect","singleSelect", "baseMode", "noAclChecks") as $token) {
+            if (isset($this->xmlData['definition'][$token]) &&
+                    $this->xmlData['definition'][$token] == "true"){
+                $this->$token= true;
+            }
+        }
 
-    // Fill objectTypes from departments and xml definition
-    $types = departmentManagement::get_support_departments();
-    foreach ($types as $class => $data) {
-      $this->objectTypes[]= array("label" => $data['TITLE'],
-                                  "objectClass" => $data['OC'],
-                                  "image" => $data['IMG']);
-    }
-    $this->categories= array();
-    if (isset($this->xmlData['definition']['objectType'])) {
-      if(isset($this->xmlData['definition']['objectType']['label'])) {
-        $this->xmlData['definition']['objectType']= array($this->xmlData['definition']['objectType']);
-      }
-      foreach ($this->xmlData['definition']['objectType'] as $index => $otype) {
-        $this->objectTypes[]= $this->xmlData['definition']['objectType'][$index];
-        if (isset($this->xmlData['definition']['objectType'][$index]['category'])){
-          $this->categories[$otype]= $this->xmlData['definition']['objectType'][$index]['category'];
-        }
-      }
-    }
+        // Fill objectTypes from departments and xml definition
+        $types = departmentManagement::get_support_departments();
+        foreach ($types as $class => $data) {
+            $this->objectTypes[$data['OC']]= array("label" => $data['TITLE'],
+                    "objectClass" => $data['OC'],
+                    "image" => $data['IMG']);
+        }
+        $this->categories= array();
+        if (isset($this->xmlData['definition']['objectType'])) {
+            if(isset($this->xmlData['definition']['objectType']['label'])) {
+                $this->xmlData['definition']['objectType']= array($this->xmlData['definition']['objectType']);
+            }
+            foreach ($this->xmlData['definition']['objectType'] as $index => $otype) {
+                $tmp = $this->xmlData['definition']['objectType'][$index];
+                $this->objectTypes[$tmp['objectClass']]= $tmp;
+                if (isset($this->xmlData['definition']['objectType'][$index]['category'])){
+                    $this->categories[]= $otype['category'];
+
+                    if(isset($otype['category']) && isset($otype['class'])){
+                        $this->aclToObjectClass[$otype['category']."/".$otype['class']][] = $otype['objectClass'];
+                    }
+                }
+            }
+        }
+        $this->objectTypes = array_values($this->objectTypes);
 
-    // Parse layout per column
-    $this->colprops= $this->parseLayout($this->xmlData['table']['layout']);
+        // Parse layout per column
+        $this->colprops= $this->parseLayout($this->xmlData['table']['layout']);
 
-    // Prepare table headers
-    $this->renderHeader();
+        // Prepare table headers
+        $this->renderHeader();
 
-    // Assign headline/module
-    $this->headline= _($this->xmlData['definition']['label']);
-    $this->module= $this->xmlData['definition']['module'];
-    if (!is_array($this->categories)){
-      $this->categories= array($this->categories);
-    }
+        // Assign headline/Categories
+        $this->headline= _($this->xmlData['definition']['label']);
+        if (!is_array($this->categories)){
+            $this->categories= array($this->categories);
+        }
 
-    // Evaluate columns to be exported
-    if (isset($this->xmlData['table']['column'])){
-      foreach ($this->xmlData['table']['column'] as $index => $config) {
-        if (isset($config['export']) && $config['export'] == "true"){
-          $this->exportColumns[]= $index;
+        // Evaluate columns to be exported
+        if (isset($this->xmlData['table']['column'])){
+            foreach ($this->xmlData['table']['column'] as $index => $config) {
+                if (isset($config['export']) && $config['export'] == "true"){
+                    $this->exportColumns[]= $index;
+                }
+            }
         }
-      }
-    }
 
-    return true;  
-  }
-
-
-  function renderHeader()
-  {
-    $this->header= array();
-    $this->plainHeader= array();
-
-    // Initialize sort?
-    $sortInit= false;
-    if (!$this->sortDirection) {
-      $this->sortColumn= 0;
-      if (isset($this->xmlData['definition']['defaultSortColumn'])){
-        $this->sortColumn= $this->xmlData['definition']['defaultSortColumn'];
-      } else {
-        $this->sortAttribute= "";
-      }
-      $this->sortDirection= array();
-      $sortInit= true;
+        return true;  
     }
 
-    if (isset($this->xmlData['table']['column'])){
-      foreach ($this->xmlData['table']['column'] as $index => $config) {
-        // Initialize everything to one direction
-        if ($sortInit) {
-          $this->sortDirection[$index]= false;
-        }
-
-        $sorter= "";
-        if ($index == $this->sortColumn && isset($config['sortAttribute']) &&
-            isset($config['sortType'])) {
-          $this->sortAttribute= $config['sortAttribute'];
-          $this->sortType= $config['sortType'];
-          $sorter= "&nbsp;<img border='0' title='".($this->sortDirection[$index]?_("Up"):_("Down"))."' src='images/lists/sort-".($this->sortDirection[$index]?"up":"down").".png' align='top'>";
-        }
-        $sortable= (isset($config['sortAttribute']));
-
-        $link= "href='?plug=".$_GET['plug']."&amp;PID=".$this->pid."&amp;act=SORT_$index'";
-        if (isset($config['label'])) {
-          if ($sortable) {
-            $this->header[$index]= "<td class='listheader' ".$this->colprops[$index]."><a $link>"._($config['label'])."$sorter</a></td>";
-          } else {
-            $this->header[$index]= "<td class='listheader' ".$this->colprops[$index].">"._($config['label'])."</td>";
-          }
-          $this->plainHeader[]= _($config['label']);
-        } else {
-          if ($sortable) {
-            $this->header[$index]= "<td class='listheader' ".$this->colprops[$index]."><a $link>&nbsp;$sorter</a></td>";
-          } else {
-            $this->header[$index]= "<td class='listheader' ".$this->colprops[$index].">&nbsp;</td>";
-          }
-          $this->plainHeader[]= "";
-        }
-      }
-    }
-  }
 
+    function renderHeader()
+    {
+        $this->header= array();
+        $this->plainHeader= array();
 
-  function render()
-  {
-    // Check for exeeded sizelimit
-    if (($message= check_sizelimit()) != ""){
-      return($message);
-    }
+        // Initialize sort?
+        $sortInit= false;
+        if (!$this->sortDirection) {
+            $this->sortColumn= 0;
+            if (isset($this->xmlData['definition']['defaultSortColumn'])){
+                $this->sortColumn= $this->xmlData['definition']['defaultSortColumn'];
+            } else {
+                $this->sortAttribute= "";
+            }
+            $this->sortDirection= array();
+            $sortInit= true;
+        }
 
-    // Some browsers don't have the ability do do scrollable table bodies, filter them
-    // here.
-    $switch= false;
-    if (preg_match('/(Opera|Konqueror|Safari|msie)/i', $_SERVER['HTTP_USER_AGENT'])){
-      $switch= true;
+        if (isset($this->xmlData['table']['column'])){
+            foreach ($this->xmlData['table']['column'] as $index => $config) {
+                // Initialize everything to one direction
+                if ($sortInit) {
+                    $this->sortDirection[$index]= false;
+                }
+
+                $sorter= "";
+                if ($index == $this->sortColumn && isset($config['sortAttribute']) &&
+                        isset($config['sortType'])) {
+                    $this->sortAttribute= $config['sortAttribute'];
+                    $this->sortType= $config['sortType'];
+                    $sorter= "&nbsp;".image("images/lists/sort-".($this->sortDirection[$index]?"up":"down").".png", null, $this->sortDirection[$index]?_("Sort ascending"):_("Sort descending"), "text-top");
+                }
+                $sortable= (isset($config['sortAttribute']));
+
+                $link= "href='?plug=".$_GET['plug']."&amp;PID=".$this->pid."&amp;act=SORT_$index'";
+                if (isset($config['label'])) {
+                    if ($sortable) {
+                        $this->header[$index]= "<td class='listheader' ".$this->colprops[$index]."><a $link>"._($config['label'])."</a>$sorter</td>";
+                    } else {
+                        $this->header[$index]= "<td class='listheader' ".$this->colprops[$index].">"._($config['label'])."</td>";
+                    }
+                    $this->plainHeader[]= _($config['label']);
+                } else {
+                    if ($sortable) {
+                        $this->header[$index]= "<td class='listheader' ".$this->colprops[$index]."><a $link>&nbsp;</a>$sorter</td>";
+                    } else {
+                        $this->header[$index]= "<td class='listheader' ".$this->colprops[$index].">&nbsp;</td>";
+                    }
+                    $this->plainHeader[]= "";
+                }
+            }
+        }
     }
 
-    // Initialize list
-    $result= "<input type='hidden' value='$this->pid' name='PID'>\n";
-    $result.= "<input type='hidden' name='position_".$this->pid."' id='position_".$this->pid."'>\n";
-    $height= 450;
-    if ($this->height != 0) {
-      $result.= "<input type='hidden' value='$this->height' id='d_height'>\n";
-      $height= $this->height;
-    }
-    
-    $result.= "<table cellpadding='0' cellspacing='0' border='0'><tr><td><div class='listContainer' id='d_scrollbody' style='border-top:1px solid #B0B0B0;width:700px;min-height:".($height+25)."px;'>\n";
 
-    $height= "";
-    if ($switch){
-      $height= "height:100%;";
-    }
-    $result.= "<table summary='$this->headline' style='${height}width:100%; table-layout:fixed;' cellspacing='0' cellpadding='0' id='t_scrolltable'>\n";
-    $this->numColumns= count($this->colprops) + ($this->multiSelect?1:0);
-
-    // Build list header
-    $result.= "<thead class='fixedListHeader listHeaderFormat'><tr>\n";
-    if ($this->multiSelect) {
-      $width= "24px";
-      if (preg_match('/Konqueror/i', $_SERVER['HTTP_USER_AGENT'])){
-        $width= "28px";
-      }
-      $result.= "<td class='listheader' style='text-align:center;padding:0;width:$width;'><input type='checkbox' id='select_all' name='select_all' title='"._("Select all")."' onClick='toggle_all_(\"listing_selected_[0-9]*$\",\"select_all\");' ></td>\n";
-    }
-    foreach ($this->header as $header) {
-      $result.= $header;
-    }
-    $result.= "</tr></thead>\n";
+    function render()
+    {
+        // Check for exeeded sizelimit
+        if (($message= check_sizelimit()) != ""){
+            return($message);
+        }
 
-    // Build list body
-    $result.= "<tbody class='listScrollContent listBodyFormat' id='t_nscrollbody' style='height:".$height."px;'>\n";
+        // Some browsers don't have the ability do do scrollable table bodies, filter them
+        // here.
+        $switch= false;
+        if (preg_match('/(Opera|Konqueror|Safari)/i', $_SERVER['HTTP_USER_AGENT'])){
+            $switch= true;
+        }
 
-    // No results? Just take an empty colspanned row
-    if (count($this->entries) + count($this->departments) == 0) {
-      $result.= "<tr class='rowxp0'><td class='list1nohighlight' colspan='$this->numColumns' style='height:100%;border-right:0px;width:100%;'>&nbsp;</td></tr>";
-    }
+        // Initialize list
+        $result= "<input type='hidden' value='$this->pid' name='PID'>\n";
+        $result.= "<input type='hidden' name='position_".$this->pid."' id='position_".$this->pid."'>\n";
+        $height= 450;
+        if ($this->height != 0) {
+            $result.= "<input type='hidden' value='$this->height' id='d_height'>\n";
+            $height= $this->height;
+        }
 
-    // Line color alternation
-    $alt= 0;
-    $deps= 0;
-
-    // Draw department browser if configured and we're not in sub mode
-    $this->useSpan= false;
-    if ($this->departmentBrowser && $this->filter->scope != "sub") {
-      // Fill with department browser if configured this way
-      $departmentIterator= new departmentSortIterator($this->departments, $this->sortDirection[$this->sortColumn]);
-      foreach ($departmentIterator as $row => $entry){
-        $result.="<tr class='rowxp".($alt&1)."'>";
-
-        // Render multi select if needed
-        if ($this->multiSelect) {
-          $result.="<td style='text-align:center;padding:0;' class='list1'>&nbsp;</td>";
-        }
-
-        // Render defined department columns, fill the rest with some stuff
-        $rest= $this->numColumns - 1;
-        foreach ($this->xmlData['table']['department'] as $index => $config) {
-          $colspan= 1;
-          if (isset($config['span'])){
-            $colspan= $config['span'];
-            $this->useSpan= true;
-          }
-          $result.="<td colspan='$colspan' ".$this->colprops[$index]." class='list1'>".$this->renderCell($config['value'], $entry, $row)."</td>";
-          $rest-= $colspan;
-        }
-
-        // Fill remaining cols with nothing
-        $last= $this->numColumns - $rest;
-        for ($i= 0; $i<$rest; $i++){
-          $result.= "<td ".$this->colprops[$last+$i-1]." class='list1'>&nbsp;</td>";
-        }
-        $result.="</tr>";
-
-        $alt++;
-      }
-      $deps= $alt;
-    }
+        $result.= "<div class='listContainer' id='d_scrollbody' style='height:{$height}px; overflow: auto;min-height:".($height+25)."px;'>\n";
+        $result.= "<table summary='$this->headline' style='width:100%;table-layout:fixed' cellspacing='0' cellpadding='0' id='t_scrolltable'>\n";
+        $this->numColumns= count($this->colprops) + (($this->multiSelect|$this->singleSelect)?1:0);
 
-    // Fill with contents, sort as configured
-    foreach ($this->entries as $row => $entry) {
-      $trow= "";
+        // Build list header
+        $result.= "<thead class='fixedListHeader listHeaderFormat'><tr>\n";
+        if ($this->multiSelect || $this->singleSelect) {
+            $width= "24px";
+            if (preg_match('/Konqueror/i', $_SERVER['HTTP_USER_AGENT'])){
+                $width= "28px";
+            }
+            $result.= "<td class='listheader' style='text-align:center;padding:0;width:$width;'>";
+            if($this->multiSelect){
+                $result.= "<input type='checkbox' id='select_all' name='select_all' 
+                    title='"._("Select all")."' onClick='toggle_all_(\"listing_selected_[0-9]*$\",\"select_all\");' >";
+            }else{
+                $result.= "&nbsp;";
+            }
+            $result.="</td>\n";
+        }
+        foreach ($this->header as $header) {
+            $result.= $header;
+        }
+        $result.= "</tr></thead>\n";
+
+        // Build list body
+        $result.= "<tbody class='listScrollContent listBodyFormat' id='t_nscrollbody' style='height:".$height."px;'>\n";
 
-      // Render multi select if needed
-      if ($this->multiSelect) {
-        $trow.="<td style='text-align:center;width:20px;' class='list0'><input type='checkbox' id='listing_selected_$row' name='listing_selected_$row'></td>\n";
-      }
+        // No results? Just take an empty colspanned row
+        if (count($this->entries) + count($this->departments) == 0) {
+            $result.= "<tr><td class='list1nohighlight' colspan='$this->numColumns' style='height:100%;border-right:0px;width:100%;'>&nbsp;</td></tr>";
+        }
+
+        // Line color alternation
+        $alt= 0;
+        $deps= 0;
+
+        // Draw department browser if configured and we're not in sub mode
+        $this->useSpan= false;
+        if ($this->departmentBrowser && $this->filter->scope != "sub") {
+            // Fill with department browser if configured this way
+            $departmentIterator= new departmentSortIterator($this->departments, $this->sortDirection[$this->sortColumn]);
+            foreach ($departmentIterator as $row => $entry){
+                $rowResult= "<tr>";
+
+                // Render multi select if needed
+                if ($this->multiSelect || $this->singleSelect) {
+                    $rowResult.="<td style='text-align:center;padding:0;' class='list1'>&nbsp;</td>";
+                }
+
+                // Render defined department columns, fill the rest with some stuff
+                $rest= $this->numColumns - 1;
+                foreach ($this->xmlData['table']['department'] as $index => $config) {
+                    $colspan= 1;
+                    if (isset($config['span'])){
+                        $colspan= $config['span'];
+                        $this->useSpan= true;
+                    }
+                    $rowResult.="<td colspan='$colspan' ".$this->colprops[$index]." class='list1'>".$this->renderCell($config['value'], $entry, $row)."</td>";
+                    $rest-= $colspan;
+                }
+
+                // Fill remaining cols with nothing
+                $last= $this->numColumns - $rest;
+                for ($i= 0; $i<$rest; $i++){
+                    $rowResult.= "<td ".$this->colprops[$last+$i-1]." class='list1'>&nbsp;</td>";
+                }
+                $rowResult.="</tr>";
+
+                // Apply label to objecttype icon?
+                if (preg_match("/<objectType:([^:]+):(.*)\/>/i", $rowResult, $matches)){
+                    $objectType= image($matches[1], null, LDAP::fix(base64_decode($matches[2])));
+                    $rowResult= preg_replace("/<objectType[^>]+>/", $objectType, $rowResult);
+                }
+                $result.= $rowResult;
+                $alt++;
+            }
 
-      foreach ($this->xmlData['table']['column'] as $index => $config) {
-        $renderedCell= $this->renderCell($config['value'], $entry, $row);
-        $trow.="<td ".$this->colprops[$index]." class='list0'>".$renderedCell."</td>\n";
 
-        // Save rendered column
-        $sort= preg_replace('/.*>([^<]+)<.*$/', '$1', $renderedCell);
-        $sort= preg_replace('/&nbsp;/', '', $sort);
-        if (preg_match('/</', $sort)){
-          $sort= "";
+            $deps= $alt;
         }
-        $this->entries[$row]["_sort$index"]= $sort;
-      }
 
-      // Save rendered entry
-      $this->entries[$row]['_rendered']= $trow;
-    }
+        // Fill with contents, sort as configured
+        $ui = get_userinfo();
+        foreach ($this->entries as $row => $entry) {
+            $trow= "";
 
-    // Complete list by sorting entries for _sort$index and appending them to the output
-    $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType);
-    foreach ($entryIterator as $row => $entry){
-      $alt++;
-      $result.="<tr class='rowxp".($alt&1)."'>\n";
-      $result.= $entry['_rendered'];
-      $result.="</tr>\n";
-    }
+            // Render multi select if needed
+            if ($this->multiSelect) {
+                $trow.="<td style='text-align:center;width:20px;' class='list0'><input type='checkbox' id='listing_selected_$row' name='listing_selected_$row'></td>\n";
+            }
 
-    // Need to fill the list if it's not full (nobody knows why this is 22 ;-))
-    $emptyListStyle= (count($this->entries) + (($this->useSpan && count($this->entries))?$deps:0) == 0)?"border:0;":"";
-    if ((count($this->entries) + $deps) < 22) {
-      $result.= "<tr>";
-      for ($i= 0; $i<$this->numColumns; $i++) {
-        if ($i == 0) {
-          $result.= "<td class='list1nohighlight' style='$emptyListStyle height:100%;'>&nbsp;</td>";
-          continue;
-        }
-        if ($i != $this->numColumns-1) {
-          $result.= "<td class='list1nohighlight' style='$emptyListStyle'>&nbsp;</td>";
-        } else {
-          $result.= "<td class='list1nohighlight' style='border-right:1px solid #AAA;$emptyListStyle'>&nbsp;</td>";
+            if ($this->singleSelect) {
+                $trow.="<td style='text-align:center;width:20px;' class='list0'><input type='radio' id='listing_radio_selected_$row' name='listing_radio_selected' value='{$row}'></td>\n";
+            }
+
+            foreach ($this->xmlData['table']['column'] as $index => $config) {
+                $renderedCell= $this->renderCell($config['value'], $entry, $row);
+                $trow.="<td ".$this->colprops[$index]." class='list0'>".$renderedCell."</td>\n";
+
+                // Save rendered column
+                $sort= preg_replace('/.*>([^<]+)<.*$/', '$1', $renderedCell);
+                $sort= preg_replace('/&nbsp;/', '', $sort);
+                if (preg_match('/</', $sort)){
+                    $sort= "";
+                }
+                $this->entries[$row]["_sort$index"]= $sort;
+            }
+
+            // Save rendered entry
+            $this->entries[$row]['_rendered']= $trow;
         }
-      }
-      $result.= "</tr>";
-    }
 
-    // Close list body
-    $result.= "</tbody></table></div></td></tr>";
+        // Complete list by sorting entries for _sort$index and appending them to the output
+        $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType);
+        foreach ($entryIterator as $row => $entry){
+
+            // Apply label to objecttype icon?
+            if (preg_match("/<objectType:([^:]+):(.*)\/>/i", $entry['_rendered'], $matches)){
+                if (preg_match("/<rowLabel:([a-z0-9_-]*)\/>/i", $entry['_rendered'], $m)) {
+                    $objectType= image($matches[1]."[".$m[1]."]", null, LDAP::fix(base64_decode($matches[2])));
+                } else {
+                    $objectType= image($matches[1], null, LDAP::fix(base64_decode($matches[2])));
+                }
+                $entry['_rendered']= preg_replace("/<objectType[^>]+>/", $objectType, $entry['_rendered']);
+                $entry['_rendered']= preg_replace("/<rowLabel[^>]+>/", '', $entry['_rendered']);
+            }
 
-    // Add the footer if requested
-    if ($this->showFooter) {
-      $result.= "<tr><td class='nlistFooter'>";
+            // Apply custom class to row?
+            if (preg_match("/<rowClass:([a-z0-9_-]*)\/>/i", $entry['_rendered'], $matches)) {
+                $result.="<tr class='".$matches[1]."'>\n";
+                $result.= preg_replace("/<rowClass[^>]+>/", '', $entry['_rendered']);
+            } else {
+                $result.="<tr>\n";
+                $result.= $entry['_rendered'];
+            }
 
-      foreach ($this->objectTypes as $objectType) {
-        if (isset($this->objectTypeCount[$objectType['label']])) {
-          $label= _($objectType['label']);
-          $result.= "<img class='center' src='".$objectType['image']."' title='$label' alt='$label'>&nbsp;".$this->objectTypeCount[$objectType['label']]."&nbsp;&nbsp;&nbsp;&nbsp;";
+            $result.="</tr>\n";
+            $alt++;
         }
-      }
 
-      $result.= "</td></tr>";
-    }
+        // Need to fill the list if it's not full (nobody knows why this is 22 ;-))
+        $emptyListStyle= (count($this->entries) + (($this->useSpan && count($this->entries))?$deps:0) == 0)?"border:0;":"";
+        if ((count($this->entries) + $deps) < 22) {
+            $result.= "<tr>";
+            for ($i= 0; $i<$this->numColumns; $i++) {
+                if ($i == 0) {
+                    $result.= "<td class='list1nohighlight' style='$emptyListStyle height:100%;'>&nbsp;</td>";
+                    continue;
+                }
+                if ($i != $this->numColumns-1) {
+                    $result.= "<td class='list1nohighlight' style='$emptyListStyle'>&nbsp;</td>";
+                } else {
+                    $result.= "<td class='list1nohighlight' style='border-right:0;$emptyListStyle'>&nbsp;</td>";
+                }
+            }
 
-    // Close list
-    $result.= "</table>";
-    $result.= $switch?"<input type='hidden' id='list_workaround'>":"";
-
-    // Add scroll positioner
-    $result.= '<script type="text/javascript" language="javascript">';
-    $result.= '$("t_nscrollbody").scrollTop= '.$this->scrollPosition.';';
-    $result.= 'var box = $("t_nscrollbody").onscroll= function() {$("position_'.$this->pid.'").value= this.scrollTop;}';
-    $result.= '</script>';
-
-    $smarty= get_smarty();
-    $smarty->assign("usePrototype", "true");
-    $smarty->assign("FILTER", $this->filter->render());
-    $smarty->assign("SIZELIMIT", print_sizelimit_warning());
-    $smarty->assign("LIST", $result);
-
-    // Assign navigation elements
-    $nav= $this->renderNavigation();
-    foreach ($nav as $key => $html) {
-      $smarty->assign($key, $html);
-    }
+            $result.= "</tr>";
+        }
 
-    // Assign action menu / base
-    $smarty->assign("ACTIONS", $this->renderActionMenu());
-    $smarty->assign("BASE", $this->renderBase());
+        // Close list body
+        $result.= "</tbody></table></div>";
 
-    // Assign separator
-    $smarty->assign("SEPARATOR", "<img src='images/lists/seperator.png' alt='-' align='middle' height='16' width='1' class='center'>");
+        // Add the footer if requested
+        if ($this->showFooter) {
+            $result.= "<div class='nlistFooter'><div style='padding:3px'>";
 
-    // Assign summary
-    $smarty->assign("HEADLINE", $this->headline);
+            foreach ($this->objectTypes as $objectType) {
+                if (isset($this->objectTypeCount[$objectType['label']])) {
+                    $label= _($objectType['label']);
+                    $result.= image($objectType['image'], null, $label)."&nbsp;".$this->objectTypeCount[$objectType['label']]."&nbsp;&nbsp;";
+                }
+            }
 
-    // Try to load template from plugin the folder first...
-    $file = get_template_path($this->xmlData['definition']['template'], true);
+            $result.= "</div></div>";
+        }
 
-    // ... if this fails, try to load the file from the theme folder.
-    if(!file_exists($file)){
-      $file = get_template_path($this->xmlData['definition']['template']);
-    }
+        // Close list
+        $result.= $switch?"<input type='hidden' id='list_workaround'>":"";
 
-    return ($smarty->fetch($file));
-  }
+        // Add scroll positioner
+        $result.= '<script type="text/javascript" language="javascript">';
+        $result.= '$("t_nscrollbody").scrollTop= '.$this->scrollPosition.';';
+        $result.= 'var box = $("t_nscrollbody").onscroll= function() {$("position_'.$this->pid.'").value= this.scrollTop;}';
+        $result.= '</script>';
 
+        $smarty= get_smarty();
 
-  function update()
-  {
-    global $config;
-    $ui= get_userinfo();
+        $smarty->assign("FILTER", $this->filter->render());
+        $smarty->assign("SIZELIMIT", print_sizelimit_warning());
+        $smarty->assign("LIST", $result);
 
-    // Reset object counter / DN mapping
-    $this->objectTypeCount= array();
-    $this->objectDnMapping= array();
+        // Assign navigation elements
+        $nav= $this->renderNavigation();
+        foreach ($nav as $key => $html) {
+            $smarty->assign($key, $html);
+        }
 
-    // Do not do anything if this is not our PID
-    if(isset($_REQUEST['PID']) && $_REQUEST['PID'] != $this->pid) {
-      return;
-    }
+        // Assign action menu / base
+        $smarty->assign("HEADLINE", $this->headline);
+        $smarty->assign("ACTIONS", $this->renderActionMenu());
+        $smarty->assign("BASE", $this->renderBase());
 
-    // Save position if set
-    if (isset($_POST['position_'.$this->pid]) && is_numeric($_POST['position_'.$this->pid])) {
-      $this->scrollPosition= $_POST['position_'.$this->pid];
-    }
+        // Assign separator
+        $smarty->assign("SEPARATOR", "<img src='images/lists/seperator.png' alt='-' align='middle' height='16' width='1' class='center'>");
 
-    // Save base
-    if (isset($_POST['BASE']) && $this->baseMode) {
-      $base= get_post('BASE');
-      if (isset($this->bases[$base])) {
-        $this->base= $base;
-        session::global_set("CurrentMainBase", $this->base);
-      }
-    }
+        // Assign summary
+        $smarty->assign("HEADLINE", $this->headline);
+
+        // Try to load template from plugin the folder first...
+        $file = get_template_path($this->xmlData['definition']['template'], true);
 
-    // Override the base if we got a message from the browser navigation
-    if ($this->departmentBrowser && isset($_GET['act'])) {
-      if (preg_match('/^department_([0-9]+)$/', validate($_GET['act']), $match)){
-        if (isset($this->departments[$match[1]])){
-          $this->base= $this->departments[$match[1]]['dn'];
-          session::global_set("CurrentMainBase", $this->base);
+        // ... if this fails, try to load the file from the theme folder.
+        if(!file_exists($file)){
+            $file = get_template_path($this->xmlData['definition']['template']);
         }
-      }
-    }
 
-    // Filter POST with "act" attributes -> posted from action menu
-    if (isset($_POST['exec_act']) && $_POST['act'] != '') {
-      if (preg_match('/^export.*$/', $_POST['act']) && isset($this->exporter[$_POST['act']])) {
-        $exporter= $this->exporter[$_POST['act']];
-        $userinfo= ", "._("created by")." ".$ui->cn." - ".strftime('%A, %d. %B %Y, %H:%M:%S');
-        $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType);
-        $sortedEntries= array();
-        foreach ($entryIterator as $entry){
-          $sortedEntries[]= $entry;
-        }
-        $instance= new $exporter['class']($this->headline.$userinfo, $this->plainHeader, $sortedEntries, $this->exportColumns);
-        $type= call_user_func(array($exporter['class'], "getInfo"));
-        $type= $type[$_POST['act']];
-        send_binary_content($instance->query(), $type['filename'], $type= $type['mime']);
-      }
+        return ($smarty->fetch($file));
     }
 
-    // Filter GET with "act" attributes
-    if (isset($_GET['act'])) {
-      $key= validate($_GET['act']);
-      if (preg_match('/^SORT_([0-9]+)$/', $key, $match)) {
-        // Switch to new column or invert search order?
-        $column= $match[1];
-        if ($this->sortColumn != $column) {
-          $this->sortColumn= $column;
-        } else {
-          $this->sortDirection[$column]= !$this->sortDirection[$column];
+
+    function update()
+    {
+        global $config;
+        $ui= get_userinfo();
+
+        // Take care of base selector
+        if ($this->baseMode) {
+            $this->baseSelector->update();
+
+            // Check if a wrong base was supplied
+            if(!$this->baseSelector->checkLastBaseUpdate()){
+                msg_dialog::display(_("Error"), msgPool::check_base(), ERROR_DIALOG);
+            }
         }
 
-        // Allow header to update itself according to the new sort settings
-        $this->renderHeader();
-      }
-    }
+        // Save base
+        $refresh= false;
+        if ($this->baseMode) {
+            $this->base= $this->baseSelector->getBase();
+            session::global_set("CurrentMainBase", $this->base);
+            $refresh= true;
+        }
 
-    // Override base if we got signals from the navigation elements
-    $action= "";
-    foreach ($_POST as $key => $value) {
-      if (preg_match('/^(ROOT|BACK|HOME)_x$/', $key, $match)) {
-        $action= $match[1];
-        break;
-      }
-    }
 
-    // Navigation handling
-    if ($action == 'ROOT') {
-      $deps= $ui->get_module_departments($this->module);
-      $this->base= $deps[0];
-    }
-    if ($action == 'BACK') {
-      $deps= $ui->get_module_departments($this->module);
-      $base= preg_replace("/^[^,]+,/", "", $this->base);
-      if(in_array_ics($base, $deps)){
-        $this->base= $base;
-      }
-    }
-    if ($action == 'HOME') {
-      $ui= get_userinfo();
-      $this->base= $this->filter->getObjectBase($ui->dn);
-    }
+        // Reset object counter / DN mapping
+        $this->objectTypeCount= array();
+        $this->objectDnMapping= array();
 
-    // Reload departments
-    if ($this->departmentBrowser){
-      $this->departments= $this->getDepartments();
-    }
+        // Do not do anything if this is not our PID
+        if($refresh || !(isset($_REQUEST['PID']) && $_REQUEST['PID'] != $this->pid)) {
 
-    // Update filter and refresh entries
-    $this->filter->setBase($this->base);
-    $this->entries= $this->filter->query();
-  }
+            // Save position if set
+            if (isset($_POST['position_'.$this->pid]) && is_numeric($_POST['position_'.$this->pid])) {
+                $this->scrollPosition= get_post('position_'.$this->pid);
+            }
 
+            // Override the base if we got a message from the browser navigation
+            if ($this->departmentBrowser && isset($_GET['act'])) {
+                if (preg_match('/^department_([0-9]+)$/', validate($_GET['act']), $match)){
+                    if (isset($this->departments[$match[1]])){
+                        $this->base= $this->departments[$match[1]]['dn'];
+                        if ($this->baseMode) {
+                            $this->baseSelector->setBase($this->base);
+                        }
+                        session::global_set("CurrentMainBase", $this->base);
+                    }
+                }
+            }
 
-  function setBase($base)
-  {
-    $this->base= $base;
-  }
+            // Filter POST with "act" attributes -> posted from action menu
+            if (isset($_POST['exec_act']) && $_POST['act'] != '') {
+                if (preg_match('/^export.*$/', $_POST['act']) && isset($this->exporter[$_POST['act']])) {
+                    $exporter= $this->exporter[get_post('act')];
+                    $userinfo= ", "._("created by")." ".$ui->cn." - ".strftime('%A, %d. %B %Y, %H:%M:%S');
+                    $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType);
+                    $sortedEntries= array();
+                    foreach ($entryIterator as $entry){
+                        $sortedEntries[]= $entry;
+                    }
+                    $instance= new $exporter['class']($this->headline.$userinfo, $this->plainHeader, $sortedEntries, $this->exportColumns);
+                    $type= call_user_func(array($exporter['class'], "getInfo"));
+                    $type= $type[get_post('act')];
+                    send_binary_content($instance->query(), $type['filename'], $type= $type['mime']);
+                }
+            }
 
+            // Filter GET with "act" attributes
+            if (isset($_GET['act'])) {
+                $key= validate($_GET['act']);
+                if (preg_match('/^SORT_([0-9]+)$/', $key, $match)) {
+                    // Switch to new column or invert search order?
+                    $column= $match[1];
+                    if ($this->sortColumn != $column) {
+                        $this->sortColumn= $column;
+                    } else {
+                        $this->sortDirection[$column]= !$this->sortDirection[$column];
+                    }
+
+                    // Allow header to update itself according to the new sort settings
+                    $this->renderHeader();
+                }
+            }
 
-  function getBase()
-  {
-    return $this->base;
-  }
+            // Override base if we got signals from the navigation elements
+            $action= "";
+            foreach ($_POST as $key => $value) {
+                if (preg_match('/^(ROOT|BACK|HOME)(_x)?$/', $key, $match)) {
+                    $action= $match[1];
+                    break;
+                }
+            }
 
+            // Navigation handling
+            if ($action == 'ROOT') {
+                $deps= $ui->get_module_departments($this->categories);
+                $this->base= $deps[0];
+                $this->baseSelector->setBase($this->base);
+                session::global_set("CurrentMainBase", $this->base);
+            }
+            if ($action == 'BACK') {
+                $deps= $ui->get_module_departments($this->categories);
+                $base= preg_replace("/^[^,]+,/", "", $this->base);
+                if(in_array_ics($base, $deps)){
+                    $this->base= $base;
+                    $this->baseSelector->setBase($this->base);
+                    session::global_set("CurrentMainBase", $this->base);
+                }
+            }
+            if ($action == 'HOME') {
+                $ui= get_userinfo();
+                $this->base= get_base_from_people($ui->dn);
+                $this->baseSelector->setBase($this->base);
+                session::global_set("CurrentMainBase", $this->base);
+            }
+        }
 
-  function parseLayout($layout)
-  {
-    $result= array();
-    $layout= preg_replace("/^\|/", "", $layout);
-    $layout= preg_replace("/\|$/", "", $layout);
-    $cols= split("\|", $layout);
-
-    foreach ($cols as $index => $config) {
-      if ($config != "") {
-        $res= "";
-        $components= split(';', $config);
-        foreach ($components as $part) {
-          if (preg_match("/^r$/", $part)) {
-            $res.= "text-align:right;";
-            continue;
-          }
-          if (preg_match("/^l$/", $part)) {
-            $res.= "text-align:left;";
-            continue;
-          }
-          if (preg_match("/^c$/", $part)) {
-            $res.= "text-align:center;";
-            continue;
-          }
-          if (preg_match("/^[0-9]+(|px|%)$/", $part)) {
-            $res.= "width:$part;min-width:$part;";
-            continue;
-          }
+        // Reload departments
+        if ($this->departmentBrowser){
+            $this->departments= $this->getDepartments();
         }
 
-        // Add minimum width for scalable columns
-        if (!preg_match('/width:/', $res)){
-          $res.= "min-width:200px;";
+        // Update filter and refresh entries
+        $this->filter->setBase($this->base);
+        $this->entries= $this->filter->query();
+
+        // Check entry acls
+        if(!$this->noAclChecks){
+            foreach($this->entries as $row => $entry){
+                $acl = "";
+                $found = false;
+                foreach($this->aclToObjectClass as $category => $ocs){
+                    if(count(array_intersect($ocs, $entry['objectClass']))){
+                        $acl .= $ui->get_permissions($entry['dn'],$category, 0);
+                        $found = true;
+                    }
+                }
+                if(!preg_match("/r/", $acl) && $found){
+                    unset($this->entries[$row]);
+                    continue;
+                }
+            }
         }
 
-        $result[$index]= " style='$res' ";
-      } else {
-        $result[$index]= " style='min-width:100px'";
-      }
+        // Fix filter if querie returns NULL
+        if ($this->entries == null) {
+            $this->entries= array();
+        }
     }
 
-    // Save number of columns for later use
-    $this->numColumns= count($cols);
 
-    return $result;
-  }
-
-
-  function renderCell($data, $config, $row)
-  {
-    // Replace flat attributes in data string
-    for ($i= 0; $i<$config['count']; $i++) {
-      $attr= $config[$i];
-      $value= "";
-      if (is_array($config[$attr])) {
-        $value= $config[$attr][0];
-      } else {
-        $value= $config[$attr];
-      }
-      $data= preg_replace("/%\{$attr\}/", $value, $data);
+    function setBase($base)
+    {
+        $this->base= $base;
+        if ($this->baseMode) {
+            $this->baseSelector->setBase($this->base);
+        }
     }
 
-    // Watch out for filters and prepare to execute them
-    $data= $this->processElementFilter($data, $config, $row);
 
-    // Replace all non replaced %{...} instances because they
-    // are non resolved attributes or filters
-    $data= preg_replace('/%{[^}]+}/', '&nbsp;', $data);
+    function getBase()
+    {
+        return $this->base;
+    }
+
+
+    function parseLayout($layout)
+    {
+        $result= array();
+        $layout= preg_replace("/^\|/", "", $layout);
+        $layout= preg_replace("/\|$/", "", $layout);
+        $cols= explode("|", $layout);
+
+        foreach ($cols as $index => $config) {
+            if ($config != "") {
+                $res= "";
+                $components= explode(';', $config);
+                foreach ($components as $part) {
+                    if (preg_match("/^r$/", $part)) {
+                        $res.= "text-align:right;";
+                        continue;
+                    }
+                    if (preg_match("/^l$/", $part)) {
+                        $res.= "text-align:left;";
+                        continue;
+                    }
+                    if (preg_match("/^c$/", $part)) {
+                        $res.= "text-align:center;";
+                        continue;
+                    }
+                    if (preg_match("/^[0-9]+(|px|%)$/", $part)) {
+                        $res.= "width:$part;min-width:$part;";
+                        continue;
+                    }
+                }
+
+                // Add minimum width for scalable columns
+                if (!preg_match('/width:/', $res)){
+                    $res.= "min-width:200px;";
+                }
+
+                $result[$index]= " style='$res'";
+            } else {
+                $result[$index]= " style='min-width:100px;'";
+            }
+        }
 
-    return $data;
-  }
+        // Save number of columns for later use
+        $this->numColumns= count($cols);
 
+        // Add no border to the last column
+        $result[$this->numColumns-1]= preg_replace("/'$/", "border-right:0;'", $result[$this->numColumns-1]);
 
-  function renderBase()
-  {
-    if (!$this->baseMode) {
-      return;
+        return $result;
     }
 
-    $result= "<select name='BASE' onChange='mainform.submit()' size='1'>";
-    $firstDN= null;
-    $found= false;
 
-    foreach ($this->bases as $key=>$value) {
-      // Keep first entry to fall back eventually
-      if(!$firstDN) {
-        $firstDN= $key;
-      }
+    function renderCell($data, $config, $row)
+    {
+        // Replace flat attributes in data string
+        for ($i= 0; $i<$config['count']; $i++) {
+            $attr= $config[$i];
+            $value= "";
+            if (is_array($config[$attr])) {
+                $value= $config[$attr][0];
+            } else {
+                $value= $config[$attr];
+            }
+            $data= preg_replace("/%\{$attr\}/", $value, $data);
+        }
 
-      // Prepare to render entry
-      $selected= "";
-      if ($key == $this->base) {
-        $selected= " selected";
-        $found= true;
-      }
-      $key = htmlentities($key,ENT_QUOTES);
-      $result.= "\n<option value=\"".$key."\"$selected>".$value."</option>";
-    }
+        // Watch out for filters and prepare to execute them
+        $data= $this->processElementFilter($data, $config, $row);
+
+        // Replace all non replaced %{...} instances because they
+        // are non resolved attributes or filters
+        $data= preg_replace('/%{[^}]+}/', '&nbsp;', $data);
 
-    $result.= "</select>";
+        return $data;
+}
 
-    // Reset the currently used base to the first DN we found if there
-    // was no match.
-    if(!$found){
-      $this->base = $firstDN;
+
+function renderBase()
+{
+    if (!$this->baseMode) {
+        return;
     }
 
-    return $result;
-  }
+    return $this->baseSelector->render();
+}
 
 
-  function processElementFilter($data, $config, $row)
-  {
+function processElementFilter($data, $config, $row)
+{
     preg_match_all("/%\{filter:([^(]+)\((.*)\)\}/", $data, $matches, PREG_SET_ORDER);
 
     foreach ($matches as $match) {
-      $cl= "";
-      $method= "";
-      if (preg_match('/::/', $match[1])) {
-        $cl= preg_replace('/::.*$/', '', $match[1]);
-        $method= preg_replace('/^.*::/', '', $match[1]);
-      } else {
-        if (!isset($this->filters[$match[1]])) {
-          continue;
+        $cl= "";
+        $method= "";
+        if (preg_match('/::/', $match[1])) {
+            $cl= preg_replace('/::.*$/', '', $match[1]);
+            $method= preg_replace('/^.*::/', '', $match[1]);
+        } else {
+            if (!isset($this->filters[$match[1]])) {
+                continue;
+            }
+            $cl= preg_replace('/::.*$/', '', $this->filters[$match[1]]);
+            $method= preg_replace('/^.*::/', '', $this->filters[$match[1]]);
         }
-        $cl= preg_replace('/::.*$/', '', $this->filters[$match[1]]);
-        $method= preg_replace('/^.*::/', '', $this->filters[$match[1]]);
-      }
 
-      // Prepare params for function call
-      $params= array();
-      preg_match_all('/"[^"]+"|[^,]+/', $match[2], $parts);
-      foreach ($parts[0] as $param) {
+        // Prepare params for function call
+        $params= array();
+        preg_match_all('/"[^"]+"|[^,]+/', $match[2], $parts);
+        foreach ($parts[0] as $param) {
 
-        // Row is replaced by the row number
-        if ($param == "row") {
-          $params[]= $row;
-          continue;
-        }
+            // Row is replaced by the row number
+            if ($param == "row") {
+                $params[]= $row;
+                continue;
+            }
 
-        // pid is replaced by the current PID
-        if ($param == "pid") {
-          $params[]= $this->pid;
-          continue;
-        }
+            // pid is replaced by the current PID
+            if ($param == "pid") {
+                $params[]= $this->pid;
+                continue;
+            }
 
-        // base is replaced by the current base
-        if ($param == "base") {
-          $params[]= $this->getBase();
-          continue;
-        }
+            // base is replaced by the current base
+            if ($param == "base") {
+                $params[]= $this->getBase();
+                continue;
+            }
 
-        // Fixie with "" is passed directly
-        if (preg_match('/^".*"$/', $param)){
-          $params[]= preg_replace('/"/', '', $param);
-          continue;
-        }
+            // Fixie with "" is passed directly
+            if (preg_match('/^".*"$/', $param)){
+                $params[]= preg_replace('/"/', '', $param);
+                continue;
+            }
 
-        // Move acl information if needed
-        if ($param == "acl") {
-          $otype= $this->getObjectType($this->objectTypes, $config["objectClass"]);
-          $category= $this->category[$otype];
-          $params[]= $ui->get_category_permissions($config["dn"], $category);
-          continue;
-        }
+            // Move dn if needed
+            if ($param == "dn") {
+                $params[]= LDAP::fix($config["dn"]);
+                continue;
+            }
 
-        // Move dn if needed
-        if ($param == "dn") {
-          $params[]= LDAP::fix($config["dn"]);
-          continue;
+            // LDAP variables get replaced by their objects
+            for ($i= 0; $i<$config['count']; $i++) {
+                if ($param == $config[$i]) {
+                    $values= $config[$config[$i]];
+                    if (is_array($values)){
+                        unset($values['count']);
+                    }
+                    $params[]= $values;
+                    break;
+                }
+            }
         }
 
-        // LDAP variables get replaced by their objects
-        for ($i= 0; $i<$config['count']; $i++) {
-          if ($param == $config[$i]) {
-            $values= $config[$config[$i]];
-            if (is_array($values)){
-              unset($values['count']);
-            }
-            $params[]= $values;
-            break;
-          }
-        }
-      }
-
-      // Replace information
-      if ($cl == "listing") {
-        // Non static call - seems to result in errors
-        $data= @preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($this, "$method"), $params), $data);
-      } else {
-        // Static call
-        $data= preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($cl, $method), $params), $data);
-      }
+        // Replace information
+        if ($cl == "listing") {
+            // Non static call - seems to result in errors
+            $data= @preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($this, "$method"), $params), $data);
+        } else {
+            // Static call
+            $data= preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($cl, $method), $params), $data);
+        }
     }
 
     return $data;
-  }
+}
 
 
-  function getObjectType($types, $classes)
-  {
+function getObjectType($types, $classes)
+{
     // Walk thru types and see if there's something matching
     foreach ($types as $objectType) {
-      $ocs= $objectType['objectClass'];
-      if (!is_array($ocs)){
-        $ocs= array($ocs);
-      }
-
-      $found= true;
-      foreach ($ocs as $oc){
-        if (preg_match('/^!(.*)$/', $oc, $match)) {
-          $oc= $match[1];
-          if (in_array($oc, $classes)) {
-            $found= false;
-          }
-        } else {
-          if (!in_array($oc, $classes)) {
-            $found= false;
-          }
+        $ocs= $objectType['objectClass'];
+        if (!is_array($ocs)){
+            $ocs= array($ocs);
         }
-      }
 
-      if ($found) {
-        return $objectType;
-      }
+        $found= true;
+        foreach ($ocs as $oc){
+            if (preg_match('/^!(.*)$/', $oc, $match)) {
+                $oc= $match[1];
+                if (in_array_strict($oc, $classes)) {
+                    $found= false;
+                }
+            } else {
+                if (!in_array_strict($oc, $classes)) {
+                    $found= false;
+                }
+            }
+        }
+
+        if ($found) {
+            return $objectType;
+        }
     }
 
     return null;
-  }
+}
 
 
-  function filterObjectType($dn, $classes)
-  {
+function filterObjectType($dn, $classes)
+{
     // Walk thru classes and return on first match
     $result= "&nbsp;";
 
     $objectType= $this->getObjectType($this->objectTypes, $classes);
     if ($objectType) {
-      $this->objectDnMapping[$dn]= $objectType["objectClass"];
-      $result= "<img class='center' title='".LDAP::fix($dn)."' src='".$objectType["image"]."'>";
-      if (!isset($this->objectTypeCount[$objectType['label']])) {
-        $this->objectTypeCount[$objectType['label']]= 0;
-      }
-      $this->objectTypeCount[$objectType['label']]++;
+        $this->objectDnMapping[$dn]= $objectType["objectClass"];
+        $result= "<objectType:".$objectType["image"].":".base64_encode(LDAP::fix($dn))."/>";
+        if (!isset($this->objectTypeCount[$objectType['label']])) {
+            $this->objectTypeCount[$objectType['label']]= 0;
+        }
+        $this->objectTypeCount[$objectType['label']]++;
     }
 
     return $result;
-  }
+}
 
 
-  function filterActions($dn, $row, $classes)
-  {
+function filterActions($dn, $row, $classes)
+{
     // Do nothing if there's no menu defined
     if (!isset($this->xmlData['actiontriggers']['action'])) {
-      return "&nbsp;";
+        return "&nbsp;";
     }
 
     // Go thru all actions
     $result= "";
     $actions= $this->xmlData['actiontriggers']['action'];
+
+    // Ensure we've a valid actions array, if there is only one action in the actiontriggers col
+    //  then we've to create a valid array here.
+    if(isset($actions['name'])) $actions = array($actions);
+
     foreach($actions as $action) {
-      // Skip the entry completely if there's no permission to execute it
-      if (!$this->hasActionPermission($action, $dn)) {
-        $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-        continue;
-      }
-
-      // Skip entry if the pseudo filter does not fit
-      if (isset($action['filter']) && preg_match('/^[a-z0-9_]+!?=[a-z0-9_]+$/i', $action['filter'])) {
-        list($fa, $fv)= split('=', $action['filter']);
-        if (preg_match('/^(.*)!$/', $fa, $m)){
-          $fa= $m[1];
-          if (isset($this->entries[$row][$fa]) && $this->entries[$row][$fa][0] == $fv) {
-            $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-            continue;
-          }
-        } else {
-          if (!isset($this->entries[$row][$fa]) && !$this->entries[$row][$fa][0] == $fv) {
-            $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
+        // Skip the entry completely if there's no permission to execute it
+        if (!$this->hasActionPermission($action, $dn, $classes)) {
+            $result.= image('images/empty.png');
             continue;
-          }
         }
-      }
 
-
-      // If there's an objectclass definition and we don't have it
-      // add an empty picture here.
-      if (isset($action['objectclass'])){
-        $objectclass= $action['objectclass'];
-        if (preg_match('/^!(.*)$/', $objectclass, $m)){
-          $objectclass= $m[1];
-          if(in_array($objectclass, $classes)) {
-            $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-            continue;
-          }
-        } elseif (is_string($objectclass)) {
-          if(!in_array($objectclass, $classes)) {
-            $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-            continue;
-          }
-        } elseif (is_array($objectclass)) {
-          if(count(array_intersect($objectclass, $classes)) != count($objectclass)){
-            $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-            continue;
-          }
+        // Skip entry if the pseudo filter does not fit
+        if (isset($action['filter']) && preg_match('/^[a-z0-9_]+!?=[a-z0-9_]+$/i', $action['filter'])) {
+            list($fa, $fv)= explode('=', $action['filter']);
+            if (preg_match('/^(.*)!$/', $fa, $m)){
+                $fa= $m[1];
+                if (isset($this->entries[$row][$fa]) && $this->entries[$row][$fa][0] == $fv) {
+                    $result.= image('images/empty.png');
+                    continue;
+                }
+            } else {
+                if (!isset($this->entries[$row][$fa]) && !$this->entries[$row][$fa][0] == $fv) {
+                    $result.= image('images/empty.png');
+                    continue;
+                }
+            }
         }
-      }
 
-      // Render normal entries as usual
-      if ($action['type'] == "entry") {
-        $label= $this->processElementFilter($action['label'], $this->entries[$row], $row);
-        $image= $this->processElementFilter($action['image'], $this->entries[$row], $row);
-        $result.="<input class='center' type='image' src='$image' title='$label' ".
-                 "name='listing_".$action['name']."_$row' style='padding:1px'>";
-      }
 
-      // Handle special types
-      if ($action['type'] == "copypaste" || $action['type'] == "snapshot") {
+        // If there's an objectclass definition and we don't have it
+        // add an empty picture here.
+        if (isset($action['objectclass'])){
+            $objectclass= $action['objectclass'];
+            if (preg_match('/^!(.*)$/', $objectclass, $m)){
+                $objectclass= $m[1];
+                if(in_array_strict($objectclass, $classes)) {
+                    $result.= image('images/empty.png');
+                    continue;
+                }
+            } elseif (is_string($objectclass)) {
+                if(!in_array_strict($objectclass, $classes)) {
+                    $result.= image('images/empty.png');
+                    continue;
+                }
+            } elseif (is_array($objectclass)) {
+                if(count(array_intersect($objectclass, $classes)) != count($objectclass)){
+                    $result.= image('images/empty.png');
+                    continue;
+                }
+            }
+        }
 
-        $objectType= $this->getObjectType($this->objectTypes, $this->entries[$row]['objectClass']);
-        $category= $class= null;
-        if ($objectType) {
-          $category= $objectType['category'];
-          $class= $objectType['class'];
+        // Render normal entries as usual
+        if ($action['type'] == "entry") {
+            $label= $this->processElementFilter($action['label'], $this->entries[$row], $row);
+            $image= $this->processElementFilter($action['image'], $this->entries[$row], $row);
+            $result.= image($image, "listing_".$action['name']."_$row", $label);
         }
 
-        if ($action['type'] == "copypaste") {
-          $copy = !isset($action['copy']) || $action['copy'] == "true";
-          $cut = !isset($action['cut']) || $action['cut'] == "true";
-          $result.= $this->renderCopyPasteActions($row, $this->entries[$row]['dn'], $category, $class,$copy,$cut);
-        } else {
-          $result.= $this->renderSnapshotActions($row, $this->entries[$row]['dn'], $category, $class);
+        // Handle special types
+        if ($action['type'] == "copypaste" || $action['type'] == "snapshot") {
+
+            $objectType= $this->getObjectType($this->objectTypes, $this->entries[$row]['objectClass']);
+            $category= $class= null;
+            if ($objectType) {
+                $category= $objectType['category'];
+                $class= $objectType['class'];
+            }
+
+            if ($action['type'] == "copypaste") {
+                $copy = !isset($action['copy']) || $action['copy'] == "true";
+                $cut = !isset($action['cut']) || $action['cut'] == "true";
+                $result.= $this->renderCopyPasteActions($row, $this->entries[$row]['dn'], $category, $class,$copy,$cut);
+            } else {
+                $result.= $this->renderSnapshotActions($row, $this->entries[$row]['dn'], $category, $class);
+            }
         }
-      }
     }
 
     return $result;
-  }
+}
 
 
-  function filterDepartmentLink($row, $dn, $description)
-  {
+function filterDepartmentLink($row, $dn, $description)
+{
     $attr= $this->departments[$row]['sort-attribute'];
     $name= $this->departments[$row][$attr];
     if (is_array($name)){
-      $name= $name[0];
+        $name= $name[0];
     }
     $result= sprintf("%s [%s]", $name, $description[0]);
-    return("<a href='?plug=".$_GET['plug']."&amp;PID=$this->pid&amp;act=department_$row' title='$dn'>$result</a>");
-  }
+    return("<a href='?plug=".$_GET['plug']."&amp;PID=$this->pid&amp;act=department_$row' title='$dn'>".set_post($result)."</a>");
+}
 
 
-  function filterLink()
-  {
+function filterLink()
+{
     $result= "&nbsp;";
 
     $row= func_get_arg(0);
     $pid= $this->pid;
-    $dn= LDAP::fix(func_get_arg(1));
+
+    // Prepare title attribute
+    $titleAttr = func_get_arg(1);
+    if(is_array($titleAttr) && isset($titleAttr[0])){
+        $titleAttr = $titleAttr[0];
+    }
+    $titleAttr = LDAP::fix($titleAttr);
+
     $params= array(func_get_arg(2));
 
     // Collect sprintf params
     for ($i = 3;$i < func_num_args();$i++) {
-      $val= func_get_arg($i);
-      if (is_array($val)){
-        $params[]= $val[0];
-        continue;
-      }
-      $params[]= $val;
+        $val= func_get_arg($i);
+        if (is_array($val)){
+            $params[]= $val[0];
+            continue;
+        }
+        $params[]= $val;
     }
 
     $result= "&nbsp;";
     $trans= call_user_func_array("sprintf", $params);
     if ($trans != "") {
-      return("<a href='?plug=".$_GET['plug']."&amp;PID=$pid&amp;act=listing_edit_$row' title='$dn'>$trans</a>");
+        return("<a href='?plug=".$_GET['plug']."&amp;PID=$pid&amp;act=listing_edit_$row' title='{$titleAttr}'>".set_post($trans)."</a>");
     }
 
     return $result;
-  }
+}
 
 
-  function renderNavigation()
-  {
+function renderNavigation()
+{
     $result= array();
     $enableBack = true;
     $enableRoot = true;
@@ -979,153 +1062,159 @@ class listing {
     $ui = get_userinfo();
 
     /* Check if base = first available base */
-    $deps = $ui->get_module_departments($this->module);
+    $deps = $ui->get_module_departments($this->categories);
 
     if(!count($deps) || $deps[0] == $this->filter->base){
-      $enableBack = false;
-      $enableRoot = false;
+        $enableBack = false;
+        $enableRoot = false;
     }
 
     $listhead ="";
 
     /* Check if we are in users home  department */
-    if(!count($deps) || $this->filter->base == $this->filter->getObjectBase($ui->dn)){
-      $enableHome = false;
+    if(!count($deps) || $this->filter->base == get_base_from_people($ui->dn)){
+        $enableHome = false;
     }
 
     /* Draw root button */
     if($enableRoot){
-      $result["ROOT"]= "<input class='center' type='image' src='images/lists/root.png' align='middle' ".
-                       "title='"._("Go to root department")."' name='ROOT' alt='"._("Root")."'>";
+        $result["ROOT"]= image('images/lists/root.png', 'ROOT', _("Root"));
     }else{
-      $result["ROOT"]= "<img src='images/lists/root_grey.png' class='center' alt='"._("Root")."'>";
+        $result["ROOT"]= image('images/lists/root-grey.png', null, _("Root"));
     }
 
     /* Draw back button */
     if($enableBack){
-      $result["BACK"]= "<input class='center' type='image' align='middle' src='images/lists/back.png' ".
-                       "title='"._("Go up one department")."' alt='"._("Up")."' name='BACK'>";
+        $result["BACK"]= image('images/lists/back.png', 'BACK', _("Go to preceding level"));
     }else{
-      $result["BACK"]= "<img src='images/lists/back_grey.png' class='center' alt='"._("Up")."'>";
+        $result["BACK"]= image('images/lists/back-grey.png', null, _("Go to preceding level"));
     }
 
+    /* Draw home button */
     /* Draw home button */
     if($enableHome){
-      $result["HOME"]= "<input class='center' type='image' align='middle' src='images/lists/home.png' ".
-                       "title='"._("Go to users department")."' alt='"._("Home")."' name='HOME'>";
+        $result["HOME"]= image('images/lists/home.png', 'HOME', _("Go to current users level"));
     }else{
-      $result["HOME"]= "<img src='images/lists/home_grey.png' class='center' alt='"._("Home")."'>";
+        $result["HOME"]= image('images/lists/home-grey.png', null, _("Go to current users level"));
     }
 
+
     /* Draw reload button, this button is enabled everytime */
-    $result["RELOAD"]= "<input class='center' type='image' src='images/lists/reload.png' align='middle' ".
-                       "title='"._("Reload list")."' name='REFRESH' alt='"._("Submit")."'>";
+    $result["RELOAD"]= image('images/lists/reload.png', 'REFRESH', _("Reload list"));
 
     return ($result);
-  }
+}
 
 
-  function getAction()
-  {
+function getAction()
+{
     // Do not do anything if this is not our PID, or there's even no PID available...
     if(!isset($_REQUEST['PID']) || $_REQUEST['PID'] != $this->pid) {
-      return;
+        return;
     }
 
     // Save position if set
     if (isset($_POST['position_'.$this->pid]) && is_numeric($_POST['position_'.$this->pid])) {
-      $this->scrollPosition= $_POST['position_'.$this->pid];
+        $this->scrollPosition= get_post('position_'.$this->pid);
     }
 
     $result= array("targets" => array(), "action" => "");
 
     // Filter GET with "act" attributes
     if (isset($_GET['act'])) {
-      $key= validate($_GET['act']);
-      $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)$/', '$1', $key);
-      if (isset($this->entries[$target]['dn'])) {
-        $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+$/', '$1', $key);
-        $result['targets'][]= $this->entries[$target]['dn'];
-      }
-
-      // Drop targets if empty
-      if (count($result['targets']) == 0) {
-        unset($result['targets']);
-      }
-      return $result;
+        $key= validate($_GET['act']);
+        $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)$/', '$1', $key);
+        if (isset($this->entries[$target]['dn'])) {
+            $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+$/', '$1', $key);
+            $result['targets'][]= $this->entries[$target]['dn'];
+        }
+
+        // Drop targets if empty
+        if (count($result['targets']) == 0) {
+            unset($result['targets']);
+        }
+        return $result;
+    }
+
+    // Get single selection (radio box)
+    if($this->singleSelect && isset($_POST['listing_radio_selected'])){
+        $entry = get_post('listing_radio_selected');
+        $result['targets']= array($this->entries[$entry]['dn']);
     }
 
     // Filter POST with "listing_" attributes
     foreach ($_POST as $key => $prop) {
 
-      // Capture selections
-      if (preg_match('/^listing_selected_[0-9]+$/', $key)) {
-        $target= preg_replace('/^listing_selected_([0-9]+)$/', '$1', $key);
-        if (isset($this->entries[$target]['dn'])) {
-          $result['targets'][]= $this->entries[$target]['dn'];
+        $prop = get_post($key);
+
+        // Capture selections
+        if (preg_match('/^listing_selected_[0-9]+$/', $key)) {
+            $target= preg_replace('/^listing_selected_([0-9]+)$/', '$1', $key);
+            if (isset($this->entries[$target]['dn'])) {
+                $result['targets'][]= $this->entries[$target]['dn'];
+            }
+            continue;
         }
-        continue;
-      }
 
-      // Capture action with target - this is a one shot
-      if (preg_match('/^listing_[a-zA-Z_]+_[0-9]+(|_x)$/', $key)) {
-        $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)(|_x)$/', '$1', $key);
-        if (isset($this->entries[$target]['dn'])) {
-          $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+(|_x)$/', '$1', $key);
-          $result['targets']= array($this->entries[$target]['dn']);
+        // Capture action with target - this is a one shot
+        if (preg_match('/^listing_[a-zA-Z_]+_[0-9]+(|_x)$/', $key)) {
+            $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)(|_x)$/', '$1', $key);
+            if (isset($this->entries[$target]['dn'])) {
+                $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+(|_x)$/', '$1', $key);
+                $result['targets']= array($this->entries[$target]['dn']);
+            }
+            break;
         }
-        break;
-      }
 
-      // Capture action without target
-      if (preg_match('/^listing_[a-zA-Z_]+(|_x)$/', $key)) {
-        $result['action']= preg_replace('/^listing_([a-zA-Z_]+)(|_x)$/', '$1', $key);
-        continue;
-      }
+        // Capture action without target
+        if (preg_match('/^listing_[a-zA-Z_]+(|_x)$/', $key)) {
+            $result['action']= preg_replace('/^listing_([a-zA-Z_]+)(|_x)$/', '$1', $key);
+            continue;
+        }
     }
 
     // Filter POST with "act" attributes -> posted from action menu
     if (isset($_POST['act']) && $_POST['act'] != '') {
-      if (!preg_match('/^export.*$/', $_POST['act'])){
-        $result['action']= validate($_POST['act']);
-      }
+        if (!preg_match('/^export.*$/', $_POST['act'])){
+            $result['action']= get_post('act');
+        }
     }
 
     // Drop targets if empty
     if (count($result['targets']) == 0) {
-      unset($result['targets']);
+        unset($result['targets']);
     }
     return $result;
-  }
+}
+
 
+function renderActionMenu()
+{
+    $result= "<input type='hidden' name='act' id='act' value=''><div style='display:none'><input type='submit' name='exec_act' id='exec_act' value=''></div>";
 
-  function renderActionMenu()
-  {
     // Don't send anything if the menu is not defined
     if (!isset($this->xmlData['actionmenu']['action'])){
-      return "";
+        return $result;
     }
 
     // Array?
     if (isset($this->xmlData['actionmenu']['action']['type'])){
-      $this->xmlData['actionmenu']['action']= array($this->xmlData['actionmenu']['action']);
+        $this->xmlData['actionmenu']['action']= array($this->xmlData['actionmenu']['action']);
     }
 
     // Load shortcut
     $actions= &$this->xmlData['actionmenu']['action'];
-    $result= "<input type='hidden' name='act' id='actionmenu' value=''><div style='display:none'><input type='submit' name='exec_act' id='exec_act' value=''></div>".
-             "<ul class='level1' id='root'><li><a href='#'>"._("Actions")."&nbsp;<img ".
-             "border=0 class='center' src='images/lists/sort-down.png'></a>";
+    $result.= "<ul class='level1' id='root'><li><a href='#'>"._("Actions")."&nbsp;".image("images/lists/sort-down.png")."</a>";
 
     // Build ul/li list
     $result.= $this->recurseActions($actions);
 
-    return "<div id='pulldown'>".$result."</li></ul><div>";
-  }
+    return "<div id='pulldown'>".$result."</li></ul></div>";
+}
 
 
-  function recurseActions($actions)
-  {
+function recurseActions($actions)
+{
     global $class_mapping;
     static $level= 2;
     $result= "<ul class='level$level'>";
@@ -1133,177 +1222,189 @@ class listing {
 
     foreach ($actions as $action) {
 
-      // Skip the entry completely if there's no permission to execute it
-      if (!$this->hasActionPermission($action, $this->filter->base)) {
-        continue;
-      }
-
-      // Skip entry if there're missing dependencies
-      if (isset($action['depends'])) {
-        $deps= is_array($action['depends'])?$action['depends']:array($action['depends']);
-        foreach($deps as $clazz) {
-          if (!isset($class_mapping[$clazz])){
-            continue 2;
-          }
-        }
-      }
-
-      // Fill image if set
-      $img= "";
-      if (isset($action['image'])){
-        $img= "<img border='0' class='center' src='".$action['image']."'>&nbsp;";
-      }
-
-      if ($action['type'] == "separator"){
-        $separator= " style='border-top:1px solid #AAA' ";
-        continue;
-      }
-
-      // Dive into subs
-      if ($action['type'] == "sub" && isset($action['action'])) {
-        $level++;
+        // Skip the entry completely if there's no permission to execute it
+        if (!$this->hasActionPermission($action, $this->filter->base)) {
+            continue;
+        }
+
+        // Skip entry if there're missing dependencies
+        if (isset($action['depends'])) {
+            $deps= is_array($action['depends'])?$action['depends']:array($action['depends']);
+            foreach($deps as $clazz) {
+                if (!isset($class_mapping[$clazz])){
+                    continue 2;
+                }
+            }
+        }
+
+        // Fill image if set
+        $img= "";
+        if (isset($action['image'])){
+            $img= image($action['image'])."&nbsp;";
+        }
+
+        if ($action['type'] == "separator"){
+            $separator= " style='border-top:1px solid #AAA' ";
+            continue;
+        }
+
+        // Dive into subs
+        if ($action['type'] == "sub" && isset($action['action'])) {
+            $level++;
+            if (isset($action['label'])){
+                $result.= "<li$separator><a href='#'>$img"._($action['label'])."&nbsp;".image('images/forward-arrow.png')."</a>";
+            }
+
+            // Ensure we've an array of actions, this enables sub menus with only one action.
+            if(isset($action['action']['type'])){
+                $action['action'] = array($action['action']);
+            }
+
+            $result.= $this->recurseActions($action['action'])."</li>";
+            $level--;
+            $separator= "";
+            continue;
+        }
+
+        // Render entry elseways
         if (isset($action['label'])){
-          $result.= "<li$separator><a href='#'>$img"._($action['label'])."&nbsp;<img border='0' src='images/forward-arrow.png'></a>";
+            $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"".$action['name']."\";\$(\"exec_act\").click();'>$img"._($action['label'])."</a></li>";
         }
 
-        // Ensure we've an array of actions, this enables sub menus with only one action.
-        if(isset($action['action']['type'])){
-          $action['action'] = array($action['action']);
+        // Check for special types
+        switch ($action['type']) {
+            case 'copypaste':
+                $cut = !isset($action['cut']) || $action['cut'] != "false";
+                $copy = !isset($action['copy']) || $action['copy'] != "false";
+                $result.= $this->renderCopyPasteMenu($separator, $copy , $cut);
+                break;
+
+            case 'snapshot':
+                $result.= $this->renderSnapshotMenu($separator);
+                break;
+
+            case 'exporter':
+                $result.= $this->renderExporterMenu($separator);
+                break;
+
+            case 'daemon':
+                $result.= $this->renderDaemonMenu($separator);
+                break;
         }
 
-        $result.= $this->recurseActions($action['action'])."</li>";
-        $level--;
         $separator= "";
-        continue;
-      }
-
-      // Render entry elseways
-      if (isset($action['label'])){
-        $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"".$action['name']."\";mainform.submit();'>$img"._($action['label'])."</a></li>";
-      }
-
-      // Check for special types
-      switch ($action['type']) {
-        case 'copypaste':
-          $cut = !isset($action['cut']) || $action['cut'] != "false";
-          $copy = !isset($action['copy']) || $action['copy'] != "false";
-          $result.= $this->renderCopyPasteMenu($separator, $copy , $cut);
-          break;
-
-        case 'snapshot':
-          $result.= $this->renderSnapshotMenu($separator);
-          break;
-
-        case 'exporter':
-          $result.= $this->renderExporterMenu($separator);
-          break;
-
-        case 'daemon':
-          $result.= $this->renderDaemonMenu($separator);
-          break;
-      }
-
-      $separator= "";
     }
 
     $result.= "</ul>";
     return $result;
-  }
+}
 
 
-  function hasActionPermission($action, $dn)
-  {
+function hasActionPermission($action, $dn, $classes= null)
+{
     $ui= get_userinfo();
 
     if (isset($action['acl'])) {
-      $acls= $action['acl'];
-      if (!is_array($acls)) {
-        $acls= array($acls);
-      }
-
-      // Every ACL has to pass
-      foreach ($acls as $acl) {
-        $module= $this->module;
-        $aclList= array();
-
-        // Split for category and plugins if needed
-        // match for "[rw]" style entries
-        if (preg_match('/^\[([rwcdm]+)\]$/', $acl, $match)){
-          $aclList= array($match[1]);
+        $acls= $action['acl'];
+        if (!is_array($acls)) {
+            $acls= array($acls);
         }
 
-        // match for "users[rw]" style entries
-        if (preg_match('/^([a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){
-          $module= $match[1];
-          $aclList= array($match[2]);
-        }
+        // Every ACL has to pass
+        foreach ($acls as $acl) {
+            $module= $this->categories;
+            $aclList= array();
 
-        // match for "users/user[rw]" style entries
-        if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){
-          $module= $match[1];
-          $aclList= array($match[2]);
-        }
+            // Replace %acl if available
+            if ($classes) {
+                $otype= $this->getObjectType($this->objectTypes, $classes);
+                $acl= str_replace('%acl', $otype['category']."/".$otype['class'], $acl);
+            }
 
-        // match "users/user[userPassword:rw(,...)*]" style entries
-        if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([a-zA-Z0-9]+:[rwcdm]+(,[a-zA-Z0-9]+:[rwcdm]+)*)\]$/', $acl, $match)){
-          $module= $match[1];
-          $aclList= split(',', $match[2]);
-        }
+            // Split for category and plugins if needed
+            // match for "[rw]" style entries
+            if (preg_match('/^\[([rwcdm]+)\]$/', $acl, $match)){
+                $aclList= array($match[1]);
+            }
 
-        // Walk thru prepared ACL by using $module
-        foreach($aclList as $sAcl) {
-          $checkAcl= "";
+            // match for "users[rw]" style entries
+            if (preg_match('/^([a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){
+                $module= $match[1];
+                $aclList= array($match[2]);
+            }
 
-          // Category or detailed permission?
-          if (strpos('/', $module) === false) {
-            if (preg_match('/([a-zA-Z0-9]+):([rwcdm]+)/', $sAcl, $m) ) {
-              $checkAcl= $ui->get_permissions($dn, $module, $m[1]);
-              $sAcl= $m[2];
-            } else {
-              $checkAcl= $ui->get_permissions($dn, $module, '0');
+            // match for "users/user[rw]" style entries
+            if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){
+                $module= $match[1];
+                $aclList= array($match[2]);
             }
-          } else {
-            $checkAcl= $ui->get_category_permissions($dn, $module);
-          }
-
-          // Split up remaining part of the acl and check if it we're
-          // allowed to do something...
-          $parts= str_split($sAcl);
-          foreach ($parts as $part) {
-            if (strpos($checkAcl, $part) === false){
-              return false;
+
+            // match "users/user[userPassword:rw(,...)*]" style entries
+            if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([a-zA-Z0-9]+:[rwcdm]+(,[a-zA-Z0-9]+:[rwcdm]+)*)\]$/', $acl, $match)){
+                $module= $match[1];
+                $aclList= explode(',', $match[2]);
             }
-          }
 
+            // Walk thru prepared ACL by using $module
+            foreach($aclList as $sAcl) {
+                $checkAcl= "";
+
+                // Category or detailed permission?
+                if (strpos($module, '/') !== false) {
+                    if (preg_match('/([a-zA-Z0-9]+):([rwcdm]+)/', $sAcl, $m) ) {
+                        $checkAcl= $ui->get_permissions($dn, $module, $m[1]);
+                        $sAcl= $m[2];
+                    } else {
+                        $checkAcl= $ui->get_permissions($dn, $module, '0');
+                    }
+                } else {
+                    $checkAcl= $ui->get_category_permissions($dn, $module);
+                }
+
+                // Split up remaining part of the acl and check if it we're
+                // allowed to do something...
+                $parts= str_split($sAcl);
+                foreach ($parts as $part) {
+                    if (strpos($checkAcl, $part) === false){
+                        return false;
+                    }
+                }
+
+            }
         }
-      }
     }
 
     return true;
-  }
+}
 
 
-  function refreshBasesList()
-  {
+function refreshBasesList()
+{
     global $config;
     $ui= get_userinfo();
 
     // Do some array munching to get it user friendly
     $ids= $config->idepartments;
-    $d= $ui->get_module_departments($this->module);
+    $d= $ui->get_module_departments($this->categories);
     $k_ids= array_keys($ids);
     $deps= array_intersect($d,$k_ids);
 
     // Fill internal bases list
     $this->bases= array();
     foreach($k_ids as $department){
-      $this->bases[$department] = $ids[$department];
+        $this->bases[$department] = $ids[$department];
+    }
+
+    // Populate base selector if already present
+    if ($this->baseSelector && $this->baseMode) {
+        $this->baseSelector->setBases($this->bases);
+        $this->baseSelector->update(TRUE);
     }
-  }
+}
 
 
-  function getDepartments()
-  {
+function getDepartments()
+{
     $departments= array();
     $ui= get_userinfo();
 
@@ -1311,49 +1412,49 @@ class listing {
     $types = departmentManagement::get_support_departments();
 
     // Load departments allowed by ACL
-    $validDepartments = $ui->get_module_departments($this->module);
+    $validDepartments = $ui->get_module_departments($this->categories);
 
     // Build filter and look in the LDAP for possible sub departments
     // of current base
     $filter= "(&(objectClass=gosaDepartment)(|";
     $attrs= array("description", "objectClass");
     foreach($types as $name => $data){
-      $filter.= "(objectClass=".$data['OC'].")";
-      $attrs[]= $data['ATTR'];
+        $filter.= "(objectClass=".$data['OC'].")";
+        $attrs[]= $data['ATTR'];
     }
     $filter.= "))";
-    $res= get_list($filter, $this->module, $this->base, $attrs, GL_NONE);
+    $res= get_list($filter, $this->categories, $this->base, $attrs, GL_NONE);
 
     // Analyze list of departments
     foreach ($res as $department) {
-      if (!in_array($department['dn'], $validDepartments)) {
-        continue;
-      }
-
-      // Add the attribute where we use for sorting
-      $oc= null;
-      foreach(array_keys($types) as $type) {
-        if (in_array($type, $department['objectClass'])) {
-          $oc= $type;
-          break;
-        }
-      }
-      $department['sort-attribute']= $types[$oc]['ATTR'];
-
-      // Move to the result list
-      $departments[]= $department;
+        if (!in_array_strict($department['dn'], $validDepartments)) {
+            continue;
+        }
+
+        // Add the attribute where we use for sorting
+        $oc= null;
+        foreach(array_keys($types) as $type) {
+            if (in_array_strict($type, $department['objectClass'])) {
+                $oc= $type;
+                break;
+            }
+        }
+        $department['sort-attribute']= $types[$oc]['ATTR'];
+
+        // Move to the result list
+        $departments[]= $department;
     }
 
     return $departments;
-  }
+}
 
 
-  function renderCopyPasteMenu($separator, $copy= true, $cut= true)
-  {
+function renderCopyPasteMenu($separator, $copy= true, $cut= true)
+{
     // We can only provide information if we've got a copypaste handler
     // instance
     if(!(isset($this->copyPasteHandler) && is_object($this->copyPasteHandler))){
-      return "";
+        return "";
     }
 
     // Presets
@@ -1363,46 +1464,46 @@ class listing {
 
     // Switch flags to on if there's at least one category which allows read/paste
     foreach($this->categories as $category){
-      $read= $read || preg_match('/r/', $ui->get_category_permissions($this->base, $category));
-      $paste= $paste || $ui->is_pasteable($this->base, $category) == 1;
+        $read= $read || preg_match('/r/', $ui->get_category_permissions($this->base, $category));
+        $paste= $paste || $ui->is_pasteable($this->base, $category) == 1;
     }
 
 
     // Draw entries that allow copy and cut
     if($read){
 
-      // Copy entry
-      if($copy){
-        $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"copy\";document.getElementById(\"exec_act\").click();'><img src='images/lists/copy.png' alt='' border='0' class='center'>&nbsp;"._("Copy")."</a></li>";
-        $separator= "";
-      }
+        // Copy entry
+        if($copy){
+            $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"copy\";\$(\"exec_act\").click();'>".image('images/lists/copy.png')."&nbsp;"._("Copy")."</a></li>";
+            $separator= "";
+        }
 
-      // Cut entry
-      if($cut){
-        $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"cut\";document.getElementById(\"exec_act\").click();'><img src='images/lists/cut.png' alt='' border='0' class='center'>&nbsp;"._("Cut")."</a></li>";
-        $separator= "";
-      }
+        // Cut entry
+        if($cut){
+            $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"cut\";\$(\"exec_act\").click();'>".image("images/lists/cut.png")."&nbsp;"._("Cut")."</a></li>";
+            $separator= "";
+        }
     }
 
     // Draw entries that allow pasting entries
     if($paste){
-      if($this->copyPasteHandler->entries_queued()){
-        $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"paste\";document.getElementById(\"exec_act\").click();'><img src='images/lists/paste.png' alt='' border='0' class='center'>&nbsp;"._("Paste")."</a></li>";
-      }else{
-        $result.= "<li$separator><a href='#'><img src='images/lists/paste-grey.png' alt='' border='0' class='center'>&nbsp;"._("Paste")."</a></li>";
-      }
+        if($this->copyPasteHandler->entries_queued()){
+            $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"paste\";\$(\"exec_act\").click();'>".image("images/lists/paste.png")."&nbsp;"._("Paste")."</a></li>";
+        }else{
+            $result.= "<li$separator><a href='#'>".image('images/lists/paste-grey.png')."&nbsp;"._("Paste")."</a></li>";
+        }
     }
-    
+
     return($result);
-  }
+}
 
 
-  function renderCopyPasteActions($row, $dn, $category, $class, $copy= true, $cut= true)
-  {
+function renderCopyPasteActions($row, $dn, $category, $class, $copy= true, $cut= true)
+{
     // We can only provide information if we've got a copypaste handler
     // instance
     if(!(isset($this->copyPasteHandler) && is_object($this->copyPasteHandler))){
-      return "";
+        return "";
     }
 
     // Presets
@@ -1411,86 +1512,84 @@ class listing {
 
     // Render cut entries
     if($cut){
-      if($ui->is_cutable($dn, $category, $class)){
-        $result .= "<input class='center' type='image'
-          src='images/lists/cut.png' alt='"._("Cut")."' name='listing_cut_$row' title='"._("Cut this entry")."' style='padding:1px'>";
-      }else{
-        $result.="<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-      }
+        if($ui->is_cutable($dn, $category, $class)){
+            $result.= image('images/lists/cut.png', "listing_cut_$row", _("Cut this entry"));
+        }else{
+            $result.= image('images/empty.png');
+        }
     }
 
     // Render copy entries
     if($copy){
-      if($ui->is_copyable($dn, $category, $class)){
-        $result.= "<input class='center' type='image'
-          src='images/lists/copy.png' alt='"._("Copy")."' name='listing_copy_$row' title='"._("Copy this entry")."' style='padding:1px'>";
-      }else{
-        $result.="<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-      }
+        if($ui->is_copyable($dn, $category, $class)){
+            $result.= image('images/lists/copy.png', "listing_copy_$row", _("Copy this entry"));
+        }else{
+            $result.= image('images/empty.png');
+        }
     }
 
     return($result);
-  }
+}
 
 
-  function renderSnapshotMenu($separator)
-  {
+function renderSnapshotMenu($separator)
+{
     // We can only provide information if we've got a snapshot handler
     // instance
     if(!(isset($this->snapshotHandler) && is_object($this->snapshotHandler))){
-      return "";
+        return "";
     }
 
     // Presets
     $result = "";
     $ui = get_userinfo();
 
-    if($this->snapshotHandler->enabled() && $ui->allow_snapshot_restore($this->base, $this->module)){
+    if($this->snapshotHandler->enabled() && $ui->allow_snapshot_restore($this->base, $this->categories)){
 
-      // Check if there is something to restore
-      $restore= false;
-      foreach($this->snapshotHandler->getSnapshotBases() as $base){
-        $restore= $restore || count($this->snapshotHandler->getDeletedSnapshots($base)) > 0;
-      }
+        // Check if there is something to restore
+        $restore= false;
+        foreach($this->snapshotHandler->getSnapshotBases() as $base){
+            $restore= $restore || count($this->snapshotHandler->getDeletedSnapshots($base)) > 0;
+        }
 
-      // Draw icons according to the restore flag
-      if($restore){
-        $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"restore\";document.getElementById(\"exec_act\").click();'><img src='images/lists/restore.png' alt='' border='0' class='center'>&nbsp;"._("Restore snapshots")."</a></li>";
-      }else{
-        $result.= "<li$separator><a href='#'><img src='images/lists/restore_grey.png' alt='' border='0' class='center'>&nbsp;"._("Restore snapshots")."</a></li>";
-      }
+        // Draw icons according to the restore flag
+        if($restore){
+            $result.= "<li$separator><a href='#' onClick='\$(\"act\").value= \"restore\";\$(\"exec_act\").click();'>".image('images/lists/restore.png')."&nbsp;"._("Restore snapshots")."</a></li>";
+        }else{
+            $result.= "<li$separator><a href='#'>".image('images/lists/restore-grey.png')."&nbsp;"._("Restore snapshots")."</a></li>";
+        }
     }
 
     return($result);
-  }
+}
 
 
-  function renderExporterMenu($separator)
-  {
+function renderExporterMenu($separator)
+{
     // Presets
     $result = "";
 
     // Draw entries
-    $result.= "<li$separator><a href='#'><img border='0' class='center' src='images/lists/export.png'>&nbsp;"._("Export list")."&nbsp;<img border='0' src='images/forward-arrow.png'></a><ul class='level3'>";
+    $result.= "<li$separator><a href='#'>".image('images/lists/export.png')."&nbsp;"._("Export list")."&nbsp;".image("images/forward-arrow.png")."</a><ul class='level3'>";
 
     // Export CVS as build in exporter
     foreach ($this->exporter as $action => $exporter) {
-      $result.= "<li><a href='#' onClick='document.getElementById(\"actionmenu\").value= \"$action\";document.getElementById(\"exec_act\").click();'><img border='0' class='center' src='".$exporter['image']."'>&nbsp;".$exporter['label']."</a></li>";
+        $result.= "<li><a href='#' onClick='\$(\"act\").value= \"$action\";\$(\"exec_act\").click();'>".image($exporter['image'])."&nbsp;".$exporter['label']."</a></li>";
     }
 
     // Finalize list
     $result.= "</ul></li>";
 
     return($result);
-  }
+}
 
 
-  function renderSnapshotActions($row, $dn, $category, $class, $copy= true, $cut= true)
-  {
+function renderSnapshotActions($row, $dn, $category, $class, $copy= true, $cut= true)
+{
     // We can only provide information if we've got a snapshot handler
     // instance
     if(!(isset($this->snapshotHandler) && is_object($this->snapshotHandler))){
-      return "";
+        return "";
     }
 
     // Presets
@@ -1500,70 +1599,73 @@ class listing {
     // Only act if enabled here
     if($this->snapshotHandler->enabled()){
 
-      // Draw restore button
-      if ($ui->allow_snapshot_restore($dn, $category)){
+        // Draw restore button
+        if ($ui->allow_snapshot_restore($dn, $category)){
 
-        // Do we have snapshots for this dn?
-        if($this->snapshotHandler->hasSnapshots($dn)){
-          $result.= "<input class='center' type='image' src='images/lists/restore.png' ".
-                     "alt='"._("Restore snapshot")."' name='listing_restore_$row' title='".
-                     _("Restore snapshot")."' style='padding:1px'>";
-        } else {
-          $result.= "<img src='images/lists/restore_grey.png' alt=' ' class='center' style='padding:1px'>";
-        }
-      }
-
-      // Draw snapshot button
-      if($ui->allow_snapshot_create($dn, $category)){
-          $result.= "<input class='center' type='image' src='images/snapshot.png' ".
-                     "alt='"._("Create snapshot")."' name='listing_snapshot_$row' title='".
-                     _("Create a new snapshot from this object")."' style='padding:1px'>";
-      }else{
-          $result.= "<img src='images/empty.png' alt=' ' class='center' style='padding:1px'>";
-      }
+            // Do we have snapshots for this dn?
+            if($this->snapshotHandler->hasSnapshots($dn)){
+                $result.= image('images/lists/restore.png', "listing_restore_$row", _("Restore snapshot"));
+            } else {
+                $result.= image('images/lists/restore-grey.png');
+            }
+        }
+
+        // Draw snapshot button
+        if($ui->allow_snapshot_create($dn, $category)){
+            $result.= image('images/snapshot.png', "listing_snapshot_$row", _("Create new snapshot for this object"));
+        }else{
+            $result.= image('images/empty.png');
+        }
     }
 
     return($result);
-  }
+}
 
 
-  function renderDaemonMenu($separator)
-  {
+function renderDaemonMenu($separator)
+{
     $result= "";
 
     // If there is a daemon registered, draw the menu entries
     if(class_available("DaemonEvent")){
-      $events= DaemonEvent::get_event_types_by_category($this->categories);
-      if(isset($events['BY_CLASS']) && count($events['BY_CLASS'])){
-        foreach($events['BY_CLASS'] as $name => $event){
-          $result.= "<li$separator><a href='#' onClick='document.getElementById(\"actionmenu\").value=\"$name\";document.getElementById(\"exec_act\").click();'>".$event['MenuImage']."&nbsp;".$event['s_Menu_Name']."</a></li>";
-          $separator= "";
+        $events= DaemonEvent::get_event_types_by_category($this->categories);
+        if(isset($events['BY_CLASS']) && count($events['BY_CLASS'])){
+            foreach($events['BY_CLASS'] as $name => $event){
+                $result.= "<li$separator><a href='#' onClick='\$(\"act\").value=\"$name\";\$(\"exec_act\").click();'>".$event['MenuImage']."&nbsp;".$event['s_Menu_Name']."</a></li>";
+                $separator= "";
+            }
         }
-      }
     }
 
     return $result;
-  }
+}
 
 
-  function getEntry($dn)
-  {
+function getEntry($dn)
+{
     foreach ($this->entries as $entry) {
-      if (isset($entry['dn']) && strcasecmp($dn, $entry['dn']) == 0){
-        return $entry;
-      }
+        if (isset($entry['dn']) && strcasecmp($dn, $entry['dn']) == 0){
+            return $entry;
+        }
     }
     return null;
-  }
+}
 
 
-  function getType($dn)
-  {
+function getEntries()
+{
+    return $this->entries;
+}
+
+
+function getType($dn)
+{
+    $dn = LDAP::fix($dn);
     if (isset($this->objectDnMapping[$dn])) {
-      return $this->objectDnMapping[$dn];
+        return $this->objectDnMapping[$dn];
     }
     return null;
-  }
+}
 
 }