Code

Updated comments in heimdal plugin
[gosa.git] / include / class_ldap.inc
index 2fbf59e6d13ae06276577540a9397453c2d4e919..1973c820b5a408931b378533829a10d632d1f16b 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*****************************************************************************
   newldap.inc - version 1.0
-  Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
+  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
@@ -37,7 +37,7 @@ class LDAP{
     global $config;
     $this->follow_referral= $follow_referral;
     $this->tls=$tls;
-    $this->binddn=$this->convert($binddn);
+    $this->binddn=LDAP::convert($binddn);
 
     $this->bindpw=$bindpw;
     $this->hostname=$hostname;
@@ -62,12 +62,13 @@ class LDAP{
       (   => OB
       )   => CB
       /   => SL                                                                  */
-  function convert($dn)
+  static function convert($dn)
   {
     if (SPECIALS_OVERRIDE == TRUE){
-      return (preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
+      $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
                            array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
-                           $dn));
+                           $dn);
+      return (preg_replace('/,\s+/', ',', $tmp));
     } else {
       return ($dn);
     }
@@ -78,7 +79,7 @@ class LDAP{
      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)
+  static function fix($dn)
   {
     if (SPECIALS_OVERRIDE == TRUE){
       return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
@@ -105,7 +106,7 @@ class LDAP{
       }
 
       $this->error = "No Error";
-      if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
+      if ($bid = @ldap_bind($this->cid, LDAP::fix($this->binddn), $this->bindpw)) {
         $this->error = "Success";
         $this->hascon=true;
       } else {
@@ -125,7 +126,7 @@ class LDAP{
   function rebind($ldap, $referral)
   {
     $credentials= $this->get_credentials($referral);
-    if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
+    if (@ldap_bind($ldap, LDAP::fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
       $this->error = "Success";
       $this->hascon=true;
       $this->reconnect= true;
@@ -163,7 +164,7 @@ class LDAP{
     if ($dir == "..")
       $this->basedn = $this->getParentDir();
     else
-      $this->basedn = $this->convert($dir);
+      $this->basedn = LDAP::convert($dir);
   }
 
   function getParentDir($basedn = "")
@@ -171,7 +172,7 @@ class LDAP{
     if ($basedn=="")
       $basedn = $this->basedn;
     else
-      $basedn = $this->convert($this->basedn);
+      $basedn = LDAP::convert($this->basedn);
     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
   }
 
@@ -183,7 +184,7 @@ class LDAP{
       $start = microtime();
    
       $this->clearResult();
-      $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
+      $this->sr = @ldap_search($this->cid, LDAP::fix($this->basedn), $filter, $attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -196,6 +197,7 @@ class LDAP{
         }
       }
 
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".LDAP::fix($this->basedn)."', '$filter')");
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -211,11 +213,10 @@ class LDAP{
       if ($basedn == "")
         $basedn = $this->basedn;
       else
-        $basedn= $this->convert($basedn);
+        $basedn= LDAP::convert($basedn);
   
       $start = microtime();
-
-      $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
+      $this->sr = @ldap_list($this->cid, LDAP::fix($basedn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -228,6 +229,8 @@ class LDAP{
         }
       }
 
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".LDAP::fix($basedn)."', '$filter')");
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -241,7 +244,7 @@ class LDAP{
       if ($this->reconnect) $this->connect();
       $this->clearResult();
       $filter = "(objectclass=*)";
-      $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
+      $this->sr = @ldap_read($this->cid, LDAP::fix($dn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -272,15 +275,19 @@ class LDAP{
       if($this->hasres){
         if ($this->start == 0)
         {
-          $this->start = 1;
-          $this->re= @ldap_first_entry($this->cid, $this->sr);
+          if ($this->sr){
+            $this->start = 1;
+            $this->re= @ldap_first_entry($this->cid, $this->sr);
+          } else {
+            return array();
+          }
         } else {
           $this->re= @ldap_next_entry($this->cid, $this->re);
         }
         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(LDAP::convert(@ldap_get_dn($this->cid, $this->re)));
         }
         $this->error = @ldap_error($this->cid);
         if (!isset($att)){
@@ -324,7 +331,7 @@ class LDAP{
           $rv = @ldap_get_dn($this->cid, $this->re);
         
           $this->error = @ldap_error($this->cid);
-          return($this->convert($rv));
+          return(trim(LDAP::convert($rv)));
            }
       }else{
         $this->error = "Perform a Fetch with no Search";
@@ -360,7 +367,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
+      $r = @ldap_mod_del($this->cid, LDAP::fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -376,7 +383,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
+      $r = @ldap_mod_replace($this->cid, LDAP::fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -389,7 +396,7 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_delete($this->cid, $this->fix($deletedn));
+      $r = @ldap_delete($this->cid, LDAP::fix($deletedn));
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -428,7 +435,7 @@ class LDAP{
       }
       
       /* Finally Delete own Node */
-      $r = @ldap_delete($this->cid, $this->fix($deletedn));
+      $r = @ldap_delete($this->cid, LDAP::fix($deletedn));
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -439,21 +446,21 @@ class LDAP{
 
   /* Copy given attributes and sub-dns with attributes to destination dn 
   */
-  function copy_FAI_resource_recursive($sourcedn,$destinationdn,$type="branch",$is_first = true,$depth=0)
+  function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
   {
-    error_reporting(E_ALL);
+    error_reporting(E_ALL | E_STRICT);
     
     if($is_first){
-      echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
+      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>";
+        echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
       }else{
         $tmp = split(",",$sourcedn);
         
         echo "&nbsp;<b>"._("Object").":</b> ";
 
-        $deststr = @LDAP::fix($destinationdn);
+        $deststr = LDAP::fix($destinationdn);
         if(strlen($deststr) > 96){
           $deststr = substr($deststr,0,96)."...";
         }
@@ -493,7 +500,7 @@ class LDAP{
   
         /* check if this is a department */
         if(in_array("organizationalUnit",$attr['objectClass'])){
-          $attr['dn'] = $this->convert($destinationdn);
+          $attr['dn'] = LDAP::convert($destinationdn);
           $this->cd($basedn);
           $this->create_missing_trees($destinationdn);
           $this->cd($destinationdn);
@@ -526,8 +533,8 @@ class LDAP{
 
           /* If this is no department */
           foreach($attr as $key => $value){
-            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
-              $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
+            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
+              $sr= ldap_read($this->cid, LDAP::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;
@@ -544,7 +551,8 @@ class LDAP{
           unset($attr['count']);
           unset($attr['dn']);
 
-          if(!in_array("gosaApplication" , $attr['objectClass'])){
+          if((!in_array("gosaApplication" , $attr['objectClass'])) && (!in_array("gotoMimeType", $attr['objectClass']))){
+            $attr['FAIdebianRelease'] = $destinationName;
             if($type=="branch"){
               $attr['FAIstate'] ="branch";
             }elseif($type=="freeze"){
@@ -554,6 +562,11 @@ class LDAP{
             }
           }
 
+          /* Replace FAIdebianRelease with new release name */
+          if(in_array("FAIpackageList" , $attr['objectClass'])){
+            $attr['FAIdebianRelease'] = $destinationName; 
+          }
+
           /* Add entry */
           $this->cd($destinationdn);
           $this->cat($destinationdn);
@@ -563,7 +576,7 @@ class LDAP{
           }
 
           if($this->error != "Success"){
-            /* Some error occured */
+            /* Some error occurred */
             print "---------------------------------------------";
             print $this->get_error()."<br>";
             print $sourcedn."<br>";
@@ -574,6 +587,8 @@ class LDAP{
         }
       }
 
+      echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
+
       $this->ls ("(objectClass=*)",$sourcedn);
       while ($this->fetch()){
         $deldn= $this->getDN();
@@ -588,7 +603,7 @@ class LDAP{
           $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,false,$depth);
+            $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
           } 
         }
       }
@@ -606,7 +621,7 @@ class LDAP{
     }
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
+      $r = @ldap_modify($this->cid, LDAP::fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -619,7 +634,7 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
+      $r = @ldap_add($this->cid, LDAP::fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -630,19 +645,26 @@ class LDAP{
 
   function create_missing_trees($target)
   {
-    /* Ignore create_missing trees if the base equals target */
-    if ($target == $this->basedn){
-     return;
-    }
+    global $config;
 
     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
-    $l= array_reverse(ldap_explode_dn($real_path,0));
+
+    if ($target == $this->basedn){
+      $l= array("dummy");
+    } else {
+      $l= array_reverse(gosa_ldap_explode_dn($real_path));
+    }
     unset($l['count']);
     $cdn= $this->basedn;
     $tag= "";
 
+    /* Load schema if available... */
+    $classes= $this->get_objectclasses();
+
     foreach ($l as $part){
-      $cdn= "$part,$cdn";
+      if ($part != "dummy"){
+        $cdn= "$part,$cdn";
+      }
 
       /* Ignore referrals */
       $found= false;
@@ -673,36 +695,98 @@ class LDAP{
         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
 
         $na= array();
-        switch ($type){
-          case 'ou':
-            if ($tag != ""){
-              $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
-              $na["gosaUnitTag"]= $tag;
-            } else {
-              $na["objectClass"]= "organizationalUnit";
-            }
-            $na["ou"]= $param;
-            break;
-          case 'dc':
-            if ($tag != ""){
-              $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
-              $na["gosaUnitTag"]= $tag;
-            } else {
-              $na["objectClass"]= array("dcObject", "top", "locality");
+
+        /* Automatic or traditional? */
+        if(count($classes)){
+
+          /* Get name of first matching objectClass */
+          $ocname= "";
+          foreach($classes as $class){
+            if (isset($class['MUST']) && $class['MUST'] == "$type"){
+
+              /* Look for first classes that is structural... */
+              if (isset($class['STRUCTURAL'])){
+                $ocname= $class['NAME'];
+                break;
+              }
+
+              /* Look for classes that are auxiliary... */
+              if (isset($class['AUXILIARY'])){
+                $ocname= $class['NAME'];
+              }
             }
-            $na["dc"]= $param;
-            break;
-          default:
-            print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
+          }
+
+          /* Bail out, if we've nothing to do... */
+          if ($ocname == ""){
+            print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
             echo $_SESSION['errors'];
             exit;
+          }
+
+          /* Assemble_entry */
+          if ($tag != ""){
+            $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
+          } else {
+            $na['objectClass']= array($ocname);
+          }
+          if (isset($classes[$ocname]['AUXILIARY'])){
+            $na['objectClass'][]= $classes[$ocname]['SUP'];
+          }
+          if ($type == "dc"){
+            /* This is bad actually, but - tell me a better way? */
+            $na['objectClass'][]= 'locality';
+          }
+          $na[$type]= $param;
+          if (is_array($classes[$ocname]['MUST'])){
+            foreach($classes[$ocname]['MUST'] as $attr){
+              $na[$attr]= "filled";
+            }
+          }
+
+        } else {
+
+          /* Use alternative add... */
+          switch ($type){
+            case 'ou':
+              if ($tag != ""){
+                $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
+                $na["gosaUnitTag"]= $tag;
+              } else {
+                $na["objectClass"]= "organizationalUnit";
+              }
+              $na["ou"]= $param;
+              break;
+            case 'dc':
+              if ($tag != ""){
+                $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
+                $na["gosaUnitTag"]= $tag;
+              } else {
+                $na["objectClass"]= array("dcObject", "top", "locality");
+              }
+              $na["dc"]= $param;
+              break;
+            default:
+              print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
+              echo $_SESSION['errors'];
+              exit;
+          }
+
         }
         $this->cd($cdn);
         $this->add($na);
+    
+        show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
+        if (!preg_match('/success/i', $this->error)){
+          return FALSE;
+        }
       }
     }
+
+    return TRUE;
   }
 
+
   function recursive_remove()
   {
     $delarray= array();
@@ -726,7 +810,7 @@ class LDAP{
   {
     $data= "";
     if ($this->reconnect) $this->connect();
-    $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
+    $sr= @ldap_read($this->cid, LDAP::fix($dn), "objectClass=*", array("$name"));
 
     /* fill data from LDAP */
     if ($sr) {
@@ -735,7 +819,6 @@ class LDAP{
         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
           $data= $info[0];
         }
-
       }
     }
     if($r_array==0)
@@ -762,7 +845,7 @@ class LDAP{
     } else {
       $adderror= $this->get_additional_error();
       if ($adderror != ""){
-        $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->base, $this->hostname).")";
+        $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).")";
       }
@@ -776,14 +859,14 @@ class LDAP{
     $url= preg_replace('!\?\?.*$!', '', $url);
     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
 
-    if ($referrals == NULL){
+    if ($referrals === NULL){
       $referrals= $this->referrals;
     }
 
     if (isset($referrals[$server])){
       return ($referrals[$server]);
     } else {
-      $ret['ADMIN']= $this->fix($this->binddn);
+      $ret['ADMIN']= LDAP::fix($this->binddn);
       $ret['PASSWORD']= $this->bindpw;
     }
 
@@ -797,21 +880,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");
@@ -841,7 +930,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     }
 
     /* Searching Ldap Tree */
-    $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
+    $sr= @ldap_read($this->cid, LDAP::fix($dn), $filter, $name);
 
     /* Get the first entry */   
     $entry= @ldap_first_entry($this->cid, $sr);
@@ -885,12 +974,19 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
 
   function dn_exists($dn)
   {
-    return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
+    return @ldap_list($this->cid, LDAP::fix($dn), "(objectClass=*)", array("objectClass"));
   }
   
 
 
-  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();
 
@@ -902,8 +998,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 .. 
@@ -927,15 +1036,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";
           }
         }
       }
@@ -951,9 +1060,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];
@@ -970,18 +1079,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;
@@ -998,9 +1107,20 @@ 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)
   {
+    global $config;
+
+    if(!$config){
+      trigger_error("Can't import ldif, can't read config object.");
+    }
+  
+
     if($this->reconnect) $this->connect();
 
     $ret = false;
@@ -1012,19 +1132,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]])) {
@@ -1045,30 +1173,68 @@ 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->create_missing_trees($data['dn']);
+      $this->cd ($this->basedn);
+      $this->cd($config->current['BASE']);
+      $this->create_missing_trees(preg_replace("/^[^,]+,/","",$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);
   }
 
@@ -1097,16 +1263,28 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
   
   function get_objectclasses()
   {
-         $objectclasses = array();
-       
+    $objectclasses = array();
+    global $config;
+
+    /* Only read schema if it is allowed */
+    if(isset($config) && preg_match("/config/i",get_class($config))){
+      if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
+        return($objectclasses);
+      } 
+    }
+       
          # Get base to look for schema 
          $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
+    if(!$sr){
+           $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
+    }
+
          $attr = @ldap_get_entries($this->cid,$sr);
          if (!isset($attr[0]['subschemasubentry'][0])){
            return array();
          }
        
-         # Get list of objectclasses
+         /* Get list of objectclasses and fill array */
          $nb= $attr[0]['subschemasubentry'][0];
          $objectclasses= array();
          $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
@@ -1115,15 +1293,146 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
            return array();
          }
          foreach ($attrs[0]['objectclasses'] as $val){
-           $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
-           if ($name != $val){
-             $objectclasses[$name]= $val;
-           }
+      if (preg_match('/^[0-9]+$/', $val)){
+        continue;
+      }
+      $name= "OID";
+      $pattern= split(' ', $val);
+      $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
+      $objectclasses[$ocname]= array();
+
+      foreach($pattern as $chunk){
+        switch($chunk){
+
+          case '(':
+                    $value= "";
+                    break;
+
+          case ')': if ($name != ""){
+                      $objectclasses[$ocname][$name]= $this->value2container($value);
+                    }
+                    $name= "";
+                    $value= "";
+                    break;
+
+          case 'NAME':
+          case 'DESC':
+          case 'SUP':
+          case 'STRUCTURAL':
+          case 'ABSTRACT':
+          case 'AUXILIARY':
+          case 'MUST':
+          case 'MAY':
+                    if ($name != ""){
+                      $objectclasses[$ocname][$name]= $this->value2container($value);
+                    }
+                    $name= $chunk;
+                    $value= "";
+                    break;
+
+          default:  $value.= $chunk." ";
+        }
+      }
+
          }
-         
          return $objectclasses;
   }
 
+
+  function value2container($value)
+  {
+    /* Set emtpy values to "true" only */
+    if (preg_match('/^\s*$/', $value)){
+      return true;
+    }
+
+    /* Remove ' and " if needed */
+    $value= preg_replace('/^[\'"]/', '', $value);
+    $value= preg_replace('/[\'"] *$/', '', $value);
+
+    /* Convert to array if $ is inside... */
+    if (preg_match('/\$/', $value)){
+      $container= preg_split('/\s*\$\s*/', $value);
+    } else {
+      $container= chop($value);
+    }
+
+    return ($container);
+  }
+
+
+  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("+"));
+    $attr= @ldap_get_entries($ds,$sr);
+
+    return ($attr[0]['namingcontexts']);
+  }
+
+
+  function get_root_dse($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("+"));
+    $attr= @ldap_get_entries($ds,$sr);
+   
+    /* Return empty array, if nothing was set */
+    if (!isset($attr[0])){
+      return array();
+    }
+
+    /* Rework array... */
+    $result= array();
+    for ($i= 0; $i<$attr[0]['count']; $i++){
+      $result[$attr[0][$i]]= $attr[0][$attr[0][$i]];
+      unset($result[$attr[0][$i]]['count']);
+    }
+
+    return ($result);
+  }
+
+
 }
 
 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: