steffen: server/kolab-horde-fbview/kolab-horde-fbview/fbview/turba/lib .htaccess, NONE, 1.1 AbstractObject.php, NONE, 1.1 Driver.php, NONE, 1.1 Group.php, NONE, 1.1 List.php, NONE, 1.1 ListView.php, NONE, 1.1 Object.php, NONE, 1.1 ObjectView.php, NONE, 1.1 Renderer.php, NONE, 1.1 Source.php, NONE, 1.1 Turba.php, NONE, 1.1 api.php, NONE, 1.1 base.php, NONE, 1.1 prefs.php, NONE, 1.1 version.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
In directory doto:/tmp/cvs-serv18388/kolab-horde-fbview/kolab-horde-fbview/fbview/turba/lib

Added Files:
	.htaccess AbstractObject.php Driver.php Group.php List.php 
	ListView.php Object.php ObjectView.php Renderer.php Source.php 
	Turba.php api.php base.php prefs.php version.php 
Log Message:
Fbview in separate package

--- NEW FILE: .htaccess ---
Deny from all

--- NEW FILE: AbstractObject.php ---
<?php
/**
 * The Turba_AbstractObject:: class provides an interface for Turba objects -
 * people, groups, restaurants, etc.
 *
 * $Horde: turba/lib/AbstractObject.php,v 1.28 2004/04/28 20:13:39 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_AbstractObject {

    /**
     * Underlying instance of Turba_Source.
     * @var object Turba_Source $source
     */
    var $source;

    /**
     * Hash of attributes for this contact.
     * @var array $attributes
     */
    var $attributes;

    /**
     * Constructs a new Turba_AbstractObject object.
     *
     * @param object Turba_Source $source      The source that this object came from.
     * @param array               $attributes  (optional) Hash of attributes for this object.
     */
    function Turba_AbstractObject(&$source, $attributes = array())
    {
        $this->source = &$source;
        $this->attributes = $attributes;
    }

    /**
     * Returns a key-value hash containing all properties of this
     * object.
     *
     * @return array  All properties of this object.
     */
    function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * Return the name of the Turba_Source that this object is from.
     */
    function getSource()
    {
        return $this->source->name;
    }

    /**
     * Returns the value of the specified attribute.
     *
     * @param string $attribute  The attribute to retrieve.
     *
     * @return string  The value of $attribute, or the empty string.
     */
    function getValue($attribute)
    {
        if (file_exists(HORDE_BASE . '/config/hooks.php')) {
            require_once HORDE_BASE . '/config/hooks.php';
            $function = '_turba_hook_decode_' . $attribute;
            if (function_exists($function)) {
                return call_user_func($function, $this->attributes[$attribute]);
            }
        }

        if (isset($this->source->map[$attribute]) && is_array($this->source->map[$attribute])) {
            $args = array($this->source->map[$attribute]['format']);
            foreach ($this->source->map[$attribute]['fields'] as $field) {
                $args[] = $this->getValue($field);
            }
            return call_user_func_array('sprintf', $args);
        } else {
            return (isset($this->attributes[$attribute]) ? $this->attributes[$attribute] : null);
        }
    }

    /**
     * Sets the value of the specified attribute.
     *
     * @param string $attribute  The attribute to set.
     * @param string $value      The value of $attribute.
     */
    function setValue($attribute, $value)
    {
        if (file_exists(HORDE_BASE . '/config/hooks.php')) {
            require_once HORDE_BASE . '/config/hooks.php';
            $function = '_turba_hook_encode_' . $attribute;
            if (function_exists($function)) {
                $value = call_user_func($function, $value,
                                        $this->attributes[$attribute]);
            }
        }

        if (isset($this->source->map[$attribute]) && is_array($this->source->map[$attribute])) {
            return false;
        }

        $this->attributes[$attribute] = $value;
        return true;
    }

    /**
     * Determines whether or not the object has a value for the
     * specified attribute.
     *
     * @param string $attribute  The attribute to check.
     *
     * @return boolean  Whether or not there is a value for $attribute.
     */
    function hasValue($attribute)
    {
        if (isset($this->source->map[$attribute]) && is_array($this->source->map[$attribute])) {
            foreach ($this->source->map[$attribute]['fields'] as $field) {
                if ($this->hasValue($field)) {
                    return true;
                }
            }
            return false;
        } else {
            return !is_null($this->getValue($attribute));
        }
    }

    /**
     * Returns true if this instance is a member of a group.
     *
     * @return boolean  True if this instances is the member of a group.
     */
    function isGroup()
    {
        return false;
    }

    /**
     * Returns true if this object is editable by the current user.
     *
     * @return boolean  Whether or not the current user can edit this object
     */
    function isEditable()
    {
        if (!$this->source->readonly) {
            return true;
        } elseif (isset($source['admin']) &&
                  in_array(Auth::getAuth(), $source['admin'])) {
            return true;
        } elseif ($this->hasValue('__owner') &&
                  $this->getValue('__owner') == Auth::getAuth()) {
            return true;
        }
        return false;
    }

    /**
     * Save the current state of the object to the storage backend.
     */
    function store()
    {
        $object_id = $this->source->setObject($this);
        if (is_a($object_id, 'PEAR_Error')) {
            return $object_id;
        }

        return $this->setValue('__key', $object_id);
    }

}

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

require_once TURBA_BASE . '/lib/Turba.php';

/**
 * The Turba_Driver:: class provides a common abstracted interface to the
 * various directory search drivers.  It includes functions for searching,
 * adding, removing, and modifying directory entries.
 *
 * $Horde: turba/lib/Driver.php,v 1.43 2004/02/24 19:31:00 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 {

    /**
     * Hash holding the driver's additional parameters.
     * @var array $_params
     */
    var $_params = array();

    /**
     * Constructs a new Turba_Driver object.
     *
     * @param array $params  Hash containing additional configuration parameters.
     */
    function Turba_Driver($params)
    {
        $this->_params = $params;
    }

    /**
     * Returns the current driver's additional parameters.
     *
     * @return          Hash containing the driver's additional parameters.
     */
    function getParams()
    {
        return $this->_params;
    }

    /**
     * Searches the backend with the given criteria and returns a
     * filtered list of results. If no criteria are specified, all
     * records are returned.
     *
     * @abstract
     *
     * @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 PEAR::raiseError('Not supported');
    }

    /**
     * Initialize any connections, etc. for this driver that might
     * return an error.
     *
     * @abstract
     */
    function init()
    {
    }

    /**
     * Read the given data from the backend and returns
     * the result's fields.
     *
     * @abstract
     *
     * @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)
    {
        return PEAR::raiseError('Not supported');
    }

    /**
     * Adds the specified object to the backend.
     *
     * @abstract
     */
    function addObject($attributes)
    {
        return PEAR::raiseError('Not supported');
    }

    /**
     * Deletes the specified object from the backend.
     *
     * @abstract
     */
    function removeObject($object_key, $object_id)
    {
        return PEAR::raiseError('Not supported');
    }

    /**
     * Saves the specified object to the backend.
     *
     * @abstract
     */
    function setObject($object_key, $object_id, $attributes)
    {
        return PEAR::raiseError('Not supported');
    }

    /**
     * Create an object key for a new object.
     *
     * @abstract
     * @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)
    {
    }

    /**
     * Attempts to return a concrete Turba_Driver instance based on $driver.
     *
     * @param $driver   The type of Turba_Driver subclass to return.  The
     *                  code is dynamically included.
     * @param $params   Hash containing additional paramters to be passed to
     *                  the subclass's constructor.
     *
     * @return          The newly created concrete Turba_Driver instance, or
     *                  false on an error.
     */
    function &factory($driver, $params = array())
    {
        $driver = basename($driver);
        include_once dirname(__FILE__) . '/Driver/' . $driver . '.php';
        $class = 'Turba_Driver_' . $driver;
        if (class_exists($class)) {
            return $ret = &new $class($params);
        } else {
            Horde::fatal(PEAR::raiseError(sprintf(_("Unable to load the definition of %s."), $class)), __FILE__, __LINE__);
        }
    }

    /**
     * Attempts to return a reference to a concrete Turba_Driver instance
     * based on $driver. It will only create a new instance if no
     * Turba_Driver instance with the same parameters currently exists.
     *
     * This method must be invoked as: $var = &Turba_Driver::singleton()
     *
     * @param $driver   The type of concrete Turba_Driver subclass to return.
     *                  This is based on the storage driver ($driver). The
     *                  code is dynamically included.
     * @param $params   A hash containing additional parameters for the
     *                  subclass.
     *
     * @return          The concrete Turba_Driver reference, or false on an
     *                  error.
     */
    function &singleton($driver, $params)
    {
        static $instances;

        if (!isset($instances)) {
            $instances = array();
        }

        $signature = serialize(array($driver, $params));
        if (!isset($instances[$signature])) {
            $instances[$signature] = &Turba_Driver::factory($driver, $params);
        }

        return $instances[$signature];
    }

}

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

require_once TURBA_BASE . '/lib/AbstractObject.php';

/**
 * The Turba_Group:: class provides a set of methods for dealing with
 * contact groups.
 *
 * $Horde: turba/lib/Group.php,v 1.20 2004/05/20 16:39:08 jan 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_Group extends Turba_AbstractObject {

    /**
     * Constructs a new Turba_Group object.
     *
     * @param Turba_Source $source   The source object that this group comes from
     * @param array $attributes      (optional) Hash of attributes for this group.
     */
    function Turba_Group(&$source, $attributes = array())
    {
        $this->Turba_AbstractObject($source, $attributes);
        $this->attributes['__type'] = 'Group';
    }

    /**
     * Returns true if this object is a group of multiple contacts.
     *
     * @return          True if this a group of multiple contacts.
     */
    function isGroup()
    {
        return true;
    }

    /**
     * Adds a new contact entry to this group.
     *
     * @param Turba_AbstractObject $object   The object to add to the Group
     *
     * @since Turba 1.2
     */
    function addMember($object)
    {
        // Can't add itself.
        if ($object->getValue('__key') != $this->attributes['__key']) {
            $members = @unserialize($this->attributes['__members']);
            if (!is_array($members)) {
                $members = array();
            }

            $members[] = $object->getValue('__key');
            // Remove duplicates
            $members = array_unique($members);
            $this->attributes['__members'] = serialize($members);
        }
    }

    /**
     * Deletes a contact entry from this group.
     *
     * @param Turba_AbstractObject $object   The object to remove from the Group
     *
     * @since Turba 1.2
     */
    function removeMember($object)
    {
        $members = unserialize($this->attributes['__members']);
        $key = $object->getValue('__key');

        if (($i = array_search($key, $members)) !== false) {
            unset($members[$i]);
        }

        $this->attributes['__members'] = serialize($members);
        $this->store();
        return true;
    }

    /**
     * Retrieve the Objects in this group
     *
     * @param $sort_criteria     The requested sort order which is passed to
     *                           Turba_List::sort().
     *
     * @param $sort_direction    The requested sort direction which is passed to
     *                           Turba_List::sort().
     *
     * @return Turba_List        List containing the members of this group
     *
     * @since Turba 1.2
     */
    function listMembers($sort_criteria = 'lastname', $sort_direction = 0)
    {
        require_once TURBA_BASE . '/lib/List.php';
        $list = &new Turba_List();

        $children = unserialize($this->attributes['__members']);
        if (!is_array($children)) {
            $children = array();
        }

        reset($children);
        foreach ($children as $member) {
            $newMember = $this->source->getObject($member);
            if (is_object($newMember)) {
                $list->insert($newMember);
            }
        }
        $list->sort($sort_criteria, $sort_direction);

        return $list;
    }

    /**
     * Searches the group based on the provided criteria.
     *
     * TODO: Allow $criteria to contain the comparison operator (<, =, >,
     *       'like') and modify the drivers accordingly.
     *
     * @param $search_criteria   Hash containing the search criteria.
     * @param $sort_criteria     The requested sort order which is passed to
     *                           Turba_List::sort().
     *
     * @return Turba_List        The sorted, filtered list of search results.
     *
     * @since Turba 1.2
     */
    function search($search_criteria, $sort_criteria = 'lastname')
    {
        require_once TURBA_BASE . '/lib/List.php';
        $results = new Turba_List();

        /* Get all members. */
        $members = $this->listMembers($sort_criteria);

        $members->reset();
        while ($member = $members->next()) {
            $match = true;
            foreach ($search_criteria as $key => $value) {
                if ($member->hasValue($key)) {
                    if ($member->getValue($key) == $value) {
                        $match = false;
                    }
                }
            }
            if ($match) {
                $results->insert($member);
            }
        }

        /* Return the filtered (sorted) results. */
        return $results;
    }

}

--- NEW FILE: List.php ---
<?php
/**
 * The Turba_List:: class provides an interface for dealing with a
 * list of Turba_AbstractObjects.
 *
 * $Horde: turba/lib/List.php,v 1.39 2004/02/24 23:05:21 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_List {

    /**
     * The array containing the Turba_Objects represented in this
     * list.
     * @var array $objects
     */
    var $objects = array();

    /**
     * An array of objects which have just been added during this page
     * load.
     * @var array $fresh
     */
    var $fresh = array();

    /**
     * The field to compare objects by.
     * @var string $_usortCriteria
     */
    var $_usortCriteria;

    /**
     * Inserts a new list.
     *
     * @param          object Turba_Object $object  The object to insert.
     * @param optional boolean             $new     This object is from a new search (defaults to true).
     */
    function insert($object, $new = true)
    {
        if (is_a($object, 'Turba_AbstractObject')) {
            $key = $object->source->name . ':' . $object->getValue('__key');
            if (!isset($this->objects[$key])) {
                if ($new) {
                    $this->fresh[$key] = 1;
                }
                $this->objects[$key] = $object;
            }
        }
    }

    /**
     * Remove an entry from the list.
     *
     * @param string $key  The key of the object to remove.
     *
     * @since Turba 1.2
     */
    function remove($key)
    {
        if (isset($this->objects[$key])) {
            unset($this->objects[$key]);
        }
    }

    /**
     * Merges an existing Turba_List into this one.
     *
     * @param          mixed   $list  The list to merge - either a Turba_List object or an array.
     * @param optional boolean $new   These objects are coming from a new search (defaults to true).
     */
    function merge($list, $new = true)
    {
        if (is_object($list)) {
            $list = $list->objects;
        }
        if (is_array($list)) {
            foreach ($list as $object) {
                $this->insert($object, $new);
            }
        }
    }

    /**
     * Reset our internal pointer to the beginning of the list. Use
     * this to hide the internal storage (array, list, etc.) from
     * client objects.
     */
    function reset()
    {
        reset($this->objects);
    }

    /**
     * Return the next Turba_Object in the list. Use this to hide
     * internal implementation details from client objects.
     *
     * @return Turba_Object $object   The next object in the list.
     */
    function next()
    {
        list(,$tmp) = each($this->objects);
        return $tmp;
    }

    /**
     * Return the number of Turba_Objects that are in the list. Use
     * this to hide internal implementation details from client
     * objects.
     *
     * @return integer $count The number of objects in the list.
     */
    function count()
    {
        return count($this->objects);
    }

    /**
     * Filters/Sorts the list based on the specified sort routine.
     *
     * @param $sort         The sort method.
     * @param $low          The low end of the sort range.
     * @param $high         The high end of the sort range.
     * @param $dir          Sort direction, 0 = ascending, 1 = descending
     */
    function sort($sort = 'lastname', $dir = 0)
    {
        global $prefs, $attributes;

        $sorted_objects = array();

        foreach ($this->objects as $key => $object) {
            $lastname = $object->getValue('lastname');
            if (!$lastname) {
                $lastname = Turba::guessLastname($object->getValue('name'));
            }
            $object->setValue('lastname', $lastname);
            $sorted_objects[$key] = $object;
        }

        $this->_usortCriteria = $sort;

        // Set the comparison type based on the type of attribute
        // we're sorting by.
        $this->_usortType = 'text';
        if (isset($attributes[$sort])) {
            if (!empty($attributes[$sort]['cmptype'])) {
                $this->_usortType = $attributes[$sort]['cmptype'];
            } elseif ($attributes[$sort]['type'] == 'int' ||
                      $attributes[$sort]['type'] == 'intlist' ||
                      $attributes[$sort]['type'] == 'number') {
                $this->_usortType = 'int';
            }
        }

        usort($sorted_objects, array($this, 'cmp'));

        if ($dir == 1) {
            $this->objects = array_reverse($sorted_objects);
        } else {
            $this->objects = $sorted_objects;
        }
    }

    /**
     * Usort helper function. Compares two Turba_AbstractObjects
     * based on the member variable $_usortCriteria, taking care
     * to sort numerically if it is an integer field.
     *
     * @param $a        The first Turba_AbstractObject to compare.
     * @param $b        The second Turba_AbstroctObject to compare.
     *
     * @return          Integer comparison of the two field values.
     */
    function cmp($a, $b)
    {
        switch ($this->_usortType) {
        case 'int':
            return ($a->getValue($this->_usortCriteria) > $b->getValue($this->_usortCriteria)) ? 1 : -1;
            break;

        case 'text':
        default:
            $acmp = String::lower($a->getValue($this->_usortCriteria), true);
            $bcmp = String::lower($b->getValue($this->_usortCriteria), true);

            // Use strcoll for locale-safe comparisons.
            return strcoll($acmp, $bcmp);
        }
    }

    function isFresh($object)
    {
        return isset($this->fresh[$object->source->name . ':' . $object->getValue('__key')]);
    }

    function serialize()
    {
        $data = array();
        $data['keys'] = array();
        $data['fresh'] = $this->fresh;
        foreach ($this->objects as $key => $object) {
            $data['keys'][] = $object->source->name . ':' . $object->getValue('__key');
        }
        return $data;
    }

    function unserialize($data)
    {
        if (!isset($data) || !is_array($data)) {
            return null;
        }

        $tmp = &new Turba_List();
        $objects = array();
        foreach ($data['keys'] as $value) {
            list($source, $key) = explode(':', $value);
            if (isset($GLOBALS['cfgSources'][$source])) {
                $sourceOb = &Turba_Source::singleton($source, $GLOBALS['cfgSources'][$source]);
                $tmp->insert($sourceOb->getObject($key));
            }
        }

        /* Not the best way of doing this, but it works for now. */
        $tmp->fresh = $data['fresh'];
        return $tmp;
    }

}

--- NEW FILE: ListView.php ---
<?php
/**
 * The Turba_ListView:: class provides an interface for objects that
 * visualize Turba_lists.
 *
 * $Horde: turba/lib/ListView.php,v 1.17 2004/04/01 21:23:37 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_ListView {

    /**
     * The Turba_List object that we are visualizing.
     * @var object Turba_List $list
     */
    var $list;

    /**
     * The template used to display each row of the list.
     * @var string $template
     */
    var $template;

    /**
     * Constructs a new Turba_ListView object.
     *
     * @param $list     List of contacts to display.
     * @param $template What template file to display this contact with.
     */
    function Turba_ListView(&$list, $template)
    {
        $this->list = &$list;
        $this->template = $template;
    }

    /**
     * Renders the list contents into an HTML view.
     *
     * @return integer $count The number of objects in the list.
     */
    function display($min, $max)
    {
        $i = 0;
        $this->list->reset();

        while ($ob = $this->list->next()) {
            if ($i++ < $min || $i > $max) {
                continue;
            }

            include $this->template;
        }
        return $i;
    }

    /**
     * Renders the list contents that match $alpha into and HTML view.
     *
     * @param $alpha    The letter to display.
     */
    function displayAlpha($alpha)
    {
        $this->list->reset();
        $alpha = String::lower($alpha);

        $i = 0;
        while ($ob = $this->list->next()) {
            $name = Turba::formatName($ob);

            if ($alpha != '*' && String::lower($name{0}) != $alpha) {
                continue;
            }

            include $this->template;
            $i++;
        }
    }

}

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

require_once TURBA_BASE . '/lib/AbstractObject.php';

/**
 * The Turba_Object:: class provides a set of methods for dealing with
 * individual Turba objects - whether those are people, restaurants, etc.
 *
 * $Horde: turba/lib/Object.php,v 1.15 2004/02/20 19:44:54 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_Object extends Turba_AbstractObject {

    /**
     * Constructs a new Turba_Object() object.
     *
     * @param $source       Hash describing the object Source.
     * @param $attributes   (optional) Hash of attributes for this object.
     */
    function Turba_Object(&$source, $attributes = array())
    {
        parent::Turba_AbstractObject($source, $attributes);
        $this->attributes['__type'] = 'Object';
    }

}

--- NEW FILE: ObjectView.php ---
<?php
/**
 * The Turba_ObjectView:: class provides an interface for visualizing
 * a Turba_AbstractObject.
 *
 * $Horde: turba/lib/ObjectView.php,v 1.19 2004/04/07 14:43:52 chuck Exp $
 *
 * @author   Chuck Hagenbuch <chuck at horde.org>
 * @version  $Revision: 1.1 $
 * @since    Turba 0.0.1
 * @package  Turba
 */
class Turba_ObjectView {

	/**
     * A reference to the Turba_AbstractObject that this
     * Turba_ObjectView displays.
     * @private
     * @var	object Turba_AbstractObject $_object
     */
    var $_object;

    /**
     * The template used to display the object.
     * @private
     * @var string $_template
     */
    var $_template;

    /**
     * Do we have the creation timestamp of the object?
     * @var boolean $_created
     */
    var $_created = false;

    /**
     * Do we have the modified timestamp of the object?
     * @var boolean $_modified
     */
    var $_modified = false;

    /**
     * Constructs a new Turba_ObjectView object.
     *
     * @param object Turba_AbstractObject $object    The object to display.
     * @param string                      $template  Which template file to display this object with.
     */
    function Turba_ObjectView(&$object, $template = null)
    {
        $this->_object = &$object;
        $this->_template = $template;
    }

    /**
     * Set up the Horde_Form for the current object's attributes.
     *
     * @param object Horde_Form &$form  The form to set variables on.
     */
    function setupForm(&$form)
    {
        require TURBA_BASE . '/config/attributes.php';

        $fields = array_keys($this->_object->source->getCriteria());

        // Run through once to see what form actions, if any, we need
        // to set up.
        $actions = array();
        $map = $this->_object->source->map;
        foreach ($fields as $field) {
            if (is_array($map[$field])) {
                foreach ($map[$field]['fields'] as $action_field) {
                    if (!isset($actions[$action_field])) {
                        $actions[$action_field] = array();
                    }
                    $actions[$action_field]['fields'] = $map[$field]['fields'];
                    $actions[$action_field]['format'] = $map[$field]['format'];
                    $actions[$action_field]['target'] = $field;
                }
            }
        }

        // Now run through and add the form variables.
        foreach ($fields as $field) {
            if (!isset($attributes[$field])) {
                continue;
            }

            $attribute = $attributes[$field];
            $params = isset($attribute['params']) ? $attribute['params'] : array();
            $desc = isset($attribute['desc']) ? $attribute['desc'] : null;

            if (is_array($map[$field])) {
                $v = &$form->addVariable($attribute['label'], 'object[' . $field . ']', $attribute['type'], false, false, $desc, $params);
                $v->disable();
            } else {
                $readonly = isset($attribute['readonly']) ? $attribute['readonly'] : null;
                $v = &$form->addVariable($attribute['label'], 'object[' . $field . ']', $attribute['type'], $attribute['required'], $readonly, $desc, $params);

                if (!empty($actions[$field])) {
                    require_once 'Horde/Form/Action.php';
                    $actionfields = array();
                    foreach ($actions[$field]['fields'] as $f) {
                        $actionfields[] = 'object[' . $f . ']';
                    }
                    $a = &Horde_Form_Action::factory('updatefield',
                                                     array('format' => $actions[$field]['format'],
                                                           'target' => 'object[' . $actions[$field]['target'] . ']',
                                                           'fields' => $actionfields));
                    $v->setAction($a);
                }
            }
        }

        if ($this->_created) {
            $v = &$form->addVariable(_("Created"), 'object[__created]', 'text', false, false);
            $v->disable();
        }

        if ($this->_modified) {
            $v = &$form->addVariable(_("Last Modified"), 'object[__modified]', 'text', false, false);
            $v->disable();
        }
    }

    /**
     * Renders the object into an HTML view.
     */
    function display()
    {
        require TURBA_BASE . '/config/attributes.php';
        $fields = $this->_object->source->getCriteria();
        require $this->_template;
    }

    /**
     * Set $attribute to $value.
     *
     * @param string $attribute  The attribute to set.
     * @param mixed  $value      The value for $attribute.
     */
    function set($attribute, $value)
    {
        $attribute = '_' . $attribute;
        $this->$attribute = $value;
    }

}

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

require_once 'Horde/Form/Renderer.php';

/**
 * Turba Form Renderer
 *
 * $Horde: turba/lib/Renderer.php,v 1.14 2004/05/20 16:39:08 jan Exp $
 *
 * @package Turba
 */
class Turba_Renderer extends Horde_Form_Renderer {

    var $_active = false;
    var $_object;

    function setObject(&$object)
    {
        $this->_object = &$object;
    }

    function beginActive($name)
    {
        $this->_active = true;
        parent::beginActive($name);
    }

    function beginInactive($name)
    {
        $this->_active = false;
        parent::beginInactive($name);
    }

    function _sectionHeader($title)
    {
?><table border="0" cellpadding="2" cellspacing="0" width="100%">
<tr><td align="left" class="header"><b><?php echo $title ?></b></td>
<?php
if (!$this->_active &&
    Turba::checkPermissions($this->_object, 'object', PERMS_EDIT)) {
    $url = Util::addParameter('', 'source', $this->_object->source->name);
    $url = Util::addParameter($url, 'key', $this->_object->getValue('__key'));
?>
  <td align="right" class="header">
    <span class="smallheader">
    <?php echo Horde::link(Horde::applicationUrl('edit.php' . $url), _("Edit"), 'smallheader') . _("Edit") ?></a> |
    <?php echo Horde::link(Horde::applicationUrl('delete.php' . $url), _("Delete"), 'smallheader') . _("Delete") ?></a>
    </span>
  </td>
<?php } ?>
</tr></table><?php
    }

}

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

require_once 'Horde/History.php';

/**
 * The Turba_Source:: class provides a set of methods for dealing with
 * specific contact sources.
 *
 * $Horde: turba/lib/Source.php,v 1.88 2004/05/25 00:11:06 jan 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_Source {

    /**
     * The internal name of this source.
     * @var string $name
     */
    var $name;

    /**
     * The symbolic title of this source.
     * @var string $title
     */
    var $title;

    /**
     * Instance of the underlying Turba_Driver class.
     * @var object Turba_Driver $driver
     */
    var $driver;

    /**
     * Hash describing the mapping between Turba attributes and
     * driver-specific fields.
     * @var array $map
     */
    var $map = array();

    /**
     * List of all fields that can be accessed in the backend
     * (excludes composite attributes, etc.).
     * @var array $fields
     */
    var $fields = array();

    /**
     * Array of fields that must match exactly.
     * @var array $strict
     */
    var $strict = array();

    /**
     * Whether this source is publicly searchable.
     * @var boolean $public
     */
    var $public = false;

    /**
     * Whether this source is read-only (not editable).
     * @var boolean $readonly
     */
    var $readonly = true;

    /**
     * Any admins for this source.
     * @var array $admin
     */
    var $admin = array();

    /**
     * Translates the keys of the first hash from the generalized
     * Turba attributes to the driver-specific fields. The translation
     * is based on the contents of $this->map. This ignores composite
     * fields.
     *
     * @param array $hash  Hash using Turba keys.
     *
     * @return array  Translated version of $hash.
     */
    function toDriverKeys($hash)
    {
        $fields = array();
        foreach ($hash as $key => $val) {
            if (isset($this->map[$key]) && !is_array($this->map[$key])) {
                $fields[$this->map[$key]] = $val;
            }
        }
        return $fields;
    }

    /**
     * Takes a hash of Turba key => search value and return a
     * (possibly nested) array, using backend attribute names, that
     * can be turned into a search by the driver. The translation is
     * based on the contents of $this->map, and includes nested OR
     * searches for composite fields.
     *
     * @param array  $hash         Hash of criteria using Turba keys.
     * @param string $search_type  OR search or AND search?
     * @param array  $strict       Fields that must be matched exactly.
     *
     * @return array  An array of search criteria.
     */
    function makeSearch($criteria, $search_type, $strict)
    {
        $search = array();
        $strict_search = array();
        foreach ($criteria as $key => $val) {
            if (isset($this->map[$key])) {
                if (is_array($this->map[$key])) {
                    $subsearch = array();
                    foreach ($this->map[$key]['fields'] as $field) {
                        $field = $this->toDriver($field);
                        if (!empty($strict[$field])) {
                            $strict_search[] = array('field' => $field, 'op' => '=', 'test' => $val);
                        } else {
                            $subsearch[] = array('field' => $field, 'op' => 'LIKE', 'test' => $val);
                        }
                    }
                    if (count($subsearch)) {
                        $search[] = array('OR' => $subsearch);
                    }
                } else {
                    if (!empty($strict[$this->map[$key]])) {
                        $strict_search[] = array('field' => $this->map[$key], 'op' => '=', 'test' => $val);
                    } else {
                        $search[] = array('field' => $this->map[$key], 'op' => 'LIKE', 'test' => $val);
                    }
                }
            }
        }

        if (count($strict_search) && count($search)) {
            return array('AND' => array($strict_search, array($search_type => $search)));
        } elseif (count($strict_search)) {
            return array('AND' => $strict_search);
        } elseif (count($search)) {
            return array($search_type => $search);
        } else {
            return array();
        }
    }

    /**
     * Translates a single Turba attribute to the driver-specific
     * counterpart. The translation is based on the contents of
     * $this->map. This ignores composite fields.
     *
     * @param string $attribute  The Turba attribute to translate.
     *
     * @return string  The driver name for this attribute.
     */
    function toDriver($attribute)
    {
        return isset($this->map[$attribute]) && !is_array($this->map[$attribute]) ? $this->map[$attribute] : null;
    }

    /**
     * Translates an array of hashes from being keyed on
     * driver-specific fields to being keyed on the generalized Turba
     * attributes. The translation is based on the contents of
     * $this->map.
     *
     * @param array $objects  Array of hashes using driver-specific keys.
     *
     * @return array  Translated version of $objects.
     */
    function toTurbaKeys($objects)
    {
        $attributes = array();
        foreach ($objects as $entry) {
            $new_entry = array();

            foreach ($this->map as $key => $val) {
                if (!is_array($val)) {
                    $new_entry[$key] = null;
                    if (isset($entry[$val]) && !empty($entry[$val]) && !is_null($entry[$val])) {
                        $new_entry[$key] = $entry[$val];
                    }
                }
            }

            $attributes[] = $new_entry;
        }
        return $attributes;
    }

    /**
     * Searches the source based on the provided criteria.
     *
     * TODO: Allow $criteria to contain the comparison operator (<, =, >,
     *       'like') and modify the drivers accordingly.
     *
     * @param $search_criteria   Hash containing the search criteria.
     * @param $sort_criteria     The requested sort order which is passed to
     *                           Turba_List::sort().
     * @param string $search_type  (optional) Do an AND or an OR search (defaults to AND).
     *
     * @return                   The sorted, filtered list of search results.
     */
    function &search($search_criteria, $sort_criteria = 'lastname',
                     $search_type = 'AND', $sort_direction = 0)
    {
        require_once TURBA_BASE . '/lib/List.php';
        require_once TURBA_BASE . '/lib/Object.php';

        /* If this is not a public source, enforce the requirement
         * that the source's owner must be equal to the current
         * user. */
        $strict_fields = array();
        if (!$this->public && !in_array(Auth::getAuth(), $this->admin)) {
            $search_criteria['__owner'] = Auth::getAuth();
            $strict_fields = array($this->toDriver('__owner') => true);
        }

        /* Add any fields that much match exactly for this source to
           the $strict_fields array. */
        foreach ($this->strict as $strict_field) {
            $strict_fields[$strict_field] = true;
        }

        /* Translate the Turba attributes to a driver-specific search
         * array. */
        $fields = $this->makeSearch($search_criteria, $search_type, $strict_fields);

        /* Retrieve the search results from the driver. */
        $results = $this->driver->search($fields, array_values($this->fields), $strict_fields);

        /* Translate the driver-specific fields in the result back to
         * the more generalized common Turba attributes using the
         * map. */
        $results = $this->toTurbaKeys($results);

        require_once TURBA_BASE . '/lib/Object.php';
        require_once TURBA_BASE . '/lib/Group.php';
        $list = &new Turba_List();
        foreach ($results as $attributes) {
            if (!empty($attributes['__type']) &&
                $attributes['__type'] == 'Group') {
                $list->insert(new Turba_Group($this, $attributes));
            } else {
                $list->insert(new Turba_Object($this, $attributes));
            }
        }
        $list->sort($sort_criteria, $sort_direction);

        /* Return the filtered (sorted) results. */
        return $list;
    }

    /**
     * Retrieve a set of objects from the source.
     *
     * @param array $objectIds  The unique ids of the objects to retrieve.
     *
     * @return array  The array of retrieved objects (Turba_AbstractObjects).
     */
    function &getObjects($objectIds)
    {
        require_once TURBA_BASE . '/lib/Object.php';
        $criteria = $this->map['__key'];

        $objects = $this->driver->read($criteria, $objectIds, array_values($this->fields));
        if (!is_array($objects)) {
            return PEAR::raiseError(_("Requested object not found."));
        }

        $results = array();
        $objects = $this->toTurbaKeys($objects);
        foreach ($objects as $object) {
            $done = false;
            if (!empty($object['__type'])) {
                $type = ucwords($object['__type']);
                $class = 'Turba_' . $type;
                if (!class_exists($class)) {
                    @require_once TURBA_BASE . '/lib/' . $type . '.php';
                }

                if (class_exists($class)) {
                    $results[] = &new $class($this, $object);
                    $done = true;
                }
            }
            if (!$done) {
                $results[] = &new Turba_Object($this, $object);
            }
        }

        return $results;
    }

    /**
     * Retrieve one object from the source.
     *
     * @param string $objectId  The unique id of the object to retrieve.
     *
     * @return object Turba_AbstractObject  The retrieved object.
     */
    function &getObject($objectId)
    {
        $result = &$this->getObjects(array($objectId));
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        } elseif (empty($result[0])) {
            return PEAR::raiseError('No results');
        } else {
            if (isset($this->map['__owner'])) {
                $result[0]->attributes['__owner'] = Auth::getAuth();
            }
            return $result[0];
        }
    }

    /**
     * Adds a new entry to the contact source.
     *
     * @param array $attributes  The attributes of the new object to add.
     *
     * @return mixed             The new __key value on success, or a
     *                           PEAR_Error object on failure.
     */
    function addObject($attributes)
    {
        if ($this->readonly) {
            return false;
        }

        // Always generate a new key.
        $attributes['__key'] = $this->driver->makeKey($this->toDriverKeys($attributes));

        if (!isset($attributes['__type'])) {
            $attributes['__type'] = 'Object';
        }
        if (isset($this->map['__owner'])) {
            $attributes['__owner'] = Auth::getAuth();
        }

        $key = $attributes['__key'];
        $attributes = $this->toDriverKeys($attributes);
        $result = $this->driver->addObject($attributes);

        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        /* Log the creation of this item in the history log. */
        $history = &Horde_History::singleton();
        $history->log($this->getGUID($key), array('action' => 'add'), true);

        return $key;
    }

    /**
     * Deletes the specified entry from the contact source.
     *
     * @param string $object_id     The ID of the object to delete.
     */
    function removeObject($object_id)
    {
        if ($this->readonly) {
            return false;
        }

        $result = $this->driver->removeObject($this->toDriver('__key'), $object_id);
        if (is_a($result, 'PEAR_Error')) {
            return $result;
        }

        /* Log the deletion of this item in the history log. */
        $history = &Horde_History::singleton();
        $history->log($this->getGUID($object_id), array('action' => 'delete'), true);

        return true;
    }

    /**
     * Modifies an existing entry in the contact source.
     *
     * @param Turba_AbstractObject $object     The object to update.
     *
     * @return string  The object id, possibly updated.
     */
    function setObject($object)
    {
        if ($this->readonly) {
            return PEAR::raiseError(_("Address book is read-only."));
        }

        $attributes = $this->toDriverKeys($object->getAttributes());
        list($object_key, $object_id) = each($this->toDriverKeys(array('__key' => $object->getValue('__key'))));

        $object_id = $this->driver->setObject($object_key, $object_id, $attributes);
        if (is_a($object_id, 'PEAR_Error')) {
            return $object_id;
        }

        /* Log the modification of this item in the history log. */
        $history = &Horde_History::singleton();
        $history->log($this->getGUID($object_id), array('action' => 'modify'), true);

        return $object_id;
    }

    /**
     * Returns the criteria available for this source except '__key'.
     *
     * @return array  An array containing the criteria.
     */
    function getCriteria()
    {
        $criteria = $this->map;
        unset($criteria['__key']);
        return $criteria;
    }

    /**
     * Get a globally unique ID for a contact object.
     *
     * @param integer $objectId  The object id.
     *
     * @return string  A GUID referring to $objectId.
     */
    function getGUID($objectId)
    {
        return 'turba:' . $this->name . ':' . $objectId;
    }

    /**
     * Returns all non-composite fields for this source. Useful for
     * importing and exporting data, etc.
     *
     * @return array  The field list.
     */
    function getFields()
    {
        return array_flip($this->fields);
    }

    /**
     * Static method to contruct Turba_Source objects. Use this so
     * that we can return PEAR_Error objects if anything goes wrong.
     *
     * @param $name         String containing the internal name of this source.
     * @param $source       Array containing the configuration information for this source.
     */
    function &factory($name, $source)
    {
        $object = &new Turba_Source();

        $object->name = $name;
        $object->title = $source['title'];

        // Obtain a handle to a driver of the requested type. If an
        // instance of that driver doesn't already exist, a new one
        // will be created and returned.
        require_once TURBA_BASE . '/lib/Driver.php';
        $object->driver = &Turba_Driver::singleton($source['type'], $source['params']);
        $init = $object->driver->init();
        if (is_a($init, 'PEAR_Error')) {
            return $init;
        }

        /* Store and translate the map at the Source level. */
        $object->map = $source['map'];
        foreach ($object->map as $key => $val) {
            if (!is_array($val)) {
                $object->fields[$key] = $val;
            }
        }

        /* Store strict fields. */
        if (isset($source['strict'])) {
            $object->strict = $source['strict'];
        }

        /* Store admins. */
        if (isset($source['admin'])) {
            $object->admin = $source['admin'];
        }

        /* Set flags. */
        if (isset($source['public'])) {
            $object->public = $source['public'];
        }
        if (isset($source['readonly'])) {
            $object->readonly = $source['readonly'] &&
                (!isset($source['admin']) || !in_array(Auth::getAuth(), $source['admin']));
        }

        return $object;
    }

    /**
     * Attempts to return a reference to a concrete Turba_Source instance
     * based on $driver. It will only create a new instance if no
     * Turba_Source instance with the same parameters currently exists.
     *
     * This method must be invoked as: $source = &Turba_Source::singleton()
     *
     * @param $name         String containing the internal name of this source.
     * @param $source       Array containing the configuration information for this source.
     *
     * @return          The concrete Turba_Source reference, or false on an
     *                  error.
     */
    function &singleton($name, $source)
    {
        static $instances;

        if (!isset($instances)) {
            $instances = array();
        }

        $signature = serialize(array($name, $source));
        if (!isset($instances[$signature])) {
            $instances[$signature] = &Turba_Source::factory($name, $source);
        }

        return $instances[$signature];
    }

}

--- NEW FILE: Turba.php ---
<?php
/**
 * Turba Base Class.
 *
 * $Horde: turba/lib/Turba.php,v 1.48 2004/04/07 14:43:52 chuck Exp $
 *
 * @author  Chuck Hagenbuch <chuck at horde.org>
 * @author  Jon Parise <jon at horde.org>
 * @version $Revision: 1.1 $
 * @package Turba
 */
class Turba {

    /**
     * Split a GUID into source and contactId parts.
     *
     * @param string $guid  The GUID.
     *
     * @return array  array($source, $contactId)
     */
    function splitGUID($guid)
    {
        $pieces = explode(':', $guid);

        /* Make sure this is a Turba GUID. */
        if ($pieces[0] != 'turba') {
            return array(false, false);
        }

        /* Strip off the turba entry. */
        array_shift($pieces);

        /* The contact id is the last entry in the array. */
        $contactId = array_pop($pieces);

        /* The source id is everything else. */
        $source = implode(':', $pieces);

        return array($source, $contactId);
    }

    function formatEmailAddresses($data, &$ob)
    {
        require_once 'Horde/MIME.php';

        $email_vals = explode(',', $data);
        $email_values = false;
        foreach ($email_vals as $email_val) {
            $email_val = trim($email_val);

            // Format the address according to RFC822.
            $mailbox_host = explode('@', $email_val);
            if (!isset($mailbox_host[1])) {
                $mailbox_host[1] = '';
            }
            $name = $ob->getValue('name');
            $address = MIME::rfc822WriteAddress($mailbox_host[0], $mailbox_host[1], $name);

            // Get rid of the trailing @ (when no host is included in
            // the email address).
            $address = str_replace('@>', '>', $address);
            $mail_link = $GLOBALS['registry']->call('mail/compose', array(array('to' => addslashes($address))));
            if (is_a($mail_link, 'PEAR_Error')) {
                $mail_link = 'mailto:' . urlencode($address);
            }

            $email_value = Horde::link($mail_link, $email_val) . htmlspecialchars($email_val) . '</a>';
            if ($email_values) {
                $email_values .= ', ' . $email_value;
            } else {
                $email_values = $email_value;
            }
        }

        return $email_values;
    }

    function string2Columns($string)
    {
        $ret = array();
        $lines = explode("\n", $string);
        foreach ($lines as $line) {
            $line = trim($line);
            if (!empty($line)) {
                $columns = explode("\t", $line);
                if (count($columns) > 1) {
                    $source = array_splice($columns, 0, 1);
                    $ret[$source[0]] = $columns;
                }
            }
        }

        return $ret;
    }

    /**
     * Returns a best guess at the lastname in a string.
     *
     * @param $name     String contain the full name.
     *
     * @return          String containing the last name.
     */
    function guessLastname($name)
    {
        $name = trim(preg_replace('|\s|', ' ', $name));
        if (!empty($name)) {
            /* Assume that last names are always before any commas. */
            if (is_int(strpos($name, ','))) {
                $name = String::substr($name, 0, strpos($name, ','));
            }

            /* Take out anything in parentheses. */
            $name = trim(preg_replace('|\(.*\)|', '', $name));

            $namelist = explode(' ', $name);
            $name = $namelist[($nameindex = (count($namelist) - 1))];

            while (String::length($name) < 5 &&
                   strspn($name[(String::length($name) - 1)], '.:-') &&
                   !empty($namelist[($nameindex - 1)])) {
                $nameindex--;
                $name = $namelist[$nameindex];
            }
        }
        return $name;
    }

    /**
     * Formats the name according to the user's preference.
     *
     * @param object Turba_Object $ob  The object to get a name from.
     *
     * @return string  The formatted name, either "Firstname Lastname"
     *                 or "Lastname, Firstname" depending on the user's
     *                 preference.
     */
    function formatName($ob)
    {
        global $prefs;

        /* See if we have the name fields split out explicitly. */
        if ($ob->hasValue('firstname') && $ob->hasValue('lastname')) {
            if ($prefs->getValue('name_format') == 'last_first') {
                return $ob->getValue('lastname') . ', ' . $ob->getValue('firstname');
            } else {
                return $ob->getValue('firstname') . ' ' . $ob->getValue('lastname');
            }
        } else {
            /* One field, we'll have to guess. */
            $format = $prefs->getValue('name_format');
            $name = $ob->getValue('name');
            $lastname = Turba::guessLastname($name);
            if ($format == 'last_first' &&
                !is_int(strpos($name, ',')) &&
                String::length($name) > String::length($lastname)) {
                $name = preg_replace("|\s+$lastname|", '', $name);
                $name = $lastname . ', ' . $name;
            }
            if ($format == 'first_last' &&
                is_int(strpos($name, ',')) &&
                String::length($name) > String::length($lastname)) {
                $name = preg_replace("|$lastname,\s*|", '', $name);
                $name = $name . ' ' . $lastname;
            }
            return $name;
        }
    }

    /**
     * Checks if a user has the specified permissions on the passed-in
     * object.
     *
     * @param array $in        The data to check on.
     * @param string $filter   What are we checking for.
     * @param int $permission  What permission to check for.
     *
     * @return array           An array containing the criteria.
     */
    function checkPermissions($in, $filter, $permission = PERMS_READ)
    {
        $userID = Auth::getAuth();
        $admin = Auth::isAdmin();

        switch ($filter) {
        case 'object':
            if ($admin || in_array($userID, $in->source->admin)) {
                return true;
            }

            switch ($permission) {
            case PERMS_SHOW:
            case PERMS_READ:
                if ($in->source->public ||
                    ($in->hasValue('__owner') &&
                     $in->getValue('__owner') == $userID)) {
                    return true;
                }
                break;

            case PERMS_EDIT:
            case PERMS_DELETE:
                /* Find out if this is a case that the object is
                 * editable. */
                if (!$in->source->readonly &&
                    $in->hasValue('__owner') &&
                    $in->getValue('__owner') == $userID) {
                    return true;
                }
                return false;
                break;
            }
            break;

        default:
            return true;
        }

        return false;
    }

    function permissionsFilter($in, $filter, $permission = PERMS_READ)
    {
        global $perms;

        $out = array();
        $userID = Auth::getAuth();
        $admin = Auth::isAdmin();

        switch ($filter) {
        case 'source':
            if ($admin) {
                return $in;
            }

            foreach ($in as $sourceID => $name) {
                $sourceTag = 'turba:sources:' . $sourceID;
                if (!$perms->exists($sourceTag) || $perms->hasPermission($sourceTag, $userID, $permission)) {
                    $out[$sourceID] = $name;
                }
            }
            break;

        default:
            $out = $in;
        }

        return $out;
    }

    function menu()
    {
        global $conf, $registry, $notification;
        require_once 'Horde/Menu.php';
        require TURBA_TEMPLATES . '/menu/menu.inc';

        $notification->notify(array('listeners' => 'status'));

        /* Include the JavaScript for the help system. */
        Help::javascript();
    }

}

--- NEW FILE: api.php ---
<?php
/**
 * Turba external API interface.
 *
 * $Horde: turba/lib/api.php,v 1.84 2004/05/29 21:12:45 jan Exp $
 *
 * This file defines Turba's external API interface. Other
 * applications can interact with Turba through this API.
 *
 * @package Turba
 */

$_services['perms'] = array(
    'args' => array(),
    'type' => 'stringArray');

$_services['import_vcard'] = array(
    'args' => array('source', 'vcard_data'),
    'type' => 'stringArray');

$_services['show'] = array(
    'link' => '%application%/display.php?source=|source|&key=|key|');

$_services['followLink'] = array(
    'link' => '%application%/display.php?source=|source|&key=|to_value|');

$_services['search'] = array(
    'args' => array('addresses', 'addressbooks', 'fields'),
    'type' => 'stringArray');

$_services['clientSearch'] = array(
    'checkperms' => false,
    'args' => array('addresses', 'fields'),
    'type' => 'stringArray');

$_services['listBy'] = array(
    'args' => array('action', 'timestamp'),
    'type' => 'stringArray');

$_services['add'] = array(
    'args' => array('name', 'address', 'addressbook'),
    'type' => 'boolean');

$_services['sources'] = array(
    'args' => array('writeable'),
    'type' => 'stringArray');

$_services['fields'] = array(
    'args' => array('addressbook'),
    'type' => 'stringArray');

$_services['addField'] = array(
    'args' => array('address', 'name', 'field', 'value', 'addressbook'),
    'type' => 'stringArray');

$_services['deleteField'] = array(
    'args' => array('address', 'field', 'addressbooks'),
    'type' => 'stringArray');

$_services['getField'] = array(
    'args' => array('address', 'field', 'addressbooks'),
    'type' => 'stringArray');

$_services['listField'] = array(
    'args' => array('field', 'addressbooks'),
    'type' => 'stringArray');

$_services['getContact'] = array(
    'args' => array('addressbook', 'key'),
    'type' => 'stringArray');

$_services['getContacts'] = array(
    'args' => array('addressbook', 'keys'),
    'type' => 'stringArray');

$_services['addContact'] = array(
    'args' => array('addressbook', 'attributes'),
    'type' => 'string');

$_services['updateContact'] = array(
    'args' => array('addressbook', 'key', 'attributes'),
    'type' => 'stringArray');

$_services['deleteContact'] = array(
    'args' => array('addressbook', 'key'),
    'type' => 'boolean');

$_services['clientSourceConfigured'] = array(
    'checkperms' => false,
    'args' => array(),
    'type' => 'boolean');

$_services['getClient'] = array(
    'checkperms' => false,
    'args' => array('key'),
    'type' => 'stringArray');

$_services['getClients'] = array(
    'checkperms' => false,
    'args' => array('keys'),
    'type' => 'stringArray');

$_services['getClientSource'] = array(
    'checkperms' => false,
    'args' => array(),
    'type' => 'string');

$_services['addClient'] = array(
    'args' => array('attributes'),
    'type' => 'string');

$_services['updateClient'] = array(
    'args' => array('key', 'attributes'),
    'type' => 'stringArray');

$_services['deleteClient'] = array(
    'args' => array('key'),
    'type' => 'stringArray');

$_services['block'] = array(
    'args' => array('type', 'params'),
    'type' => 'stringArray');

$_services['linkParameters'] = array(
    'args' => array(),
    'type' => 'stringArray');

$_services['getLinkDescription'] = array(
    'args' => array(),
    'type' => 'string');

$_services['getLinkSummary'] = array(
    'args' => array(),
    'type' => 'string');

$_services['addLink'] = array(
    'link' => '%application%/addlink.php?link_type=|link_type|' .
    ini_get('arg_separator.output') . 'from_application=|from_application|' .
    ini_get('arg_separator.output') . 'from_parameters=|from_parameters|' .
    ini_get('arg_separator.output') . 'url=|url|');


function _turba_perms()
{
    static $perms = array();
    if (!empty($perms)) {
        return $perms;
    }

    @define('TURBA_BASE', dirname(__FILE__) . '/..');
    require_once TURBA_BASE . '/lib/base.php';
    global $cfgSources;

    $perms['tree']['turba']['sources'] = false;
    $perms['title']['turba:sources'] = _("Sources");

    // Run through every contact source.
    foreach ($cfgSources as $source => $curSource) {
        $perms['tree']['turba']['sources'][$source] = false;
        $perms['title']['turba:sources:' . $source] = $curSource['title'];
    }

    return $perms;
}

/**
 * Return the requested block and include needed libs.
 */
function &_turba_block($type, $params)
{
    @define('TURBA_BASE', dirname(__FILE__) . '/..');
    require_once TURBA_BASE . '/lib/base.php';

    include_once TURBA_BASE . '/lib/Block/' . $type . '.php';
    $class = 'Horde_Block_Turba_' . $type;
    if (class_exists($class)) {
        return $ret = &new $class($params);
    }

    return PEAR::raiseError('Not found');
}

function _turba_import_vcard($source, $vcard_data)
{
    require_once dirname(__FILE__) . '/base.php';
    require_once 'Horde/Data.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require_once TURBA_BASE . '/lib/Object.php';
    global $cfgSources;

    if (empty($source) || !isset($cfgSources[$source])) {
        return PEAR::raiseError(_("Invalid address book."), 'horde.error', null, null, $source);
    }

    if ($cfgSources[$source]['readonly']
        && (!isset($cfgSources[$source]['admin'])
        || !in_array(Auth::getAuth(), $cfgSources[$source]['admin']))) {
        return PEAR::raiseError(_("Address book is read-only."), 'horde.error', null, null, $source);
    }

    $vcard = &Horde_Data::singleton('vcard');
    if (!$data = $vcard->importData($vcard_data)) {
        return PEAR::raiseError(_("There was an error importing the vCard data."));
    }

    $driver = &Turba_Source::singleton($source, $cfgSources[$source]);

    $objects = array();
    foreach ($data as $object) {
        if ($object['type'] == 'VCARD') {
            $hash = $vcard->toHash($object);
            $res = $driver->search($hash);
            if (is_a($res, 'PEAR_Error') || $res->count() > 0) {
                $objects[] = PEAR::raiseError(_("This person is already in your address book."), 'horde.message', null, null, $source);
            } else {
                $hash['__owner'] = Auth::getAuth();
                $objectID = $driver->addObject($hash);
                if (!is_a($objectID, 'PEAR_Error')) {
                    $objects[$objectID] = isset($hash['name']) ? $hash['name'] : _("Unnamed Contact");
                } else {
                    if (count($objects)) {
                        foreach ($objects as $id => $name) {
                            $driver->removeObject($id);
                        }
                    }
                    return PEAR::raiseError(_("There was an error importing the vCard data."));
                }
            }
        }
    }

    return $objects;
}

function _turba_search($names = array(), $addressbooks = array(), $fields = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (count($addressbooks) == 0) {
        $addressbooks = array(key($cfgSources));
    }

    $results = array();
    $seen = array();
    foreach ($addressbooks as $source) {
        if (isset($cfgSources[$source])) {
            $driver = &Turba_Source::singleton($source, $cfgSources[$source]);
            if (is_a($driver, 'PEAR_Error')) {
                return PEAR::raiseError(_("Failed to connect to the specified directory."), 'horde.error', null, null, $source);
            }

            foreach ($names as $name) {
                $criteria = array();
                if (isset($fields[$source])) {
                    foreach ($fields[$source] as $field) {
                        $criteria[$field] = trim($name);
                    }
                }
                if (count($criteria) == 0) {
                    $criteria['name'] = trim($name);
                }
                $res = $driver->search($criteria, 'lastname', 'OR');

                if (!isset($results[$name])) {
                    $results[$name] = array();
                }
                if (is_a($res, 'Turba_List')) {
                    while ($ob = $res->next()) {
                        if (!$ob->isGroup()) {
                            /* Not a group. */
                            $att = $ob->getAttributes();

                            $email = null;
                            foreach (array_keys($att) as $key) {
                                if ($ob->getValue($key) && isset($attributes[$key]) &&
                                    $attributes[$key]['type'] == 'email') {
                                    $email = $ob->getValue($key);
                                    break;
                                }
                            }
                            if (!is_null($email)) {
                                $seen_key = trim(String::lower($ob->getValue('name'))) . '/' . trim(String::lower($email));
                                if (!empty($seen[$seen_key])) {
                                    continue;
                                }
                                $seen[$seen_key] = true;
                            }
                            $results[$name][] = array_merge($att,
                                                array('id' => $att['__key'],
                                                      'name' => $ob->getValue('name'),
                                                      'email' => $email,
                                                      '__type' => 'Object',
                                                      'source' => $source));
                        } else {
                            /* Is a distribution list. */
                            $listatt = $ob->getAttributes();
                            $seeninlist = array();
                            $members = $ob->listMembers();
                            if (is_a($members, 'Turba_List')) {
                                if ($members->count() == 1) {
                                    $ob = $members->next();
                                    $att = $ob->getAttributes();
                                    $email = '';
                                    foreach ($att as $key => $value) {
                                        if (!empty($value) && isset($attributes[$key]) &&
                                            $attributes[$key]['type'] == 'email') {
                                            $email = $value;
                                        }
                                    }
                                    $results[$name][] = array('name' => $listatt['name'] . ' - ' . $att['name'], 'email' => $email, 'id' => $att['__key'], 'source' => $source );
                                } else {
                                    $email = '';
                                    while ($ob = $members->next()) {
                                        $att = $ob->getAttributes();
                                        foreach ($att as $key => $value) {
                                            if (!empty($value) && isset($attributes[$key]) &&
                                                $attributes[$key]['type'] == 'email' &&
                                                empty($seeninlist[trim(String::lower($att['name'])) . trim(String::lower($value))])) {

                                                $email .= ($email == '') ? '' : ', ';
                                                $email .= '"' . $att['name'] . '" <' . $value . '>';
                                                $seeninlist[trim(String::lower($att['name'])) . trim(String::lower($value))] = true;
                                            }
                                        }
                                    }
                                    $results[$name][] = array('name' => $listatt['name'], 'email' => $email, 'id' => $listatt['__key'], 'source' => $source);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return $results;
}

function _turba_clientSearch($names = array(), $fields = array())
{
    global $conf;
    return _turba_search($names, array($conf['client']['addressbook']),
                         $fields);
}

function _turba_add($name = '', $address = '', $addressbook = '')
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    global $cfgSources;

    if (empty($addressbook) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("Invalid address book."), 'horde.error', null, null, $addressbook);
    }

    if (empty($name)) {
        return PEAR::raiseError(_("Invalid name."), 'horde.error', null, null, $addressbook);
    }

    if (empty($address)) {
        return PEAR::raiseError(_("Invalid e-mail address."), 'horde.error', null, null, $addressbook);
    }

    if ($cfgSources[$addressbook]['readonly']
        && (!isset($cfgSources[$addressbook]['admin'])
        || !in_array(Auth::getAuth(), $cfgSources[$addressbook]['admin']))) {
        return PEAR::raiseError(_("Address book is read-only."), 'horde.error', null, null, $addressbook);
    }

    $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);
    $res = $driver->search(array('name' => $name, 'email' => $address));
    if (is_a($res, 'PEAR_Error') || $res->count() > 0) {
        return PEAR::raiseError(_("This person is already in your address book."), 'horde.message', null, null, $addressbook);
    }

    return $driver->addObject(array('name' => $name, 'email' => $address, '__owner' => Auth::getAuth()));
}

function _turba_sources($writeable = false)
{
    require_once dirname(__FILE__) . '/base.php';
    global $cfgSources;

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    $sources = array();
    foreach ($cfgSources as $key => $entry) {
        if (!$writeable || (!$entry['readonly'] ||
                           (isset($entry['admin']) && in_array(Auth::getAuth(), $entry['admin'])))) {
            $sources[$key] = $entry['title'];
        }
    }
    return $sources;
}

function _turba_fields($addressbook = '')
{
    require_once dirname(__FILE__) . '/base.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    if (empty($addressbook) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("Invalid address book."), 'horde.error', null, null, $addressbook);
    }

    $fields = array();
    foreach ($cfgSources[$addressbook]['map'] as $field_name => $null) {
        if (substr($field_name, 0, 2) != '__') {
            $fields[$field_name] = array('name' => $field_name,
                                         'type' => $attributes[$field_name]['type'],
                                         'label' => $attributes[$field_name]['label'],
                                         'search' => in_array($field_name, $cfgSources[$addressbook]['search']));
        }
    }

    return $fields;
}

/**
 * Returns an array of GUIDs for contacts that have had $action happen
 * since $timestamp.
 *
 * @param integer $timestamp  The time to start the search.
 * @param string  $action     The action to check for - add, modify, or delete.
 *
 * @return array  An array of GUIDs matching the action and time criteria.
 */
function &_turba_listBy($action, $timestamp)
{
    require_once dirname(__FILE__) . '/base.php';
    require_once 'Horde/History.php';

    $history = &Horde_History::singleton();
    $histories = $history->getByTimestamp('>', $timestamp, array(array('op' => '=', 'field' => 'action', 'value' => $action)), 'turba');
    if (is_a($histories, 'PEAR_Error')) {
        return $histories;
    }

    return array_keys($histories);
}

function _turba_addField($address = '', $name = '', $field = '', $value = '', $addressbook = '')
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    global $cfgSources;

    if (empty($addressbook) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("Invalid address book."), 'horde.error', null, null, $addressbook);
    }

    if (empty($address)) {
        return PEAR::raiseError(_("Invalid e-mail address."), 'horde.error', null, null, $addressbook);
    }

    if (empty($name)) {
        return PEAR::raiseError(_("Invalid name."), 'horde.error', null, null, $addressbook);
    }

    if (empty($value)) {
        return PEAR::raiseError(_("Invalid entry."), 'horde.error', null, null, $addressbook);
    }

    if ($cfgSources[$addressbook]['readonly']
        && (!isset($cfgSources[$addressbook]['admin'])
        || !in_array(Auth::getAuth(), $cfgSources[$addressbook]['admin']))) {
        return PEAR::raiseError(_("Address book is read-only."), 'horde.error', null, null, $addressbook);
    }

    $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);
    $res = $driver->search(array('email' => trim($address)), null, 'AND');
    if (is_a($res, 'PEAR_Error')) {
        return PEAR::raiseError(_("Error while searching directory."), 'horde.message', null, null, $addressbook);
    } elseif ($res->count() > 1) {
        $res2 = $driver->search(array('email' => trim($address), 'name' => trim($name)), null, 'AND');
        if (is_a($res2, 'PEAR_Error')) {
            return PEAR::raiseError(_("Error while searching directory."), 'horde.message', null, null, $addressbook);
        } elseif ($res2->count() > 0) {
            $res3 = $driver->search(array('email' => $address, 'name' => $name, $field => $value));
            if (is_a($res3, 'PEAR_Error')) {
                return PEAR::raiseError(_("Error while searching directory."), 'horde.message', null, null, $addressbook);
            } elseif ($res3->count() > 0) {
                return PEAR::raiseError(sprintf(_("This person already has a %s entry in the address book."), $field), 'horde.message', null, null, $addressbook);
            } else {
                $ob = $res2->next();
                $ob->setValue($field, $value);
                $ob->store();
            }
        } else {
            return PEAR::raiseError(sprintf(_("Multiple persons with address [%s], but none with name [%s] in address book."), trim($address), trim($name)), 'horde.message', null, null, $addressbook);
        }
    } elseif ($res->count() == 1) {
        $res4 = $driver->search(array('email' => $address, $field => $value));
        if (is_a($res4, 'PEAR_Error')) {
            return PEAR::raiseError(_("Error while searching directory."), 'horde.message', null, null, $addressbook);
        } elseif ($res4->count() > 0) {
            return PEAR::raiseError(sprintf(_("This person already has a %s entry in the address book."), $field), 'horde.message', null, null, $addressbook);
        } else {
            $ob = $res->next();
            $ob->setValue($field, $value);
            $ob->store();
        }
    } else {
        return $driver->addObject(array('email' => $address, 'name' => $name, $field => $value, '__owner' => Auth::getAuth()));
    }

    return;
}

function _turba_getField($address = '', $field = '', $addressbooks = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    if (empty($address)) {
        return PEAR::raiseError(_("Invalid email."), 'horde.error');
    }

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (count($addressbooks) == 0) {
        $addressbooks = array(key($cfgSources));
    }

    $count = 0;
    foreach ($addressbooks as $source) {
        if (isset($cfgSources[$source])) {
            $driver = &Turba_Source::singleton($source, $cfgSources[$source]);
            if (!is_a($driver, 'PEAR_Error')) {
                $res = $driver->search(array('email' => $address));
                if (is_a($res, 'Turba_List')) {
                    $count += $res->count();
                    if ($res->count() == 1) {
                        $ob = $res->next();
                        if ($ob->hasValue($field)) {
                            $result = $ob->getValue($field);
                        }
                    }
                }
            }
        }
    }

    if ($count > 1) {
        return PEAR::raiseError(_("More than 1 entry returned."), 'horde.warning', null, null, $source);
    } elseif (!isset($result)) {
        return PEAR::raiseError(sprintf(_("No %s entry found for %s."), $field, $address), 'horde.warning', null, null, $source);
    }

    return $result;
}

function _turba_getContact($addressbook = '', $key = '')
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;
    $result = array();

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (isset($cfgSources[$addressbook])) {
        $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);
        if (!is_a($driver, 'PEAR_Error')) {
            $object = $driver->getObject($key);
            /* Check permissions on this object. */
            if (Turba::checkPermissions($object, 'object', PERMS_READ)) {
                $result = $object->attributes;
            }
        }
    }

    return $result;
}

function _turba_getContacts($addressbook = '', $keys = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;
    $result = array();
    if (!is_array($keys)) {
        $keys = array($keys);
    }

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (isset($cfgSources[$addressbook])) {
        $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);
        if (!is_a($driver, 'PEAR_Error')) {
            $objects = $driver->getObjects($keys);
            foreach ($objects as $object) {
                /* Check permissions on this object. */
                if (Turba::checkPermissions($object, 'object', PERMS_READ)) {
                    $result[] = $object->attributes;
                }
            }
        }
    }

    return $result;
}


function _turba_addContact($addressbook = '', $attributes = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    global $cfgSources;

    $key = null;

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("The source you requested does not exist."), 'horde.warning');
    }

    $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);

    /* Create Object. */
    $key = $driver->addObject($attributes);

    return $key;
}

function _turba_updateContact($addressbook = '', $key = '', $attributes = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    global $cfgSources;

    $result = null;

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("The object you requested does not exist."), 'horde.warning');
    }

    $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);

    $object = $driver->getObject($key);
    /* Check permissions on this object. */
    if (!Turba::checkPermissions($object, 'object', PERMS_EDIT)) {
        $result = PEAR::raiseError(_("You do not have permission to edit this object."), 'horde.warning');
    } else {
        foreach ($attributes as $info_key => $info_val) {
            if ($info_key != '__key') {
                $object->setValue($info_key, $info_val);
            }
        }
        $success = $object->store();
        if (!is_a($success, 'PEAR_Error')) {
            $result = PEAR::raiseError(sprintf(_("Entry for %s updated."), $object->getValue('name')), 'horde.success');
        } else {
            $result = PEAR::raiseError(sprintf(_("There was an error updating this entry: %s."), $success->getMessage()), 'horde.error');
        }
    }

    return $result;
}

function _turba_deleteContact($addressbook = '', $key = '')
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    global $cfgSources;

    if (empty($addressbook) || !isset($cfgSources[$addressbook])) {
        return PEAR::raiseError(_("Invalid address book."), 'horde.error', null, null, $addressbook);
    }

    if (empty($key)) {
        return PEAR::raiseError(_("Invalid key."), 'horde.error', null, null, $addressbook);
    }

    if ($cfgSources[$addressbook]['readonly']
        && (!isset($cfgSources[$addressbook]['admin'])
            || !in_array(Auth::getAuth(), $cfgSources[$addressbook]['admin']))) {
        return PEAR::raiseError(_("Address book is read-only."), 'horde.error', null, null, $addressbook);
    }

    $driver = &Turba_Source::singleton($addressbook, $cfgSources[$addressbook]);

    // Check if entry is in addressbook, if not raise a warning.
    $res = $driver->search(array('__key' => $key));
    if (is_a($res, 'PEAR_Error') || $res->count() == 0) {
        return PEAR::raiseError(_("Address not in addressbook."), 'horde.warning', null, null, $addressbook);
    }

    if (!$driver->removeObject($key)) {
        return PEAR::raiseError(_("There was an error deleting this entry."), 'horde.message', null, null, $addressbook);
    }

    return true;
}

function _turba_clientSourceConfigured()
{
    global $conf;
    if (!empty($conf['client']['addressbook'])) {
        return true;
    } else {
        return false;
    }
}

function _turba_getClient($key = '')
{
    global $conf;
    $args = array('addressbook' => $conf['client']['addressbook'],
                  'key' => $key);
    return $GLOBALS['registry']->call('clients/getContact', $args);
}

function _turba_getClients($keys = array())
{
    global $conf;
    $args = array('addressbook' => $conf['client']['addressbook'],
                  'keys' => $keys);
    return $GLOBALS['registry']->call('clients/getContacts', $args);
}

function _turba_getClientSource()
{
    global $conf;
    return $conf['client']['addressbook'];
}

function _turba_addClient($attributes = array())
{
    $addressbook = $GLOBALS['registry']->call('clients/getClientSource', array());
    return $GLOBALS['registry']->call('clients/addContact', array($addressbook, $attributes));
}

function _turba_updateClient($key = '', $attributes = array())
{
    $addressbook = $GLOBALS['registry']->call('clients/getClientSource', array());
    return $GLOBALS['registry']->call('clients/updateContact', array($addressbook, $key, $attributes));
}

function _turba_deleteClient($key = '')
{
    $addressbook = $GLOBALS['registry']->call('clients/getClientSource', array());
    return $GLOBALS['registry']->call('clients/deleteContact', array($addressbook, $key));
}

function _turba_getFieldById($source, $id, $field)
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    if (empty($id)) {
        return PEAR::raiseError(_("Empty key"), 'horde.error');
    }

    if (empty($source)) {
        return PEAR::raiseError(_("Empty source"), 'horde.error');
    }

    if (!isset($cfgSources[$source])) {
        return PEAR::raiseError(_("Unknown source"), 'horde.error');
    }

    $count = 0;
    $driver = &Turba_Source::singleton($source, $cfgSources[$source]);
    if (is_a($driver, 'PEAR_Error')) {
        return PEAR::raiseError(_("Failed to connect to the specified directory."), 'horde.error', null, null, $source);
    }

    $ob = $driver->getObject($id);
    if ($ob->hasValue($field)) {
        return $ob->getValue($field);
    } else {
        return PEAR::raiseError(sprintf(_("No %s entry found for %s."), $field, $address), 'horde.warning', null, null, $source);
    }
}

function _turba_listField($field = '', $addressbooks = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    $results = array();

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (count($addressbooks) == 0) {
        $addressbooks = array(key($cfgSources));
    }

    foreach ($addressbooks as $source) {
        if (isset($cfgSources[$source])) {
            $driver = &Turba_Source::singleton($source, $cfgSources[$source]);
            if (is_a($driver, 'PEAR_Error')) {
                return PEAR::raiseError(_("Failed to connect to the specified directory."), 'horde.error', null, null, $source);
            } else {
                $res = $driver->search(array());
                if (is_a($res, 'Turba_List')) {
                    while ($ob = $res->next()) {
                        if ($ob->hasValue($field)) {
                            $results[$ob->getValue('email')]['name'] = $ob->getValue('name');
                            $results[$ob->getValue('email')][$field] = $ob->getValue($field);
                        }
                    }
                } else {
                    return PEAR::raiseError(_("Failed to search the specified directory."), 'horde.error', null, null, $source);
                }
            }
        }
    }

    return $results;
}

function _turba_deleteField($address = '', $field = '', $addressbooks = array())
{
    require_once dirname(__FILE__) . '/base.php';
    require_once TURBA_BASE . '/lib/Source.php';
    require TURBA_BASE . '/config/attributes.php';
    global $cfgSources;

    if (empty($address)) {
        return PEAR::raiseError(_("Invalid email."), 'horde.error');
    }

    if (!isset($cfgSources) || !is_array($cfgSources) || !count($cfgSources)) {
        return array();
    }

    if (count($addressbooks) == 0) {
        $addressbooks = array(key($cfgSources));
    }

    foreach ($addressbooks as $source) {
        if (isset($cfgSources[$source])) {
            $driver = &Turba_Source::singleton($source, $cfgSources[$source]);
            if (is_a($driver, 'PEAR_Error')) {
                return PEAR::raiseError(_("Failed to connect to the specified directory."), 'horde.error', null, null, $source);
            } else {
                $res = $driver->search(array('email' => $address));
                if (is_a($res, 'Turba_List')) {
                    if ($res->count() > 1) {
                        return PEAR::raiseError(_("More than 1 entry returned."), 'horde.error', null, null, $source);
                    } else {
                        $ob = $res->next();
                        if (is_object($ob) && $ob->hasValue($field)) {
                            $ob->setValue($field, '');
                            $ob->store();
                        } else {
                            return PEAR::raiseError(sprintf(_("No %s entry found for %s."), $field, $address), 'horde.error', null, null, $source);
                        }
                    }
                }
            }
        }
    }

    return;
}

function _turba_linkParameters()
{
    return array('source', 'id');
}

function _turba_getLinkDescription($link_data = array())
{
    if (!isset($link_data['to_params']['source']) || !isset($link_data['to_params']['to_value'])) {
        return PEAR::raiseError(_("Missing information"));
    }
    return _turba_getFieldById($link_data['to_params']['source'], $link_data['to_params']['to_value'], $field = 'name');
}

function _turba_getLinkSummary($link_data = array())
{
    if (!isset($link_data['to_params']['source']) || !isset($link_data['to_params']['to_value'])) {
        return PEAR::raiseError(_("Missing information"));
    }
    $source = $link_data['to_params']['source'];
    $id = $link_data['to_params']['to_value'];
    $t = _turba_getFieldById($source, $id, $field = 'name');
    if (!is_a($t, 'PEAR_Error')) {
        return $t;
    } else {
        return _("Contact not found.") . "source: $source. id: $id";
    }
}

--- NEW FILE: base.php ---
<?php
/**
 * Turba base inclusion file.
 *
 * $Horde: turba/lib/base.php,v 1.58 2004/04/07 14:43:52 chuck Exp $
 *
 * This file brings in all of the dependencies that every Turba script
 * will need, and sets up objects that all scripts use.
 */

// Check for a prior definition of HORDE_BASE (perhaps by an
// auto_prepend_file definition for site customization).
if (!defined('HORDE_BASE')) {
    @define('HORDE_BASE', dirname(__FILE__) . '/../..');
}

// Load the Horde Framework core, and set up inclusion paths.
require_once HORDE_BASE . '/lib/core.php';

// Registry.
$registry = &Registry::singleton();
if (is_a(($pushed = $registry->pushApp('turba', !defined('AUTH_HANDLER'))), 'PEAR_Error')) {
    if ($pushed->getCode() == 'permission_denied') {
        Horde::authenticationFailureRedirect();
    }
    Horde::fatal($pushed, __FILE__, __LINE__, false);
}
$conf = &$GLOBALS['conf'];
@define('TURBA_TEMPLATES', $registry->getParam('templates'));

// Notification system.
$notification = &Notification::singleton();
$notification->attach('status');

// Find the base file path of Turba.
@define('TURBA_BASE', dirname(__FILE__) . '/..');

// Turba base library.
require_once TURBA_BASE . '/lib/Turba.php';

// Turba sources configuration.
require TURBA_BASE . '/config/sources.php';
$GLOBALS['cfgSources'] = Turba::permissionsFilter($cfgSources, 'source');

// Help.
require_once 'Horde/Help.php';

/* Start compression, if requested. */
Horde::compressOutput();

--- NEW FILE: prefs.php ---
<?php
/**
 * $Horde: turba/lib/prefs.php,v 1.1 2004/02/23 07:20:29 slusarz Exp $
 *
 * Copyright 2001-2004 Jon Parise <jon at horde.org>
 * Copyright 2002-2004 Jan Schneider <jan at horde.org>
 *
 * See the enclosed file COPYING for license information (GPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 */

function handle_columnselect($updated)
{
    $columns = Util::getFormData('columns');
    if (!empty($columns)) {
        $GLOBALS['prefs']->setValue('columns', $columns);
        return true;
    }

    return false;
}

/* Assign variables for select lists. */
if (!$prefs->isLocked('default_dir')) {
    $default_dir_options = array();
    foreach ($cfgSources as $key => $info) {
        $default_dir_options[$key] = $info['title'];
    }
}

--- NEW FILE: version.php ---
<?php define('TURBA_VERSION', '2.0-cvs') ?>





More information about the commits mailing list