alecpl
2012-03-05 8eae72a53cf4e359643a75c03d4317bd9afbac77
program/include/rcube_ldap.php
@@ -4,9 +4,12 @@
 | program/include/rcube_ldap.php                                        |
 |                                                                       |
 | This file is part of the Roundcube Webmail client                     |
 | Copyright (C) 2006-2011, The Roundcube Dev Team                       |
 | Copyright (C) 2006-2012, The Roundcube Dev Team                       |
 | Copyright (C) 2011, Kolab Systems AG                                  |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | Licensed under the GNU General Public License version 3 or            |
 | any later version with exceptions for skins & plugins.                |
 | See the README file for a full license statement.                     |
 |                                                                       |
 | PURPOSE:                                                              |
 |   Interface to an LDAP address directory                              |
@@ -35,8 +38,6 @@
    public $readonly = true;
    public $ready = false;
    public $group_id = 0;
    public $list_page = 1;
    public $page_size = 10;
    public $coltypes = array();
    /** private properties */
@@ -47,7 +48,6 @@
    protected $filter = '';
    protected $result = null;
    protected $ldap_result = null;
    protected $sort_col = '';
    protected $mail_domain = '';
    protected $debug = false;
@@ -63,7 +63,7 @@
    /**
    * Object constructor
    *
    * @param array    LDAP connection properties
    * @param array        LDAP connection properties
    * @param boolean    Enables debug mode
    * @param string    Current user mail domain name
    * @param integer User-ID
@@ -95,7 +95,7 @@
            foreach ($p['fieldmap'] as $rf => $lf)
                $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf));
        }
        else {
        else if (!empty($p)) {
            // read deprecated *_field properties to remain backwards compatible
            foreach ($p as $prop => $value)
                if (preg_match('/^(.+)_field$/', $prop, $matches))
@@ -176,7 +176,7 @@
            $host     = idn_to_ascii(rcube_parse_host($host));
            $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : '');
            $this->_debug("C: Connect [$hostname]");
            $this->_debug("C: Connect [$hostname] [{$this->prop['name']}]");
            if ($lc = @ldap_connect($host, $this->prop['port']))
            {
@@ -236,6 +236,10 @@
            $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u);
            if ($this->prop['search_base_dn'] && $this->prop['search_filter']) {
                if (!empty($this->prop['search_bind_dn']) && !empty($this->prop['search_bind_pw'])) {
                    $this->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']);
                }
                // Search for the dn to use to authenticate
                $this->prop['search_base_dn'] = strtr($this->prop['search_base_dn'], $replaces);
                $this->prop['search_filter'] = strtr($this->prop['search_filter'], $replaces);
@@ -410,24 +414,15 @@
    /**
     * Set internal list page
     * Set internal sort settings
     *
     * @param number $page Page number to list
     * @param string $sort_col Sort column
     * @param string $sort_order Sort order
     */
    function set_page($page)
    function set_sort_order($sort_col, $sort_order = null)
    {
        $this->list_page = (int)$page;
    }
    /**
     * Set internal page size
     *
     * @param number $size Number of messages to display on one page
     */
    function set_pagesize($size)
    {
        $this->page_size = (int)$size;
        if ($this->fieldmap[$sort_col])
            $this->sort_col = $this->fieldmap[$sort_col];
    }
@@ -559,7 +554,7 @@
            $entries = @ldap_get_entries($this->conn, $result);
        }
        for ($i=0; $i < $entries["count"]; $i++)
        for ($i=0; $i < $entries['count']; $i++)
        {
            $entry = $entries[$i];
@@ -569,6 +564,7 @@
            foreach ((array)$entry['objectclass'] as $objectclass)
            {
                switch (strtolower($objectclass)) {
                    case "group":
                    case "groupofnames":
                    case "kolabgroupofnames":
                        $group_members = array_merge($group_members, $this->_list_group_members($dn, $entry, 'member', $count));
@@ -582,7 +578,7 @@
                        break;
                }
            }
            if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit'])
              break;
        }
@@ -615,6 +611,9 @@
        for ($i=0; $i < $entry[$attr]['count']; $i++)
        {
            if (empty($entry[$attr][$i]))
                continue;
            $result = @ldap_read($this->conn, $entry[$attr][$i], '(objectclass=*)',
                $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']);
@@ -659,14 +658,11 @@
            $attrib = $count ? array('dn') : array_values($this->fieldmap);
            if ($result = @$func($this->conn, $m[1], $filter,
                $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']))
            {
                $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])
            ) {
                $this->_debug("S: ".ldap_count_entries($this->conn, $result)." record(s) for ".$m[1]);
                if ($err = ldap_errno($this->conn))
                    $this->_debug("S: Error: " .ldap_err2str($err));
            }
            else
            {
            else {
                $this->_debug("S: ".ldap_error($this->conn));
                return $group_members;
            }
@@ -869,10 +865,8 @@
                // The filter is not set, set it.
                $this->filter = $this->prop['filter'];
            }
            $this->_exec_search(true);
            if ($this->ldap_result) {
                $count = ldap_count_entries($this->conn, $this->ldap_result);
            }
            $count = (int) $this->_exec_search(true);
        }
        return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
@@ -1026,7 +1020,7 @@
        $dn = self::dn_encode($dn);
        // add new contact to the selected group
        if ($this->groups)
        if ($this->group_id)
            $this->add_to_group($this->group_id, $dn);
        return $dn;
@@ -1231,23 +1225,28 @@
            // only fetch dn for count (should keep the payload low)
            $attrs = $count ? array('dn') : array_values($this->fieldmap);
            if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter,
                $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']))
            {
                $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])
            ) {
                // when running on a patched PHP we can use the extended functions to retrieve the total count from the LDAP search result
                if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control') &&
                    ldap_parse_result($this->conn, $this->ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)) {
                    ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $this->vlv_count, $vresult);
                    $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$this->vlv_count");
                if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) {
                    if (ldap_parse_result($this->conn, $this->ldap_result,
                        $errcode, $matcheddn, $errmsg, $referrals, $serverctrls)
                    ) {
                        ldap_parse_virtuallist_control($this->conn, $serverctrls,
                            $last_offset, $this->vlv_count, $vresult);
                        $this->_debug("S: VLV result: last_offset=$last_offset; content_count=$this->vlv_count");
                    }
                    else {
                        $this->_debug("S: ".($errmsg ? $errmsg : ldap_error($this->conn)));
                    }
                }
                $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)");
                if ($err = ldap_errno($this->conn))
                    $this->_debug("S: Error: " .ldap_err2str($err));
                $entries_count = ldap_count_entries($this->conn, $this->ldap_result);
                $this->_debug("S: $entries_count record(s)");
                return $count ? ldap_count_entries($this->conn, $this->ldap_result) : true;
                return $count ? $entries_count : true;
            }
            else
            {
            else {
                $this->_debug("S: ".ldap_error($this->conn));
            }
        }
@@ -1314,12 +1313,13 @@
                if (!($value = $rec[$lf][$i]))
                    continue;
                list($col, $subtype) = explode(':', $rf);
                $out['_raw_attrib'][$lf][$i] = $value;
                if ($rf == 'email' && $this->mail_domain && !strpos($value, '@'))
                    $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain);
                else if (in_array($rf, array('street','zipcode','locality','country','region')))
                    $out['address'][$i][$rf] = $value;
                else if (in_array($col, array('street','zipcode','locality','country','region')))
                    $out['address'.($subtype?':':'').$subtype][$i][$col] = $value;
                else if ($rec[$lf]['count'] > 1)
                    $out[$rf][] = $value;
                else
@@ -1542,6 +1542,7 @@
            // check objectClass attributes of group and act accordingly
            for ($j=0; $j < $ldap_data[$i]['objectclass']['count']; $j++) {
                switch (strtolower($ldap_data[$i]['objectclass'][$j])) {
                    case 'group':
                    case 'groupofnames':
                    case 'kolabgroupofnames':
                        $groups[$group_id]['member_attr'] = 'member';
@@ -1716,13 +1717,16 @@
        if (($group_cache = $this->cache->get('groups')) === null)
            $group_cache = $this->_fetch_groups();
        if (!is_array($contact_ids))
            $contact_ids = explode(',', $contact_ids);
        $base_dn     = $this->groups_base_dn;
        $group_name  = $group_cache[$group_id]['name'];
        $member_attr = $group_cache[$group_id]['member_attr'];
        $group_dn    = "cn=$group_name,$base_dn";
        $new_attrs = array();
        foreach (explode(",", $contact_ids) as $id)
        foreach ($contact_ids as $id)
            $new_attrs[$member_attr][] = self::dn_decode($id);
        $this->_debug("C: Add [dn: $group_dn]: ".print_r($new_attrs, true));