Changeset 4f9c833 in github
- Timestamp:
- May 7, 2008 6:16:00 PM (5 years ago)
- Branches:
- master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
- Children:
- 1a659d7
- Parents:
- 1854c45
- Files:
-
- 9 edited
-
CHANGELOG (modified) (1 diff)
-
config/main.inc.php.dist (modified) (3 diffs)
-
program/include/main.inc (modified) (1 diff)
-
program/include/rcube_ldap.php (modified) (9 diffs)
-
program/js/app.js (modified) (1 diff)
-
program/steps/addressbook/delete.inc (modified) (1 diff)
-
program/steps/addressbook/edit.inc (modified) (1 diff)
-
program/steps/addressbook/func.inc (modified) (3 diffs)
-
program/steps/mail/addcontact.inc (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
CHANGELOG
r32ac953 r4f9c833 1 1 CHANGELOG RoundCube Webmail 2 2 --------------------------- 3 4 2008/05/07 (davidke/richs) 5 ---------- 6 - Completed LDAP address book support so it can now write to an LDAP server. 7 - Expanded LDAP configuration options to support LDAP server writes. 8 - Modified config/main.inc.php.dist: 9 New Option: $rcmail_config['use_SQL_address_book'] 10 Changed Option: $rcmail_config['ldap_public']['Verisign'] 3 11 4 12 2008/05/05 (alec) -
config/main.inc.php.dist
r197601e r4f9c833 214 214 $rcmail_config['session_domain'] = ''; 215 215 216 // in order to enable public ldap search, create a config array 217 // like the Verisign example below. if you would like to test, 218 // simply uncomment the Verisign example. 216 // This indicates whether or not to use the SQL address book. 217 // If set to false then it will look at using the first writable LDAP 218 // address book as the primary address book and it will not display the 219 // SQL address book in the 'Address Book' view. 220 $rcmail_config['use_SQL_address_book'] = true; 221 222 // In order to enable public ldap search, configure an array like the Verisign 223 // example further below. if you would like to test, simply uncomment the example. 224 // 225 // If you are going to use LDAP for individual address books, you will need to 226 // set 'user_specific' to true and use the variables to generate the appropriate DNs to access it. 227 // 228 // The recommended directory structure for LDAP is to store all the address book entries 229 // under the users main entry, e.g.: 230 // 231 // o=root 232 // ou=people 233 // uid=user@domain 234 // mail=contact@contactdomain 235 // 236 // So the base_dn would be uid=%fu,ou=people,o=root 237 // The bind_dn would be the same as based_dn or some super user login. 219 238 /** 220 239 * example config for Verisign directory … … 224 243 * 'hosts' => array('directory.verisign.com'), 225 244 * 'port' => 389, 245 * 'user_specific' => false, // If true the base_dn, bind_dn and bind_pass default to the user's IMAP login. 246 * // %fu - The full username provided, assumes the username is an email 247 * // address, uses the username_domain value if not an email address. 248 * // %u - The username prior to the '@'. 249 * // %d - The domain name after the '@'. 226 250 * 'base_dn' => '', 227 251 * 'bind_dn' => '', 228 252 * 'bind_pass' => '', 253 * 'writable' => false, // Indicates if we can write to the LDAP directory or not. 254 * // If writable is true then these fields need to be populated: 255 * // LDAP_Object_Classes, required_fields, LDAP_rdn 256 * 'LDAP_Object_Classes' => array("top", "inetOrgPerson"), // To create a new contact these are the object classes to specify (or any other classes you wish to use). 257 * 'required_fields' => array("cn", "sn", "mail"), // The required fields needed to build a new contact as required by the object classes (can include additional fields not required by the object classes). 258 * 'LDAP_rdn' => 'mail', // The RDN field that is used for new entries, this field needs to be one of the search_fields, the base of base_dn is appended to the RDN to insert into the LDAP directory. 229 259 * 'ldap_version' => 3, // using LDAPv3 230 260 * 'search_fields' => array('mail', 'cn'), // fields to search in … … 233 263 * 'surname_field' => 'sn', // this field represents the contact's last name 234 264 * 'firstname_field' => 'gn', // this field represents the contact's first name 265 * 'sort' => 'cn', // The field to sort the listing by. 235 266 * 'scope' => 'sub', // search mode: sub|base|list 236 267 * 'filter' => '', // used for basic listing (if not empty) and will be &'d with search queries. example: status=act -
program/include/main.inc
r1854c45 r4f9c833 603 603 $zebra_class = $c%2 ? 'even' : 'odd'; 604 604 605 $table .= sprintf('<tr id="rcmrow% d" class="contact '.$zebra_class.'">'."\n", $row_data[$id_col]);605 $table .= sprintf('<tr id="rcmrow%s" class="contact '.$zebra_class.'">'."\n", $row_data[$id_col]); 606 606 607 607 // format each col -
program/include/rcube_ldap.php
r47124c22 r4f9c833 57 57 if (preg_match('/^(.+)_field$/', $prop, $matches)) 58 58 $this->fieldmap[$matches[1]] = $value; 59 59 60 $this->sort_col = $p["sort"]; 61 60 62 $this->connect(); 61 63 } … … 103 105 { 104 106 $this->ready = true; 105 if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass'])) 107 108 if ($this->prop["user_specific"]) { 109 // User specific access, generate the proper values to use. 110 global $CONFIG, $RCMAIL; 111 if (empty($this->prop['bind_pass'])) { 112 // No password set, use the users. 113 $this->prop['bind_pass'] = $RCMAIL->decrypt_passwd($_SESSION["password"]); 114 } // end if 115 116 // Get the pieces needed for variable replacement. 117 // See if the logged in username has an "@" in it. 118 if (is_bool(strstr($_SESSION["username"], "@"))) { 119 // It does not, use the global default. 120 $fu = $_SESSION["username"]."@".$CONFIG["username_domain"]; 121 $u = $_SESSION["username"]; 122 $d = $CONFIG["username_domain"]; 123 } // end if 124 else { 125 // It does. 126 $fu = $_SESSION["username"]; 127 // Get the pieces needed for username and domain. 128 list($u, $d) = explode("@", $_SESSION["username"]); 129 } # end else 130 131 // Replace the bind_dn variables. 132 $bind_dn = str_replace(array("%fu", "%u", "%d"), 133 array($fu, $u, $d), 134 $this->prop['bind_dn']); 135 $this->prop['bind_dn'] = $bind_dn; 136 // Replace the base_dn variables. 137 $base_dn = str_replace(array("%fu", "%u", "%d"), 138 array($fu, $u, $d), 139 $this->prop['base_dn']); 140 $this->prop['base_dn'] = $base_dn; 141 142 $this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']); 143 } // end if 144 elseif (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass'])) 106 145 $this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']); 107 146 } 108 147 else 109 148 raise_error(array('type' => 'ldap', 'message' => "Could not connect to any LDAP server, tried $host:{$this->prop[port]} last"), true); 149 150 // See if the directory is writeable. 151 if ($this->prop['writable']) { 152 $this->readonly = false; 153 } // end if 154 110 155 } 111 156 … … 212 257 * 213 258 * @param array List of cols to show 214 * @param int Only return this number of records (not implemented)259 * @param int Only return this number of records 215 260 * @return array Indexed list of contact records, each a hash array 216 261 */ … … 236 281 if ($this->sort_col && $this->prop['scope'] !== "base") 237 282 @ldap_sort($this->conn, $this->ldap_result, $this->sort_col); 238 283 284 $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; 285 $last_row = $this->result->first + $this->page_size; 286 $last_row = $subset != 0 ? $start_row + abs($subset) : $last_row; 287 239 288 $entries = ldap_get_entries($this->conn, $this->ldap_result); 240 for ($i = $ this->result->first; $i < min($entries['count'], $this->result->first + $this->page_size); $i++)289 for ($i = $start_row; $i < min($entries['count'], $last_row); $i++) 241 290 $this->result->add($this->_ldap2result($entries[$i])); 242 291 } … … 314 363 { 315 364 $count = 0; 316 if ($this->conn && $this->ldap_result) 365 if ($this->conn && $this->ldap_result) { 317 366 $count = ldap_count_entries($this->conn, $this->ldap_result); 367 } // end if 368 elseif ($this->conn) { 369 // We have a connection but no result set, attempt to get one. 370 if (empty($this->filter)) { 371 // The filter is not set, set it. 372 $this->filter = $this->prop['filter']; 373 } // end if 374 $this->_exec_search(); 375 if ($this->ldap_result) { 376 $count = ldap_count_entries($this->conn, $this->ldap_result); 377 } // end if 378 } // end else 318 379 319 380 return new rcube_result_set($count, ($this->list_page-1) * $this->page_size); … … 349 410 if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) 350 411 { 412 // Add in the dn for the entry. 413 $rec["dn"] = base64_decode($dn); 351 414 $res = $this->_ldap2result($rec); 352 415 $this->result = new rcube_result_set(1); … … 363 426 * 364 427 * @param array Hash array with save data 365 * @return boolean The createrecord ID on success, False on error428 * @return encoded record ID on success, False on error 366 429 */ 367 430 function insert($save_cols) 368 431 { 369 // TODO 370 return false; 432 // Map out the column names to their LDAP ones to build the new entry. 433 $newentry = array(); 434 $newentry["objectClass"] = $this->prop["LDAP_Object_Classes"]; 435 foreach ($save_cols as $col => $val) { 436 $fld = ""; 437 $fld = $this->_map_field($col); 438 if ($fld != "") { 439 // The field does exist, add it to the entry. 440 $newentry[$fld] = $val; 441 } // end if 442 } // end foreach 443 444 // Verify that the required fields are set. 445 // We know that the email address is required as a default of rcube, so 446 // we will default its value into any unfilled required fields. 447 foreach ($this->prop["required_fields"] as $fld) { 448 if (!isset($newentry[$fld])) { 449 $newentry[$fld] = $newentry[$this->_map_field("email")]; 450 } // end if 451 } // end foreach 452 453 // Build the new entries DN. 454 $dn = $this->prop["LDAP_rdn"]."=".$newentry[$this->prop["LDAP_rdn"]].",".$this->prop['base_dn']; 455 $res = @ldap_add($this->conn, $dn, $newentry); 456 if ($res === FALSE) { 457 return false; 458 } // end if 459 460 return base64_encode($dn); 371 461 } 372 462 … … 381 471 function update($id, $save_cols) 382 472 { 383 // TODO 384 return false; 473 $record = $this->get_record($id, true); 474 $result = $this->get_result(); 475 $record = $result->first(); 476 477 $newdata = array(); 478 $replacedata = array(); 479 $deletedata = array(); 480 foreach ($save_cols as $col => $val) { 481 $fld = ""; 482 $fld = $this->_map_field($col); 483 if ($fld != "") { 484 // The field does exist compare it to the ldap record. 485 if ($record[$col] != $val) { 486 // Changed, but find out how. 487 if (!isset($record[$col])) { 488 // Field was not set prior, need to add it. 489 $newdata[$fld] = $val; 490 } // end if 491 elseif ($val == "") { 492 // Field supplied is empty, verify that it is not required. 493 if (!in_array($fld, $this->prop["required_fields"])) { 494 // It is not, safe to clear. 495 $deletedata[$fld] = $record[$col]; 496 } // end if 497 } // end elseif 498 else { 499 // The data was modified, save it out. 500 $replacedata[$fld] = $val; 501 } // end else 502 } // end if 503 } // end if 504 } // end foreach 505 506 // Update the entry as required. 507 $dn = base64_decode($id); 508 if (!empty($deletedata)) { 509 // Delete the fields. 510 $res = @ldap_mod_del($this->conn, $dn, $deletedata); 511 if ($res === FALSE) { 512 return false; 513 } // end if 514 } // end if 515 516 if (!empty($replacedata)) { 517 // Replace the fields. 518 $res = @ldap_mod_replace($this->conn, $dn, $replacedata); 519 if ($res === FALSE) { 520 return false; 521 } // end if 522 } // end if 523 524 if (!empty($newdata)) { 525 // Add the fields. 526 $res = @ldap_mod_add($this->conn, $dn, $newdata); 527 if ($res === FALSE) { 528 return false; 529 } // end if 530 } // end if 531 532 return true; 385 533 } 386 534 … … 394 542 function delete($ids) 395 543 { 396 // TODO 397 return false; 544 if (!is_array($ids)) { 545 // Not an array, break apart the encoded DNs. 546 $dns = explode(",", $ids); 547 } // end if 548 549 foreach ($dns as $id) { 550 $dn = base64_decode($id); 551 // Delete the record. 552 $res = @ldap_delete($this->conn, $dn); 553 if ($res === FALSE) { 554 return false; 555 } // end if 556 } // end foreach 557 558 return true; 398 559 } 399 560 -
program/js/app.js
rac23884 r4f9c833 2477 2477 2478 2478 // send request to server 2479 this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_ from='+(this.env.action ? this.env.action : '')+qs);2479 this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs); 2480 2480 return true; 2481 2481 }; -
program/steps/addressbook/delete.inc
r8d07583 r4f9c833 20 20 */ 21 21 22 if (($cid = get_input_value('_cid', RCUBE_INPUT_POST)) && preg_match('/^[0-9]+(,[0-9]+)*$/', $cid)) 22 if (($cid = get_input_value('_cid', RCUBE_INPUT_POST)) && 23 (preg_match('/^[0-9]+(,[0-9]+)*$/', $cid) || 24 preg_match('/^[a-zA-Z0-9=]+(,[a-zA-Z0-9=]+)*$/', $cid)) 25 ) 23 26 { 24 27 $deleted = $CONTACTS->delete($cid); -
program/steps/addressbook/edit.inc
r197601e r4f9c833 92 92 $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); 93 93 $hiddenfields->add(array('name' => '_action', 'value' => 'save', 'source' => get_input_value('_source', RCUBE_INPUT_GPC))); 94 $hiddenfields->add(array('name' => '_source', 'value' => get_input_value('_source', RCUBE_INPUT_GPC))); 94 95 95 96 if (($result = $CONTACTS->get_result()) && ($record = $result->first())) -
program/steps/addressbook/func.inc
r47124c22 r4f9c833 23 23 if (($source = get_input_value('_source', RCUBE_INPUT_GPC)) && isset($CONFIG['ldap_public'][$source])) 24 24 $CONTACTS = new rcube_ldap($CONFIG['ldap_public'][$source]); 25 else 26 $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']); 25 else { 26 if (!$CONFIG["use_SQL_address_book"]) { 27 // Get the first LDAP address book. 28 $source = key((array)$CONFIG['ldap_public']); 29 $prop = current((array)$CONFIG['ldap_public']); 30 $CONTACTS = new rcube_ldap($prop); 31 } // end if 32 else { 33 $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']); 34 } // end else 35 } // end else 27 36 28 37 $CONTACTS->set_pagesize($CONFIG['pagesize']); … … 43 52 44 53 // add list of address sources to client env 45 $js_list = array("0" => array('id' => 0, 'readonly' => false)); 54 $js_list = array(); 55 if ($CONFIG["use_SQL_address_book"]) { 56 // We are using the DB address book, add it. 57 $js_list = array("0" => array('id' => 0, 'readonly' => false)); 58 } // end if 46 59 foreach ((array)$CONFIG['ldap_public'] as $id => $prop) 47 $js_list[$id] = array('id' => $id, 'readonly' => !$prop['writ eable']);60 $js_list[$id] = array('id' => $id, 'readonly' => !$prop['writable']); 48 61 $OUTPUT->set_env('address_sources', $js_list); 49 62 … … 67 80 // allow the following attributes to be added to the <ul> tag 68 81 $out = '<ul' . create_attrib_string($attrib, array('style', 'class', 'id')) . ">\n"; 69 $out .= sprintf($line_templ, 70 'rcmli'.$local_id, 71 !$current ? 'selected' : '', 72 Q(rcmail_url('list', array('_source' => 0))), 73 JS_OBJECT_NAME, 74 $local_id, 75 JS_OBJECT_NAME, 76 $local_id, 77 JS_OBJECT_NAME, 78 $local_id, 79 JS_OBJECT_NAME, 80 $local_id, 81 rcube_label('personaladrbook')); 82 if ($CONFIG["use_SQL_address_book"]) { 83 $out .= sprintf($line_templ, 84 'rcmli'.$local_id, 85 !$current ? 'selected' : '', 86 Q(rcmail_url('list', array('_source' => 0))), 87 JS_OBJECT_NAME, 88 $local_id, 89 JS_OBJECT_NAME, 90 $local_id, 91 JS_OBJECT_NAME, 92 $local_id, 93 JS_OBJECT_NAME, 94 $local_id, 95 rcube_label('personaladrbook')); 96 } // end if 97 else { 98 // DB address book not used, see if a source is set, if not use the 99 // first LDAP directory. 100 if (!$current) { 101 $current = key((array)$CONFIG['ldap_public']); 102 } // end if 103 } // end else 82 104 83 105 foreach ((array)$CONFIG['ldap_public'] as $id => $prop) -
program/steps/mail/addcontact.inc
r47124c22 r4f9c833 24 24 if (!empty($_POST['_address'])) 25 25 { 26 $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']); 26 $CONTACTS = array(); 27 if (!$CONFIG["use_SQL_address_book"]) { 28 // Use the first writable LDAP address book. 29 foreach ($CONFIG["ldap_public"] as $id => $prop) { 30 if ($prop["writable"]) { 31 $CONTACTS = new rcube_ldap($prop); 32 break; 33 } // end if 34 } // end foreach 35 } // end if 36 else { 37 $CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']); 38 } // end else 27 39 $contact_arr = $IMAP->decode_address_list(get_input_value('_address', RCUBE_INPUT_POST, true), 1, false); 28 40
Note: See TracChangeset
for help on using the changeset viewer.
