From e83f035887e3a463568465673ae92f365788c2a5 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Sat, 29 Aug 2009 14:41:17 -0400
Subject: [PATCH] - Fix LDAP contact update when RDN field is changed (#1485788)

---
 CHANGELOG                          |    1 
 program/include/rcube_ldap.php     |   31 ++++++++++-----
 program/steps/addressbook/save.inc |   13 +++++-
 program/js/app.js                  |   73 ++++++++++++++++++++----------------
 4 files changed, 73 insertions(+), 45 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 4faf7cb..0477935 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG RoundCube Webmail
 ===========================
 
+- Fix LDAP contact update when RDN field is changed (#1485788)
 - Fix LDAP attributes case senitivity problems (#1485830)
 - Fix LDAP addressbook browsing when only one directory is used (#1486022)
 - Fix endless loop on error response for APPEND command (#1486060)
diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index 37edca7..b13e883 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -480,32 +480,43 @@
       } // end if
     } // end foreach
 
-    // Update the entry as required.
     $dn = base64_decode($id);
+
+    // Update the entry as required.
     if (!empty($deletedata)) {
       // Delete the fields.
-      $res = ldap_mod_del($this->conn, $dn, $deletedata);
-      if ($res === FALSE) {
+      if (!ldap_mod_del($this->conn, $dn, $deletedata))
         return false;
-      } // end if
     } // end if
 
     if (!empty($replacedata)) {
+      // Handle RDN change
+      if ($replacedata[$this->prop['LDAP_rdn']]) {
+        $newdn = $this->prop['LDAP_rdn'].'='.$replacedata[$this->prop['LDAP_rdn']].','.$this->prop['base_dn']; 
+        if ($dn != $newdn) {
+          $newrdn = $this->prop['LDAP_rdn'].'='.$replacedata[$this->prop['LDAP_rdn']];
+          unset($replacedata[$this->prop['LDAP_rdn']]);
+        }
+      }
       // Replace the fields.
-      $res = ldap_mod_replace($this->conn, $dn, $replacedata);
-      if ($res === FALSE) {
-        return false;
+      if (!empty($replacedata)) {
+        if (!ldap_mod_replace($this->conn, $dn, $replacedata))
+          return false;
       } // end if
     } // end if
 
     if (!empty($newdata)) {
       // Add the fields.
-      $res = ldap_mod_add($this->conn, $dn, $newdata);
-      if ($res === FALSE) {
+      if (!ldap_mod_add($this->conn, $dn, $newdata))
         return false;
-      } // end if
     } // end if
 
+    // Handle RDN change
+    if (!empty($newrdn)) {
+      if (@ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE))
+        return base64_encode($newdn);
+    }
+
     return true;
   }
   
diff --git a/program/js/app.js b/program/js/app.js
index 6adc7f4..2d0be0f 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -2926,7 +2926,7 @@
     };
 
   // update a contact record in the list
-  this.update_contact_row = function(cid, cols_arr)
+  this.update_contact_row = function(cid, cols_arr, newcid)
   {
     var row;
     if (this.contact_list.rows[cid] && (row = this.contact_list.rows[cid].obj)) {
@@ -2934,11 +2934,50 @@
         if (row.cells[c])
           $(row.cells[c]).html(cols_arr[c]);
 
+      // cid change
+      if (newcid) {
+	row.id = 'rcmrow' + newcid;
+        this.contact_list.remove_row(cid);
+        this.contact_list.init_row(row);
+	this.contact_list.selection[0] = newcid;
+	row.style.display = '';
+      }
+
       return true;
     }
 
     return false;
   };
+
+  // add row to contacts list
+  this.add_contact_row = function(cid, cols, select)
+    {
+    if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
+      return false;
+    
+    var tbody = this.gui_objects.contactslist.tBodies[0];
+    var rowcount = tbody.rows.length;
+    var even = rowcount%2;
+    
+    var row = document.createElement('tr');
+    row.id = 'rcmrow'+cid;
+    row.className = 'contact '+(even ? 'even' : 'odd');
+	    
+    if (this.contact_list.in_selection(cid))
+      row.className += ' selected';
+
+    // add each submitted col
+    for (var c in cols) {
+      col = document.createElement('td');
+      col.className = String(c).toLowerCase();
+      col.innerHTML = cols[c];
+      row.appendChild(col);
+    }
+    
+    this.contact_list.insert_row(row);
+    
+    this.enable_command('export', (this.contact_list.rowcount > 0));
+    };
 
 
   /*********************************************************/
@@ -2993,7 +3032,7 @@
       this.load_identity(id, 'edit-identity');
     };
 
-  // load contact record
+  // load identity record
   this.load_identity = function(id, action)
     {
     if (action=='edit-identity' && (!id || id==this.env.iid))
@@ -3883,36 +3922,6 @@
     else
       window.focus();
     }
-
-  // add row to contacts list
-  this.add_contact_row = function(cid, cols, select)
-    {
-    if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
-      return false;
-    
-    var tbody = this.gui_objects.contactslist.tBodies[0];
-    var rowcount = tbody.rows.length;
-    var even = rowcount%2;
-    
-    var row = document.createElement('tr');
-    row.id = 'rcmrow'+cid;
-    row.className = 'contact '+(even ? 'even' : 'odd');
-	    
-    if (this.contact_list.in_selection(cid))
-      row.className += ' selected';
-
-    // add each submitted col
-    for (var c in cols) {
-      col = document.createElement('td');
-      col.className = String(c).toLowerCase();
-      col.innerHTML = cols[c];
-      row.appendChild(col);
-    }
-    
-    this.contact_list.insert_row(row);
-    
-    this.enable_command('export', (this.contact_list.rowcount > 0));
-    };
 
   this.toggle_prefer_html = function(checkbox)
     {
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index 639e0f2..b28294e 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -57,17 +57,24 @@
   $plugin = $RCMAIL->plugins->exec_hook('save_contact', array('id' => $cid, 'record' => $a_record, 'source' => get_input_value('_source', RCUBE_INPUT_GPC)));
   $a_record = $plugin['record'];
   
-  if (!$plugin['abort'] && $CONTACTS->update($cid, $a_record))
+  if (!$plugin['abort'] && ($result = $CONTACTS->update($cid, $a_record)))
   {
+    // LDAP DN change
+    if (is_string($result) && strlen($result)>1) {
+      $newcid = $result;
+      // change cid in POST for 'show' action
+      $_POST['_cid'] = $newcid;
+    }
+    
     // define list of cols to be displayed
     $a_js_cols = array();
-    $record = $CONTACTS->get_record($cid, true);
+    $record = $CONTACTS->get_record($newcid ? $newcid : $cid, true);
 
     foreach (array('name', 'email') as $col)
       $a_js_cols[] = (string)$record[$col];
 
     // update the changed col in list
-    $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols);
+    $OUTPUT->command('parent.update_contact_row', $cid, $a_js_cols, $newcid);
       
     // show confirmation
     $OUTPUT->show_message('successfullysaved', 'confirmation', null, false);

--
Gitblit v1.9.1