Revert "Remove DataTree code from Horde_Perms"
authorChuck Hagenbuch <chuck@horde.org>
Sat, 17 Jul 2010 04:38:08 +0000 (00:38 -0400)
committerChuck Hagenbuch <chuck@horde.org>
Sat, 17 Jul 2010 04:38:08 +0000 (00:38 -0400)
This reverts commit f866a2f5cb272ffe5cd0857b84774107d0df85f9, except for
removing the DataTree support from the Perms binder, which has been kept.

framework/Perms/lib/Horde/Perms/Datatree.php [new file with mode: 0644]
framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php [new file with mode: 0644]
framework/Perms/package.xml

diff --git a/framework/Perms/lib/Horde/Perms/Datatree.php b/framework/Perms/lib/Horde/Perms/Datatree.php
new file mode 100644 (file)
index 0000000..85e5a90
--- /dev/null
@@ -0,0 +1,248 @@
+<?php
+/**
+ * The Horde_Perms_Datatree:: class provides a DataTree driver for the Horde
+ * permissions system.
+ *
+ * Copyright 2001-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @author   Jan Schneider <jan@horde.org>
+ * @category Horde
+ * @package  Horde_Perms
+ */
+class Horde_Perms_Datatree extends Horde_Perms
+{
+    /**
+     * Pointer to a DataTree instance to manage the different permissions.
+     *
+     * @var DataTree
+     */
+    protected $_datatree;
+
+    /**
+     * Incrementing version number if cached classes change.
+     *
+     * @var integer
+     */
+    private $_cacheVersion = 2;
+
+    /**
+     * Cache for getPermission().
+     *
+     * @var array
+     */
+    protected $_permsCache = array();
+
+    /**
+     * Constructor.
+     *
+     * @param array $params  Configuration parameters (in addition to base
+     *                       Horde_Perms parameters):
+     * <pre>
+     * 'datatree' - (DataTree) A datatree object. [REQUIRED]
+     * </pre>
+     *
+     * @throws Horde_Perms_Exception
+     */
+    public function __construct($params = array())
+    {
+        if (empty($params['datatree'])) {
+            throw new Horde_Perms_Exception('You must configure a DataTree backend.');
+        }
+
+        $this->_datatree = $params['datatree'];
+
+        parent::__construct($params);
+    }
+
+    /**
+     * Returns a new permissions object.
+     *
+     * @param string $name  The permission's name.
+     *
+     * @return DataTreeObject_Permissions  A new permissions object.
+     */
+    public function newPermission($name)
+    {
+        $type = 'matrix';
+        $params = null;
+
+        if ($pos = strpos($name, ':')) {
+            try {
+                $info = $this->getApplicationPermissions(substr($name, 0, $pos));
+                if (isset($info['type']) && isset($info['type'][$name])) {
+                    $type = $info['type'][$name];
+                }
+
+                if (isset($info['params']) && isset($info['params'][$name])) {
+                    $params = $info['params'][$name];
+                }
+            } catch (Horde_Perms_Exception $e) {}
+        }
+
+        $perm = new Horde_Perms_Permission_DataTreeObject($name, $this->_cacheVersion, $type, $params);
+        $perm->setCacheOb($this->_cache);
+        $perm->setDataTree($this->_datatree);
+
+        return $perm;
+    }
+
+    /**
+     * Returns a permission object corresponding to the named permission,
+     * with the users and other data retrieved appropriately.
+     *
+     * @param string $name  The name of the permission to retrieve.
+     *
+     * @return TODO
+     */
+    public function getPermission($name)
+    {
+        if (isset($this->_permsCache[$name])) {
+            return $this->_permsCache[$name];
+        }
+
+        $perm = $this->_cache->get('perm_' . $this->_cacheVersion . $name, $GLOBALS['conf']['cache']['default_lifetime']);
+        if ($perm === false) {
+            $perm = $this->_datatree->getObject($name, 'Horde_Perms_Permission_DataTreeObject');
+            $perm->setCacheVersion($this->_cacheVersion);
+            $this->_cache->set('perm_' . $this->_cacheVersion . $name, serialize($perm), $GLOBALS['conf']['cache']['default_lifetime']);
+            $this->_permsCache[$name] = $perm;
+        } else {
+            $this->_permsCache[$name] = unserialize($perm);
+        }
+
+        $this->_permsCache[$name]->setCacheOb($this->_cache);
+        $this->_permsCache[$name]->setDataTree($this->_datatree);
+
+        return $this->_permsCache[$name];
+    }
+
+    /**
+     * Returns a permission object corresponding to the given unique ID,
+     * with the users and other data retrieved appropriately.
+     *
+     * @param integer $cid  The unique ID of the permission to retrieve.
+     */
+    public function getPermissionById($cid)
+    {
+        if ($cid == Horde_Perms::ROOT) {
+            return $this->newPermission(Horde_Perms::ROOT);
+        }
+        $perm = $this->_datatree->getObjectById($cid, 'Horde_Perms_Permission_DataTreeObject');
+        $perm->setCacheVersion($this->_cacheVersion);
+        return $perm;
+    }
+
+    /**
+     * Adds a permission to the permissions system. The permission must first
+     * be created with newPermission(), and have any initial users added to
+     * it, before this function is called.
+     *
+     * @param Horde_Perms_Permission_DataTreeObject $perm  The new perm
+     *                                                     object.
+     * @throws Horde_Perms_Exception
+     */
+    public function addPermission(Horde_Perms_Permission_DataTreeObject $perm)
+    {
+        $name = $perm->getName();
+        if (empty($name)) {
+            throw Horde_Perms_Exception('Permission names must be non-empty.');
+        }
+        $this->_cache->expire('perm_' . $this->_cacheVersion . $name);
+        $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $name);
+
+        return $this->_datatree->add($perm);
+    }
+
+    /**
+     * Removes a permission from the permissions system permanently.
+     *
+     * @param Horde_Perms_Permission_DataTreeObject $perm  The permission to
+     *                                                     remove.
+     * @param boolean $force                               Force to remove
+     *                                                     every child.
+     */
+    public function removePermission(Horde_Perms_Permission_DataTreeObject $perm, $force = false)
+    {
+        $keys = $this->_datatree->get(DATATREE_FORMAT_FLAT, $perm->name, true);
+        foreach ($keys as $key) {
+            $this->_cache->expire('perm_' . $this->_cacheVersion . $key);
+            $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $key);
+        }
+
+        return $this->_datatree->remove($perm->name, $force);
+    }
+
+    /**
+     * Returns the unique identifier of this permission.
+     *
+     * @param Horde_Perms_Permission_DataTreeObject $perm  The permission
+     *                                                     object to get the
+     *                                                     ID of.
+     *
+     * @return integer  The unique id.
+     */
+    public function getPermissionId($permission)
+    {
+        return $this->_datatree->getId($permission->getName());
+    }
+
+    /**
+     * Checks if a permission exists in the system.
+     *
+     * @param string $permission  The permission to check.
+     *
+     * @return boolean  True if the permission exists.
+     */
+    public function exists($permission)
+    {
+        $key = 'perm_exists_' . $this->_cacheVersion . $permission;
+        $exists = $this->_cache->get($key, $GLOBALS['conf']['cache']['default_lifetime']);
+        if ($exists === false) {
+            $exists = $this->_datatree->exists($permission);
+            $this->_cache->set($key, (string)$exists);
+        }
+
+        return (bool)$exists;
+    }
+
+    /**
+     * Returns a list of parent permissions.
+     *
+     * @param string $child  The name of the child to retrieve parents for.
+     *
+     * @return array  A hash with all parents in a tree format.
+     */
+    public function getParents($child)
+    {
+        return $this->_datatree->getParents($child);
+    }
+
+    /**
+     * Returns a child's direct parent ID.
+     *
+     * @param mixed $child  Either the object, an array containing the
+     *                      path elements, or the object name for which
+     *                      to look up the parent's ID.
+     *
+     * @return mixed  The unique ID of the parent or PEAR_Error on error.
+     */
+    public function getParent($child)
+    {
+        return $this->_datatree->getParent($child);
+    }
+
+    /**
+     * Returns all permissions of the system in a tree format.
+     *
+     * @return array  A hash with all permissions in a tree format.
+     */
+    public function getTree()
+    {
+        return $this->_datatree->get(DATATREE_FORMAT_FLAT, Horde_Perms::ROOT, true);
+    }
+
+}
diff --git a/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php b/framework/Perms/lib/Horde/Perms/Permission/DataTreeObject.php
new file mode 100644 (file)
index 0000000..af66847
--- /dev/null
@@ -0,0 +1,590 @@
+<?php
+/**
+ * Extension of the DataTreeObject class for storing Permission information in
+ * the DataTree driver. If you want to store specialized Permission
+ * information, you should extend this class instead of extending
+ * DataTreeObject directly.
+ *
+ * @TODO This class duplicates most of the functionality of the
+ * Horde_Permission class. However, because for BC/DataTree reasons it
+ * must extend DataTreeObject, we can't remove these methods yet.
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @author   Jan Schneider <jan@horde.org>
+ * @category Horde
+ * @package  Horde_Perms
+ */
+class Horde_Perms_Permission_DataTreeObject extends DataTreeObject
+{
+    /**
+     * Cache object.
+     *
+     * @var Horde_Cache
+     */
+    protected $_cache;
+
+    /**
+     * Constructor. Just makes sure to call the parent constructor so that
+     * the perm's name is set properly.
+     *
+     * @param string $name   The name of the perm.
+     * @param string $type   The permission type.
+     * @param array $params  A hash with any parameters that the permission
+     *                       type needs.
+     */
+    public function __construct($name, $type = 'matrix', $params = null)
+    {
+        parent::DataTreeObject($name);
+
+        $this->data['type'] = $type;
+        if (is_array($params)) {
+            $this->data['params'] = $params;
+        }
+    }
+
+    /**
+     * Don't store cache object on serialize().
+     *
+     * @return array  List of variables to serialize.
+     */
+    public function __sleep()
+    {
+        return array_diff(array_keys(get_class_vars(__CLASS__)), array('_cache'));
+    }
+
+    /**
+     * Sets the cache instance in the object.
+     *
+     * @param Horde_Cache $cache  The cache object.
+     */
+    public function setCacheOb(Horde_Cache $cache)
+    {
+        $this->_cache = $cache;
+    }
+
+    /**
+     * Gets one of the attributes of the object, or null if it isn't defined.
+     *
+     * @param string $attribute  The attribute to get.
+     *
+     * @return mixed  The value of the attribute, or null.
+     */
+    public function get($attribute)
+    {
+        $value = parent::get($attribute);
+
+        return (is_null($value) && $attribute == 'type')
+            ? 'matrix'
+            : $value;
+    }
+
+    /**
+     * Updates the permissions based on data passed in the array.
+     *
+     * @param array $perms  An array containing the permissions which are to
+     *                      be updated.
+     */
+    public function updatePermissions($perms)
+    {
+        $type = $this->get('type');
+
+        if ($type == 'matrix') {
+            /* Array of permission types to iterate through. */
+            $perm_types = Horde_Perms::getPermsArray();
+        }
+
+        foreach ($perms as $perm_class => $perm_values) {
+            switch ($perm_class) {
+            case 'default':
+            case 'guest':
+            case 'creator':
+                if ($type == 'matrix') {
+                    foreach ($perm_types as $val => $label) {
+                        if (!empty($perm_values[$val])) {
+                            $this->setPerm($perm_class, $val, false);
+                        } else {
+                            $this->unsetPerm($perm_class, $val, false);
+                        }
+                    }
+                } elseif (!empty($perm_values)) {
+                    $this->setPerm($perm_class, $perm_values, false);
+                } else {
+                    $this->unsetPerm($perm_class, null, false);
+                }
+                break;
+
+            case 'u':
+            case 'g':
+                $permId = array('class' => $perm_class == 'u' ? 'users' : 'groups');
+                /* Figure out what names that are stored in this permission
+                 * class have not been submitted for an update, ie. have been
+                 * removed entirely. */
+                $current_names = isset($this->data[$permId['class']])
+                    ? array_keys($this->data[$permId['class']])
+                    : array();
+                $updated_names = array_keys($perm_values);
+                $removed_names = array_diff($current_names, $updated_names);
+
+                /* Remove any names that have been completely unset. */
+                foreach ($removed_names as $name) {
+                    unset($this->data[$permId['class']][$name]);
+                }
+
+                /* If nothing to actually update finish with this case. */
+                if (is_null($perm_values)) {
+                    continue;
+                }
+
+                /* Loop through the names and update permissions for each. */
+                foreach ($perm_values as $name => $name_values) {
+                    $permId['name'] = $name;
+
+                    if ($type == 'matrix') {
+                        foreach ($perm_types as $val => $label) {
+                            if (!empty($name_values[$val])) {
+                                $this->setPerm($permId, $val, false);
+                            } else {
+                                $this->unsetPerm($permId, $val, false);
+                            }
+                        }
+                    } elseif (!empty($name_values)) {
+                        $this->setPerm($permId, $name_values, false);
+                    } else {
+                        $this->unsetPerm($permId, null, false);
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    /**
+     * TODO
+     */
+    public function setPerm($permId, $permission, $update = true)
+    {
+        if (is_array($permId)) {
+            if (empty($permId['name'])) {
+                return;
+            }
+            if ($this->get('type') == 'matrix' &&
+                isset($this->data[$permId['class']][$permId['name']])) {
+                $this->data[$permId['class']][$permId['name']] |= $permission;
+            } else {
+                $this->data[$permId['class']][$permId['name']] = $permission;
+            }
+        } else {
+            if ($this->get('type') == 'matrix' &&
+                isset($this->data[$permId])) {
+                $this->data[$permId] |= $permission;
+            } else {
+                $this->data[$permId] = $permission;
+            }
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * TODO
+     */
+    public function unsetPerm($permId, $permission, $update = true)
+    {
+        if (is_array($permId)) {
+            if (empty($permId['name'])) {
+                return;
+            }
+            if ($this->get('type') == 'matrix') {
+                if (isset($this->data[$permId['class']][$permId['name']])) {
+                    $this->data[$permId['class']][$permId['name']] &= ~$permission;
+                    if (empty($this->data[$permId['class']][$permId['name']])) {
+                        unset($this->data[$permId['class']][$permId['name']]);
+                    }
+                    if ($update) {
+                        $this->save();
+                    }
+                }
+            } else {
+                unset($this->data[$permId['class']][$permId['name']]);
+                if ($update) {
+                    $this->save();
+                }
+            }
+        } else {
+            if ($this->get('type') == 'matrix') {
+                if (isset($this->data[$permId])) {
+                    $this->data[$permId] &= ~$permission;
+                    if ($update) {
+                        $this->save();
+                    }
+                }
+            } else {
+                unset($this->data[$permId]);
+                if ($update) {
+                    $this->save();
+                }
+            }
+        }
+    }
+
+    /**
+     * Grants a user additional permissions to this object.
+     *
+     * @param string $user         The user to grant additional permissions
+     *                             to.
+     * @param integer $permission  The permission (DELETE, etc.) to add.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function addUserPermission($user, $permission, $update = true)
+    {
+        if (empty($user)) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix' &&
+            isset($this->data['users'][$user])) {
+            $this->data['users'][$user] |= $permission;
+        } else {
+            $this->data['users'][$user] = $permission;
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Grants guests additional permissions to this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to add.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function addGuestPermission($permission, $update = true)
+    {
+        if ($this->get('type') == 'matrix' &&
+            isset($this->data['guest'])) {
+            $this->data['guest'] |= $permission;
+        } else {
+            $this->data['guest'] = $permission;
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Grants creators additional permissions to this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to add.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function addCreatorPermission($permission, $update = true)
+    {
+        if ($this->get('type') == 'matrix' &&
+            isset($this->data['creator'])) {
+            $this->data['creator'] |= $permission;
+        } else {
+            $this->data['creator'] = $permission;
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Grants additional default permissions to this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to add.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function addDefaultPermission($permission, $update = true)
+    {
+        if ($this->get('type') == 'matrix' &&
+            isset($this->data['default'])) {
+            $this->data['default'] |= $permission;
+        } else {
+            $this->data['default'] = $permission;
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Grants a group additional permissions to this object.
+     *
+     * @param integer $groupId     The id of the group to grant additional
+     *                             permissions to.
+     * @param integer $permission  The permission (DELETE, etc.) to add.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function addGroupPermission($groupId, $permission, $update = true)
+    {
+        if (empty($groupId)) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix' &&
+            isset($this->data['groups'][$groupId])) {
+            $this->data['groups'][$groupId] |= $permission;
+        } else {
+            $this->data['groups'][$groupId] = $permission;
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Removes a permission that a user currently has on this object.
+     *
+     * @param string $user         The user to remove the permission from.
+     * @param integer $permission  The permission (DELETE, etc.) to
+     *                             remove.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function removeUserPermission($user, $permission, $update = true)
+    {
+        if (empty($user) || !isset($this->data['users'][$user])) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix') {
+            $this->data['users'][$user] &= ~$permission;
+            if (empty($this->data['users'][$user])) {
+                unset($this->data['users'][$user]);
+            }
+        } else {
+            unset($this->data['users'][$user]);
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Removes a permission that guests currently have on this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to remove.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function removeGuestPermission($permission, $update = true)
+    {
+        if (!isset($this->data['guest'])) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix') {
+            $this->data['guest'] &= ~$permission;
+        } else {
+            unset($this->data['guest']);
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Removes a permission that creators currently have on this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to remove.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function removeCreatorPermission($permission, $update = true)
+    {
+        if (!isset($this->data['creator'])) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix') {
+            $this->data['creator'] &= ~$permission;
+        } else {
+            unset($this->data['creator']);
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Removes a default permission on this object.
+     *
+     * @param integer $permission  The permission (DELETE, etc.) to remove.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function removeDefaultPermission($permission, $update = true)
+    {
+        if (!isset($this->data['default'])) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix') {
+            $this->data['default'] &= ~$permission;
+        } else {
+            unset($this->data['default']);
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Removes a permission that a group currently has on this object.
+     *
+     * @param integer $groupId     The id of the group to remove the
+     *                             permission from.
+     * @param integer $permission  The permission (DELETE, etc.) to remove.
+     * @param boolean $update      Whether to automatically update the
+     *                             backend.
+     */
+    public function removeGroupPermission($groupId, $permission,
+                                          $update = true)
+    {
+        if (empty($groupId) || !isset($this->data['groups'][$groupId])) {
+            return;
+        }
+
+        if ($this->get('type') == 'matrix') {
+            $this->data['groups'][$groupId] &= ~$permission;
+            if (empty($this->data['groups'][$groupId])) {
+                unset($this->data['groups'][$groupId]);
+            }
+        } else {
+            unset($this->data['groups'][$groupId]);
+        }
+
+        if ($update) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Returns an array of all user permissions on this object.
+     *
+     * @param integer $perm  List only users with this permission level.
+     *                       Defaults to all users.
+     *
+     * @return array  All user permissions for this object, indexed by user.
+     */
+    public function getUserPermissions($perm = null)
+    {
+        if (!isset($this->data['users']) || !is_array($this->data['users'])) {
+            return array();
+        } elseif (!$perm) {
+            return $this->data['users'];
+        }
+
+        $users = array();
+        foreach ($this->data['users'] as $user => $uperm) {
+            if ($uperm & $perm) {
+                $users[$user] = $uperm;
+            }
+        }
+
+        return $users;
+    }
+
+    /**
+     * Returns the guest permissions on this object.
+     *
+     * @return integer  The guest permissions on this object.
+     */
+    public function getGuestPermissions()
+    {
+        return empty($this->data['guest'])
+            ? null
+            : $this->data['guest'];
+    }
+
+    /**
+     * Returns the creator permissions on this object.
+     *
+     * @return integer  The creator permissions on this object.
+     */
+    public function getCreatorPermissions()
+    {
+        return empty($this->data['creator'])
+            ? null
+            : $this->data['creator'];
+    }
+
+    /**
+     * Returns the default permissions on this object.
+     *
+     * @return integer  The default permissions on this object.
+     */
+    public function getDefaultPermissions()
+    {
+        return empty($this->data['default'])
+            ? null
+            : $this->data['default'];
+    }
+
+    /**
+     * Returns an array of all group permissions on this object.
+     *
+     * @param integer $perm  List only users with this permission level.
+     *                       Defaults to all users.
+     *
+     * @return array  All group permissions for this object, indexed by group.
+     */
+    public function getGroupPermissions($perm = null)
+    {
+        if (!isset($this->data['groups']) ||
+            !is_array($this->data['groups'])) {
+            return array();
+        } elseif (!$perm) {
+            return $this->data['groups'];
+        }
+
+        $groups = array();
+        foreach ($this->data['groups'] as $group => $gperm) {
+            if ($gperm & $perm) {
+                $groups[$group] = $gperm;
+            }
+        }
+
+        return $groups;
+    }
+
+    /**
+     * Saves any changes to this object to the backend permanently. New
+     * objects are added instead.
+     *
+     * @throws Horde_Perms_Exception
+     */
+    public function save()
+    {
+        $name = $this->getName();
+        if (empty($name)) {
+            throw new Horde_Perms_Exception('Permission names must be non-empty');
+        }
+
+        parent::save();
+
+        if ($this->_cache) {
+            $this->_cache->expire('perm_' . $this->_cacheVersion . $name);
+            $this->_cache->expire('perm_exists_' . $this->_cacheVersion . $name);
+        }
+    }
+
+}
index 5a13b5e..dc9c39d 100644 (file)
@@ -39,8 +39,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
     <dir name="Horde">
      <dir name="Perms">
       <dir name="Permission">
+       <file name="DataTreeObject.php" role="php" />
        <file name="SqlObject.php" role="php" />
       </dir> <!-- /lib/Horde/Perms/Permission -->
+      <file name="Datatree.php" role="php" />
       <file name="Exception.php" role="php" />
       <file name="Permission.php" role="php" />
       <file name="Sql.php" role="php" />
@@ -72,6 +74,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
   </required>
   <optional>
    <package>
+    <name>Horde_DataTree</name>
+    <channel>pear.horde.org</channel>
+   </package>
+   <package>
     <name>Tree</name>
     <channel>pear.horde.org</channel>
    </package>
@@ -79,8 +85,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
  </dependencies>
  <phprelease>
   <filelist>
+   <install name="lib/Horde/Perms/Datatree.php" as="Horde/Perms/Datatree.php" />
    <install name="lib/Horde/Perms/Exception.php" as="Horde/Perms/Exception.php" />
    <install name="lib/Horde/Perms/Permission.php" as="Horde/Perms/Permission.php" />
+   <install name="lib/Horde/Perms/Permission/DataTreeObject.php" as="Horde/Perms/Permission/DataTreeObject.php" />
    <install name="lib/Horde/Perms/Permission/SqlObject.php" as="Horde/Perms/Permission/SqlObject.php" />
    <install name="lib/Horde/Perms/Sql.php" as="Horde/Perms/Sql.php" />
    <install name="lib/Horde/Perms.php" as="Horde/Perms.php" />