|
|
|
@ -27,6 +27,17 @@
|
|
|
|
|
*/
|
|
|
|
|
class rcube_ldap extends rcube_addressbook
|
|
|
|
|
{
|
|
|
|
|
/** public properties */
|
|
|
|
|
public $primary_key = 'ID';
|
|
|
|
|
public $groups = false;
|
|
|
|
|
public $readonly = true;
|
|
|
|
|
public $ready = false;
|
|
|
|
|
public $group_id = 0;
|
|
|
|
|
public $list_page = 1;
|
|
|
|
|
public $page_size = 10;
|
|
|
|
|
public $coltypes = array();
|
|
|
|
|
|
|
|
|
|
/** private properties */
|
|
|
|
|
protected $conn;
|
|
|
|
|
protected $prop = array();
|
|
|
|
|
protected $fieldmap = array();
|
|
|
|
@ -38,16 +49,6 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
protected $mail_domain = '';
|
|
|
|
|
protected $debug = false;
|
|
|
|
|
|
|
|
|
|
/** public properties */
|
|
|
|
|
public $primary_key = 'ID';
|
|
|
|
|
public $readonly = true;
|
|
|
|
|
public $groups = false;
|
|
|
|
|
public $list_page = 1;
|
|
|
|
|
public $page_size = 10;
|
|
|
|
|
public $group_id = 0;
|
|
|
|
|
public $ready = false;
|
|
|
|
|
public $coltypes = array();
|
|
|
|
|
|
|
|
|
|
private $group_cache = array();
|
|
|
|
|
private $group_members = array();
|
|
|
|
|
|
|
|
|
@ -87,7 +88,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
$subtypes = $type ? array($type) : null;
|
|
|
|
|
$this->coltypes[$col] = array('limit' => 2, 'subtypes' => $subtypes);
|
|
|
|
|
}
|
|
|
|
|
else if ($type) {
|
|
|
|
|
elseif ($type) {
|
|
|
|
|
$this->coltypes[$col]['subtypes'][] = $type;
|
|
|
|
|
$this->coltypes[$col]['limit']++;
|
|
|
|
|
}
|
|
|
|
@ -111,14 +112,14 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
$this->debug = $debug;
|
|
|
|
|
$this->mail_domain = $mail_domain;
|
|
|
|
|
|
|
|
|
|
$this->connect();
|
|
|
|
|
$this->_connect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Establish a connection to the LDAP server
|
|
|
|
|
*/
|
|
|
|
|
function connect()
|
|
|
|
|
private function _connect()
|
|
|
|
|
{
|
|
|
|
|
global $RCMAIL;
|
|
|
|
|
|
|
|
|
@ -138,7 +139,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
|
|
|
|
|
foreach ($this->prop['hosts'] as $host)
|
|
|
|
|
{
|
|
|
|
|
$host = rcube_idn_to_ascii(rcube_parse_host($host));
|
|
|
|
|
$host = idn_to_ascii(rcube_parse_host($host));
|
|
|
|
|
$this->_debug("C: Connect [$host".($this->prop['port'] ? ':'.$this->prop['port'] : '')."]");
|
|
|
|
|
|
|
|
|
|
if ($lc = @ldap_connect($host, $this->prop['port']))
|
|
|
|
@ -201,7 +202,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass']))
|
|
|
|
|
$this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']);
|
|
|
|
|
$this->ready = $this->_bind($this->prop['bind_dn'], $this->prop['bind_pass']);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
raise_error(array('code' => 100, 'type' => 'ldap',
|
|
|
|
@ -212,7 +213,6 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
if ($this->prop['writable']) {
|
|
|
|
|
$this->readonly = false;
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -223,7 +223,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
* @param string Bind password
|
|
|
|
|
* @return boolean True on success, False on error
|
|
|
|
|
*/
|
|
|
|
|
function bind($dn, $pass)
|
|
|
|
|
private function _bind($dn, $pass)
|
|
|
|
|
{
|
|
|
|
|
if (!$this->conn) {
|
|
|
|
|
return false;
|
|
|
|
@ -238,11 +238,11 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
|
|
|
|
|
$this->_debug("S: ".ldap_error($this->conn));
|
|
|
|
|
|
|
|
|
|
raise_error(array(
|
|
|
|
|
$error = array(
|
|
|
|
|
'code' => ldap_errno($this->conn), 'type' => 'ldap',
|
|
|
|
|
'file' => __FILE__, 'line' => __LINE__,
|
|
|
|
|
'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)),
|
|
|
|
|
true);
|
|
|
|
|
'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn));
|
|
|
|
|
raise_error($error,true);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -358,7 +358,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// temp hack for filtering group members
|
|
|
|
|
if ($this->group_id)
|
|
|
|
|
if ($this->groups and $this->group_id)
|
|
|
|
|
{
|
|
|
|
|
$result = new rcube_result_set();
|
|
|
|
|
while ($record = $this->result->iterate())
|
|
|
|
@ -395,12 +395,13 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
$ids = explode(',', $value);
|
|
|
|
|
$result = new rcube_result_set();
|
|
|
|
|
foreach ($ids as $id)
|
|
|
|
|
{
|
|
|
|
|
if ($rec = $this->get_record($id, true))
|
|
|
|
|
{
|
|
|
|
|
$result->add($rec);
|
|
|
|
|
$result->count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -409,13 +410,13 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
if (is_array($this->prop['search_fields']))
|
|
|
|
|
{
|
|
|
|
|
foreach ($this->prop['search_fields'] as $k => $field)
|
|
|
|
|
$filter .= "($field=$wc" . rcube_ldap::quote_string($value) . "$wc)";
|
|
|
|
|
$filter .= "($field=$wc" . $this->_quote_string($value) . "$wc)";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
foreach ((array)$fields as $field)
|
|
|
|
|
if ($f = $this->_map_field($field))
|
|
|
|
|
$filter .= "($f=$wc" . rcube_ldap::quote_string($value) . "$wc)";
|
|
|
|
|
$filter .= "($f=$wc" . $this->_quote_string($value) . "$wc)";
|
|
|
|
|
}
|
|
|
|
|
$filter .= ')';
|
|
|
|
|
|
|
|
|
@ -562,7 +563,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build the new entries DN.
|
|
|
|
|
$dn = $this->prop['LDAP_rdn'].'='.rcube_ldap::quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->prop['base_dn'];
|
|
|
|
|
$dn = $this->prop['LDAP_rdn'].'='.$this->_quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->prop['base_dn'];
|
|
|
|
|
|
|
|
|
|
$this->_debug("C: Add [dn: $dn]: ".print_r($newentry, true));
|
|
|
|
|
|
|
|
|
@ -575,6 +576,10 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
|
|
|
|
|
$this->_debug("S: OK");
|
|
|
|
|
|
|
|
|
|
// add new contact to the selected group
|
|
|
|
|
if ($this->groups)
|
|
|
|
|
$this->add_to_group($this->group_id, base64_encode($dn));
|
|
|
|
|
|
|
|
|
|
return base64_encode($dn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -598,6 +603,9 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
foreach ($this->fieldmap as $col => $fld) {
|
|
|
|
|
$val = $save_cols[$col];
|
|
|
|
|
if ($fld) {
|
|
|
|
|
// remove empty array values
|
|
|
|
|
if (is_array($val))
|
|
|
|
|
$val = array_filter($val);
|
|
|
|
|
// The field does exist compare it to the ldap record.
|
|
|
|
|
if ($record[$col] != $val) {
|
|
|
|
|
// Changed, but find out how.
|
|
|
|
@ -638,11 +646,11 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
// Handle RDN change
|
|
|
|
|
if ($replacedata[$this->prop['LDAP_rdn']]) {
|
|
|
|
|
$newdn = $this->prop['LDAP_rdn'].'='
|
|
|
|
|
.rcube_ldap::quote_string($replacedata[$this->prop['LDAP_rdn']], true)
|
|
|
|
|
.$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true)
|
|
|
|
|
.','.$this->prop['base_dn'];
|
|
|
|
|
if ($dn != $newdn) {
|
|
|
|
|
$newrdn = $this->prop['LDAP_rdn'].'='
|
|
|
|
|
.rcube_ldap::quote_string($replacedata[$this->prop['LDAP_rdn']], true);
|
|
|
|
|
.$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true);
|
|
|
|
|
unset($replacedata[$this->prop['LDAP_rdn']]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -671,11 +679,23 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
// Handle RDN change
|
|
|
|
|
if (!empty($newrdn)) {
|
|
|
|
|
$this->_debug("C: Rename [dn: $dn] [dn: $newrdn]");
|
|
|
|
|
if (@ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) {
|
|
|
|
|
if (!ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) {
|
|
|
|
|
$this->_debug("S: ".ldap_error($this->conn));
|
|
|
|
|
return base64_encode($newdn);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$this->_debug("S: OK");
|
|
|
|
|
|
|
|
|
|
// change the group membership of the contact
|
|
|
|
|
if ($this->groups)
|
|
|
|
|
{
|
|
|
|
|
$group_ids = $this->get_record_groups(base64_encode($dn));
|
|
|
|
|
foreach ($group_ids as $group_id)
|
|
|
|
|
{
|
|
|
|
|
$this->remove_from_group($group_id, base64_encode($dn));
|
|
|
|
|
$this->add_to_group($group_id, base64_encode($newdn));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return base64_encode($newdn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
@ -706,6 +726,16 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
return false;
|
|
|
|
|
} // end if
|
|
|
|
|
$this->_debug("S: OK");
|
|
|
|
|
|
|
|
|
|
// remove contact from all groups where he was member
|
|
|
|
|
if ($this->groups)
|
|
|
|
|
{
|
|
|
|
|
$group_ids = $this->get_record_groups(base64_encode($dn));
|
|
|
|
|
foreach ($group_ids as $group_id)
|
|
|
|
|
{
|
|
|
|
|
$this->remove_from_group($group_id, base64_encode($dn));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // end foreach
|
|
|
|
|
|
|
|
|
|
return count($dns);
|
|
|
|
@ -727,13 +757,16 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
$this->_debug("C: Search [".$filter."]");
|
|
|
|
|
|
|
|
|
|
if ($this->ldap_result = @$function($this->conn, $this->prop['base_dn'], $filter,
|
|
|
|
|
array_values($this->fieldmap), 0, (int) $this->prop['sizelimit'], (int) $this->prop['timelimit'])
|
|
|
|
|
) {
|
|
|
|
|
array_values($this->fieldmap), 0, (int) $this->prop['sizelimit'], (int) $this->prop['timelimit']))
|
|
|
|
|
{
|
|
|
|
|
$this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)");
|
|
|
|
|
return true;
|
|
|
|
|
} else
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$this->_debug("S: ".ldap_error($this->conn));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -808,7 +841,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
/**
|
|
|
|
|
* @static
|
|
|
|
|
*/
|
|
|
|
|
function quote_string($str, $dn=false)
|
|
|
|
|
private function _quote_string($str, $dn=false)
|
|
|
|
|
{
|
|
|
|
|
// take firt entry if array given
|
|
|
|
|
if (is_array($str))
|
|
|
|
@ -833,19 +866,21 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
{
|
|
|
|
|
if ($group_id)
|
|
|
|
|
{
|
|
|
|
|
if (! $this->group_cache) $this->list_groups();
|
|
|
|
|
$cache = $this->group_cache[$group_id]['members'];
|
|
|
|
|
if (!$this->group_cache)
|
|
|
|
|
$this->list_groups();
|
|
|
|
|
|
|
|
|
|
$cache_members = $this->group_cache[$group_id]['members'];
|
|
|
|
|
|
|
|
|
|
$members = array();
|
|
|
|
|
for ($i=1; $i<$cache["count"]; $i++)
|
|
|
|
|
for ($i=1; $i<$cache_members["count"]; $i++)
|
|
|
|
|
{
|
|
|
|
|
$member_dn = base64_encode($cache[$i]);
|
|
|
|
|
$members[$member_dn] = 1;
|
|
|
|
|
$members[base64_encode($cache_members[$i])] = 1;
|
|
|
|
|
}
|
|
|
|
|
$this->group_members = $members;
|
|
|
|
|
$this->group_id = $group_id;
|
|
|
|
|
}
|
|
|
|
|
else $this->group_id = 0;
|
|
|
|
|
else
|
|
|
|
|
$this->group_id = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -856,11 +891,11 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
*/
|
|
|
|
|
function list_groups($search = null)
|
|
|
|
|
{
|
|
|
|
|
if (!$this->prop['groups'])
|
|
|
|
|
if (!$this->groups)
|
|
|
|
|
return array();
|
|
|
|
|
|
|
|
|
|
$base_dn = $this->prop['groups']['base_dn'];
|
|
|
|
|
$filter = $this->prop['groups']['filter'];
|
|
|
|
|
$filter = '(objectClass=groupOfNames)';
|
|
|
|
|
|
|
|
|
|
$res = ldap_search($this->conn, $base_dn, $filter, array('cn','member'));
|
|
|
|
|
if ($res === false)
|
|
|
|
@ -883,8 +918,8 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
$group_sortnames[] = strtolower($group_name);
|
|
|
|
|
}
|
|
|
|
|
array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups);
|
|
|
|
|
|
|
|
|
|
$this->group_cache = $groups;
|
|
|
|
|
|
|
|
|
|
return $groups;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1041,7 +1076,7 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
*/
|
|
|
|
|
function get_record_groups($contact_id)
|
|
|
|
|
{
|
|
|
|
|
if (!$this->prop['groups'])
|
|
|
|
|
if (!$this->groups)
|
|
|
|
|
return array();
|
|
|
|
|
|
|
|
|
|
$base_dn = $this->prop['groups']['base_dn'];
|
|
|
|
@ -1067,4 +1102,3 @@ class rcube_ldap extends rcube_addressbook
|
|
|
|
|
return $groups;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|