Code

Fixed w3c errors/warnings
[gosa.git] / include / class_ldap.inc
index 8d4d06aef576e62556a9818eb963a9dfb0db83dc..b3ae4983b38e7ac0bfd609cd4e391325114fc3b2 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 /*****************************************************************************
   newldap.inc - version 1.0
-  Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
-  Copyright (C) 2004 Cajus Pollmeier <pollmeier@gonicus.de>
+  Copyright (C) 2003 Alejandro Escanero Blanco <aescanero@chaosdimension.org>
+  Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
 
   Based in code of ldap.inc of
   Copyright (C) 1998  Eric Kilfoil <eric@ipass.net>
@@ -12,7 +12,7 @@ define("ALREADY_EXISTING_ENTRY",-10001);
 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
 define("NO_FILE_UPLOADED",10003);
 define("INSERT_OK",10000);
-define("COLON_OVERRIDE", TRUE);
+define("SPECIALS_OVERRIDE", TRUE);
 
 class LDAP{
 
@@ -30,42 +30,61 @@ class LDAP{
   var $hostname = "";
   var $follow_referral = FALSE;
   var $referrals= array();
+  var $max_ldap_query_time = 0;   // 0, empty or negative values will disable this check 
 
   function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
   {
+    global $config;
     $this->follow_referral= $follow_referral;
     $this->tls=$tls;
     $this->binddn=$this->convert($binddn);
 
     $this->bindpw=$bindpw;
     $this->hostname=$hostname;
+
+    /* Check if MAX_LDAP_QUERY_TIME is defined */ 
+    if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){
+      $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME'];
+      $this->max_ldap_query_time = (float)($str);
+    }
+
     $this->connect();
   }
 
 
+  /* Function to replace all problematic characters inside a DN by \001XX, where
+     \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely
+     that this character is inside a DN.
+     
+     Currently used codes:
+      ,   => CO
+      \2C => CO
+      (   => OB
+      )   => CB
+      /   => SL                                                                  */
   function convert($dn)
   {
-    if (COLON_OVERRIDE == TRUE){
-      $res= preg_replace("/\\\\,/", '###GOSAREPLACED###', $dn);
-      $res= preg_replace("/\\\\2C/", '###GOSAREPLACED###', $res);
-      #if ($dn != $res){
-      #  echo "Conversation from '$dn' to '$res'<br>";
-      #}
-      return ($res);
+    if (SPECIALS_OVERRIDE == TRUE){
+      $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
+                           array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
+                           $dn);
+      return (preg_replace('/,\s+/', ',', $tmp));
     } else {
       return ($dn);
     }
   }
 
 
+  /* Function to fix all problematic characters inside a DN by replacing \001XX
+     codes to their original values. See "convert" for mor information. 
+     ',' characters are always expanded to \, (not \2C), since all tested LDAP
+     servers seem to take it the correct way.                                  */
   function fix($dn)
   {
-    if (COLON_OVERRIDE == TRUE){
-      $res= preg_replace("/###GOSAREPLACED###/", '\,', $dn);
-      #if ($dn != $res){
-      #  echo "Fix from '$dn' to '$res'<br>";
-      #}
-      return ($res);
+    if (SPECIALS_OVERRIDE == TRUE){
+      return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
+                           array("\,", "(", ")", "/"),
+                           $dn));
     } else {
       return ($dn);
     }
@@ -153,46 +172,32 @@ class LDAP{
     if ($basedn=="")
       $basedn = $this->basedn;
     else
-      $basedn = $this-convert($this->basedn);
+      $basedn = $this->convert($this->basedn);
     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
   }
 
   function search($filter, $attrs= array())
   {
-    $start = microtime();
-
     if($this->hascon){
       if ($this->reconnect) $this->connect();
+
+      $start = microtime();
+   
       $this->clearResult();
       $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
-  
-      /* Time management */
-      $r = split(" ",$start);
-      $ms = $r[0];
-      $s= $r[1];
-
-      $re = split(" ",microtime());
-      $mse = $re[0];
-      $se= $re[1];
-
-      $add = 0;
-      if(($mse -$ms)<0){
-        $se --;
-        $add = 1;
-      }
-      $secs =  ($se -$s);
-      $msecs = (int)(($add+($mse -$ms))*1000);
-      $time = $secs +($msecs/1000);
-      if($time > .2){
-        $Sattrs = "";
-        foreach($attrs as $att){
-          $Sattrs .= " ".$att;
+   
+      /* Check if query took longer as specified in max_ldap_query_time */
+      if($this->max_ldap_query_time){
+        $diff = get_MicroTimeDiff($start,microtime());
+        if($diff > $this->max_ldap_query_time){
+          print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
         }
-        print_red(sprintf(_("Ldap search took about %s seconds, used filter '%s' with following attributes '%s '. Please check for performance improvements."),$time,htmlentities($filter),$Sattrs));
       }
+
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -209,10 +214,24 @@ class LDAP{
         $basedn = $this->basedn;
       else
         $basedn= $this->convert($basedn);
+  
+      $start = microtime();
+
       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
+
+       /* Check if query took longer as specified in max_ldap_query_time */
+      if($this->max_ldap_query_time){
+        $diff = get_MicroTimeDiff($start,microtime());
+        if($diff > $this->max_ldap_query_time){
+          print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
+        }
+      }
+
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -220,13 +239,13 @@ class LDAP{
     }
   }
 
-  function cat($dn)
+  function cat($dn,$attrs= array("*"))
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
       $this->clearResult();
       $filter = "(objectclass=*)";
-      $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter);
+      $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -252,6 +271,7 @@ class LDAP{
 
   function fetch()
   {
+    $att= array();
     if($this->hascon){
       if($this->hasres){
         if ($this->start == 0)
@@ -264,7 +284,7 @@ class LDAP{
         if ($this->re)
         {
           $att= @ldap_get_attributes($this->cid, $this->re);
-          $att['dn']= $this->convert(@ldap_get_dn($this->cid, $this->re));
+          $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
         }
         $this->error = @ldap_error($this->cid);
         if (!isset($att)){
@@ -308,7 +328,7 @@ class LDAP{
           $rv = @ldap_get_dn($this->cid, $this->re);
         
           $this->error = @ldap_error($this->cid);
-          return($this->convert($rv));
+          return(trim($this->convert($rv)));
            }
       }else{
         $this->error = "Perform a Fetch with no Search";
@@ -422,27 +442,59 @@ class LDAP{
   }
 
   /* Copy given attributes and sub-dns with attributes to destination dn 
-      
   */
-  function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = false)
+  function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
   {
     error_reporting(E_ALL);
+    
+    if($is_first){
+      echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
+    }else{
+      if(preg_match("/^ou=/",$sourcedn)){
+        echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
+      }else{
+        $tmp = split(",",$sourcedn);
+        
+        echo "&nbsp;<b>"._("Object").":</b> ";
+
+        $deststr = @LDAP::fix($destinationdn);
+        if(strlen($deststr) > 96){
+          $deststr = substr($deststr,0,96)."...";
+        }
+
+        echo $deststr."<br>";
+      }
+    }
+
+    flush();
+    
     if($this->hascon){
       if ($this->reconnect) $this->connect();
 
       /* Save base dn */
       $basedn= $this->basedn;
       $delarray= array();
-      
+     
       /* Check if destination entry already exists */
-      if($this->count($this->fetch($this->cat($destinationdn)))){
+      $this->cat($destinationdn);
+
+      if($this->count()){
         return;
       }else{
+        
+        $this->clearResult();
 
-        /* Get source entrie */
+        /* Get source entry */
         $this->cd($basedn);
-        $attr = $this->fetch($this->cat($sourcedn));
+        $this->cat($sourcedn);
+        $attr = $this->fetch();
 
+        /* Error while fetching object / attribute abort*/
+        if((!$attr) || (count($attr)) ==0) {
+          echo _("Error while fetching source dn - aborted!");
+          return;
+        }
+  
         /* check if this is a department */
         if(in_array("organizationalUnit",$attr['objectClass'])){
           $attr['dn'] = $this->convert($destinationdn);
@@ -452,23 +504,19 @@ class LDAP{
 
           /* If is first entry, append FAIbranch to department entry */
           if($is_first){
-            $attr= $this->fetch($this->cat($destinationdn));
+            $this->cat($destinationdn);
+            $attr= $this->fetch();
 
             /* Filter unneeded informations */
             foreach($attr as $key => $value){
               if(is_numeric($key)) unset($attr[$key]);
-              if(isset($attr[$key]['count'])){
-                if(($attr[$key]['count']==1)&&($key!="objectClass")){
-                  $attr[$key] = $attr[$key][0];
-                }
-              }
-              
               if(isset($attr[$key]['count'])){
                 if(is_array($attr[$key])){
                   unset($attr[$key]['count']);
                 }
               }
             }
+            
             unset($attr['count']);
             unset($attr['dn']);
 
@@ -478,16 +526,19 @@ class LDAP{
             /* Add this entry */
             $this->modify($attr);
           }
-          
         }else{
-        /* If this is no department */
+
+          /* If this is no department */
           foreach($attr as $key => $value){
-            if(is_numeric($key)) unset($attr[$key]);
-            if(isset($attr[$key]['count'])){
-              if(($attr[$key]['count']==1)&&($key!="objectClass")){
-                $attr[$key] = $attr[$key][0];
+            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
+              $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
+              $ei= ldap_first_entry($this->cid, $sr);
+              if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
+                $attr[$key] = $tmp;
               }
             }
+
+            if(is_numeric($key)) unset($attr[$key]);
             if(isset($attr[$key]['count'])){
               if(is_array($attr[$key])){
                 unset($attr[$key]['count']);
@@ -496,18 +547,27 @@ class LDAP{
           }
           unset($attr['count']);
           unset($attr['dn']);
-          if($type=="branch"){
-            $attr['FAIstate'] ="branch";
-          }elseif($type=="freeze"){
-            $attr['FAIstate'] ="freeze";
-          }else{
-            print_red(_("Unknown FAIstate %s"),$type);
+
+          if((!in_array("gosaApplication" , $attr['objectClass'])) && (!in_array("gotoMimeType", $attr['objectClass']))){
+            $attr['FAIdebianRelease'] = $destinationName;
+            if($type=="branch"){
+              $attr['FAIstate'] ="branch";
+            }elseif($type=="freeze"){
+              $attr['FAIstate'] ="freeze";
+            }else{
+              print_red(_("Unknown FAIstate %s"),$type);
+            }
           }
+
+          /* Replace FAIdebianRelease with new release name */
+          if(in_array("FAIpackageList" , $attr['objectClass'])){
+            $attr['FAIdebianRelease'] = $destinationName; 
+          }
+
           /* Add entry */
           $this->cd($destinationdn);
-          $a = $this->fetch($this->cat($destinationdn));
+          $this->cat($destinationdn);
+          $a = $this->fetch();
           if(!count($a)){
             $this->add($attr);
           }
@@ -524,6 +584,8 @@ class LDAP{
         }
       }
 
+      echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
+
       $this->ls ("(objectClass=*)",$sourcedn);
       while ($this->fetch()){
         $deldn= $this->getDN();
@@ -532,20 +594,28 @@ class LDAP{
       asort ($delarray);
       reset ($delarray);
 
+       $depth ++;
       foreach($delarray as $dn => $bla){
         if($dn != $destinationdn){
           $this->cd($basedn);
           $item = $this->fetch($this->cat($dn));
           if(!in_array("FAIbranch",$item['objectClass'])){
-            $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$type);
+            $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
           } 
         }
       }
     }
+    if($is_first){
+      echo "<p class='seperator'>&nbsp;</p>";
+    }
+
   }
 
   function modify($attrs)
   {
+    if(count($attrs) == 0){
+      return (0);
+    }
     if($this->hascon){
       if ($this->reconnect) $this->connect();
       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
@@ -576,8 +646,13 @@ class LDAP{
     if ($target == $this->basedn){
      return;
     }
-    $l= array_reverse(explode(",", preg_replace("/,".$this->basedn."/", "", $target)));
+
+    $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
+    $l= array_reverse(gosa_ldap_explode_dn($real_path));
+    unset($l['count']);
     $cdn= $this->basedn;
+    $tag= "";
+
     foreach ($l as $part){
       $cdn= "$part,$cdn";
 
@@ -598,18 +673,35 @@ class LDAP{
       $attrs= $this->fetch();
 
       /* Create missing entry? */
-      if (!count ($attrs)){
+      if (count ($attrs)){
+      
+        /* Catch the tag - if present */
+        if (isset($attrs['gosaUnitTag'][0])){
+          $tag= $attrs['gosaUnitTag'][0];
+        }
+
+      } else {
         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
 
         $na= array();
         switch ($type){
           case 'ou':
-            $na["objectClass"]= "organizationalUnit";
+            if ($tag != ""){
+              $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
+              $na["gosaUnitTag"]= $tag;
+            } else {
+              $na["objectClass"]= "organizationalUnit";
+            }
             $na["ou"]= $param;
             break;
           case 'dc':
-            $na["objectClass"]= array("dcObject", "top", "locality");
+            if ($tag != ""){
+              $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
+              $na["gosaUnitTag"]= $tag;
+            } else {
+              $na["objectClass"]= array("dcObject", "top", "locality");
+            }
             $na["dc"]= $param;
             break;
           default:
@@ -680,7 +772,12 @@ class LDAP{
     if ($this->error == 'Success'){
       return $this->error;
     } else {
-      $error= $this->error." (".$this->get_additional_error().")";
+      $adderror= $this->get_additional_error();
+      if ($adderror != ""){
+        $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
+      } else {
+        $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
+      }
       return $error;
     }
   }
@@ -712,21 +809,27 @@ class LDAP{
 
     if ($recursive){
       $this->cd($dn);
-      $this->search("$filter", array('dn'));
+      $this->ls($filter,$dn, array('dn','objectClass'));
+      $deps = array();
+
+      $display .= $this->gen_one_entry($dn)."\n";
+
       while ($attrs= $this->fetch()){
-        $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
-        $display.= "\n";
+        $deps[] = $attrs['dn'];
+      }
+      foreach($deps as $dn){
+        $display .= $this->gen_ldif($dn, $filter,$attributes,$recursive);
       }
     } else {
       $display.= $this->gen_one_entry($dn);
     }
-
     return ($display);
   }
 
-function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
+
+  function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
   {
-    $display= "";
+    $display= array();
 
       $this->cd($dn);
       $this->search("$filter");
@@ -805,7 +908,14 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
   
 
 
-  function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
+  /*  This funktion imports ldifs 
+        
+      If DeleteOldEntries is true, the destination entry will be deleted first. 
+      If JustModify is true the destination entry will only be touched by the attributes specified in the ldif.
+      if JustMofify id false the destination dn will be overwritten by the new ldif. 
+    */
+
+  function import_complete_ldif($str_attr,&$error,$JustModify,$DeleteOldEntries)
   {
     if($this->reconnect) $this->connect();
 
@@ -817,8 +927,21 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     $cnt = 0; 
     $current_line = 0;
 
+    /* FIX ldif */
+    $last = "";
+    $tmp  = "";
+    $i = 0;
+    foreach($entries as $entry){
+      if(preg_match("/^ /",$entry)){
+        $tmp[$i] .= trim($entry);
+      }else{
+        $i ++;
+        $tmp[$i] = trim($entry);
+      }
+    }
+
     /* Every single line ... */
-    foreach($entries as $entry) {
+    foreach($tmp as $entry) {
       $current_line ++;
 
       /* Removing Spaces to .. 
@@ -842,15 +965,15 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
           if(ereg("::",$tmp2))
           {
             $encoded = split("::",$entry);
-            $attr  = $encoded[0];
-            $value = base64_decode($encoded[1]);
+            $attr  = trim($encoded[0]);
+            $value = base64_decode(trim($encoded[1]));
             /* Add linenumber */
-            $data .= $current_line."#".$attr.":".$value."\n";
+            $data .= $current_line."#".base64_encode($attr.":".$value)."\n";
           }
           else
           {
             /* Add Linenumber */ 
-            $data .= $current_line."#".$entry."\n";
+            $data .= $current_line."#".base64_encode($entry)."\n";
           }
         }
       }
@@ -866,9 +989,9 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     foreach ( $all as $single) {
       $lineone = split("\n",$single);  
       $ndn = split("#", $lineone[0]);
-      $line = $ndn[1];
+      $line = base64_decode($ndn[1]);
 
-      $dnn = split (":",$line);
+      $dnn = split (":",$line,2);
       $current_line = $ndn[0];
       $dn    = $dnn[0];
       $value = $dnn[1];
@@ -885,18 +1008,18 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
       /* Delete before insert */
       $usermdir= false;
     
-      /* The dn address already exists! */
-      if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
+      /* The dn address already exists, Don't delete destination entry, overwrite it */
+      if (($this->dn_exists($value))&&((!$JustModify)&&(!$DeleteOldEntries))) {
 
-        $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
-        return ALREADY_EXISTING_ENTRY;   
+        $usermdir = $usemodify = false;
 
-      } elseif(($this->dn_exists($value))&&($cleanup)){
+      /* Delete old entry first, then add new */
+      } elseif(($this->dn_exists($value))&&($DeleteOldEntries)){
 
         /* Delete first, then add */
         $usermdir = true;        
 
-      } elseif(($this->dn_exists($value))&&($overwrite)) {
+      } elseif(($this->dn_exists($value))&&($JustModify)) {
         
         /* Modify instead of Add */
         $usemodify = true;
@@ -913,7 +1036,11 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
   }
 
 
-  /* Imports a single entry */
+  /* Imports a single entry 
+      If $delete is true;  The old entry will be deleted if it exists.
+      if $modify is true;  All variables that are not touched by the new ldif will be kept.
+      if $modify is false; The new ldif overwrites the old entry, and all untouched attributes get lost.
+  */
   function import_single_entry($str_attr,$modify,$delete)
   {
     if($this->reconnect) $this->connect();
@@ -927,19 +1054,27 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
       /* Check if we use Linenumbers (when import_complete_ldif is called we use
          Linenumbers) Linenumbers are use like this 123#attribute : value */
       if(!empty($row)) {
-        if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
+        if(strpos($row,"#")!=FALSE) {
 
           /* We are using line numbers 
              Because there is a # before a : */
           $tmp1= split("#",$row);
           $current_line= $tmp1[0];
-          $row= $tmp1[1];
+          $row= base64_decode($tmp1[1]);
         }
 
         /* Split the line into  attribute  and value */
-        $attr   = split(":", $row);
+        $attr   = split(":", $row,2);
         $attr[0]= trim($attr[0]);  /* attribute */
-        $attr[1]= trim($attr[1]);  /* value */
+        $attr[1]= $attr[1];  /* value */
+
+        /* Check :: was used to indicate base64_encoded strings */
+        if($attr[1][0] == ":"){
+          $attr[1]=trim(preg_replace("/^:/","",$attr[1]));
+          $attr[1]=base64_decode($attr[1]);
+        }
+
+        $attr[1] = trim($attr[1]);
 
         /* Check for attributes that are used more than once */
         if(!isset($data[$attr[0]])) {
@@ -960,30 +1095,67 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
           }
         }
       }
-    } 
-    
+    }
+
     /* If dn is an index of data, we should try to insert the data */
     if(isset($data['dn'])) {
+
+      /* Fix dn */
+      $tmp = gosa_ldap_explode_dn($data['dn']);
+      unset($tmp['count']);
+      $newdn ="";
+      foreach($tmp as $tm){
+        $newdn.= trim($tm).",";
+      }
+      $newdn = preg_replace("/,$/","",$newdn);
+      $data['dn'] = $newdn;
+   
       /* Creating Entry */
       $this->cd($data['dn']);
 
       /* Delete existing entry */
       if($delete){
-        $this->rmdir($data['dn']);
+        $this->rmdir_recursive($data['dn']);
       }
-      
+     
       /* Create missing trees */
+      $this->cd ($this->basedn);
       $this->create_missing_trees($data['dn']);
+      $this->cd($data['dn']);
+
+      $dn = $data['dn'];
       unset($data['dn']);
       
-      /* If entry exists use modify */
       if(!$modify){
-        $ret = $this->add($data);
+
+        $this->cat($dn);
+        if($this->count()){
+        
+          /* The destination entry exists, overwrite it with the new entry */
+          $attrs = $this->fetch();
+          foreach($attrs as $name => $value ){
+            if(!is_numeric($name)){
+              if(in_array($name,array("dn","count"))) continue;
+              if(!isset($data[$name])){
+                $data[$name] = array();
+              }
+            }
+          }
+          $ret = $this->modify($data);
+    
+        }else{
+    
+          /* The destination entry doesn't exists, create it */
+          $ret = $this->add($data);
+        }
+
       } else {
+        
+        /* Keep all vars that aren't touched by this ldif */
         $ret = $this->modify($data);
       }
     }
-
+    show_ldap_error($this->get_error(), sprintf(_("Ldap import with dn '%s' failed."),$dn));
     return($ret);
   }
 
@@ -1009,6 +1181,76 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     }
 
   }
+  
+  function get_objectclasses()
+  {
+         $objectclasses = array();
+       
+         # Get base to look for schema 
+         $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
+         $attr = @ldap_get_entries($this->cid,$sr);
+         if (!isset($attr[0]['subschemasubentry'][0])){
+           return array();
+         }
+       
+         # Get list of objectclasses
+         $nb= $attr[0]['subschemasubentry'][0];
+         $objectclasses= array();
+         $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
+         $attrs= ldap_get_entries($this->cid,$sr);
+         if (!isset($attrs[0])){
+           return array();
+         }
+         foreach ($attrs[0]['objectclasses'] as $val){
+           $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
+           if ($name != $val){
+             $objectclasses[$name]= $val;
+           }
+         }
+         
+         return $objectclasses;
+  }
+
+  function log($string)
+  {
+    if (isset($_SESSION['config'])){
+      $cfg= $_SESSION['config'];
+      if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
+        syslog (LOG_INFO, $string);
+      }
+    }
+  }
+
+  /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
+  function getCn($dn){
+    $simple= split(",", $dn);
+
+    foreach($simple as $piece) {
+      $partial= split("=", $piece);
+
+      if($partial[0] == "cn"){
+        return $partial[1];
+      }
+    }
+  }
+
+  function get_naming_contexts($server, $admin= "", $password= "")
+  {
+    /* Build LDAP connection */
+    $ds= ldap_connect ($server);
+    if (!$ds) {
+      die ("Can't bind to LDAP. No check possible!");
+    }
+    ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+    $r= ldap_bind ($ds, $admin, $password);
+
+    /* Get base to look for naming contexts */
+    $sr  = @ldap_read ($ds, "", "objectClass=*", array("namingContexts"));
+    $attr= @ldap_get_entries($ds,$sr);
+    
+    return ($attr[0]['namingcontexts']);
+  }
+
 
 }