--- ldap.php	Mon Apr 18 15:46:59 2005
+++ ldap.php.1.54.4.6.php	Mon Apr 18 15:42:47 2005
@@ -226,6 +226,13 @@
         /* Take the DN out of the attributes array. */
         $dn = $attributes['dn'];
         unset($attributes['dn']);
+      
+	if (isset($this->_params['rdn_func'])) {
+	  $rdn_attr = $this->_params['rdn_attr'];
+	  $dn_parts = $this->_mungeDn($dn);
+	  $rdn = $dn_parts[0][$rdn_attr];
+	  $attributes[$rdn_attr] = $rdn;
+	}
 
         /* Put the objectClass into the attributes array. */
         if (!is_array($this->_params['objectclass'])) {
@@ -236,7 +243,7 @@
                 $attributes['objectclass'][$i] = $objectclass;
                 $i++;
             }
-        }
+        }	
 
         /* Don't add empty attributes. */
         $attributes = array_filter($attributes, array($this, '_emptyAttributeFilter'));
@@ -303,17 +310,13 @@
         /* Check if we need to rename the object. */
         if ($this->_params['version'] == 3 &&
             String::lower($this->_makeKey($attributes)) != String::lower($object_id)) {
-            if (isset($this->_params['dn']) && is_array($this->_params['dn']) && count($this->_params['dn'])) {
-                $pairs = array();
-                foreach ($this->_params['dn'] as $param) {
-                    if (isset($attributes[$param])) {
-                        $pairs[] = array($param, $attributes[$param]);
-                    }
-                }
-                $newrdn = $this->_quoteDN($pairs);
-            } else {
-                return PEAR::raiseError(_("Missing DN in LDAP source configuration."));
-            }
+
+	    if (! isset($this->_params['rdn_attr'])) {
+	      return PEAR::raiseError(_("Missing RDN Attribute name in LDAP source configuration."));
+	    }
+
+	    $dn = $object_id;
+	    $newrdn = $this->_getExistingRDN($dn);
 
             if (ldap_rename($this->_ds, $object_id, $newrdn, $this->_params['root'], true)) {
                 $object_id = $newrdn . ',' . $this->_params['root'];
@@ -375,18 +378,46 @@
      */
     function _makeKey($attributes)
     {
-        $dn = '';
-        if (is_array($this->_params['dn'])) {
-            $pairs = array();
-            foreach ($this->_params['dn'] as $param) {
-                if (isset($attributes[$param])) {
-                    $pairs[] = array($param, $attributes[$param]);
-                }
-            }
-            $dn = $this->_quoteDN($pairs);
-        }
+      
+      $rdn_attr = $this->_params['rdn_attr'];
+      $rdn_val = '';
+      $rdn = '';
+
+      // check for a function to auto-generate the RDN
+      if (isset($this->_params['rdn_func'])) {
+
+	// Does the entry already exist?
+	// If so, fetch the existing RDN and return it
+	$dn = '';
+	if (isset($attributes['dn'])) {
+	  $dn = $attributes['dn'];
+	}
+
+	$gotta_rdn = preg_match("/^$rdn_attr=/", $dn);
+
+	if ($gotta_rdn) {
+	  $rdn = $this->_getExistingRDN($dn);
+	} else {
+	  $rdn_func = $this->_params['rdn_func'];
+
+	  // yucky type-check for an anonymous function - oh, gimme Perl :)
+	  $isa_function = preg_match("/lambda_\d+/", $rdn_func);
+
+	  if ($isa_function) {
+	    // Call it! Simple, cause we're not supporting run-time params
+	    $rdn_val = $rdn_func();
+	    $rdn = $rdn_attr . '=' . $rdn_val;
+	  }
+	}
+
+      } else {
+	// nothing to autogenerate here - it must be set in $attributes
+	$rdn_val = $attributes[$rdn_attr];
+	$rdn = $rdn_attr . '=' . $rdn_val;
+      }
+
+      return $rdn . ',' . $this->_params['root'];
 
-        return $dn . ',' . $this->_params['root'];
     }
 
     /**
@@ -616,41 +647,57 @@
         }
     }
 
+
     /**
-     * Take an array of DN elements and properly quote it according to
-     * RFC 1485.
+     * Munges the DN into pieces.
      *
-     * @see Horde_LDAP::quoteDN()
+     * @access private
      *
-     * @param array $parts  An array of tuples containing the attribute
-     *                      name and that attribute's value which make
-     *                      up the DN. Example:
+     * @param string $dn  The Distinguished Name
      *
-     *    $parts = array(0 => array('cn', 'John Smith'),
-     *                   1 => array('dc', 'example'),
-     *                   2 => array('dc', 'com'));
+     * @return array  The munge-ified DN (array of hashes)
+     */
+    function _mungeDN($dn)
+    {
+      $munged_dn_hash = array(); // bizarro world
+      $attrs = explode(',', $dn);
+      foreach ($attrs as $attr) {
+	$key_and_value = explode('=', $attr);
+	$attr_arrray = array($key_and_value[0] => $key_and_value[1]);
+	array_push( $munged_dn_hash, $attr_arrray );
+      }
+      return $munged_dn_hash;
+    }
+
+
+    /**
+     * get RDN from a DN.
+     *
+     * @access private
      *
-     * @return string  The properly quoted string DN.
+     * @param string $dn  The Distinguished Name
+     *
+     * @return string  The Relative Distinguished Name
      */
-    function _quoteDN($parts)
+    function _getExistingRDN($dn)
     {
-        $dn = '';
-        $count = count($parts);
-        for ($i = 0; $i < $count; $i++) {
-            if ($i > 0) {
-                $dn .= ',';
-            }
-            $dn .= $parts[$i][0] . '=';
 
-            /* See if we need to quote the value. */
-            if (preg_match('/^\s|\s$|\s\s|[,+="\r\n<>#;]/', $parts[$i][1])) {
-                $dn .= '"' . str_replace('"', '\\"', $parts[$i][1]) . '"';
-            } else {
-                $dn .= $parts[$i][1];
-            }
-        }
+      // We have to hack the rdn_attr value out of the DN for adding,
+      // since $attributes is not accessible via an instance method here	
+      // We'll do this only if an auto-generated value was set.
+      // How would we know this? An rdn_func exists!
+
+      $rdn = '';
+      if (isset($this->_params['rdn_func'])) {
 
-        return $dn;
+	$rdn_attr = $this->_params['rdn_attr'];
+	$dn_parts = $this->_mungeDn($dn);
+	$rdn = $rdn_attr . '=' . $dn_parts[0][$rdn_attr];
+      } else {
+	// Its a user-defined value - pull it out of $attributes
+	$rdn = $rdn_attr . '=' . $attributes[$rdn_attr];
+      }
+      return $rdn;
     }
 
 }
