steffen: server/kolab-horde-fbview/kolab-horde-fbview/fbview/turba/lib/Driver imsp.php, NONE, 1.1 kolab.php, NONE, 1.1 ldap.php, NONE, 1.1 prefs.php, NONE, 1.1 sql.php, NONE, 1.1

cvs at intevation.de cvs at intevation.de
Mon Oct 31 12:43:38 CET 2005


Author: steffen

Update of /kolabrepository/server/kolab-horde-fbview/kolab-horde-fbview/fbview/turba/lib/Driver
In directory doto:/tmp/cvs-serv18388/kolab-horde-fbview/kolab-horde-fbview/fbview/turba/lib/Driver

Added Files:
	imsp.php kolab.php ldap.php prefs.php sql.php 
Log Message:
Fbview in separate package

--- NEW FILE: imsp.php ---
<?php
/**
 * Turba directory driver implementation for an IMSP server.
 * For now, provides only for addressbooks named for the user.
 *
 * @author  Michael Rubinsky<mike at theupstairsroom.com>
 * @version 1.0
 * @package Turba
 */
class Turba_Driver_imsp extends Turba_Driver {

    /**
     * Handle for the IMSP connection.
     * @var object Net_IMSP $_imsp
     */
    var $_imsp;

    /**
     * The name of the addressbook.
     * @var string $_bookName
     */
    var $_bookName  = '';

    /**
     * Holds if we are authenticated.
     * @var boolean $_authenticated
     */
    var $_authenticated = '';

    /**
     * Holds name of the field indicating an IMSP group
     * @var string $_groupField
     */
    var $_groupField = '';

    /**
     * Holds value that $_groupField will have
     * if entry is an IMSP group.
     * @var string $_groupValue
     */
    var $_groupValue = '';

    /**
     * Constructs a new Turba imsp driver object.
     *
     * @param array $params  Hash containing additional configuration parameters.
     */
    function Turba_Driver_imsp($params)
    {
        $this->type         = 'imsp';
        $this->params       = $params;
        $this->_groupField  = $params['group_id_field'];
        $this->_groupValue  = $params['group_id_value'];
        $this->_bookName    = $params['name'];
    }

    /**
     * Initialize the IMSP connection and check for error.
     */
    function init()
    {
        global $prefs;
        global $conf;

        require_once 'Net/IMSP.php';
        $this->_imsp = &Net_IMSP::singleton('Book', $this->params);
        $result = $this->_imsp->init();
        if (is_a($result, 'PEAR_Error')) {
            $this->_authenticated = false;
            return $result;
        }

        if (!empty($conf['log'])) {
            $logParams = $conf['log'];
            $result = $this->_imsp->setLogger($conf['log']);
            if (is_a($result, 'PEAR_Error')) {
                return $result;
            }
        }

        $this->_authenticated = true;
        return true;
    }

    /**
     * Returns all entries matching $critera. (For now, only supports
     * ONE search critera that will NOT match strictly. Currently,
     * only supports searching * on one IMSP field (no AND or OR
     * searches are supported yet).
     *
     * @param array $criteria  Array containing the search criteria.
     * @param array $fields    List of fields to return.
     *
     * @return array  Hash containing the search results.
     */
    function search($criteria, $fields)
    {
        if (!$this->_authenticated) {
            return array();
        }

        /* Ensure we have something to return. */
        $results = array();
        $noGroups = false;

        /* Get the search criteria. */
        $temp = array_values($criteria);
        if (count($criteria)) {
            $searchField = $temp[0][0]['field'];
            $searchValue = $temp[0][0]['test'];
        } else {
            $searchField = 'name';
            $searchValue = '';
        }



        /* Make sure the searchvalue isn't FullName, since fullname is
         * created dynamically. */
        if ($searchField == 'fullname') {
            $searchField = 'name';
        }

        /**
         * Are we searching for only Turba_Groups or Turba_Objects?
         * This is needed so the 'Show Lists' and 'Show Contacts' links
         * work correctly in Turba.
         */
        if ($searchField == '__type') {
            switch ($searchValue) {
            case 'Group':
                $searchField = $this->_groupField;
                $searchValue = $this->_groupValue;
                break;
            case 'Object':
                $searchField = 'name';
                $searchValue = '';
                $noGroups = true;
                break;
            }
        }

        /* If there is no searchValue than only use the wildcard. */
        if (strlen($searchValue) > 0 ) {
            $searchValue = $searchValue . '*';
        } else {
            $searchValue = '*';
        }

        $names = $this->_imsp->search($this->_bookName, $searchValue,
                                      $searchField);

        if (is_a($names, 'PEAR_Error')) {
            $GLOBALS['notification']->push($names, 'horde.error');
        } else {
            $namesCount = count($names);
            for ($i = 0; $i < $namesCount; $i++) {
                $temp = $this->read('name', array($names[$i]), $fields);
                $result = $temp[0];
                if (is_a($result, 'PEAR_Error')) {
                    $GLOBALS['notification']->push($results, 'horde.error');
                } elseif (($noGroups) && (isset($result[$this->_groupField])) &&
                          ($result[$this->_groupField]) == $this->_groupValue) {
                    unset($result);
                } else {
                    $results[] = $result;
                }
            }

            Horde::logMessage(sprintf('IMSP returned %s results',
                                      count($results)) ,__FILE__, __LINE__, LOG_DEBUG);
        }

        return array_values($results);
    }

    /**
     * Read the given data from the imsp database and returns the
     * result's fields.
     *
     * @param array $criteria  (Ignored: Always 'name' for imsp) Search criteria.
     * @param array $id        Array of data identifiers.
     * @param array $fields    List of fields to return.
     *
     * @return array  Hash containing the search results.
     */
    function read($criteria, $id, $fields)
    {
        $results = array();
        if (!$this->_authenticated) {
            return $results;
        }
        $id = array_values($id);
        $idCount = count($id);
        for ($i = 0; $i < $idCount; $i++) {
            $temp = $this->_imsp->getEntry($this->_bookName, $id[$i]);
            if (is_a($temp, 'PEAR_Error')) {
                $result = array();
            } else {
                $temp['fullname'] = $temp['name'];
                $isIMSPGroup = false;

                if ((isset($temp[$this->_groupField])) &&
                    ($temp[$this->_groupField] == $this->_groupValue)) {
                    $isIMSPGroup = true;
                }

                if ($isIMSPGroup) {
                    //IMSP Group
                    if (isset($temp['email'])) {
                        $emailList = $this->_getGroupEmails($temp['email']);
                        $count = count($emailList);
                        for ($j = 0; $j < $count; $j++) {
                            $memberName = $this->_imsp->search
                                ($this->_bookName,trim($emailList[$j]),'email');

                            if (count($memberName)) {
                                $members[] = $memberName[0];
                            }
                        }

                        $temp['__members'] = serialize($members);
                    }

                    $temp['__type'] = 'Group';
                    $temp['email'] = null;
                    $result = $temp;

                } else {
                    //IMSP Contact
                    $count = count($fields);
                    for ($j = 0; $j < $count; $j++) {
                        if (isset($temp[$fields[$j]])) {
                            $result[$fields[$j]] = $temp[$fields[$j]];
                        }
                    }

                }

            }

            $results[] = $result;

        }

        return $results;
    }

    /**
     * Adds the specified object to the imsp database.
     */
    function addObject($attributes)
    {
        /* We need to map out Turba_Groups back to IMSP groups before
         * writing out to the server. We need to array_values() it in
         * case an entry was deleted from the group. */
        if ($attributes['__type'] == 'Group') {
            /* We may have a newly created group. */
            $attributes[$this->_groupField] = $this->_groupValue;
            if (!isset($attributes['__members'])) {
                $attributes['__members'] = '';
                $attributes['email'] = ' ';
            }

            $temp = unserialize($attributes['__members']);
            if (is_array($temp)) {
                $members = array_values($temp);
            } else {
                $members = array();
            }

            if (count($members)) {
                $result = $this->read('name', $members, array('email'));
                $count = count($result);
                for ($i = 0; $i < $count; $i++) {
                    $contact = sprintf("%s<%s>\n", $members[$i],
                                        $result[$i]['email']);
                    $attributes['email'] .= $contact;
                }
            }
        }

        unset($attributes['__members']);
        unset($attributes['__type']);
        unset($attributes['fullname']);
        return $this->_imsp->addEntry($this->_bookName, $attributes);
    }

    /**
     * Deletes the specified object from the imsp database.
     */
    function removeObject($object_key, $object_id)
    {
        return $this->_imsp->deleteEntry($this->_bookName, $object_id);
    }

    /**
     * Saves the specified object in the imsp database.
     *
     * @param string $object_key  (Ignored) name of the field
     *                            in $attributes[] to treat as key.
     * @param string $object_id   (Ignored) the value of the key field.
     * @param array  $attributes  Contains the field names and values of the entry.
     *
     * @return string  The object id, possibly updated.
     */
    function setObject($object_key, $object_id, $attributes)
    {
        // Should we check if the key changed, because IMSP will just
        // write out a new entry without removing the previous one.
        // This will change the key though and cause the entry not to
        // display on the "success" screen.
        /*if ($attributes['name'] != $this->makeKey($attributes)) {
            $this->removeObject($object_key, $attributes['name']);
            $attributes['name'] = $this->makeKey($attributes);
        }*/

        $result = $this->addObject($attributes);
        return is_a($result, 'PEAR_Error') ? $result : $object_id;
    }

    /**
     * Create an object key for a new object.
     *
     * @param array $attributes  The attributes (in driver keys) of the
     *                           object being added.
     *
     * @return string  A unique ID for the new object.
     */
    function makeKey($attributes)
    {
        return $attributes['fullname'];
    }

    /**
     * Parses out $emailText into an array of pure email addresses
     * suitable for searching the IMSP datastore with.
     *
     * @param $emailText string single string containing email addressses.
     * @return array of pure email address.
     */
    function _getGroupEmails($emailText)
    {
        $result = preg_match_all("(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})",
                                 $emailText, $matches);

        return $matches[0];
    }

}

--- NEW FILE: kolab.php ---
<?php

require_once 'Horde/Kolab.php';
require_once 'Horde/Data.php';

/**
 * Horde Turba driver for the Kolab IMAP Server.
 * Copyright (C) 2003, 2004 Code Fusion, cc.
 *
 * $Horde: turba/lib/Driver/kolab.php,v 1.1 2004/04/21 19:05:03 chuck Exp $
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Stuart Bingë <s.binge at codefusion.co.za>
 * @version $Revision: 1.1 $
 * @package Turba
 */
class Turba_Driver_kolab extends Turba_Driver {

    /**
     * Our Kolab Cyrus server connection.
     *
     * @var object Kolab_Cyrus $_kc
     */
    var $_kc;

    function init()
    {
        $this->_params['folder'] = array_key_exists('folder', $this->_params)
            ? $this->_params['folder'] : 'Contacts';
        $this->_params['server'] = array_key_exists('server', $this->_params)
            ? $this->_params['server'] : $GLOBALS['conf']['kolab']['server'];
    }

    /**
     * Opens a connection to the Kolab Cyrus Server.
     *
     * @return mixed   True on success, PEAR_Error on failure.
     */
    function _open()
    {
        $this->_kc = new Kolab_Cyrus($this->_params['server']);

        $result = $this->_kc->openMailbox($this->_params['folder'], true);
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        return true;
    }

    /**
     * Closes the Kolab Cyrus connection.
     */
    function _close()
    {
        $this->_kc->disconnect();
    }

    /**
     * Converts Turba search criteria into a comparable IMAP search string
     *
     * @param array $criteria      The search criteria.
     *
     * @return string  The IMAP search string corresponding to $criteria.
     */
    function turbaToImap($criteria)
    {
        $values = array_values($criteria);
        $values = $values[0];
        $query = "";

        for ($current = 0; $current < count($values); $current++) {
            $temp = $values[$current];

            while (!empty($temp) && !array_key_exists('field', $temp)) {
                $temp = array_values($temp);
                $temp = $temp[0];
            }

            if (empty($temp)) continue;

            $searchkey = $temp['field'];
            $searchval = $temp['test'];

            switch ($searchkey) {
                case 'owner':
                    $query .= 'FROM "' . $searchval . '" ';
                    break;

                case 'name':
                case 'firstname':
                case 'lastname':
                    $query .= 'BODY "N:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'email':
                    $query .= 'BODY "EMAIL:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'title':
                    $query .= 'BODY "TITLE:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'company':
                    $query .= 'BODY "ORG:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'homeAddress':
                case 'homeCity':
                case 'homeProvince':
                case 'homePostalCode':
                case 'homeCountry':
                    $query .= 'BODY "ADR:" BODY "TYPE" BODY "HOME" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'workAddress':
                case 'workCity':
                case 'workProvince':
                case 'workPostalCode':
                case 'workCountry':
                    $query .= 'BODY "ADR:" BODY "TYPE" BODY "WORK" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'homePhone':
                    $query .= 'BODY "TEL:" BODY "TYPE" BODY "HOME" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'workPhone':
                    $query .= 'BODY "TEL:" BODY "TYPE" BODY "WORK" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'cellPhone':
                    $query .= 'BODY "TEL:" BODY "TYPE" BODY "CELL" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'fax':
                    $query .= 'BODY "TEL:" BODY "TYPE" BODY "FAX" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'notes':
                    $query .= 'BODY "NOTE:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'website':
                    $query .= 'BODY "URL:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                case 'nickname':
                    $query .= 'BODY "NICKNAME:" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
                    break;

                default:
                    if (!empty($searchkey))
                        $query .= 'BODY "' . $searchkey . '" ';
                    if (!empty($searchval))
                        $query .= 'BODY "' . $searchval . '" ';
            }
        }

        return $query;
    }

    /**
     * Searches the Kolab message store with the given criteria and returns a
     * filtered list of results. If the criteria parameter is an empty
     * array, all records will be returned.
     *
     * @param $criteria      Array containing the search criteria.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function search($criteria, $fields)
    {
        $query = Turba_Driver_kolab::turbaToImap($criteria);

        $result = $this->_open();
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        $results = array();

        $msgs = $this->_kc->getMessageList(SORTDATE, false, $query);
        foreach ($msgs as $msg) {
            $object = $this->_kc->getObject($msg, "text/x-vcard");
            if ($object === false) continue;

            $contact = $this->loadVCard($object);
            if ($contact === false) continue;

            $card = array();
            foreach ($fields as $field) {
                $card[$field] = (isset($contact[$field]) ? $contact[$field] : '');
            }
            $results[] = $card;
        }

        $this->_close();

        return $results;
    }

    /**
     * Read the given data from the Kolab message store and returns the
     * result's fields.
     *
     * @param $criteria      Search criteria.
     * @param $id            Data identifier.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function read($criteria, $id, $fields)
    {
        if ($criteria != 'uid') return array();

        $result = $this->_open();
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        $results = array();

        if (!is_array($id)) $id = array($id);

        foreach ($id as $i) {
            $matches = $this->_kc->getMessageList(SORTDATE, false, "BODY \"UID:\" BODY \"$i\"");
            foreach ($matches as $msg) {
                $object = $this->_kc->getObject($msg, "text/x-vcard");
                if ($object === false) continue;

                $contact = $this->loadVCard($object);
                if ($contact === false) continue;

                $card = array();
                foreach ($fields as $field) {
                    $card[$field] = (isset($contact[$field]) ? $contact[$field] : '');
                }
                $results[] = $card;
            }
        }

        $this->_close();

        return $results;
    }

    /**
     * Adds the specified object to the Kolab message store.
     */
    function addObject($attributes)
    {
        $result = $this->_open();
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        $result = $this->_kc->addObject(
            $attributes['uid'],
            $this->createVCard($attributes, NULL),
            'text/x-vcard',
            'kolab-contact-entry.vcard',
            'Turba'
        );

        $this->_close();

        return $result;
    }

    /**
     * Removes the specified object from the Kolab message store.
     */
    function removeObject($object_key, $object_id)
    {
        if ($object_key != 'uid') return false;

        $result = $this->_open();
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        $matches = $this->_kc->getMessageList(SORTDATE, false, "BODY \"UID:\" BODY \"$object_id\"");
        $this->_kc->deleteMessages($matches);

        $this->_close();

        return true;
    }

    /**
     * Updates an existing object in the Kolab message store.
     *
     * @return string  The object id, possibly updated.
     */
    function setObject($object_key, $object_id, $attributes)
    {
        if ($object_key != 'uid') return false;

        $result = $this->_open();
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        $matches = $this->_kc->getMessageList(SORTDATE, false, "BODY \"UID:\" BODY \"$object_id\"");
        $vcard = '';
        foreach ($matches as $msg) {
            $vcard = $this->_kc->getObject($msg, "text/x-vcard");
            if ($vcard === false) {
                $vcard = '';
                continue;
            }

            $this->_kc->deleteMessages($msg);
        }

        $result = $this->_kc->addObject(
            $attributes['uid'],
            $this->createVCard($attributes, $vcard),
            'text/x-vcard',
            'kolab-contact-entry.vcard',
            'Turba'
        );

        $this->_close();

        return is_a('PEAR_Error', $result) ? $result : $attributes['uid'];
    }

    /**
     * Create an object key for a new object.
     *
     * @param array $attributes  The attributes (in driver keys) of the
     *                           object being added.
     *
     * @return string  A unique ID for the new object.
     */
    function makeKey($attributes)
    {
        return md5(uniqid(mt_rand(), true));
    }

    /**
     * Converts a text VCARD representation into a Turba attribute hash
     *
     * @param string $text  The text representation of the VCARD object.
     *
     * @return array  A hash of turba attributes for the VCARD object.
     */
    function loadVCard($text)
    {
        $vcard = &Horde_Data::singleton('vcard');
        $data = $vcard->importData($text);
        if (is_a('PEAR_Error', $data)) {
            return $data;
        }

        $data = $data[0];
        $contact = $vcard->toHash($data);

        foreach ($data['params'] as $item) {
            switch ($item['name']) {
            case 'UID':
                $contact['uid'] = $vcard->read($item);
            }
        }

        $contact['owner'] = Kolab::getUser();

        return $contact;
    }

    /**
     * Converts a Turba attribute hash into a text VCARD representation.
     *
     * @param string $attributes  The turba attribute hash.
     * @param string $text (optional)  If specified, this is used as the 'base'
     *                                 VCARD object, with the neccessary
     *                                 properties being overridden by $attributes.
     *
     * @return string  The text VCARD representation.
     */
    function createVCard($attributes, $text = '')
    {
        $vcard = &Horde_Data::singleton('vcard');
        $data = array();
        if (!empty($text)) {
            $data = $vcard->importData($text);
            if (is_a('PEAR_Error', $data)) {
                return $data;
            }
        }

        $hash = $vcard->fromHash($attributes);
        $hash['AGENT'] = 'Horde/Turba/Kolab';
        $hash['CLASS'] = 'PRIVATE';
        $hash['PROFILE'] = 'VCARD';
        $hash['UID'] = $attributes['uid'];
        if (!empty($data)) {
            $hash = array_merge($data, $hash);
        }

        return $vcard->exportData($hash);
    }
}

--- NEW FILE: ldap.php ---
<?php
/**
 * Turba directory driver implementation for PHP's LDAP extension.
 *
 * $Horde: turba/lib/Driver/ldap.php,v 1.49 2004/04/07 14:43:52 chuck Exp $
 *
 * @author  Chuck Hagenbuch <chuck at horde.org>
 * @author  Jon Parise <jon at csh.rit.edu>
 * @version $Revision: 1.1 $
 * @since   Turba 0.0.1
 * @package Turba
 */
class Turba_Driver_ldap extends Turba_Driver {

    /** Handle for the current LDAP connection. */
    var $_ds = 0;

    /**
     * Constructs a new Turba LDAP driver object.
     *
     * @param $params       Hash containing additional configuration parameters.
     */
    function Turba_Driver_ldap($params)
    {
        if (!extension_loaded('ldap')) {
            Horde::fatal(PEAR::raiseError(_("LDAP support is required but the LDAP module is not available or not loaded.")), __FILE__, __LINE__);
        }

        if (empty($params['server'])) {
            $params['server'] = 'localhost';
        }
        if (empty($params['port'])) {
            $params['port'] = 389;
        }
        if (empty($params['root'])) {
            $params['root'] = '';
        }
        if (empty($params['multiple_entry_separator'])) {
            $params['multiple_entry_separator'] = ', ';
        }
        if (empty($params['charset'])) {
            $params['charset'] = '';
        }

        parent::Turba_Driver($params);
    }

    function init()
    {
        if (!($this->_ds = @ldap_connect($this->_params['server'], $this->_params['port']))) {
            return PEAR::raiseError(_("Connection failure"));
        }

        // Set the LDAP protocol version.
        if (!empty($this->_params['version'])) {
            @ldap_set_option($this->_ds, LDAP_OPT_PROTOCOL_VERSION, $this->_params['version']);
        }

        if (isset($this->_params['bind_dn']) &&
            isset($this->_params['bind_password'])) {
            if (!@ldap_bind($this->_ds, $this->_params['bind_dn'], $this->_params['bind_password'])) {
                return PEAR::raiseError(sprintf(_("Bind failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
            }
        } else if (!(@ldap_bind($this->_ds))) {
            return PEAR::raiseError(sprintf(_("Bind failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        }
    }

    /**
     * Searches the LDAP directory with the given criteria and returns
     * a filtered list of results. If no criteria are specified, all
     * records are returned.
     *
     * @param $criteria      Array containing the search criteria.
     * @param $fields        List of fields to return.
     *
     * @return array  Hash containing the search results.
     */
    function search($criteria, $fields)
    {
        /* Build the LDAP filter. */
        $filter = '';
        if (count($criteria)) {
            foreach ($criteria as $key => $vals) {
                if ($key == 'OR') {
                    $filter .= '(|' . $this->_buildSearchQuery($vals) . ')';
                } elseif ($key == 'AND') {
                    $filter .= '(&' . $this->_buildSearchQuery($vals) . ')';
                }
            }
        } else {
            // Filter on objectclass.
            $filter = $this->_buildObjectclassFilter();
        }

        /* Add source-wide filters, which are _always_ AND-ed. */
        if (!empty($this->_params['filter'])) {
            $filter = '(&' . '(' . $this->_params['filter'] . ')' . $filter . ')';
        }

        /* Four11 (at least) doesn't seem to return 'cn' if you don't
         * ask for 'sn' as well. Add 'sn' implicitly. */
        $attr = $fields;
        if (!in_array('sn', $attr)) {
            $attr[] = 'sn';
        }

        /* Add a sizelimit, if specified. Default is 0, which means no
         * limit.  Note: You cannot override a server-side limit with
         * this. */
        $sizelimit = 0;
        if (!empty($this->_params['sizelimit'])) {
            $sizelimit = $this->_params['sizelimit'];
        }

        /* Log the query at a DEBUG log level. */
        Horde::logMessage(sprintf('LDAP search by %s: root = %s (%s); filter = "%s"; attributes = "%s"; sizelimit = %d',
                                  Auth::getAuth(), $this->_params['root'], $this->_params['server'], $filter, implode(', ', $attr), $sizelimit),
                          __FILE__, __LINE__, PEAR_LOG_DEBUG);

        /* Send the query to the LDAP server and fetch the matching
         * entries. */
        if (!($res = @ldap_search($this->_ds, $this->_params['root'], $filter, $attr, 0, $sizelimit))) {
            return PEAR::raiseError(sprintf(_("Query failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        }

        return $this->getResults($fields, $res);
    }

    /**
     * Build a piece of a search query.
     *
     * @param array  $criteria  The array of criteria.
     *
     * @return string  An LDAP query fragment.
     */
    function _buildSearchQuery($criteria)
    {
        require_once 'Horde/LDAP.php';

        $clause = '';
        foreach ($criteria as $key => $vals) {
            if (!empty($vals['OR'])) {
                $clause .= '(|' . $this->_buildSearchQuery($vals) . ')';
            } elseif (!empty($vals['AND'])) {
                $clause .= '(&' . $this->_buildSearchQuery($vals) . ')';
            } else {
                if (isset($vals['field'])) {
                    $rhs = String::convertCharset($vals['test'], NLS::getCharset(), $this->_params['charset']);
                    $clause .= Horde_LDAP::buildClause($vals['field'], $vals['op'], $rhs);
                } else {
                    foreach ($vals as $test) {
                        if (!empty($test['OR'])) {
                            $clause .= '(|' . $this->_buildSearchQuery($test) . ')';
                        } elseif (!empty($test['AND'])) {
                            $clause .= '(&' . $this->_buildSearchQuery($test) . ')';
                        } else {
                            $rhs = String::convertCharset($test['test'], NLS::getCharset(), $this->_params['charset']);
                            $clause .= Horde_LDAP::buildClause($test['field'], $test['op'], $rhs);
                        }
                    }
                }
            }
        }

        return $clause;
    }

    /**
     * Reads the LDAP directory for a given element and returns
     * the result's fields.
     *
     * @param string $criteria  Search criteria (must be 'dn').
     * @param mixed  $dn        The dn of the object to read.
     * @param array  $fields    List of fields to return.
     *
     * @return array  Hash containing the search results.
     */
    function read($criteria, $dn, $fields)
    {
        // Only DN
        if ($criteria != 'dn') {
            return array();
        }

        $filter = $this->_buildObjectclassFilter();

        /* Four11 (at least) doesn't seem to return 'cn' if you don't
         * ask for 'sn' as well. Add 'sn' implicitly. */
        $attr = $fields;
        if (!in_array('sn', $attr)) {
            $attr[] = 'sn';
        }

        // Handle a request for multiple records.
        if (is_array($dn)) {
            $results = array();
            foreach ($dn as $d) {
                $res = @ldap_read($this->_ds, $d, $filter, $attr);
                if ($res) {
                    if (!is_a($result = $this->getResults($fields, $res), 'PEAR_Error')) {
                        $results += $result;
                    } else {
                        return $result;
                    }
                } else {
                    return PEAR::raiseError(sprintf(_("Read failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
                }
            }
            return $results;
        }

        $res = @ldap_read($this->_ds, $dn, $filter, $attr);
        if (!$res) {
            return PEAR::raiseError(sprintf(_("Read failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        }

        return $this->getResults($fields, $res);
    }

    /**
     * Get some results from a result identifier and clean them up.
     *
     * @param array    $fields  List of fields to return.
     * @param resource $res     Result identifier.
     *
     * @return array  Hash containing the results.
     */
    function getResults($fields, $res)
    {
        if (!($entries = @ldap_get_entries($this->_ds, $res))) {
            return PEAR::raiseError(sprintf(_("Read failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        }

        /* Return only the requested fields (from $fields, above). */
        $results = array();
        for ($i = 0; $i < $entries['count']; $i++) {
            $entry = $entries[$i];
            $result = array();

            foreach ($fields as $field) {
                $field_l = String::lower($field);
                if ($field == 'dn') {
                    $result[$field] = $entry[$field_l];
                } else {
                    $result[$field] = '';
                    if (!empty($entry[$field_l])) {
                        for ($j = 0; $j < $entry[$field_l]['count']; $j++) {
                            if (!empty($result[$field])) {
                                $result[$field] .= $this->_params['multiple_entry_separator'];
                            }
                            $result[$field] .= String::convertCharset($entry[$field_l][$j], $this->_params['charset']);
                        }
                    }
                }
            }

            $results[] = $result;
        }

        return $results;
    }

    /**
     * Adds the specified entry to the LDAP directory.
     *
     * @param array $attributes  The initial attributes for the new object.
     */
    function addObject($attributes)
    {
        if (empty($attributes['dn'])) {
            return PEAR::raiseError('Tried to add an object with no dn: [' . serialize($attributes) . '].');
        } elseif (empty($this->_params['objectclass'])) {
            return PEAR::raiseError('Tried to add an object with no objectclass: [' . serialize($attributes) . '].');
        }

        // Take the DN out of the attributes array
        $dn = $attributes['dn'];
        unset($attributes['dn']);

        // Put the Objectclass into the attributes array
        if (!is_array($this->_params['objectclass'])) {
            $attributes['objectclass'] = $this->_params['objectclass'];
        } else {
            $i = 0;
            foreach ($this->_params['objectclass'] as $objectclass) {
                $attributes['objectclass'][$i] = $objectclass;
                $i++;
            }
        }

        // Don't add empty attributes.
        $attributes = array_filter($attributes, array($this, '_emptyAttributeFilter'));

        // Encode entries.
        foreach ($attributes as $key => $val) {
            if (!is_array($val)) {
                $attributes[$key] = String::convertCharset($val, NLS::getCharset(), $this->_params['charset']);
            }
        }

        if (!@ldap_add($this->_ds, $dn, $attributes)) {
            return PEAR::raiseError('Failed to add an object: [' . ldap_errno($this->_ds) . '] "' . ldap_error($this->_ds) . '" (attributes: [' . serialize($attributes) . ']).' . "Charset:" . NLS::getCharset());
        } else {
            return true;
        }
    }

    /**
     * Deletes the specified entry from the LDAP directory.
     */
    function removeObject($object_key, $object_id)
    {
        if ($object_key != 'dn') {
            return PEAR::raiseError(_("Invalid key specified."));
        }

        if (!@ldap_delete($this->_ds, $object_id)) {
            return PEAR::raiseError(sprintf(_("Delete failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        } else {
            return true;
        }
    }

    /**
     * Modifies the specified entry in the LDAP directory.
     *
     * @return string  The object id, possibly updated.
     */
    function setObject($object_key, $object_id, $attributes)
    {
        // Get the old entry so that we can access the old
        // values. These are needed so that we can delete any
        // attributes that have been removed by using ldap_mod_del.
        $filter = $this->_buildObjectclassFilter();
        $oldres = @ldap_read($this->_ds, $object_id, $filter, array_keys($attributes));
        $info = ldap_get_attributes($this->_ds, ldap_first_entry($this->_ds, $oldres));

        // Check if we need to rename the object.
        if ($this->_params['version'] == 3 && $this->makeKey($attributes) != $object_id) {
            if (isset($this->_params['dn']) && is_array($this->_params['dn']) && count($this->_params['dn'])) {
                $newrdn = '';
                foreach ($this->_params['dn'] as $param) {
                    if (isset($attributes[$param])) {
                        $newrdn .= $param . '=' . $attributes[$param] . ',';
                    }
                }
                $newrdn = substr($newrdn, 0, -1);
            } else {
                return PEAR::raiseError(_("Missing DN in LDAP source configuration."));
            }

            if (ldap_rename($this->_ds, $object_id, $newrdn, $this->_params['root'], true)) {
                $object_id = $newrdn . ',' . $this->_params['root'];
            } else {
                return PEAR::raiseError( sprintf(_("Failed to change name: (%s) %s, %s"), ldap_errno($this->_ds), ldap_error($this->_ds), "$object_id,$newrdn,{$this->_params['root']}"));
            }
        }

        // The attributes in the attributes array are all lower case
        // while they are mixedCase in the search result. So convert
        // the keys to lower.
        $info = array_change_key_case($info, CASE_LOWER);

        foreach ($info as $key => $value) {
            $var = $info[$key];
            $oldval = null;

            // Check to see if the old value and the new value are
            // different and that the new value is empty. If so then
            // we use ldap_mod_del to delete the attribute.
            if (isset($attributes[$key]) &&
                ($var[0] != $attributes[$key]) &&
                $attributes[$key] == '') {

                $oldval[$key] = $var[0];
                if (!@ldap_mod_del($this->_ds, $object_id, $oldval)) {
                    return PEAR::raiseError(sprintf(_("Modify failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
                }
                unset($attributes[$key]);
            }
        }

        // Encode entries.
        foreach ($attributes as $key => $val) {
            if (!is_array($val)) {
                $attributes[$key] = String::convertCharset($val, NLS::getCharset(), $this->_params['charset']);
            }
        }

        unset($attributes[$object_key]);
        $attributes = array_filter($attributes, array($this, '_emptyAttributeFilter'));

        if (!@ldap_modify($this->_ds, $object_id, $attributes)) {
            return PEAR::raiseError(sprintf(_("Modify failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
        } else {
            return $object_id;
        }
    }

    /**
     * Build a DN based on a set of attributes and what attributes
     * make a DN for the current source.
     *
     * @param array $attributes The attributes (in driver keys) of the
     *                          object being added.
     *
     * @return string  The DN for the new object.
     */
    function makeKey($attributes)
    {
        $dn = '';
        if (is_array($this->_params['dn'])) {
            foreach ($this->_params['dn'] as $param) {
                if (isset($attributes[$param])) {
                    $dn .= $param . '=' . $attributes[$param] . ',';
                }
            }
        }

        $dn .= $this->_params['root'];
        return $dn;
    }

    /**
     * Remove empty attributes from attributes array
     *
     * @param mixed $val    Value from attributes array.
     * @return bool         Boolean used by array_filter.
     */
    function _emptyAttributeFilter($var)
    {
        if (!is_array($var)) {
            return ($var != '');
        } else {
            foreach ($var as $v) {
                if ($v == '') {
                    return false;
                }
            }
            return true;
        }
    }

    /**
     * Build an LDAP filter based on the objectclass parameter.
     *
     * @return string An LDAP filter.
     */
    function _buildObjectclassFilter()
    {
        $filter = '';
        if (!empty($this->_params['objectclass'])) {
            if (!is_array($this->_params['objectclass'])) {
                $filter = '(objectclass=' . $this->_params['objectclass'] . ')';
            } else {
                $filter = '(|';
                foreach ($this->_params['objectclass'] as $objectclass) {
                    $filter .= '(objectclass=' . $objectclass . ')';
                }
                $filter .= ')';
            }
        }
        return $filter;
    }

}

--- NEW FILE: prefs.php ---
<?php
/**
 * Turba directory driver implementation for Horde Preferences - very
 * simple, lightweight container.
 *
 * $Horde: turba/lib/Driver/prefs.php,v 1.8 2004/04/05 03:11:41 chuck Exp $
 *
 * @author  Chuck Hagenbuch <chuck at horde.org>
 * @version $Revision: 1.1 $
 * @since   Turba 1.2
 * @package Turba
 */
class Turba_Driver_prefs extends Turba_Driver {

    /**
     * Return all entries - searching isn't implemented here for
     * now. The parameters are simply ignored.
     *
     * @param $criteria      Array containing the search criteria.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function search($criteria, $fields)
    {
        return array_values($this->_getAddressBook());
    }

    /**
     * Read the given data from the SQL database and returns
     * the result's fields.
     *
     * @param $criteria      Search criteria.
     * @param $ids            Data identifiers.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function read($criteria, $ids, $fields)
    {
        $book = $this->_getAddressBook();
        $results = array();
        if (!is_array($ids)) {
            $ids = array($ids);
        }
        foreach ($ids as $id) {
            if (isset($book[$id])) {
                $results[] = $book[$id];
            }
        }

        return $results;
    }

    /**
     * Adds the specified object to the SQL database.
     */
    function addObject($attributes)
    {
        $book = $this->_getAddressBook();
        $book[$attributes['id']] = $attributes;
        $this->_setAddressbook($book);

        return true;
    }

    /**
     * Deletes the specified object from the SQL database.
     */
    function removeObject($object_key, $object_id)
    {
        $book = $this->_getAddressBook();
        unset($book[$object_id]);
        $this->_setAddressbook($book);

        return true;
    }

    /**
     * Saves the specified object in the SQL database.
     */
    function setObject($object_key, $object_id, $attributes)
    {
        $book = $this->_getAddressBook();
        $book[$object_id] = $attributes;
        $this->_setAddressBook($book);
    }

    /**
     * Create an object key for a new object.
     *
     * @param array $attributes  The attributes (in driver keys) of the
     *                           object being added.
     *
     * @return string  A unique ID for the new object.
     */
    function makeKey($attributes)
    {
        return md5(mt_rand());
    }

    function _getAddressBook()
    {
        global $prefs;

        $val = $prefs->getValue('prefbooks');
        if (!empty($val)) {
            $prefbooks = unserialize($val);
            return $prefbooks[$this->_params['name']];
        } else {
            return array();
        }
    }

    function _setAddressBook($addressbook)
    {
        global $prefs;

        $val = $prefs->getValue('prefbooks');
        if (!empty($val)) {
            $prefbooks = unserialize($val);
        } else {
            $prefbooks = array();
        }

        $prefbooks[$this->_params['name']] = $addressbook;
        $prefs->setValue('prefbooks', serialize($prefbooks));
        $prefs->store();
    }

}

--- NEW FILE: sql.php ---
<?php
/**
 * Turba directory driver implementation for PHP's PEAR database abstraction
 * layer.
 *
 * $Horde: turba/lib/Driver/sql.php,v 1.50 2004/04/07 14:43:52 chuck Exp $
 *
 * @author  Jon Parise <jon at csh.rit.edu>
 * @version $Revision: 1.1 $
 * @since   Turba 0.0.1
 * @package Turba
 */
class Turba_Driver_sql extends Turba_Driver {

    /** Handle for the current database connection. */
    var $_db = null;

    function init()
    {
        include_once 'DB.php';
        $this->_db = &DB::connect($this->_params,
                                  array('persistent' => !empty($this->_params['persistent'])));
        if (is_a($this->_db, 'PEAR_Error')) {
            return $this->_db;
        }

        $this->_db->setOption('optimize', 'portability');

        if ($this->_params['phptype'] == 'oci8') {
            $this->_db->query('ALTER SESSION SET NLS_DATE_FORMAT = \'YYYY-MM-DD\'');
        }
    }

    /**
     * Searches the SQL database with the given criteria and returns a
     * filtered list of results. If the criteria parameter is an empty
     * array, all records will be returned.
     *
     * @param $criteria      Array containing the search criteria.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function search($criteria, $fields)
    {
        /* Build the WHERE clause. */
        $where = '';
        if (count($criteria)) {
            foreach ($criteria as $key => $vals) {
                if ($key == 'OR' || $key == 'AND') {
                    if (!empty($where)) {
                        $where .= ' ' . $key . ' ';
                    }
                    $where .= '(' . $this->_buildSearchQuery($key, $vals) . ')';
                }
            }
            $where = ' WHERE ' . $where;
        }

        /* Build up the full query. */
        $query = 'SELECT ' . implode(', ', $fields) . ' FROM ' . $this->_params['table'] . $where;

        /* Log the query at a DEBUG log level. */
        Horde::logMessage(sprintf('SQL search by %s: table = %s; query = "%s"',
                                  Auth::getAuth(), $this->_params['table'], $query),
                          __FILE__, __LINE__, PEAR_LOG_DEBUG);

        /* Run query. */
        $result = $this->_db->query($query);
        if (is_a($result, 'PEAR_Error')) {
            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
            return array();
        }

        $results = array();
        $iMax = count($fields);
        while ($row = $result->fetchRow()) {
            if (is_a($row, 'PEAR_Error')) {
                Horde::logMessage($row, __FILE__, __LINE__, PEAR_LOG_ERR);
                return array();
            }

            $entry = array();
            for ($i = 0; $i < $iMax; $i++) {
                $field = $fields[$i];
                $entry[$field] = $this->_convertFromDriver($row[$i]);
            }
            $results[] = $entry;
        }

        return $results;
    }

    /**
     * Build a piece of a search query.
     *
     * @param string $glue      The glue to join the criteria (OR/AND).
     * @param array  $criteria  The array of criteria.
     *
     * @return string  An SQL fragment.
     */
    function _buildSearchQuery($glue, $criteria)
    {
        require_once 'Horde/SQL.php';

        $clause = '';
        foreach ($criteria as $key => $vals) {
            if (!empty($vals['OR']) || !empty($vals['AND'])) {
                if (!empty($clause)) {
                    $clause .= ' ' . $glue . ' ';
                }
                $clause .= '(' . $this->_buildSearchQuery($glue, $vals) . ')';
            } else {
                if (isset($vals['field'])) {
                    if (!empty($clause)) {
                        $clause .= ' ' . $glue . ' ';
                    }
                    $rhs = $this->_convertToDriver($vals['test']);
                    $clause .= Horde_SQL::buildClause($this->_db, $vals['field'], $vals['op'], $rhs);
                } else {
                    foreach ($vals as $test) {
                        if (!empty($test['OR']) || !empty($test['AND'])) {
                            if (!empty($clause)) {
                                $clause .= ' ' . $glue . ' ';
                            }
                            $clause .= '(' . $this->_buildSearchQuery($glue, $test) . ')';
                        } else {
                            if (!empty($clause)) {
                                $clause .= ' ' . $key . ' ';
                            }
                            $rhs = $this->_convertToDriver($test['test']);
                            $clause .= Horde_SQL::buildClause($this->_db, $test['field'], $test['op'], $rhs);
                        }
                    }
                }
            }
        }

        return $clause;
    }

    /**
     * Read the given data from the SQL database and returns the
     * result's fields.
     *
     * @param $criteria      Search criteria.
     * @param $id            Data identifier.
     * @param $fields        List of fields to return.
     *
     * @return               Hash containing the search results.
     */
    function read($criteria, $id, $fields)
    {
        $in = '';
        if (is_array($id)) {
            if (!count($id)) {
                return array();
            }

            foreach ($id as $key) {
                $in .= empty($in) ? $this->_db->quote($this->_convertToDriver($key)) 
                                    : ', ' . $this->_db->quote($this->_convertToDriver($key));
            }
            $where = $criteria . ' IN (' . $in . ')';
        } else {
            $where = $criteria . ' = ' . $this->_db->quote($this->_convertToDriver($id));
        }

        $query  = 'SELECT ' . implode(', ', $fields) . ' ';
        $query .= 'FROM ' . $this->_params['table'] . ' WHERE ' . $where;

        /* Log the query at a DEBUG log level. */
        Horde::logMessage(sprintf('SQL read by %s: table = %s; query = "%s"',
                                  Auth::getAuth(), $this->_params['table'], $query),
                          __FILE__, __LINE__, PEAR_LOG_DEBUG);

        $result = $this->_db->getAll($query);
        if (is_a($result, 'PEAR_Error')) {
            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
        }

        $results = array();
        $iMax = count($fields);
        if (!is_a($result, 'PEAR_Error')) {
            foreach ($result as $row) {
                $entry = array();
                for ($i=0; $i < $iMax; $i++) {
                    $field = $fields[$i];
                    $entry[$field] = $this->_convertFromDriver($row[$i]);
                }
                $results[] = $entry;
            }
        }

        return $results;
    }

    /**
     * Adds the specified object to the SQL database.
     */
    function addObject($attributes)
    {
        $fields = array();
        $values = array();
        foreach ($attributes as $field => $value) {
            $fields[] = $field;
            $values[] = $this->_db->quote($this->_convertToDriver($value));
        }

        $query  = 'INSERT INTO ' . $this->_params['table'] . ' (' . implode(', ', $fields) . ')';
        $query .= ' VALUES (' . implode(', ', $values) . ')';

        $result = $this->_db->query($query);
        if (is_a($result, 'PEAR_Error')) {
            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
            return $result;
        }

        return true;
    }

    /**
     * Deletes the specified object from the SQL database.
     */
    function removeObject($object_key, $object_id)
    {
        $where = $object_key . ' = ' . $this->_db->quote($object_id);
        $query = 'DELETE FROM ' . $this->_params['table'] . ' WHERE ' . $where;

        $result = $this->_db->query($query);
        if (is_a($result, 'PEAR_Error')) {
            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
            return $result;
        }

        return true;
    }

    /**
     * Saves the specified object in the SQL database.
     *
     * @return string  The object id, possibly updated.
     */
    function setObject($object_key, $object_id, $attributes)
    {
        $where = $object_key . ' = ' . $this->_db->quote($object_id);
        unset($attributes[$object_key]);

        $set = array();
        foreach ($attributes as $field => $value) {
            $set[] = $field . ' = ' . $this->_db->quote($this->_convertToDriver($value));
        }

        $query  = 'UPDATE ' . $this->_params['table'] . ' SET ' . implode(', ', $set) . ' ';
        $query .= 'WHERE ' . $where;

        /* Log the query at a DEBUG log level. */
        Horde::logMessage(sprintf('SQL setObject by %s: table = %s; query = "%s"',
                                  Auth::getAuth(), $this->_params['table'], $query),
                          __FILE__, __LINE__, PEAR_LOG_DEBUG);

        $result = $this->_db->query($query);
        if (is_a($result, 'PEAR_Error')) {
            Horde::logMessage($result, __FILE__, __LINE__, PEAR_LOG_ERR);
        }

        return is_a($result, 'PEAR_Error') ? $result : $object_id;
    }

    /**
     * Create an object key for a new object.
     *
     * @param array $attributes  The attributes (in driver keys) of the
     *                           object being added.
     *
     * @return string  A unique ID for the new object.
     */
    function makeKey($attributes)
    {
        return md5(uniqid(mt_rand(), true));
    }

    /**
     * Converts a value from the driver's charset to the default charset.
     *
     * @param mixed $value  A value to convert.
     * @return mixed        The converted value.
     */
    function _convertFromDriver($value) 
    {
        return String::convertCharset($value, $this->_params['charset']);
    }

    /**
     * Converts a value from the default charset to the driver's charset.
     *
     * @param mixed $value  A value to convert.
     * @return mixed        The converted value.
     */
    function _convertToDriver($value) 
    {
        return String::convertCharset($value, NLS::getCharset(), $this->_params['charset']);
    }

}





More information about the commits mailing list