* @author Michael J. Rubinsky <mrubinsk@horde.org>
* @package Ansel
*/
-
-/** Horde_Share */
-require_once 'Horde/Share.php';
-
-/** Need to bring this in explicitly since we extend the object class */
-require_once 'Horde/Share/sql_hierarchical.php';
-
class Ansel
{
/**
// should be encapsulated by the shares driver and not parsed from
// an internally generated query string fragment. Will need to split
// this out into two seperate operations somehow.
- $share = substr($GLOBALS['ansel_storage']->shares->_getShareCriteria(
+ $share = substr($GLOBALS['ansel_storage']->shares->getShareCriteria(
Horde_Auth::getAuth(), Horde_Perms::READ), 5);
$sql = 'SELECT f.face_id, f.gallery_id, f.image_id, f.face_name FROM ansel_faces f, '
{
// add gallery permission
// FIXME: Ditto on the REALLY ugly hack comment from above!
- $share = substr($GLOBALS['ansel_storage']->shares->_getShareCriteria(
+ $share = substr($GLOBALS['ansel_storage']->shares->getShareCriteria(
Horde_Auth::getAuth(), Horde_Perms::READ), 5);
$sql = 'SELECT COUNT(*) FROM ansel_faces f, '
public function __construct($attributes = array())
{
/* Pass on up the chain */
- parent::Horde_Share_Object_sql_hierarchical($attributes);
+ parent::__construct($attributes);
$this->setShareOb($GLOBALS['ansel_storage']->shares);
$mode = isset($attributes['attribute_view_mode']) ? $attributes['attribute_view_mode'] : 'Normal';
$this->_setModeHelper($mode);
'sql_hierarchical');
/* Ansel_Gallery is just a subclass of Horde_Share_Object */
- $this->_shares->_shareObject = 'Ansel_Gallery';
+ $this->_shares->setShareClass('Ansel_Gallery');
/* Database handle */
$this->_db = $GLOBALS['ansel_db'];
if (!count($galleries) && !count($slugs)) {
$sql = 'SELECT DISTINCT ' . $this->_getImageFields('i') . ' FROM ansel_images i, '
- . str_replace('WHERE' , ' WHERE i.gallery_id = s.share_id AND (', substr($this->_shares->_getShareCriteria(Horde_Auth::getAuth()), 5)) . ')';
+ . str_replace('WHERE' , ' WHERE i.gallery_id = s.share_id AND (', substr($this->_shares->getShareCriteria(Horde_Auth::getAuth()), 5)) . ')';
} elseif (!count($slugs) && count($galleries)) {
// Searching by gallery_id
$sql = 'SELECT ' . $this->_getImageFields() . ' FROM ansel_images '
public function listCategories($perm = Horde_Perms::SHOW, $from = 0, $count = 0)
{
$sql = 'SELECT DISTINCT attribute_category FROM '
- . $this->_shares->_table;
- $results = $this->_shares->_db->query($sql);
+ . $this->_shares->getTable();
+ $results = $this->_shares->getReadDb()->query($sql);
if ($results instanceof PEAR_Error) {
throw new Horde_Exception($results->getMessage());
}
+++ /dev/null
-<?php
-/**
- * Horde_Share:: provides an interface to all shares a user might have. Its
- * methods take care of any site-specific restrictions configured in in the
- * application's prefs.php and conf.php files.
- *
- * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
- * Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
- *
- * 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 Joel Vandal <joel@scopserv.com>
- * @author Mike Cochrame <mike@graftonhall.co.nz>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Jan Schneider <jan@horde.org>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share {
-
- /**
- * The application we're managing shares for.
- *
- * @var string
- */
- var $_app;
-
- /**
- * The root of the Share tree.
- *
- * @var mixed
- */
- var $_root = null;
-
- /**
- * A cache of all shares that have been retrieved, so we don't hit the
- * backend again and again for them.
- *
- * @var array
- */
- var $_cache = array();
-
- /**
- * Id-name-map of already cached share objects.
- *
- * @var array
- */
- var $_shareMap = array();
-
- /**
- * Cache used for listShares().
- *
- * @var array
- */
- var $_listcache = array();
-
- /**
- * A list of objects that we're currently sorting, for reference during the
- * sorting algorithm.
- *
- * @var array
- */
- var $_sortList;
-
- /**
- * Attempts to return a reference to a concrete Horde_Share instance.
- *
- * It will only create a new instance if no Horde_Share instance currently
- * exists.
- *
- * @param string $app The application that the shares relates to.
- * @param string $driver Type of concrete Share subclass to return,
- * based on storage driver ($driver). The code is
- * dynamically included.
- *
- * @return Horde_Share The concrete Share reference, or false on an error.
- */
- public static function singleton($app, $driver = null)
- {
- static $shares = array();
-
- // FIXME: This is a temporary solution until the configuration value
- // actually exists and all apps call this code in the correct fashion.
- $driver = basename($driver);
- if (empty($driver)) {
- if (!empty($GLOBALS['conf']['share']['driver'])) {
- $driver = $GLOBALS['conf']['share']['driver'];
- } else {
- $driver = 'datatree';
- }
- }
-
- $class = 'Horde_Share_' . $driver;
- if (!class_exists($class)) {
- include dirname(__FILE__) . '/Share/' . $driver . '.php';
- }
-
- $signature = $app . '_' . $driver;
- if (!isset($shares[$signature]) &&
- !empty($GLOBALS['conf']['share']['cache'])) {
- $session = new Horde_SessionObjects();
- $shares[$signature] = $session->query('horde_share_' . $app . '_' . $driver . '1');
- }
-
- if (empty($shares[$signature])) {
- if (class_exists($class)) {
- $shares[$signature] = new $class($app);
- } else {
- $result = PEAR::raiseError(sprintf(_("\"%s\" share driver not found."), $driver));
- return $result;
- }
- }
-
- if (!empty($GLOBALS['conf']['share']['cache'])) {
- register_shutdown_function(array($shares[$signature], 'shutdown'));
- }
-
- return $shares[$signature];
- }
-
- /**
- * Constructor.
- *
- * @param string $app The application that the shares belong to.
- */
- function Horde_Share($app)
- {
- $this->_app = $app;
- $this->__wakeup();
- }
-
- /**
- * Initializes the object.
- *
- * @throws Horde_Exception
- */
- function __wakeup()
- {
- try {
- Horde::callHook('share_init', array($this, $this->_app));
- } catch (Horde_Exception_HookNotSet $e) {}
- }
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['_sortList']);
- $properties = array_keys($properties);
- return $properties;
- }
-
- /**
- * Stores the object in the session cache.
- */
- function shutdown()
- {
- $driver = str_replace('horde_share_', '', Horde_String::lower(get_class($this)));
- $session = new Horde_SessionObjects();
- $session->overwrite('horde_share_' . $this->_app . '_' . $driver, $this, false);
- }
-
- /**
- * Returns the application we're managing shares for.
- *
- * @return string The application this share belongs to.
- */
- function getApp()
- {
- return $this->_app;
- }
-
- /**
- * Returns a Horde_Share_Object object corresponding to the given share
- * name, with the details retrieved appropriately.
- *
- * @param string $name The name of the share to retrieve.
- *
- * @return Horde_Share_Object The requested share.
- */
- function getShare($name)
- {
- if (isset($this->_cache[$name])) {
- return $this->_cache[$name];
- }
-
- $share = $this->_getShare($name);
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
- $share->setShareOb($this);
- $this->_shareMap[$share->getId()] = $name;
- $this->_cache[$name] = $share;
-
- return $share;
- }
-
- /**
- * Returns a Horde_Share_Object object corresponding to the given unique
- * ID, with the details retrieved appropriately.
- *
- * @param string $cid The id of the share to retrieve.
- *
- * @return Horde_Share_Object The requested share.
- */
- function getShareById($cid)
- {
- if (!isset($this->_shareMap[$cid])) {
- $share = $this->_getShareById($cid);
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
- $share->setShareOb($this);
- $name = $share->getName();
- $this->_cache[$name] = $share;
- $this->_shareMap[$cid] = $name;
- }
-
- return $this->_cache[$this->_shareMap[$cid]];
- }
-
- /**
- * Returns an array of Horde_Share_Object objects corresponding to the
- * given set of unique IDs, with the details retrieved appropriately.
- *
- * @param array $cids The array of ids to retrieve.
- *
- * @return array The requested shares.
- */
- function getShares($cids)
- {
- $all_shares = array();
- $missing_ids = array();
- foreach ($cids as $cid) {
- if (isset($this->_shareMap[$cid])) {
- $all_shares[$this->_shareMap[$cid]] = $this->_cache[$this->_shareMap[$cid]];
- } else {
- $missing_ids[] = $cid;
- }
- }
-
- if (count($missing_ids)) {
- $shares = $this->_getShares($missing_ids);
- if (is_a($shares, 'PEAR_Error')) {
- return $shares;
- }
-
- foreach (array_keys($shares) as $key) {
- $this->_cache[$key] = $shares[$key];
- $this->_cache[$key]->setShareOb($this);
- $this->_shareMap[$shares[$key]->getId()] = $key;
- $all_shares[$key] = $this->_cache[$key];
- }
- }
-
- return $all_shares;
- }
-
- /**
- * Lists *all* shares for the current app/share, regardless of
- * permissions.
- *
- * This is for admin functionality and scripting tools, and shouldn't be
- * called from user-level code!
- *
- * @return array All shares for the current app/share.
- */
- function listAllShares()
- {
- $shares = $this->_listAllShares();
- if (is_a($shares, 'PEAR_Error') || !count($shares)) {
- return $shares;
- }
-
- $this->_sortList = $shares;
- uasort($shares, array($this, '_sortShares'));
- $this->_sortList = null;
-
- return $shares;
- }
-
- /**
- * Returns an array of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return array The shares the user has access to.
- */
- function listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
- $from = 0, $count = 0, $sort_by = null, $direction = 0)
- {
- $shares = $this->_listShares($userid, $perm, $attributes, $from,
- $count, $sort_by, $direction);
- if (!count($shares)) {
- return $shares;
- }
- if (is_a($shares, 'PEAR_Error')) {
- return $shares;
- }
-
- /* Make sure getShares() didn't return an error. */
- $shares = $this->getShares($shares);
- if (is_a($shares, 'PEAR_Error')) {
- return $shares;
- }
-
- if (is_null($sort_by)) {
- $this->_sortList = $shares;
- uasort($shares, array($this, '_sortShares'));
- $this->_sortList = null;
- }
-
- try {
- return Horde::callHook('share_list', array($userid, $perm, $attributes, $shares));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- return $shares;
- }
-
- /**
- * Returns an array of all system shares.
- *
- * @return array All system shares.
- */
- function listSystemShares()
- {
- return array();
- }
-
- /**
- * Returns the number of shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return integer The number of shares
- */
- function countShares($userid, $perm = Horde_Perms::SHOW, $attributes = null)
- {
- return $this->_countShares($userid, $perm, $attributes);
- }
-
- /**
- * Returns a new share object.
- *
- * @param string $name The share's name.
- *
- * @return Horde_Share_Object A new share object.
- */
- function newShare($name)
- {
- if (empty($name)) {
- return PEAR::raiseError('Share names must be non-empty');
- }
- $share = $this->_newShare($name);
- $share->setShareOb($this);
- $share->set('owner', Horde_Auth::getAuth());
-
- return $share;
- }
-
- /**
- * Adds a share to the shares system.
- *
- * The share must first be created with Horde_Share::newShare(), and have
- * any initial details added to it, before this function is called.
- *
- * @param Horde_Share_Object $share The new share object.
- * @throws Horde_Exception
- */
- function addShare($share)
- {
- if (!is_a($share, 'Horde_Share_Object')) {
- return PEAR::raiseError('Shares must be Horde_Share_Object objects or extend that class.');
- }
-
- try {
- Horde::callHook('share_add', array($share));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- $result = $this->_addShare($share);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-
- /* Store new share in the caches. */
- $id = $share->getId();
- $name = $share->getName();
- $this->_cache[$name] = $share;
- $this->_shareMap[$id] = $name;
-
- /* Reset caches that depend on unknown criteria. */
- $this->_listCache = array();
-
- return $result;
- }
-
- /**
- * Removes a share from the shares system permanently.
- *
- * @param Horde_Share_Object $share The share to remove.
- *
- * @throws Horde_Exception
- */
- function removeShare($share)
- {
- if (!is_a($share, 'Horde_Share_Object')) {
- return PEAR::raiseError('Shares must be Horde_Share_Object objects or extend that class.');
- }
-
- try {
- Horde::callHook('share_remove', array($share));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- /* Remove share from the caches. */
- $id = $share->getId();
- unset($this->_shareMap[$id]);
- unset($this->_cache[$share->getName()]);
-
- /* Reset caches that depend on unknown criteria. */
- $this->_listCache = array();
-
- return $this->_removeShare($share);
- }
-
- /**
- * Checks if a share exists in the system.
- *
- * @param string $share The share to check.
- *
- * @return boolean True if the share exists.
- */
- function exists($share)
- {
- if (isset($this->_cache[$share])) {
- return true;
- }
-
- return $this->_exists($share);
- }
-
- /**
- * Finds out what rights the given user has to this object.
- *
- * @see Horde_Perms::getPermissions
- *
- * @param mixed $share The share that should be checked for the users
- * permissions.
- * @param string $user The user to check for.
- *
- * @return mixed A bitmask of permissions, a permission value, or an array
- * of permission values the user has, depending on the
- * permission type and whether the permission value is
- * ambiguous. False if there is no such permsission.
- */
- function getPermissions($share, $user = null)
- {
- if (is_a($share, 'PEAR_Error')) {
- Horde::logMessage($share, 'ERR');
- return false;
- }
-
- if (!is_a($share, 'Horde_Share_Object')) {
- $share = $this->getShare($share);
- if (is_a($share, 'PEAR_Error')) {
- Horde::logMessage($share, 'ERR');
- return false;
- }
- }
-
- $perm = $share->getPermission();
- return $GLOBALS['injector']->getInstance('Horde_Perms')->getPermissions($perm, $user);
- }
-
- /**
- * Returns the Identity for a particular share owner.
- *
- * @deprecated
- *
- * @param mixed $share The share to fetch the Identity for - either the
- * string name, or the Horde_Share_Object object.
- *
- * @return Identity An Identity instance.
- */
- function getIdentityByShare($share)
- {
- if (!is_a($share, 'Horde_Share_Object')) {
- $share = $this->getShare($share);
- if (is_a($share, 'PEAR_Error')) {
- return null;
- }
- }
-
- return $GLOBALS['injector']->getInstance('Horde_Prefs_Identity')->getIdentity($share->get('owner'));
- }
-
- /**
- * Utility function to be used with uasort() for sorting arrays of
- * Horde_Share objects.
- *
- * Example:
- * <code>
- * uasort($list, array('Horde_Share', '_sortShares'));
- * </code>
- *
- * @access protected
- */
- function _sortShares($a, $b)
- {
- $aParts = explode(':', $a->getName());
- $bParts = explode(':', $b->getName());
-
- $min = min(count($aParts), count($bParts));
- $idA = '';
- $idB = '';
- for ($i = 0; $i < $min; $i++) {
- if ($idA) {
- $idA .= ':';
- $idB .= ':';
- }
- $idA .= $aParts[$i];
- $idB .= $bParts[$i];
-
- if ($idA != $idB) {
- $curA = isset($this->_sortList[$idA]) ? $this->_sortList[$idA]->get('name') : '';
- $curB = isset($this->_sortList[$idB]) ? $this->_sortList[$idB]->get('name') : '';
- return strnatcasecmp($curA, $curB);
- }
- }
-
- return count($aParts) > count($bParts);
- }
-
-}
-
-/**
- * Abstract class for storing Share information.
- *
- * This class should be extended for the more specific drivers.
- *
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Jan Schneider <jan@horde.org>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share_Object {
-
- /**
- * The Horde_Share object which this share came from - needed for updating
- * data in the backend to make changes stick, etc.
- *
- * @var Horde_Share
- */
- var $_shareOb;
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['_shareOb']);
- $properties = array_keys($properties);
- return $properties;
- }
-
- /**
- * Associates a Share object with this share.
- *
- * @param Horde_Share $shareOb The Share object.
- */
- function setShareOb($shareOb)
- {
- if (!is_a($shareOb, 'Horde_Share')) {
- return PEAR::raiseError('This object needs a Horde_Share instance as storage handler!');
- }
- $this->_shareOb = $shareOb;
- }
-
- /**
- * Sets an attribute value in this object.
- *
- * @param string $attribute The attribute to set.
- * @param mixed $value The value for $attribute.
- *
- * @return mixed True if setting the attribute did succeed, a PEAR_Error
- * otherwise.
- */
- function set($attribute, $value)
- {
- return $this->_set($attribute, $value);
- }
-
- /**
- * Returns an attribute value from this object.
- *
- * @param string $attribute The attribute to return.
- *
- * @return mixed The value for $attribute.
- */
- function get($attribute)
- {
- return $this->_get($attribute);
- }
-
- /**
- * Returns the ID of this share.
- *
- * @return string The share's ID.
- */
- function getId()
- {
- return $this->_getId();
- }
-
- /**
- * Returns the name of this share.
- *
- * @return string The share's name.
- */
- function getName()
- {
- return $this->_getName();
- }
-
- /**
- * Saves the current attribute values.
- *
- * @throws Horde_Exception
- */
- function save()
- {
- try {
- Horde::callHook('share_modify', array($this));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- return $this->_save();
- }
-
- /**
- * Gives a user a certain privilege for this share.
- *
- * @param string $userid The userid of the user.
- * @param integer $permission A Horde_Perms::* constant.
- */
- function addUserPermission($userid, $permission)
- {
- $perm = $this->getPermission();
- $perm->addUserPermission($userid, $permission, false);
- $this->setPermission($perm);
- }
-
- /**
- * Removes a certain privilege for a user from this share.
- *
- * @param string $userid The userid of the user.
- * @param integer $permission A Horde_Perms::* constant.
- */
- function removeUserPermission($userid, $permission)
- {
- $perm = $this->getPermission();
- $perm->removeUserPermission($userid, $permission, false);
- $this->setPermission($perm);
- }
-
- /**
- * Gives a group certain privileges for this share.
- *
- * @param string $group The group to add permissions for.
- * @param integer $permission A Horde_Perms::* constant.
- */
- function addGroupPermission($group, $permission)
- {
- $perm = $this->getPermission();
- $perm->addGroupPermission($group, $permission, false);
- $this->setPermission($perm);
- }
-
- /**
- * Removes a certain privilege from a group.
- *
- * @param string $group The group to remove permissions from.
- * @param constant $permission A Horde_Perms::* constant.
- */
- function removeGroupPermission($group, $permission)
- {
- $perm = $this->getPermission();
- $perm->removeGroupPermission($group, $permission, false);
- $this->setPermission($perm);
- }
-
- /**
- * Removes a user from this share.
- *
- * @param string $userid The userid of the user to remove.
- */
- function removeUser($userid)
- {
- /* Remove all $userid's permissions. */
- $perm = $this->getPermission();
- $perm->removeUserPermission($userid, Horde_Perms::SHOW, false);
- $perm->removeUserPermission($userid, Horde_Perms::READ, false);
- $perm->removeUserPermission($userid, Horde_Perms::EDIT, false);
- $perm->removeUserPermission($userid, Horde_Perms::DELETE, false);
- return $this->setPermission($perm);
- }
-
- /**
- * Removes a group from this share.
- *
- * @param integer $groupId The group to remove.
- */
- function removeGroup($groupId)
- {
- /* Remove all $groupId's permissions. */
- $perm = $this->getPermission();
- $perm->removeGroupPermission($groupId, Horde_Perms::SHOW, false);
- $perm->removeGroupPermission($groupId, Horde_Perms::READ, false);
- $perm->removeGroupPermission($groupId, Horde_Perms::EDIT, false);
- $perm->removeGroupPermission($groupId, Horde_Perms::DELETE, false);
- return $this->setPermission($perm);
- }
-
- /**
- * Returns an array containing all the userids of the users with access to
- * this share.
- *
- * @param integer $perm_level List only users with this permission level.
- * Defaults to all users.
- *
- * @return array The users with access to this share.
- */
- function listUsers($perm_level = null)
- {
- $perm = $this->getPermission();
- $results = array_keys($perm->getUserPermissions($perm_level));
- // Always return the share's owner.
- if ($this->get('owner')) {
- array_push($results, $this->get('owner'));
- }
- return $results;
- }
-
- /**
- * Returns an array containing all the groupids of the groups with access
- * to this share.
- *
- * @param integer $perm_level List only users with this permission level.
- * Defaults to all users.
- *
- * @return array The IDs of the groups with access to this share.
- */
- function listGroups($perm_level = null)
- {
- $perm = $this->getPermission();
- return array_keys($perm->getGroupPermissions($perm_level));
- }
-
- /**
- * Locks an item from this share, or the entire share if no item defined.
- *
- * @param string $item_uid A uid of an item from this share.
- *
- * @return mixed A lock ID on success, PEAR_Error on failure, false if:
- * - The share is already locked
- * - The item is already locked
- * - A share lock was requested and an item is already
- * locked in the share
- */
- function lock($item_uid = null)
- {
- try {
- $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
- } catch (Horde_Lock_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return PEAR::raiseError($e->getMessage());
- }
-
- $shareid = $this->getId();
-
- // Default parameters.
- $locktype = Horde_Lock::TYPE_EXCLUSIVE;
- $timeout = 600;
- $itemscope = $this->_shareOb->getApp() . ':' . $shareid;
-
- if (!empty($item_uid)) {
- // Check if the share is locked. Share locks are placed at app
- // scope.
- try {
-
- $result = $locks->getLocks($this->_shareOb->getApp(), $shareid, $locktype);
- } catch (Horde_Lock_Exception $e) {
- return PEAR::raiseError($e->getMessage);
- }
- if (!empty($result)) {
- // Lock found.
- return false;
- }
- // Try to place the item lock at app:shareid scope.
- return $locks->setLock(Horde_Auth::getAuth(), $itemscope, $item_uid,
- $timeout, $locktype);
- } else {
- // Share lock requested. Check for locked items.
- try {
- $result = $locks->getLocks($itemscope, null, $locktype);
- } catch (Horde_Lock_Exception $e) {
- return PEAR::raiseError($e->getException);
- }
- if (!empty($result)) {
- // Lock found.
- return false;
- }
- // Try to place the share lock
- return $locks->setLock(Horde_Auth::getAuth(), $this->_shareOb->getApp(),
- $shareid, $timeout, $locktype);
- }
- }
-
- /**
- * Removes the lock for a lock ID.
- *
- * @param string $lockid The lock ID as generated by a previous call
- * to lock().
- *
- * @return mixed True on success, PEAR_Error on failure.
- */
- function unlock($lockid)
- {
- try {
- $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
- } catch (Horde_Lock_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return PEAR::raiseError($e->getMessage());
- }
-
- return $locks->clearLock($lockid);
- }
-
- /**
- * Checks for existing locks.
- *
- * First this checks for share locks and if none exists, checks for item
- * locks (if item_uid defined). It will return the first lock found.
- *
- * @param string $item_uid A uid of an item from this share.
- *
- * @return mixed Hash with the found lock information in 'lock' and the
- * lock type ('share' or 'item') in 'type', or an empty
- * array if there are no locks, or a PEAR_Error on failure.
- */
- function checkLocks($item_uid = null)
- {
- try {
- $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
- } catch (Horde_Lock_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return PEAR::raiseError($e->getMessage());
- }
-
- $shareid = $this->getId();
- $locktype = Horde_Lock::TYPE_EXCLUSIVE;
-
- // Check for share locks
- try {
- $result = $locks->getLocks($this->_shareOb->getApp(), $shareid, $locktype);
- } catch (Horde_Lock_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return PEAR::raiseError($e->getMessage());
- }
-
- if (empty($result) && !empty($item_uid)) {
- // Check for item locks
- $locktargettype = 'item';
- try {
- $result = $locks->getLocks($this->_shareOb->getApp() . ':' . $shareid, $item_uid, $locktype);
- } catch (Horde_Lock_Exception $e) {
- Horde::logMessage($e, 'ERR');
- return PEAR::raiseError($e->getMessage());
- }
- } else {
- $locktargettype = 'share';
- }
-
- if (empty($result)) {
- return array();
- }
-
- return array('type' => $locktargettype,
- 'lock' => reset($result));
- }
-
-}
+++ /dev/null
-<?php
-
-require_once 'Horde/DataTree.php';
-
-/**
- * Horde_Share_datatree:: provides the datatree backend for the horde share
- * driver.
- *
- * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
- * Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
- *
- * 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 Joel Vandal <joel@scopserv.com>
- * @author Mike Cochrame <mike@graftonhall.co.nz>
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @author Jan Schneider <jan@horde.org>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share_datatree extends Horde_Share {
-
- /**
- * The Horde_Share_Object subclass to instantiate objects as
- *
- * @var string
- */
- var $_shareObject = 'Horde_Share_Object_datatree';
-
- /**
- * Pointer to a DataTree instance to manage/store shares
- *
- * @var DataTree
- */
- var $_datatree;
-
- /**
- * Initializes the object.
- *
- * @throws Horde_Exception
- */
- function __wakeup()
- {
- if (empty($GLOBALS['conf']['datatree']['driver'])) {
- throw new Horde_Exception('You must configure a DataTree backend to use Shares.');
- }
-
- $driver = $GLOBALS['conf']['datatree']['driver'];
- $this->_datatree = &DataTree::singleton(
- $driver,
- array_merge(Horde::getDriverConfig('datatree', $driver),
- array('group' => 'horde.shares.' . $this->_app))
- );
-
- foreach (array_keys($this->_cache) as $name) {
- if (!is_a($this->_datatree, 'PEAR_Error')) {
- $this->_cache[$name]->setShareOb($this);
- $this->_cache[$name]->datatreeObject->setDataTree($this->_datatree);
- }
- }
-
- parent::__wakeup();
- }
-
- /**
- * Returns a Horde_Share_Object_datatree object corresponding to the given
- * share name, with the details retrieved appropriately.
- *
- * @param string $name The name of the share to retrieve.
- *
- * @return Horde_Share_Object_datatree The requested share.
- */
- function &_getShare($name)
- {
- $datatreeObject = $this->_datatree->getObject($name, 'DataTreeObject_Share');
- if (is_a($datatreeObject, 'PEAR_Error')) {
- return $datatreeObject;
- }
- $share = new $this->_shareObject($datatreeObject);
- return $share;
- }
-
- /**
- * Returns a Horde_Share_Object_datatree object corresponding to the given
- * unique ID, with the details retrieved appropriately.
- *
- * @param string $cid The id of the share to retrieve.
- *
- * @return Horde_Share_Object_datatree The requested share.
- */
- function &_getShareById($id)
- {
- $datatreeObject = $this->_datatree->getObjectById($id, 'DataTreeObject_Share');
- if (is_a($datatreeObject, 'PEAR_Error')) {
- return $datatreeObject;
- }
- $share = new $this->_shareObject($datatreeObject);
- return $share;
- }
-
- /**
- * Returns an array of Horde_Share_Object_datatree objects corresponding
- * to the given set of unique IDs, with the details retrieved
- * appropriately.
- *
- * @param array $cids The array of ids to retrieve.
- *
- * @return array The requested shares.
- */
- function &_getShares($ids)
- {
- $shares = array();
- $objects = &$this->_datatree->getObjects($ids, 'DataTreeObject_Share');
- if (is_a($objects, 'PEAR_Error')) {
- return $objects;
- }
- foreach (array_keys($objects) as $key) {
- if (is_a($objects[$key], 'PEAR_Error')) {
- return $objects[$key];
- }
- $shares[$key] = new $this->_shareObject($objects[$key]);
- }
- return $shares;
- }
-
- /**
- * Lists *all* shares for the current app/share, regardless of
- * permissions.
- *
- * @return array All shares for the current app/share.
- */
- function &_listAllShares()
- {
- $sharelist = $this->_datatree->get(DATATREE_FORMAT_FLAT, DATATREE_ROOT,
- true);
- if (is_a($sharelist, 'PEAR_Error') || !count($sharelist)) {
- // If we got back an error or an empty array, just return it.
- return $sharelist;
- }
- unset($sharelist[DATATREE_ROOT]);
-
- return $this->getShares(array_keys($sharelist));
- }
-
- /**
- * Returns an array of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return array The shares the user has access to.
- */
- function &_listShares($userid, $perm = Horde_Perms::SHOW,
- $attributes = null, $from = 0, $count = 0,
- $sort_by = null, $direction = 0)
- {
- $key = serialize(array($userid, $perm, $attributes));
- if (empty($this->_listCache[$key])) {
- $criteria = $this->_getShareCriteria($userid, $perm, $attributes);
- $sharelist = $this->_datatree->getByAttributes($criteria,
- DATATREE_ROOT,
- true, 'id', $from,
- $count, $sort_by,
- null, $direction);
- if (is_a($sharelist, 'PEAR_Error')) {
- return $sharelist;
- }
- $this->_listCache[$key] = array_keys($sharelist);
- }
-
- return $this->_listCache[$key];
- }
-
- /**
- * Returns the number of shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return integer The number of shares
- */
- function _countShares($userid, $perm = Horde_Perms::SHOW,
- $attributes = null)
- {
- $criteria = $this->_getShareCriteria($userid, $perm, $attributes);
- return $this->_datatree->countByAttributes($criteria, DATATREE_ROOT, true, 'id');
- }
-
- /**
- * Returns a new share object.
- *
- * @param string $name The share's name.
- *
- * @return Horde_Share_Object_datatree A new share object.
- */
- function &_newShare($name)
- {
- $datatreeObject = new DataTreeObject_Share($name);
- $datatreeObject->setDataTree($this->_datatree);
- $share = new $this->_shareObject($datatreeObject);
- return $share;
- }
-
- /**
- * Adds a share to the shares system.
- *
- * The share must first be created with
- * Horde_Share_datatreee::_newShare(), and have any initial details added
- * to it, before this function is called.
- *
- * @param Horde_Share_Object_datatree $share The new share object.
- */
- function _addShare(&$share)
- {
- return $this->_datatree->add($share->datatreeObject);
- }
-
- /**
- * Removes a share from the shares system permanently.
- *
- * @param Horde_Share_Object_datatree $share The share to remove.
- */
- function _removeShare(&$share)
- {
- return $this->_datatree->remove($share->datatreeObject);
- }
-
- /**
- * Checks if a share exists in the system.
- *
- * @param string $share The share to check.
- *
- * @return boolean True if the share exists.
- */
- function _exists($share)
- {
- return $this->_datatree->exists($share);
- }
-
- /**
- * Returns an array of criteria for querying shares.
- * @access protected
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares returned to those who
- * have these attribute values.
- *
- * @return array The criteria tree for fetching this user's shares.
- */
- function _getShareCriteria($userid, $perm = Horde_Perms::SHOW,
- $attributes = null)
- {
- if (!empty($userid)) {
- $criteria = array(
- 'OR' => array(
- // (owner == $userid)
- array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'owner'),
- array('field' => 'value', 'op' => '=', 'test' => $userid))),
-
- // (name == perm_users and key == $userid and val & $perm)
- array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'perm_users'),
- array('field' => 'key', 'op' => '=', 'test' => $userid),
- array('field' => 'value', 'op' => '&', 'test' => $perm))),
-
- // (name == perm_creator and val & $perm)
- array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'perm_creator'),
- array('field' => 'value', 'op' => '&', 'test' => $perm))),
-
- // (name == perm_default and val & $perm)
- array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'perm_default'),
- array('field' => 'value', 'op' => '&', 'test' => $perm)))));
-
- // If the user has any group memberships, check for those also.
- require_once 'Horde/Group.php';
- $group = &Group::singleton();
- $groups = $group->getGroupMemberships($userid, true);
- if (!is_a($groups, 'PEAR_Error') && $groups) {
- // (name == perm_groups and key in ($groups) and val & $perm)
- $criteria['OR'][] = array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'),
- array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)),
- array('field' => 'value', 'op' => '&', 'test' => $perm)));
- }
- } else {
- $criteria = array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'perm_guest'),
- array('field' => 'value', 'op' => '&', 'test' => $perm)));
- }
-
- if (is_array($attributes)) {
- // Build attribute/key filter.
- foreach ($attributes as $key => $value) {
- $criteria = array(
- 'AND' => array(
- $criteria,
- array(
- 'JOIN' => array(
- 'AND' => array(
- array('field' => 'name', 'op' => '=', 'test' => $key),
- array('field' => 'value', 'op' => '=', 'test' => $value))))));
- }
- } elseif (!is_null($attributes)) {
- // Restrict to shares owned by the user specified in the
- // $attributes string.
- $criteria = array(
- 'AND' => array(
- $criteria,
- array(
- 'JOIN' => array(
- array('field' => 'name', 'op' => '=', 'test' => 'owner'),
- array('field' => 'value', 'op' => '=', 'test' => $attributes)))));
- }
-
- return $criteria;
- }
-
-}
-
-/**
- * Extension of the Horde_Share_Object class for storing share information in
- * the DataTree driver.
- *
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Jan Schneider <jan@horde.org>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share_Object_datatree extends Horde_Share_Object {
-
- /**
- * The actual storage object that holds the data.
- *
- * @var mixed
- */
- var $datatreeObject;
-
- /**
- * Constructor.
- *
- * @param DataTreeObject_Share $datatreeObject A DataTreeObject_Share
- * instance.
- */
- function Horde_Share_Object_datatree($datatreeObject)
- {
- if (is_a($datatreeObject, 'PEAR_Error')) {
- debug_context();
- }
- $this->datatreeObject = $datatreeObject;
- }
-
- /**
- * Sets an attribute value in this object.
- *
- * @param string $attribute The attribute to set.
- * @param mixed $value The value for $attribute.
- *
- * @return mixed True if setting the attribute did succeed, a PEAR_Error
- * otherwise.
- */
- function _set($attribute, $value)
- {
- return $this->datatreeObject->set($attribute, $value);
- }
-
- /**
- * Returns one of the attributes of the object, or null if it isn't
- * defined.
- *
- * @param string $attribute The attribute to retrieve.
- *
- * @return mixed The value of the attribute, or an empty string.
- */
- function _get($attribute)
- {
- return $this->datatreeObject->get($attribute);
- }
-
- /**
- * Returns the ID of this share.
- *
- * @return string The share's ID.
- */
- function _getId()
- {
- return $this->datatreeObject->getId();
- }
-
- /**
- * Returns the name of this share.
- *
- * @return string The share's name.
- */
- function _getName()
- {
- return $this->datatreeObject->getName();
- }
-
- /**
- * Saves the current attribute values.
- */
- function _save()
- {
- return $this->datatreeObject->save();
- }
-
- /**
- * Checks to see if a user has a given permission.
- *
- * @param string $userid The userid of the user.
- * @param integer $permission A Horde_Perms::* constant to test for.
- * @param string $creator The creator of the event.
- *
- * @return boolean Whether or not $userid has $permission.
- */
- function hasPermission($userid, $permission, $creator = null)
- {
- if ($userid && $userid == $this->datatreeObject->get('owner')) {
- return true;
- }
-
- return $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($this->getPermission(), $userid, $permission, $creator);
- }
-
- /**
- * Sets the permission of this share.
- *
- * @param Horde_Perms_Permission $perm Permission object.
- * @param boolean $update Should the share be saved
- * after this operation?
- *
- * @return boolean True if no error occured, PEAR_Error otherwise
- */
- function setPermission(&$perm, $update = true)
- {
- $this->datatreeObject->data['perm'] = $perm->getData();
- if ($update) {
- return $this->datatreeObject->save();
- }
- return true;
- }
-
- /**
- * Returns the permission of this share.
- *
- * @return Horde_Persm_Permission Permission object that represents the
- * permissions on this share
- */
- function &getPermission()
- {
- $perm = new Horde_Perms_Permission($this->datatreeObject->getName());
- $perm->data = isset($this->datatreeObject->data['perm'])
- ? $this->datatreeObject->data['perm']
- : array();
-
- return $perm;
- }
-
-}
-
-/**
- * Extension of the DataTreeObject class for storing Share information in the
- * DataTree driver. If you want to store specialized Share information, you
- * should extend this class instead of extending DataTreeObject directly.
- *
- * @author Mike Cochrane <mike@graftonhall.co.nz>
- * @author Jan Schneider <jan@horde.org>
- * @package Horde_Share
- */
-class DataTreeObject_Share extends DataTreeObject {
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['datatree']);
- $properties = array_keys($properties);
- return $properties;
- }
-
- /**
- * Maps this object's attributes from the data array into a format that we
- * can store in the attributes storage backend.
- *
- * @access protected
- *
- * @param boolean $permsonly Only process permissions? Lets subclasses
- * override part of this method while handling
- * their additional attributes seperately.
- *
- * @return array The attributes array.
- */
- function _toAttributes($permsonly = false)
- {
- // Default to no attributes.
- $attributes = array();
-
- foreach ($this->data as $key => $value) {
- if ($key == 'perm') {
- foreach ($value as $type => $perms) {
- if (is_array($perms)) {
- foreach ($perms as $member => $perm) {
- $attributes[] = array('name' => 'perm_' . $type,
- 'key' => $member,
- 'value' => $perm);
- }
- } else {
- $attributes[] = array('name' => 'perm_' . $type,
- 'key' => '',
- 'value' => $perms);
- }
- }
- } elseif (!$permsonly) {
- $attributes[] = array('name' => $key,
- 'key' => '',
- 'value' => $value);
- }
- }
-
- return $attributes;
- }
-
- /**
- * Takes in a list of attributes from the backend and maps it to our
- * internal data array.
- *
- * @access protected
- *
- * @param array $attributes The list of attributes from the backend
- * (attribute name, key, and value).
- * @param boolean $permsonly Only process permissions? Lets subclasses
- * override part of this method while handling
- * their additional attributes seperately.
- */
- function _fromAttributes($attributes, $permsonly = false)
- {
- // Initialize data array.
- $this->data['perm'] = array();
-
- foreach ($attributes as $attr) {
- if (substr($attr['name'], 0, 4) == 'perm') {
- if (!empty($attr['key'])) {
- $this->data['perm'][substr($attr['name'], 5)][$attr['key']] = $attr['value'];
- } else {
- $this->data['perm'][substr($attr['name'], 5)] = $attr['value'];
- }
- } elseif (!$permsonly) {
- $this->data[$attr['name']] = $attr['value'];
- }
- }
- }
-
-}
+++ /dev/null
-<?php
-/**
- * @package Horde_Share
- */
-
-/**
- * Horde_Share_kolab:: provides the kolab backend for the horde share driver.
- *
- * Copyright 2004-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 Stuart Binge <omicron@mighty.co.za>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share_kolab extends Horde_Share {
-
- /**
- * Our Kolab folder list handler
- *
- * @var Kolab_List
- */
- var $_list;
-
- /**
- * The share type
- *
- * @var string
- */
- var $_type;
-
- /**
- * A marker for the validity of the list cache
- *
- * @var int
- */
- var $_listCacheValidity;
-
- /**
- * The session handler.
- *
- * @var Horde_Kolab_Session
- */
- private $_session;
-
- /**
- * Initializes the object.
- *
- * @throws Horde_Exception
- */
- function __wakeup()
- {
- if (empty($GLOBALS['conf']['kolab']['enabled'])) {
- throw new Horde_Exception('You must enable the kolab settings to use the Kolab Share driver.');
- }
-
- $this->_type = $this->_getFolderType($this->_app);
- if (is_a($this->_type, 'PEAR_Error')) {
- return $this->_type;
- }
-
- $this->_list = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
-
- parent::__wakeup();
- }
-
- private function _getFolderType($app)
- {
- switch ($app) {
- case 'mnemo':
- return 'note';
- case 'kronolith':
- return 'event';
- case 'turba':
- return 'contact';
- case 'nag':
- return 'task';
- default:
- return PEAR::raiseError(sprintf(_("The Horde/Kolab integration engine does not support \"%s\""), $app));
- }
- }
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['_sortList'], $properties['_list']);
- $properties = array_keys($properties);
- return $properties;
- }
-
- /**
- * Returns a Horde_Share_Object_kolab object of the request folder.
- *
- * @param string $object The share to fetch.
- *
- * @return Horde_Share_Object_kolab The share object.
- */
- function &_getShare($object)
- {
- if (empty($object)) {
- $error = PEAR::raiseError('No object requested.');
- return $error;
- }
-
- /** Get the corresponding folder for this share ID */
- $folder = $this->_list->getByShare($object, $this->_type);
- if (is_a($folder, 'PEAR_Error')) {
- return $folder;
- }
-
- /** Does the folder exist? */
- if (!$folder->exists()) {
- return PEAR::raiseError(sprintf(_("Share \"%s\" does not exist."), $object));
- }
-
- /** Create the object from the folder */
- $share = new Horde_Share_Object_kolab($object, $this->_type);
- $result = $share->setFolder($folder);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-
- return $share;
- }
-
- /**
- * Returns a Horde_Share_Object_kolab object of the requested folder.
- *
- * @param string $id The id of the share to fetch.
- *
- * @return Horde_Share_Object_kolab The share object.
- */
- function &_getShareById($id)
- {
- return $this->_getShare($id);
- }
-
- /**
- * Returns an array of Horde_Share_Object_kolab objects corresponding to
- * the requested folders.
- *
- * @param string $ids The ids of the shares to fetch.
- *
- * @return array An array of Horde_Share_Object_kolab objects.
- */
- function &_getShares($ids)
- {
- $objects = array();
- foreach ($ids as $id) {
- $result = &$this->_getShare($id);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- $objects[$id] = &$result;
- }
- return $objects;
- }
-
- /**
- * Lists *all* shares for the current app/share, regardless of
- * permissions.
- *
- * Currently not implemented in this class.
- *
- * @return array All shares for the current app/share.
- */
- function &_listAllShares()
- {
- $shares = array();
- return $shares;
- }
-
- /**
- * Returns an array of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return array The shares the user has access to.
- */
- function &_listShares($userid, $perm = Horde_Perms::SHOW,
- $attributes = null, $from = 0, $count = 0,
- $sort_by = null, $direction = 0)
- {
- $key = serialize(array($this->_type, $userid, $perm, $attributes));
- if ($this->_list === false) {
- $this->_listCache[$key] = array();
- } else if (empty($this->_listCache[$key])
- || $this->_list->validity != $this->_listCacheValidity) {
- $sharelist = $this->_list->getByType($this->_type);
- if (is_a($sharelist, 'PEAR_Error')) {
- return $sharelist;
- }
-
- $shares = array();
- foreach ($sharelist as $folder) {
- $id = $folder->getShareId();
- $share = &$this->getShare($id);
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
-
- $keep = true;
- if (!$share->hasPermission($userid, $perm)) {
- $keep = false;
- }
- if (isset($attributes) && $keep) {
- if (is_array($attributes)) {
- foreach ($attributes as $key => $value) {
- if (!$share->get($key) == $value) {
- $keep = false;
- break;
- }
- }
- } elseif (!$share->get('owner') == $attributes) {
- $keep = false;
- }
- }
- if ($keep) {
- $shares[] = $id;
- }
- }
- $this->_listCache[$key] = $shares;
- $this->_listCacheValidity = $this->_list->validity;
- }
-
- return $this->_listCache[$key];
- }
-
- /**
- * Returns the number of shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return integer The number of shares
- */
- function _countShares($userid, $perm = Horde_Perms::SHOW,
- $attributes = null)
- {
- $shares = $this->_listShares($userid, $perm, $attributes);
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
-
- return count($shares);
- }
-
- /**
- * Returns a new share object.
- *
- * @param string $name The share's name.
- *
- * @return Horde_Share_Object_kolab A new share object.
- */
- function &_newShare($name)
- {
- $storageObject = new Horde_Share_Object_kolab($name, $this->_type);
- return $storageObject;
- }
-
- /**
- * Adds a share to the shares system.
- *
- * The share must first be created with Horde_Share_kolab::_newShare(),
- * and have any initial details added to it, before this function is
- * called.
- *
- * @param Horde_Share_Object_kolab $share The new share object.
- */
- function _addShare(&$share)
- {
- return $share->save();
- }
-
- /**
- * Removes a share from the shares system permanently.
- *
- * @param Horde_Share_Object_kolab $share The share to remove.
- */
- function _removeShare(&$share)
- {
- $share_id = $share->getName();
-
- $result = $share->delete();
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- }
-
- /**
- * Checks if a share exists in the system.
- *
- * @param string $share The share to check.
- *
- * @return boolean True if the share exists.
- */
- function _exists($object)
- {
- if (empty($object)) {
- return false;
- }
-
- /** Get the corresponding folder for this share ID */
- $folder = $this->_list->getByShare($object, $this->_type);
- if (is_a($folder, 'PEAR_Error')) {
- return $folder;
- }
-
- return $folder->exists();
- }
-
- /**
- * Create a default share for the current app
- *
- * @return string The share ID of the new default share.
- */
- function getDefaultShare()
- {
- $default = $this->_list->getDefault($this->_type);
- if (is_a($default, 'PEAR_Error')) {
- return $default;
- }
- if ($default !== false) {
- return $this->getShare($default->getShareId());
- }
-
- /** Okay, no default folder yet */
- $share = $this->newShare(Horde_Auth::getAuth());
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
- /** The value does not matter here as the share will rewrite it */
- $share->set('name', '');
- $result = $this->addShare($share);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- return $share;
- }
-}
-
-/**
- * Extension of the Horde_Share_Object class for handling Kolab share
- * information.
- *
- * @author Stuart Binge <omicron@mighty.co.za>
- * @author Gunnar Wrobel <wrobel@pardus.de>
- * @package Horde_Share
- */
-class Horde_Share_Object_kolab extends Horde_Share_Object {
-
- /**
- * The Kolab folder this share is based on.
- *
- * @var Kolab_Folder
- */
- var $_folder;
-
- /**
- * The Kolab folder name.
- *
- * @var string
- */
- var $_folder_name;
-
- /**
- * A cache for the share attributes.
- *
- * @var array
- */
- var $_data;
-
- /**
- * Our Kolab folder list handler
- *
- * @var Kolab_List
- */
- var $_list;
-
- /**
- * The session handler.
- *
- * @var Horde_Kolab_Session
- */
- private $_session;
-
- /**
- * Constructor.
- *
- * Sets the folder name.
- *
- * @param string $id The share id.
- */
- function Horde_Share_Object_kolab($id, $type)
- {
- // We actually ignore the random id string that all horde apps provide
- // as initial name and wait for a set('name', 'xyz') call. But we want
- // to know if we should create a default share.
- if ($id == Horde_Auth::getAuth()) {
- $this->_data['default'] = true;
- } else {
- $this->_data['default'] = false;
- }
- $this->_type = $type;
- $this->__wakeup();
- }
-
- /**
- * Associates a Share object with this share.
- *
- * @param Horde_Share $shareOb The Share object.
- */
- function setShareOb(&$shareOb)
- {
- /** Ignore the parent as we don't need it */
- }
-
- /**
- * Initializes the object.
- */
- function __wakeup()
- {
- $this->_list = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
- if (isset($this->_folder_name)) {
- $this->_folder = $this->_list->getFolder($this->_folder_name);
- }
- }
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['_shareOb'], $properties['_list'],
- $properties['_folder']);
- $properties = array_keys($properties);
- return $properties;
- }
-
- /**
- * Returns the default share name for the current application.
- *
- * @return string The default share name.
- */
- function getDefaultShareName()
- {
- switch ($this->_type) {
- case 'contact':
- return _("Contacts");
- case 'note':
- return _("Notes");
- case 'event':
- return _("Calendar");
- case 'task':
- return _("Tasks");
- case 'filter':
- return _("Filters");
- case 'h-prefs':
- return _("Preferences");
- }
- }
-
- /**
- * Sets the folder for this storage object.
- *
- * @param string $folder Name of the Kolab folder.
- * @param array $perms The permissions of the folder if they are known.
- */
- function setFolder(&$folder)
- {
- if (!isset($this->_folder)) {
- $this->_folder = &$folder;
- $this->_folder_name = $folder->name;
- } else {
- return PEAR::raiseError(_("The share has already been initialized!"));
- }
- }
-
- /**
- * Returns the ID of this share.
- *
- * @return string The share's ID.
- */
- function _getId()
- {
- return $this->_folder->getShareId();
- }
-
- /**
- * Returns the name of this share.
- *
- * @return string The share's name.
- */
- function _getName()
- {
- return $this->_folder->getShareId();
- }
-
- /**
- * Returns an attribute value from this object.
- *
- * @param string $attribute The attribute to return.
- *
- * @return mixed The value for $attribute.
- */
- function _get($attribute)
- {
- if (isset($this->_data[$attribute])) {
- return $this->_data[$attribute];
- }
-
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
-
- switch ($attribute) {
- case 'owner':
- $this->_data['owner'] = $this->_folder->getOwner();
- break;
-
- case 'name':
- $this->_data['name'] = $this->_folder->getTitle();
- break;
-
- case 'type':
- $this->_data['type'] = $this->_folder->getType();
- break;
-
- case 'params':
- $params = @unserialize($this->_folder->getAttribute('params'));
- $default = array('source' => 'kolab',
- 'default' => $this->get('default'),
- 'name' => $this->get('name'));
- $type = $this->get('type');
- if (!is_a($type, 'PEAR_Error') && $type == 'event') {
- $default = array_merge($default, array(
- 'fbrelevance' => $this->_folder->getFbrelevance(),
- 'xfbaccess' => $this->_folder->getXfbaccess()
- ));
- }
- if (is_a($params, 'PEAR_Error') || $params == '') {
- $params = $default;
- }
- $this->_data['params'] = serialize(array_merge($default, $params));
- break;
-
- case 'default':
- $this->_data['default'] = $this->_folder->isDefault();
- break;
-
- default:
- $annotation = $this->_folder->getAttribute($attribute);
- if (is_a($annotation, 'PEAR_Error') || empty($annotation)) {
- $annotation = '';
- }
- $this->_data[$attribute] = $annotation;
- break;
- }
-
- return $this->_data[$attribute];
- }
-
- /**
- * Sets an attribute value in this object.
- *
- * @param string $attribute The attribute to set.
- * @param mixed $value The value for $attribute.
- *
- * @return mixed True if setting the attribute did succeed, a PEAR_Error
- * otherwise.
- */
- function _set($attribute, $value)
- {
- switch ($attribute) {
- case 'name':
- /* On folder creation of default shares we wish to ignore
- * the names provided by the Horde applications. We use
- * the Kolab default names. */
- if (!isset($this->_folder)) {
- if ($this->get('default')) {
- $value = $this->getDefaultShareName();
- }
- $this->setFolder($this->_list->getNewFolder());
- }
- $this->_folder->setName($value);
- $this->_data['name'] = $this->_folder->getTitle();
- break;
-
- case 'params':
- $value = unserialize($value);
- if (isset($value['default'])) {
- $this->_data['default'] = $value['default'];
- unset($value['default']);
- }
- $value = serialize($value);
-
- default:
- $this->_data[$attribute] = $value;
- }
- }
-
- /**
- * Saves the current attribute values.
- */
- function _save()
- {
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
-
- $data = $this->_data;
- /** The name is handled immediately when set */
- unset($data['name']);
- $data['type'] = $this->_type;
-
- $result = $this->_folder->save($data);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-
- /** The name may have changed */
- $this->_data['name'] = $this->_folder->getTitle();
- $this->_folder_name = $this->_folder->name;
- return true;
- }
-
- /**
- * Delete this share.
- *
- * @return boolean|PEAR_Error True on success.
- */
- function delete()
- {
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
- return $this->_folder->delete();
- }
-
- /**
- * Checks to see if a user has a given permission.
- *
- * @param string $userid The userid of the user.
- * @param integer $permission A Horde_Perms::* constant to test for.
- * @param string $creator The creator of the shared object.
- *
- * @return boolean|PEAR_Error Whether or not $userid has $permission.
- */
- function hasPermission($userid, $permission, $creator = null)
- {
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
- return $this->_folder->hasPermission($userid, $permission, $creator);
- }
-
- /**
- * Returns the permissions from this storage object.
- *
- * @return Horde_Perms_Permission_Kolab|PEAR_Error The permissions on the share.
- */
- function &getPermission()
- {
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
- return $this->_folder->getPermission();
- }
-
- /**
- * Sets the permissions on the share.
- *
- * @param Horde_Perms_Permission_Kolab $perms Permission object to folder on the
- * object.
- * @param boolean $update Save the updated information?
- *
- * @return boolean|PEAR_Error True on success.
- */
- function setPermission(&$perms, $update = true)
- {
- if (!isset($this->_folder)) {
- return $this->_folderError();
- }
- return $this->_folder->setPermission($perms, $update);
- }
-
- /**
- * Return a standard error in case the share has not been
- * correctly initialized.
- *
- * @return PEAR_Error The PEAR_Error to return.
- */
- function _folderError()
- {
- return PEAR::raiseError(_("The Kolab share object has not been initialized yet!"));
- }
-}
+++ /dev/null
-<?php
-/**
- * Horde_Share_sql:: provides the sql backend for the horde share
- * driver.
- *
- * Copyright 2008-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 Duck <duck@obala.net>
- * @package Horde_Share
- */
-
-/** The share has user permissions */
-define('HORDE_SHARE_SQL_FLAG_USERS', 1);
-
-/** The share has group permissions */
-define('HORDE_SHARE_SQL_FLAG_GROUPS', 2);
-
-/**
- * @package Horde_Share
- */
-class Horde_Share_sql extends Horde_Share {
-
- /**
- * Handle for the current database connection.
- *
- * @var DB
- */
- var $_db;
-
- /**
- * Handle for the current database connection, used for writing. Defaults
- * to the same handle as $db if a separate write database is not required.
- *
- * @var DB
- */
- var $_write_db;
-
- /**
- * SQL connection parameters
- */
- var $_params = array();
-
- /**
- * Main share table for the current scope.
- *
- * @var string
- */
- var $_table;
-
- /**
- * The Horde_Share_Object subclass to instantiate objects as
- *
- * @var string
- */
- var $_shareObject = 'Horde_Share_Object_sql';
-
- /**
- * Initializes the object.
- */
- function __wakeup()
- {
- $this->_table = $this->_app . '_shares';
- $this->_connect();
-
- foreach (array_keys($this->_cache) as $name) {
- $this->_cache[$name]->setShareOb($this);
- }
-
- parent::__wakeup();
- }
-
- /**
- * Returns the properties that need to be serialized.
- *
- * @return array List of serializable properties.
- */
- function __sleep()
- {
- $properties = get_object_vars($this);
- unset($properties['_sortList'],
- $properties['_db'],
- $properties['_write_db']);
- return array_keys($properties);
- }
-
- /**
- * Get storage table
- */
- function getTable()
- {
- return $this->_table;
- }
-
- /**
- * Refetence to write db
- */
- function getWriteDb()
- {
- return $this->_write_db;
- }
-
- /**
- * Finds out if the share has user set
- */
- function _hasUsers($share)
- {
- return $share['share_flags'] & HORDE_SHARE_SQL_FLAG_USERS;
- }
-
- /**
- * Finds out if the share has user set
- */
- function _hasGroups($share)
- {
- return $share['share_flags'] & HORDE_SHARE_SQL_FLAG_GROUPS;
- }
-
- /**
- * Get users permissions
- *
- * @param array $share Share data array
- */
- function _getShareUsers(&$share)
- {
- if ($this->_hasUsers($share)) {
- $stmt = $this->_db->prepare('SELECT user_uid, perm FROM ' . $this->_table . '_users WHERE share_id = ?');
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($share['share_id']));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $share['perm']['users'][$row['user_uid']] = (int)$row['perm'];
- }
- }
- $stmt->free();
- $result->free();
- }
- }
-
- /**
- * Get groups permissions
- *
- * @param array $share Share data array
- */
- function _getShareGroups(&$share)
- {
- if ($this->_hasGroups($share)) {
- // Get groups permissions
- $stmt = $this->_db->prepare('SELECT group_uid, perm FROM ' . $this->_table . '_groups WHERE share_id = ?');
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($share['share_id']));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $share['perm']['groups'][$row['group_uid']] = (int)$row['perm'];
- }
- }
- $stmt->free();
- $result->free();
- }
- }
-
- /**
- * Returns a Horde_Share_Object_sql object corresponding to the given
- * share name, with the details retrieved appropriately.
- *
- * @param string $name The name of the share to retrieve.
- *
- * @return Horde_Share_Object_sql The requested share.
- */
- function _getShare($name)
- {
- $stmt = $this->_db->prepare('SELECT * FROM ' . $this->_table . ' WHERE share_name = ?');
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $results = $stmt->execute(array($name));
- if (is_a($results, 'PEAR_Error')) {
- Horde::logMessage($results, 'ERR');
- return $results;
- }
- $data = $results->fetchRow(MDB2_FETCHMODE_ASSOC);
- if (is_a($data, 'PEAR_Error')) {
- Horde::logMessage($data, 'ERR');
- return $data;
- } elseif (empty($data)) {
- return PEAR::RaiseError(sprintf(_("Share \"%s\" does not exist."), $name));
- }
- $stmt->free();
- $results->free();
-
- // Convert charset
- $data = $this->_fromDriverCharset($data);
-
- // Populate the perms array
- $this->_loadPermissions($data);
-
- return new $this->_shareObject($data);
- }
-
- /**
- * Helper function to load the permissions data into the share data
- *
- * @param array $data Array of share attributes
- */
- function _loadPermissions(&$data)
- {
- $this->_getShareUsers($data);
- $this->_getShareGroups($data);
- $this->_getSharePerms($data);
- }
-
- function _getSharePerms(&$data)
- {
- $data['perm']['type'] = 'matrix';
- $data['perm']['default'] = isset($data['perm_default']) ? (int)$data['perm_default'] : 0;
- $data['perm']['guest'] = isset($data['perm_guest']) ? (int)$data['perm_guest'] : 0;
- $data['perm']['creator'] = isset($data['perm_creator']) ? (int)$data['perm_creator'] : 0;
- unset($data['perm_creator'], $data['perm_guest'], $data['perm_default']);
- }
-
- /**
- * Returns a Horde_Share_Object_sql object corresponding to the given
- * unique ID, with the details retrieved appropriately.
- *
- * @param integer $cid The id of the share to retrieve.
- *
- * @return Horde_Share_Object_sql The requested share.
- */
- function _getShareById($id)
- {
- $params = array($id);
- $stmt = $this->_db->prepare('SELECT * FROM ' . $this->_table . ' WHERE share_id = ?');
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $results = $stmt->execute($params);
- if (is_a($results, 'PEAR_Error')) {
- Horde::logMessage($results, 'ERR');
- return $results;
- }
- $data = $results->fetchRow(MDB2_FETCHMODE_ASSOC);
- if (is_a($data, 'PEAR_Error')) {
- Horde::logMessage($data, 'ERR');
- return $data;
- } elseif (empty($data)) {
- return PEAR::RaiseError(sprintf(_("Share ID %d does not exist."), $id));
- }
-
- $stmt->free();
- $results->free();
-
- // Convert charset
- $data = $this->_fromDriverCharset($data);
-
- // Get permissions
- $this->_loadPermissions($data);
-
- return new $this->_shareObject($data);
- }
-
- /**
- * Returns an array of Horde_Share_Object_sql objects corresponding
- * to the given set of unique IDs, with the details retrieved
- * appropriately.
- *
- * @param array $cids The array of ids to retrieve.
- *
- * @return array The requested shares.
- */
- function _getShares($ids)
- {
- $shares = array();
- $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_id IN (' . implode(', ', $ids) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- $groups = array();
- $users = array();
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
- if ($this->_hasUsers($share)) {
- $users[] = (int)$share['share_id'];
- }
- if ($this->_hasGroups($share)) {
- $groups[] = (int)$share['share_id'];
- }
- }
- $result->free();
-
- // Get users permissions
- if (!empty($users)) {
- $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users '
- . ' WHERE share_id IN (' . implode(', ', $users) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- // Get groups permissions
- if (!empty($groups)) {
- $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups'
- . ' WHERE share_id IN (' . implode(', ', $groups) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- $sharelist = array();
- foreach ($shares as $id => $data) {
- $this->_getSharePerms($data);
- $sharelist[$data['share_name']] = new $this->_shareObject($data);
- }
-
- return $sharelist;
- }
-
- /**
- * Lists *all* shares for the current app/share, regardless of
- * permissions.
- *
- * This is for admin functionality and scripting tools, and shouldn't be
- * called from user-level code!
- *
- * @return array All shares for the current app/share.
- */
- function listAllShares()
- {
- return $this->_listAllShares();
- }
-
- /**
- * Lists *all* shares for the current app/share, regardless of
- * permissions.
- *
- * @return array All shares for the current app/share.
- */
- function _listAllShares()
- {
- $shares = array();
- $query = 'SELECT * FROM ' . $this->_table . ' ORDER BY share_name ASC';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
- }
- $result->free();
-
- // Get users permissions
- $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
-
- // Get groups permissions
- $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
-
- $sharelist = array();
- foreach ($shares as $id => $data) {
- $this->_getSharePerms($data);
- $sharelist[$data['share_name']] = new $this->_shareObject($data);
- $sharelist[$data['share_name']]->setShareOb($this);
- }
-
- return $sharelist;
- }
-
- /**
- * Returns an array of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return array The shares the user has access to.
- * @throws Horde_Exception
- */
- function listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
- $from = 0, $count = 0, $sort_by = null, $direction = 0)
- {
- $shares = array();
- if (is_null($sort_by)) {
- $sortfield = 's.share_name';
- } elseif ($sort_by == 'owner' || $sort_by == 'id') {
- $sortfield = 's.share_' . $sort_by;
- } else {
- $sortfield = 's.attribute_' . $sort_by;
- }
-
- $query = 'SELECT DISTINCT s.* '
- . $this->_getShareCriteria($userid, $perm, $attributes)
- . ' ORDER BY ' . $sortfield
- . (($direction == 0) ? ' ASC' : ' DESC');
- if ($from > 0 || $count > 0) {
- $this->_db->setLimit($count, $from);
- }
-
- // Fix field names for sqlite. MDB2 tries to handle this with
- // MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES, but it doesn't stick.
- if ($this->_db->phptype == 'sqlite') {
- $connection = $this->_db->getConnection();
- @sqlite_query('PRAGMA full_column_names=0', $connection);
- @sqlite_query('PRAGMA short_column_names=1', $connection);
- }
-
- Horde::logMessage(sprintf("SQL Query by Horde_Share_sql::listShares: %s", $query), 'DEBUG');
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- $users = array();
- $groups = array();
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
- if ($this->_hasUsers($share)) {
- $users[] = (int)$share['share_id'];
- }
- if ($this->_hasGroups($share)) {
- $groups[] = (int)$share['share_id'];
- }
- }
- $result->free();
-
- // Get users permissions
- if (!empty($users)) {
- $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table
- . '_users WHERE share_id IN (' . implode(', ', $users)
- . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- // Get groups permissions
- if (!empty($groups)) {
- $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table
- . '_groups WHERE share_id IN (' . implode(', ', $groups)
- . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- $sharelist = array();
- foreach ($shares as $id => $data) {
- $this->_getSharePerms($data);
- $sharelist[$data['share_name']] = new $this->_shareObject($data);
- $sharelist[$data['share_name']]->setShareOb($this);
- }
- unset($shares);
-
- try {
- return Horde::callHook('share_list', array($userid, $perm, $attributes, $sharelist));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- return $sharelist;
- }
-
- /**
- * Returns an array of all system shares.
- *
- * @return array All system shares.
- */
- function listSystemShares()
- {
- // Fix field names for sqlite. MDB2 tries to handle this with
- // MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES, but it doesn't stick.
- if ($this->_db->phptype == 'sqlite') {
- $connection = $this->_db->getConnection();
- @sqlite_query('PRAGMA full_column_names=0', $connection);
- @sqlite_query('PRAGMA short_column_names=1', $connection);
- }
-
- $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_owner IS NULL';
- Horde::logMessage('SQL Query by Horde_Share_sql::listSystemShares: ' . $query, 'DEBUG');
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- $sharelist = array();
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $data = $this->_fromDriverCharset($share);
- $this->_getSharePerms($data);
- $sharelist[$data['share_name']] = new $this->_shareObject($data);
- $sharelist[$data['share_name']]->setShareOb($this);
- }
- $result->free();
-
- return $sharelist;
- }
-
- /**
- * Returns the number of shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- *
- * @return integer The number of shares
- */
- function _countShares($userid, $perm = Horde_Perms::SHOW,
- $attributes = null)
- {
- $query = $this->_getShareCriteria($userid, $perm, $attributes);
- $query = 'SELECT COUNT(DISTINCT s.share_id) ' . $query;
- Horde::logMessage(sprintf("SQL Query by Horde_Share_sql::_countShares: %s", $query), 'DEBUG');
- return $this->_db->queryOne($query);
- }
-
- /**
- * Returns a new share object.
- *
- * @param string $name The share's name.
- *
- * @return Horde_Share_Object_sql A new share object.
- */
- function _newShare($name)
- {
- return new $this->_shareObject(array('share_name' => $name));
- }
-
- /**
- * Adds a share to the shares system.
- *
- * The share must first be created with
- * Horde_Share_sql::_newShare(), and have any initial details added
- * to it, before this function is called.
- *
- * @param Horde_Share_Object_sql $share The new share object.
- */
- function _addShare($share)
- {
- return $share->save();
- }
-
- /**
- * Removes a share from the shares system permanently.
- *
- * @param Horde_Share_Object_sql $share The share to remove.
- */
- function _removeShare($share)
- {
- $params = array($share->getId());
- $tables = array($this->_table,
- $this->_table . '_users',
- $this->_table . '_groups');
- foreach ($tables as $table) {
-
- /* Remove the share entry */
- $stmt = $this->_write_db->prepare('DELETE FROM ' . $table . ' WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute($params);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
- }
-
- return true;
- }
-
- /**
- * Checks if a share exists in the system.
- *
- * @param string $share The share to check.
- *
- * @return boolean True if the share exists.
- */
- function _exists($share)
- {
- $stmt = $this->_db->prepare('SELECT 1 FROM ' . $this->_table
- . ' WHERE share_name = ?');
-
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($share));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
-
- $exists = (bool)$result->fetchOne();
- $stmt->free();
- $result->free();
-
- return $exists;
- }
-
- /**
- * Returns an array of criteria for querying shares.
- * @access protected
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares returned to those who
- * have these attribute values.
- *
- * @return string The criteria string for fetching this user's shares.
- */
- function _getShareCriteria($userid, $perm = Horde_Perms::SHOW,
- $attributes = null)
- {
- $query = ' FROM ' . $this->_table . ' s ';
- $where = '';
-
- if (!empty($userid)) {
- // (owner == $userid)
- $where .= 's.share_owner = ' . $this->_write_db->quote($userid);
-
- // (name == perm_creator and val & $perm)
- $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_creator', '&', $perm) . ')';
-
- // (name == perm_creator and val & $perm)
- $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_default', '&', $perm) . ')';
-
- // (name == perm_users and key == $userid and val & $perm)
- $query .= ' LEFT JOIN ' . $this->_table . '_users u ON u.share_id = s.share_id';
- $where .= ' OR ( u.user_uid = ' . $this->_write_db->quote($userid)
- . ' AND (' . Horde_SQL::buildClause($this->_db, 'u.perm', '&', $perm) . '))';
-
- // If the user has any group memberships, check for those also.
- require_once 'Horde/Group.php';
- $group = Group::singleton();
- $groups = $group->getGroupMemberships($userid, true);
- if (!is_a($groups, 'PEAR_Error') && $groups) {
- // (name == perm_groups and key in ($groups) and val & $perm)
- $ids = array_keys($groups);
- $group_ids = array();
- foreach ($ids as $id) {
- $group_ids[] = $this->_db->quote((string)$id);
- }
- $query .= ' LEFT JOIN ' . $this->_table . '_groups g ON g.share_id = s.share_id';
- $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')'
- . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))';
- } elseif (is_a($groups, 'PEAR_Error')) {
- Horde::logMessage($groups, 'ERR');
- }
- } else {
- $where = '(' . Horde_SQL::buildClause($this->_db, 's.perm_guest', '&', $perm) . ')';
- }
-
- $attributes = $this->_toDriverKeys($attributes);
- $attributes = $this->_toDriverCharset($attributes);
-
- if (is_array($attributes)) {
- // Build attribute/key filter.
- $where = ' (' . $where . ') ';
- foreach ($attributes as $key => $value) {
- $where .= ' AND ' . $key . ' = ' . $this->_db->quote($value);
- }
- } elseif (!empty($attributes)) {
- // Restrict to shares owned by the user specified in the
- // $attributes string.
- $where = ' (' . $where . ') AND s.share_owner = ' . $this->_db->quote($attributes);
- }
-
- return $query . ' WHERE ' . $where;
- }
-
- /**
- * Resets the current database name so that MDB2 is always selecting the
- * database before sending a query.
- */
- function _selectDB($db, $scope, $message, $is_manip = null)
- {
- if ($scope == 'query') {
- $db->connected_database_name = '';
- }
- }
-
- /**
- * Attempts to open a connection to the sql server.
- *
- * @return boolean True on success.
- * @throws Horde_Exception
- */
- function _connect()
- {
- $this->_params = $GLOBALS['conf']['sql'];
- if (!isset($this->_params['database'])) {
- $this->_params['database'] = '';
- }
- if (!isset($this->_params['username'])) {
- $_params['username'] = '';
- }
- if (!isset($this->_params['hostspec'])) {
- $this->_params['hostspec'] = '';
- }
-
- /* Connect to the sql server using the supplied parameters. */
- $params = $this->_params;
- unset($params['charset']);
- $this->_write_db = MDB2::factory($params);
- if (is_a($this->_write_db, 'PEAR_Error')) {
- throw new Horde_Exception_Prior($this->_write_db);
- }
-
- /* Attach debug handler. */
- $this->_write_db->setOption('debug', true);
- $this->_write_db->setOption('debug_handler', array($this, '_selectDB'));
- $this->_write_db->setOption('seqcol_name', 'id');
-
- /* Set DB portability options. */
- switch ($this->_write_db->phptype) {
- case 'mssql':
- $this->_write_db->setOption('field_case', CASE_LOWER);
- $this->_write_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_RTRIM | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
- break;
-
- case 'pgsql':
- /* The debug handler breaks PostgreSQL. In most cases it shouldn't
- * be necessary, but this may mean we simply can't support use of
- * multiple Postgres databases right now. See
- * http://bugs.horde.org/ticket/7825 */
- $this->_write_db->setOption('debug', false);
- // Fall through
-
- default:
- $this->_write_db->setOption('field_case', CASE_LOWER);
- $this->_write_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
- }
-
- /* Check if we need to set up the read DB connection seperately. */
- if (!empty($this->_params['splitread'])) {
- $params = array_merge($params, $this->_params['read']);
- unset($params['charset']);
- $this->_db = MDB2::singleton($params);
- if (is_a($this->_db, 'PEAR_Error')) {
- throw new Horde_Exception_Prior($this->_db);
- }
-
- $this->_db->setOption('seqcol_name', 'id');
- /* Set DB portability options. */
- switch ($this->_db->phptype) {
- case 'mssql':
- $this->_db->setOption('field_case', CASE_LOWER);
- $this->_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_RTRIM | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
- break;
-
- case 'pgsql':
- /* The debug handler breaks PostgreSQL. In most cases it shouldn't
- * be necessary, but this may mean we simply can't support use of
- * multiple Postgres databases right now. See
- * http://bugs.horde.org/ticket/7825 */
- $this->_write_db->setOption('debug', false);
- // Fall through
-
- default:
- $this->_db->setOption('field_case', CASE_LOWER);
- $this->_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
- }
- } else {
- /* Default to the same DB handle as the writer for reading too */
- $this->_db = $this->_write_db;
- }
-
- return true;
- }
-
- /**
- * Utility function to convert from the SQL server's charset.
- */
- function _fromDriverCharset($data)
- {
- foreach ($data as $key => $value) {
- if (substr($key, 0, 9) == 'attribute') {
- $data[$key] = Horde_String::convertCharset(
- $data[$key], $this->_params['charset']);
- }
- }
-
- return $data;
- }
-
- /**
- * Utility function to convert TO the SQL server's charset.
- */
- function _toDriverCharset($data)
- {
- if (!is_array($data)) {
- return $data;
- }
-
- foreach ($data as $key => $value) {
- if (substr($key, 0, 9) == 'attribute') {
- $data[$key] = Horde_String::convertCharset(
- $data[$key], Horde_Nls::getCharset(), $this->_params['charset']);
- }
- }
-
- return $data;
- }
-
- /**
- * Convert an array keyed on client keys to an array keyed on the driver
- * keys.
- *
- * @param array $data The client code keyed array.
- *
- * @return array The driver keyed array.
- */
- function _toDriverKeys($data)
- {
- if (!is_array($data)) {
- return $data;
- }
-
- $driver_keys = array();
- foreach ($data as $key => $value) {
- if ($key == 'owner') {
- $driver_keys['share_owner'] = $value;
- } else {
- $driver_keys['attribute_' . $key] = $value;
- }
- }
-
- return $driver_keys;
- }
-
-}
-
-/**
- * Extension of the Horde_Share_Object class for storing share information in
- * the sql driver.
- *
- * @author Duck <duck@obala.net>
- * @package Horde_Share
- */
-class Horde_Share_Object_sql extends Horde_Share_Object {
-
- /**
- * The actual storage object that holds the data.
- *
- * @var mixed
- */
- var $data = array();
-
- /**
- * Constructor.
- *
- * @param array $data Share data array.
- */
- function Horde_Share_Object_sql($data)
- {
- if (!isset($data['perm']) || !is_array($data['perm'])) {
- $this->data['perm'] = array(
- 'users' => array(),
- 'type' => 'matrix',
- 'default' => isset($data['perm_default'])
- ? (int)$data['perm_default'] : 0,
- 'guest' => isset($data['perm_guest'])
- ? (int)$data['perm_guest'] : 0,
- 'creator' => isset($data['perm_creator'])
- ? (int)$data['perm_creator'] : 0,
- 'groups' => array());
-
- unset($data['perm_creator'], $data['perm_guest'],
- $data['perm_default']);
- }
- $this->data = array_merge($data, $this->data);
- }
-
- /**
- * Sets an attribute value in this object.
- *
- * @param string $attribute The attribute to set.
- * @param mixed $value The value for $attribute.
- *
- * @return mixed True if setting the attribute did succeed, a PEAR_Error
- * otherwise.
- */
- function _set($attribute, $value)
- {
- if ($attribute == 'owner') {
- return $this->data['share_owner'] = $value;
- } else {
- return $this->data['attribute_' . $attribute] = $value;
- }
- }
-
- /**
- * Returns one of the attributes of the object, or null if it isn't
- * defined.
- *
- * @param string $attribute The attribute to retrieve.
- *
- * @return mixed The value of the attribute, or an empty string.
- */
- function _get($attribute)
- {
- if ($attribute == 'owner') {
- return $this->data['share_owner'];
- } elseif (isset($this->data['attribute_' . $attribute])) {
- return $this->data['attribute_' . $attribute];
- }
- }
-
- /**
- * Returns the ID of this share.
- *
- * @return string The share's ID.
- */
- function _getId()
- {
- return isset($this->data['share_id']) ? $this->data['share_id'] : null;
- }
-
- /**
- * Returns the name of this share.
- *
- * @return string The share's name.
- */
- function _getName()
- {
- return $this->data['share_name'];
- }
-
- /**
- * Saves the current attribute values.
- */
- function _save()
- {
- $db = $this->_shareOb->getWriteDb();
- $table = $this->_shareOb->getTable();
-
- $fields = array();
- $params = array();
-
- foreach ($this->_shareOb->_toDriverCharset($this->data) as $key => $value) {
- if ($key != 'share_id' && $key != 'perm' && $key != 'share_flags') {
- $fields[] = $key;
- $params[] = $value;
- }
- }
-
- $fields[] = 'perm_creator';
- $params[] = isset($this->data['perm']['creator']) ? (int)$this->data['perm']['creator'] : 0;
-
- $fields[] = 'perm_default';
- $params[] = isset($this->data['perm']['default']) ? (int)$this->data['perm']['default'] : 0;
-
- $fields[] = 'perm_guest';
- $params[] = isset($this->data['perm']['guest']) ? (int)$this->data['perm']['guest'] : 0;
-
- $fields[] = 'share_flags';
- $flags = 0;
- if (!empty($this->data['perm']['users'])) {
- $flags |= HORDE_SHARE_SQL_FLAG_USERS;
- }
- if (!empty($this->data['perm']['groups'])) {
- $flags |= HORDE_SHARE_SQL_FLAG_GROUPS;
- }
- $params[] = $flags;
-
- if (empty($this->data['share_id'])) {
- $share_id = $db->nextId($table);
- if (is_a($share_id, 'PEAR_Error')) {
- Horde::logMessage($share_id, 'ERR');
- return $share_id;
- }
-
- $this->data['share_id'] = $share_id;
- $fields[] = 'share_id';
- $params[] = $this->data['share_id'];
-
- $query = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (?' . str_repeat(', ?', count($fields) - 1) . ')';
- } else {
- $query = 'UPDATE ' . $table . ' SET ' . implode(' = ?, ', $fields) . ' = ? WHERE share_id = ?';
- $params[] = $this->data['share_id'];
- }
- $stmt = $db->prepare($query, null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute($params);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
-
- // Update the share's user permissions
- $stmt = $db->prepare('DELETE FROM ' . $table . '_users WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($this->data['share_id']));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
-
- if (!empty($this->data['perm']['users'])) {
- $data = array();
- foreach ($this->data['perm']['users'] as $user => $perm) {
- $stmt = $db->prepare('INSERT INTO ' . $table . '_users (share_id, user_uid, perm) VALUES (?, ?, ?)', null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($this->data['share_id'], $user, $perm));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
- }
- }
-
- // Update the share's group permissions
- $stmt = $db->prepare('DELETE FROM ' . $table . '_groups WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($this->data['share_id']));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
-
- if (!empty($this->data['perm']['groups'])) {
- $data = array();
- foreach ($this->data['perm']['groups'] as $group => $perm) {
- $stmt = $db->prepare('INSERT INTO ' . $table . '_groups (share_id, group_uid, perm) VALUES (?, ?, ?)', null, MDB2_PREPARE_MANIP);
- if (is_a($stmt, 'PEAR_Error')) {
- Horde::logMessage($stmt, 'ERR');
- return $stmt;
- }
- $result = $stmt->execute(array($this->data['share_id'], $group, $perm));
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- }
- $stmt->free();
- }
- }
-
- return true;
- }
-
- /**
- * Checks to see if a user has a given permission.
- *
- * @param string $userid The userid of the user.
- * @param integer $permission A Horde_Perms::* constant to test for.
- * @param string $creator The creator of the event.
- *
- * @return boolean Whether or not $userid has $permission.
- */
- function hasPermission($userid, $permission, $creator = null)
- {
- if ($userid == $this->data['share_owner']) {
- return true;
- }
-
- return $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($this->getPermission(), $userid, $permission, $creator);
- }
-
- /**
- * Sets the permission of this share.
- *
- * @param Horde_Perms_Permission $perm Permission object.
- * @param boolean $update Should the share be saved
- * after this operation?
- *
- * @return boolean True if no error occured, PEAR_Error otherwise
- */
- function setPermission($perm, $update = true)
- {
- $this->data['perm'] = $perm->getData();
- if ($update) {
- return $this->save();
- }
- return true;
- }
-
- /**
- * Returns the permission of this share.
- *
- * @return Horde_Perms_Permission Permission object that represents the
- * permissions on this share.
- */
- function getPermission()
- {
- $perm = new Horde_Perms_Permission($this->getName());
- $perm->data = isset($this->data['perm'])
- ? $this->data['perm']
- : array();
-
- return $perm;
- }
-
-}
+++ /dev/null
-<?php
-/**
- * Implementation of Horde_Share class for shared objects that are hierarchical
- * in nature.
- *
- * @author Duck <duck@obala.net>
- * @author Michael J. Rubinsky <mrubinsk@horde.org>
- * @package Horde_Share
- */
-class Horde_Share_sql_hierarchical extends Horde_Share_sql {
-
- /**
- * The Horde_Share_Object subclass to instantiate objects as
- *
- * @var string
- */
- var $_shareObject = 'Horde_Share_Object_sql_hierarchical';
-
- /**
- * Override new share creation so we can allow for shares with empty
- * share_names.
- *
- */
- function &newShare($name = '')
- {
- $share = &$this->_newShare();
- $share->setShareOb($this);
- $share->set('owner', Horde_Auth::getAuth());
- return $share;
- }
-
- /**
- * Returns a new share object.
- *
- * @param string $name The share's name.
- *
- * @return Horde_Share_Object_sql A new share object.
- */
- function &_newShare()
- {
- $share = new $this->_shareObject();
- return $share;
- }
-
- /**
- * Returns an array of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- * @param integer $from The share to start listing from.
- * @param integer $count The number of shares to return.
- * @param string $sort_by The field to sort by
- * @param integer $direction The sort direction
- * @param mixed $parent Either a share_id, Horde_Share_Object or null.
- * @param boolean $alllevels List all levels or just the direct children
- * of $parent?
- *
- * @return mixed The shares the user has access to || PEAR_Error
- */
- function &listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
- $from = 0, $count = 0, $sort_by = null,
- $direction = 0, $parent = null,
- $allLevels = true, $ignorePerms = false)
- {
- $shares = array();
- if (is_null($sort_by)) {
- $sortfield = 's.share_id';
- } elseif ($sort_by == 'owner' || $sort_by == 'id') {
- $sortfield = 's.share_' . $sort_by;
- } else {
- $sortfield = 's.attribute_' . $sort_by;
- }
-
- $query = 'SELECT DISTINCT s.* '
- . $this->_getShareCriteria($userid, $perm, $attributes,
- $parent, $allLevels, $ignorePerms)
- . ' ORDER BY ' . $sortfield
- . (($direction == 0) ? ' ASC' : ' DESC');
- if ($from > 0 || $count > 0) {
- $this->_db->setLimit($count, $from);
- }
-
- Horde::logMessage('Query By Horde_Share_sql_hierarchical: ' . $query, 'DEBUG');
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- $users = array();
- $groups = array();
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
- if ($this->_hasUsers($share)) {
- $users[] = (int)$share['share_id'];
- }
- if ($this->_hasGroups($share)) {
- $groups[] = (int)$share['share_id'];
- }
- }
- $result->free();
-
- // Get users permissions
- if (!empty($users)) {
- $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table
- . '_users WHERE share_id IN (' . implode(', ', $users)
- . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- // Get groups permissions
- if (!empty($groups)) {
- $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table
- . '_groups WHERE share_id IN (' . implode(', ', $groups)
- . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- $sharelist = array();
- foreach ($shares as $id => $data) {
- $this->_getSharePerms($data);
- $sharelist[$id] = new $this->_shareObject($data);
- $sharelist[$id]->setShareOb($this);
- }
- unset($shares);
-
- try {
- return Horde::callHook('share_list', array($userid, $perm, $attributes, $sharelist));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- return $sharelist;
- }
-
- /**
- * Returns an array of criteria for querying shares.
- * @access protected
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares returned to those who
- * have these attribute values.
- * @param mixed $parent The share to start searching in.
- * (A Horde_Share_Object, share_id or null)
- * @param boolean $allLevels Return all levels, or just the direct
- * children of $parent? Defaults to all levels.
- *
- * @return string The criteria string for fetching this user's shares.
- */
- function _getShareCriteria($userid, $perm = Horde_Perms::SHOW, $attributes = null,
- $parent = null, $allLevels = true,
- $ignorePerms = false)
- {
- static $criteria;
-
- if (is_a($parent, 'Horde_Share_Object')) {
- $parent_id = $parent->getId();
- } else {
- $parent_id = $parent;
- }
- $key = $userid . $perm . $parent_id . $allLevels
- . (is_array($attributes) ? serialize($attributes) : $attributes);
- if (isset($criteria[$key])) {
- return $criteria[$key];
- }
-
- $query = ' FROM ' . $this->_table . ' s ';
- $where = '';
-
- if (!$ignorePerms) {
- if (empty($userid)) {
- $where = '(' . Horde_SQL::buildClause($this->_db, 's.perm_guest', '&', $perm) . ')';
- } else {
- // (owner == $userid)
- $where = 's.share_owner = ' . $this->_db->quote($userid);
-
- // (name == perm_creator and val & $perm)
- $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_creator', '&', $perm) . ')';
-
- // (name == perm_creator and val & $perm)
- $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_default', '&', $perm) . ')';
-
- // (name == perm_users and key == $userid and val & $perm)
- $query .= ' LEFT JOIN ' . $this->_table . '_users AS u ON u.share_id = s.share_id';
- $where .= ' OR ( u.user_uid = ' . $this->_write_db->quote($userid)
- . ' AND (' . Horde_SQL::buildClause($this->_db, 'u.perm', '&', $perm) . '))';
-
- // If the user has any group memberships, check for those also.
- require_once 'Horde/Group.php';
- $group = &Group::singleton();
- $groups = $group->getGroupMemberships($userid, true);
- if (!is_a($groups, 'PEAR_Error') && $groups) {
- // (name == perm_groups and key in ($groups) and val & $perm)
- $ids = array_keys($groups);
- $group_ids = array();
- foreach ($ids as $id) {
- $group_ids[] = $this->_db->quote((string)$id);
- }
- $query .= ' LEFT JOIN ' . $this->_table . '_groups AS g ON g.share_id = s.share_id';
- $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')'
- . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))';
- }
- }
- }
-
- /* Convert to driver's keys */
- $attributes = $this->_toDriverKeys($attributes);
-
- /* ...and to driver charset */
- $attributes = $this->_toDriverCharset($attributes);
-
- if (is_array($attributes)) {
- // Build attribute/key filter.
- if (!empty($where)) {
- $where = ' (' . $where . ') ';
- }
- foreach ($attributes as $key => $value) {
- $where .= ' AND ' . $key;
- if (is_array($value)) {
- $where .= ' ' . $value[0]. ' ' . $this->_db->quote($value[1]);
- } else {
- $where .= ' = ' . $this->_db->quote($value);
- }
- }
- } elseif (!empty($attributes)) {
- // Restrict to shares owned by the user specified
- $where = (!empty($where) ? ' (' . $where . ') AND ' : ' ') . 's.share_owner = ' . $this->_db->quote($attributes);
- }
-
- // See if we need to filter by parent or get the parent object
- if ($parent != null) {
- if (!is_a($parent, 'Horde_Share_Object')) {
- $parent = $this->getShareById($parent);
- if (is_a($parent, 'PEAR_Error')) {
- return $parent;
- }
- }
-
- // Need to append the parent's share id to the list of parents in
- // order to search the share_parents field.
- $parents = $parent->get('parents') . ':' . $parent->getId();
- if ($allLevels) {
- $where_parent = '(share_parents = ' . $this->_db->quote($parents)
- . ' OR share_parents LIKE ' . $this->_db->quote($parents . ':%') . ')';
- } else {
- $where_parent = 's.share_parents = ' . $this->_db->quote($parents);
- }
- } elseif (!$allLevels) {
- // No parents, and we only want the root.
- $where_parent = "(s.share_parents = '' OR s.share_parents IS NULL)";
- }
-
- if (empty($where_parent)) {
- $criteria[$key] = $query . ' WHERE ' . $where;
- } else {
- if (!empty($where)) {
- $criteria[$key] = $query . ' WHERE (' . $where . ') AND ' . $where_parent;
- } else {
- $criteria[$key] = $query . ' WHERE ' . $where_parent;
- }
- }
-
- return $criteria[$key];
- }
-
- /**
- * Return a list of users who have shares with the given permissions
- * for the current user.
- *
- * @param integer $perm The level of permissions required.
- * @param mixed $parent The parent share to start looking in.
- * (Horde_Share_Object, share_id, or null)
- * @param boolean $allLevels Return all levels, or just the direct
- * children of $parent? Defaults to all levels.
- * @param integer $from The user to start listing at.
- * @param integer $count The number of users to return.
- *
- * @return array List of users.
- */
- function listOwners($perm = Horde_Perms::SHOW, $parent = null, $allLevels = true,
- $from = 0, $count = 0)
- {
- $sql = 'SELECT DISTINCT(s.share_owner) '
- . $this->_getShareCriteria(Horde_Auth::getAuth(), $perm, null,
- $parent, $allLevels);
-
- if ($count) {
- $this->_db->setLimit($count, $from);
- }
-
- $allowners = $this->_db->queryCol($sql);
- if (is_a($allowners, 'PEAR_Error')) {
- Horde::logMessage($allowners, 'ERR');
- return $allowners;
- }
-
- $owners = array();
- foreach ($allowners as $owner) {
- if ($this->countShares(Horde_Auth::getAuth(), $perm, $owner, $parent,
- $allLevels)) {
-
- $owners[] = $owner;
- }
- }
-
- return $owners;
- }
-
- /**
- * Count the number of users who have shares with the given permissions
- * for the current user.
- *
- * @param integer $perm The level of permissions required.
- * @param mixed $parent The parent share to start looking in.
- * (Horde_Share_Object, share_id, or null).
- * @param boolean $allLevels Return all levels, or just the direct
- * children of $parent?
- *
- * @return integer Number of users.
- */
- function countOwners($perm = Horde_Perms::SHOW, $parent = null, $allLevels = true)
- {
- $sql = 'SELECT COUNT(DISTINCT(s.share_owner)) '
- . $this->_getShareCriteria(Horde_Auth::getAuth(), $perm, null, $parent,
- $allLevels);
-
- return $this->_db->queryOne($sql);
- }
-
- /**
- * Returns a share's direct parent object.
- *
- * @param Horde_Share_Object $share The share to get parent for.
- *
- * @return Horde_Share_Object The parent share, if it exists.
- */
- function getParent($child)
- {
- $parents = $child->get('parents');
-
- // No parents, this is at the root.
- if (empty($parents)) {
- return null;
- }
- $parents = explode(':', $parents);
- return $this->getShareById(array_pop($parents));
- }
-
- /**
- * Returns a Horde_Share_Object object corresponding to the given unique
- * ID, with the details retrieved appropriately.
- *
- * @param string $cid The id of the share to retrieve.
- *
- * @return Horde_Share_Object The requested share.
- */
- function &getShareById($cid)
- {
- if (!isset($this->_cache[$cid])) {
- $share = &$this->_getShareById($cid);
- if (is_a($share, 'PEAR_Error')) {
- return $share;
- }
- $share->setShareOb($this);
- $this->_cache[$cid] = &$share;
- }
-
- return $this->_cache[$cid];
- }
-
- /**
- * Returns an array of Horde_Share_Object objects corresponding to the
- * given set of unique IDs, with the details retrieved appropriately.
- *
- * @param array $cids The array of ids to retrieve.
- *
- * @return array The requested shares keyed by share_id.
- */
- function &getShares($cids)
- {
- $all_shares = array();
- $missing_ids = array();
- foreach ($cids as $cid) {
- if (isset($this->_cache[$cid])) {
- $all_shares[] = &$this->_cache[$cid];
- } else {
- $missing_ids[] = $cid;
- }
- }
-
- if (count($missing_ids)) {
- $shares = &$this->_getShares($missing_ids);
- if (is_a($shares, 'PEAR_Error')) {
- return $shares;
- }
-
- foreach (array_keys($shares) as $key) {
- $this->_cache[$key] = &$shares[$key];
- $this->_cache[$key]->setShareOb($this);
- $all_shares[$key] = &$this->_cache[$key];
- }
- }
-
- return $all_shares;
- }
-
- /**
- * Removes a share from the shares system permanently. This will recursively
- * delete all child shares as well.
- *
- * @param Horde_Share_Object $share The share to remove.
- * @throws Horde_Exception
- */
- function removeShare(&$share)
- {
- if (!is_a($share, 'Horde_Share_Object')) {
- return PEAR::raiseError('Shares must be Horde_Share_Object objects or extend that class.');
- }
-
- try {
- Horde::callHook('share_remove', array($share));
- } catch (Horde_Exception_HookNotSet $e) {}
-
- /* Get the list of all $share's children */
- $children = $share->getChildren(null, true);
-
- /* Remove share from the caches. */
- $id = $share->getId();
- $this->_cache = array();
- $this->_listCache = array();
-
- foreach ($children as $child) {
- $result = $this->_removeShare($child);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
- }
-
- return $this->_removeShare($share);
- }
-
- /**
- * Returns an array of Horde_Share_Object_sql objects corresponding
- * to the given set of unique IDs, with the details retrieved
- * appropriately.
- *
- * @param array $cids The array of ids to retrieve.
- *
- * @return array The requested shares keyed by share_id.
- */
- function &_getShares($ids)
- {
- $shares = array();
- $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_id IN (' . implode(', ', $ids) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (empty($result)) {
- return array();
- }
-
- $groups = array();
- $users = array();
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
- if ($this->_hasUsers($share)) {
- $users[] = (int)$share['share_id'];
- }
- if ($this->_hasGroups($share)) {
- $groups[] = (int)$share['share_id'];
- }
- }
- $result->free();
-
- // Get users permissions
- if (!empty($users)) {
- $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users '
- . ' WHERE share_id IN (' . implode(', ', $users) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- // Get groups permissions
- if (!empty($groups)) {
- $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups'
- . ' WHERE share_id IN (' . implode(', ', $groups) . ')';
- $result = $this->_db->query($query);
- if (is_a($result, 'PEAR_Error')) {
- Horde::logMessage($result, 'ERR');
- return $result;
- } elseif (!empty($result)) {
- while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
- $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
- }
- $result->free();
- }
- }
-
- $sharelist = array();
- foreach ($shares as $id => $data) {
- $sharelist[$id] = new $this->_shareObject($data);
- }
-
- return $sharelist;
- }
-
- /**
- * Override the Horde_Share base class to avoid any confusion
- *
- */
- function getShare($name)
- {
- return PEAR::raiseError(_("Share names are not supported in this driver"));
- }
-
- /**
- * Returns the count of all shares that $userid has access to.
- *
- * @param string $userid The userid of the user to check access for.
- * @param integer $perm The level of permissions required.
- * @param mixed $attributes Restrict the shares counted to those
- * matching $attributes. An array of
- * attribute/values pairs or a share owner
- * username.
- * @param mixed $parent The share to start searching from
- * (Horde_Share_Object, share_id, or null)
- * @param boolean $allLevels Return all levels, or just the direct
- * children of $parent?
- *
- * @return integer Number of shares the user has access to.
- */
- function countShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
- $parent = null, $allLevels = true)
- {
- $query = 'SELECT COUNT(DISTINCT s.share_id) '
- . $this->_getShareCriteria($userid, $perm, $attributes,
- $parent, $allLevels);
-
- return $this->_db->queryOne($query);
- }
-
-}
-
-/**
- * Class for storing Share information.
- */
-class Horde_Share_Object_sql_hierarchical extends Horde_Share_Object_sql {
-
- /**
- * Constructor. This is here primarily to make calling the parent
- * constructor(s) from any subclasses cleaner.
- *
- * @param unknown_type $data
- * @return Horde_Share_Object_sql_hierarchical
- */
- function Horde_Share_Object_sql_hierarchical($data)
- {
- if (!isset($data['share_parents'])) {
- $data['share_parents'] = null;
- }
- parent::Horde_Share_Object_sql($data);
- }
-
- function inheritPermissions()
- {
- //FIXME: Not called from anywhere yet anyway.
- }
-
- /**
- * Return a count of the number of children this share has
- *
- * @param integer $perm A Horde_Perms::* constant
- * @param boolean $allLevels Count grandchildren or just children
- *
- * @return mixed The number of child shares || PEAR_Error
- */
- function countChildren($perm = Horde_Perms::SHOW, $allLevels = true)
- {
- return $this->_shareOb->countShares(Horde_Auth::getAuth(), $perm, null, $this, $allLevels);
- }
-
- /**
- * Get all children of this share.
- *
- * @param int $perm Horde_Perms::* constant. If NULL will return
- * all shares regardless of permissions.
- * @param boolean $allLevels Return all levels.
- *
- * @return mixed An array of Horde_Share_Object objects || PEAR_Error
- */
- function getChildren($perm = Horde_Perms::SHOW, $allLevels = true)
- {
- return $this->_shareOb->listShares(Horde_Auth::getAuth(), $perm, null, 0, 0,
- null, 1, $this, $allLevels, is_null($perm));
-
- }
-
- /**
- * Returns a child's direct parent
- *
- * @return mixed The direct parent Horde_Share_Object or PEAR_Error
- */
- function getParent()
- {
- return $this->_shareOb->getParent($this);
- }
-
- /**
- * Get all of this share's parents.
- *
- * @return array() An array of Horde_Share_Objects
- */
- function getParents()
- {
- $parents = array();
- $share = $this->getParent();
- while (is_a($share, 'Horde_Share_Object')) {
- $parents[] = $share;
- $share = $share->getParent();
- }
- return array_reverse($parents);
- }
-
- /**
- * Set the parent object for this share.
- *
- * @param mixed $parent A Horde_Share object or share id for the parent.
- *
- * @return mixed true || PEAR_Error
- */
- function setParent($parent)
- {
- if (!is_null($parent) && !is_a($parent, 'Horde_Share_Object')) {
- $parent = $this->_shareOb->getShareById($parent);
- if (is_a($parent, 'PEAR_Error')) {
- Horde::logMessage($parent, 'ERR');
- return $parent;
- }
- }
-
- /* If we are an existing share, check for any children */
- if ($this->getId()) {
- $children = $this->_shareOb->listShares(
- Horde_Auth::getAuth(), Horde_Perms::EDIT, null, 0, 0, null, 0,
- $this->getId());
- } else {
- $children = array();
- }
-
- /* Can't set a child share as a parent */
- if (!empty($parent) && in_array($parent->getId(), array_keys($children))) {
- return PEAR::raiseError('Cannot set an existing child as the parent');
- }
-
- if (!is_null($parent)) {
- $parent_string = $parent->get('parents') . ':' . $parent->getId();
- } else {
- $parent_string = null;
- }
- $this->data['share_parents'] = $parent_string;
- $query = $this->_shareOb->_write_db->prepare('UPDATE ' . $this->_shareOb->_table . ' SET share_parents = ? WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
- $result = $query->execute(array($this->data['share_parents'], $this->getId()));
- $query->free();
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-
- /* Now we can reset the children's parent */
- foreach($children as $child) {
- $child->setParent($this);
- }
-
- return true;
- }
-
- /**
- * Returns the permission of this share.
- *
- * @return Horde_Perms_Permission Permission object that represents the
- * permissions on this share.
- */
- function &getPermission()
- {
- $perm = new Horde_Perms_Permission('');
- $perm->data = isset($this->data['perm'])
- ? $this->data['perm']
- : array();
-
- return $perm;
- }
-
- /**
- * Returns one of the attributes of the object, or null if it isn't
- * defined.
- *
- * @param string $attribute The attribute to retrieve.
- *
- * @return mixed The value of the attribute, or an empty string.
- */
- function _get($attribute)
- {
- if ($attribute == 'owner' || $attribute == 'parents') {
- return $this->data['share_' . $attribute];
- } elseif (isset($this->data['attribute_' . $attribute])) {
- return $this->data['attribute_' . $attribute];
- } else {
- return null;
- }
- }
-
- /**
- * Hierarchical shares do not have share names.
- *
- * @return unknown
- */
- function _getName()
- {
- return '';
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Horde_Share:: provides an interface to all shares a user might have. Its
+ * methods take care of any site-specific restrictions configured in in the
+ * application's prefs.php and conf.php files.
+ *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ * Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
+ *
+ * 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 Joel Vandal <joel@scopserv.com>
+ * @author Mike Cochrame <mike@graftonhall.co.nz>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Jan Schneider <jan@horde.org>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share
+{
+ /**
+ * The application we're managing shares for.
+ *
+ * @var string
+ */
+ protected $_app;
+
+ /**
+ * The root of the Share tree.
+ *
+ * @var mixed
+ */
+ protected $_root = null;
+
+ /**
+ * A cache of all shares that have been retrieved, so we don't hit the
+ * backend again and again for them.
+ *
+ * @var array
+ */
+ protected $_cache = array();
+
+ /**
+ * Id-name-map of already cached share objects.
+ *
+ * @var array
+ */
+ protected $_shareMap = array();
+
+ /**
+ * Cache used for listShares().
+ *
+ * @var array
+ */
+ protected $_listcache = array();
+
+ /**
+ * A list of objects that we're currently sorting, for reference during the
+ * sorting algorithm.
+ *
+ * @var array
+ */
+ protected $_sortList;
+
+ /**
+ * The Horde_Share_Object subclass to instantiate objects as
+ *
+ * @var string
+ */
+ protected $_shareObject;
+
+
+ /**
+ * Attempts to return a reference to a concrete Horde_Share instance.
+ *
+ * It will only create a new instance if no Horde_Share instance currently
+ * exists.
+ *
+ * @param string $app The application that the shares relates to.
+ * @param string $driver Type of concrete Share subclass to return,
+ * based on storage driver ($driver). The code is
+ * dynamically included.
+ *
+ * @return Horde_Share The concrete Share reference, or false on an error.
+ */
+ public static function singleton($app, $driver = null)
+ {
+ static $shares = array();
+
+ // FIXME: This is a temporary solution until the configuration value
+ // actually exists and all apps call this code in the correct fashion.
+ $driver = basename($driver);
+ if (empty($driver)) {
+ if (!empty($GLOBALS['conf']['share']['driver'])) {
+ $driver = $GLOBALS['conf']['share']['driver'];
+ } else {
+ $driver = 'datatree';
+ }
+ }
+
+ $class = 'Horde_Share_' . $driver;
+ if (!class_exists($class)) {
+ include dirname(__FILE__) . '/Share/' . $driver . '.php';
+ }
+
+ $signature = $app . '_' . $driver;
+ if (!isset($shares[$signature]) &&
+ !empty($GLOBALS['conf']['share']['cache'])) {
+ $session = new Horde_SessionObjects();
+ $shares[$signature] = $session->query('horde_share_' . $app . '_' . $driver . '1');
+ }
+
+ if (empty($shares[$signature])) {
+ if (class_exists($class)) {
+ $shares[$signature] = new $class($app);
+ } else {
+ $result = PEAR::raiseError(sprintf(_("\"%s\" share driver not found."), $driver));
+ return $result;
+ }
+ }
+
+ if (!empty($GLOBALS['conf']['share']['cache'])) {
+ register_shutdown_function(array($shares[$signature], 'shutdown'));
+ }
+
+ return $shares[$signature];
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param string $app The application that the shares belong to.
+ */
+ public function __construct($app)
+ {
+ $this->_app = $app;
+ $this->__wakeup();
+ }
+
+ /**
+ * Initializes the object.
+ *
+ * @throws Horde_Exception
+ */
+ public function __wakeup()
+ {
+ try {
+ Horde::callHook('share_init', array($this, $this->_app));
+ } catch (Horde_Exception_HookNotSet $e) {}
+ }
+
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['_sortList']);
+ $properties = array_keys($properties);
+ return $properties;
+ }
+
+ /**
+ * Stores the object in the session cache.
+ */
+ public function shutdown()
+ {
+ $driver = str_replace('horde_share_', '', Horde_String::lower(get_class($this)));
+ $session = new Horde_SessionObjects();
+ $session->overwrite('horde_share_' . $this->_app . '_' . $driver, $this, false);
+ }
+
+ /**
+ * Returns the application we're managing shares for.
+ *
+ * @return string The application this share belongs to.
+ */
+ public function getApp()
+ {
+ return $this->_app;
+ }
+
+ /**
+ * Returns a Horde_Share_Object object corresponding to the given share
+ * name, with the details retrieved appropriately.
+ *
+ * @param string $name The name of the share to retrieve.
+ *
+ * @return Horde_Share_Object The requested share.
+ */
+ public function getShare($name)
+ {
+ if (isset($this->_cache[$name])) {
+ return $this->_cache[$name];
+ }
+
+ $share = $this->_getShare($name);
+ $share->setShareOb($this);
+ $this->_shareMap[$share->getId()] = $name;
+ $this->_cache[$name] = $share;
+
+ return $share;
+ }
+
+ /**
+ * Returns a Horde_Share_Object object corresponding to the given unique
+ * ID, with the details retrieved appropriately.
+ *
+ * @param string $cid The id of the share to retrieve.
+ *
+ * @return Horde_Share_Object The requested share.
+ */
+ public function getShareById($cid)
+ {
+ if (!isset($this->_shareMap[$cid])) {
+ $share = $this->_getShareById($cid);
+ $share->setShareOb($this);
+ $name = $share->getName();
+ $this->_cache[$name] = $share;
+ $this->_shareMap[$cid] = $name;
+ }
+
+ return $this->_cache[$this->_shareMap[$cid]];
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object objects corresponding to the
+ * given set of unique IDs, with the details retrieved appropriately.
+ *
+ * @param array $cids The array of ids to retrieve.
+ *
+ * @return array The requested shares.
+ */
+ public function getShares($cids)
+ {
+ $all_shares = array();
+ $missing_ids = array();
+ foreach ($cids as $cid) {
+ if (isset($this->_shareMap[$cid])) {
+ $all_shares[$this->_shareMap[$cid]] = $this->_cache[$this->_shareMap[$cid]];
+ } else {
+ $missing_ids[] = $cid;
+ }
+ }
+
+ if (count($missing_ids)) {
+ $shares = $this->_getShares($missing_ids);
+ foreach (array_keys($shares) as $key) {
+ $this->_cache[$key] = $shares[$key];
+ $this->_cache[$key]->setShareOb($this);
+ $this->_shareMap[$shares[$key]->getId()] = $key;
+ $all_shares[$key] = $this->_cache[$key];
+ }
+ }
+
+ return $all_shares;
+ }
+
+ /**
+ * Lists *all* shares for the current app/share, regardless of
+ * permissions.
+ *
+ * This is for admin functionality and scripting tools, and shouldn't be
+ * called from user-level code!
+ *
+ * @return array All shares for the current app/share.
+ */
+ public function listAllShares()
+ {
+ $shares = $this->_listAllShares();
+ $this->_sortList = $shares;
+ uasort($shares, array($this, '_sortShares'));
+ $this->_sortList = null;
+
+ return $shares;
+ }
+
+ /**
+ * Returns an array of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return array The shares the user has access to.
+ */
+ public function listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
+ $from = 0, $count = 0, $sort_by = null, $direction = 0)
+ {
+ $shares = $this->_listShares($userid, $perm, $attributes, $from,
+ $count, $sort_by, $direction);
+ if (!count($shares)) {
+ return $shares;
+ }
+
+ $shares = $this->getShares($shares);
+ if (is_null($sort_by)) {
+ $this->_sortList = $shares;
+ uasort($shares, array($this, '_sortShares'));
+ $this->_sortList = null;
+ }
+
+ try {
+ return Horde::callHook('share_list', array($userid, $perm, $attributes, $shares));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ return $shares;
+ }
+
+ /**
+ * Returns an array of all system shares.
+ *
+ * @return array All system shares.
+ */
+ public function listSystemShares()
+ {
+ return array();
+ }
+
+ /**
+ * Returns the number of shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return integer The number of shares
+ */
+ public function countShares($userid, $perm = Horde_Perms::SHOW, $attributes = null)
+ {
+ return $this->_countShares($userid, $perm, $attributes);
+ }
+
+ /**
+ * Returns a new share object.
+ *
+ * @param string $name The share's name.
+ *
+ * @return Horde_Share_Object A new share object.
+ * @throws Horde_Share_Exception
+ */
+ public function newShare($name)
+ {
+ if (empty($name)) {
+ throw new Horde_Share_Exception('Share names must be non-empty');
+ }
+ $share = $this->_newShare($name);
+ $share->setShareOb($this);
+ $share->set('owner', Horde_Auth::getAuth());
+
+ return $share;
+ }
+
+ /**
+ * Adds a share to the shares system.
+ *
+ * The share must first be created with Horde_Share::newShare(), and have
+ * any initial details added to it, before this function is called.
+ *
+ * @param Horde_Share_Object $share The new share object.
+ *
+ * @return boolean
+ * @throws Horde_Share_Exception
+ */
+ public function addShare($share)
+ {
+ if (!is_a($share, 'Horde_Share_Object')) {
+ throw new Horde_Share_Exception('Shares must be Horde_Share_Object objects or extend that class.');
+ }
+
+ try {
+ Horde::callHook('share_add', array($share));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ $result = $this->_addShare($share);
+
+ /* Store new share in the caches. */
+ $id = $share->getId();
+ $name = $share->getName();
+ $this->_cache[$name] = $share;
+ $this->_shareMap[$id] = $name;
+
+ /* Reset caches that depend on unknown criteria. */
+ $this->_listCache = array();
+
+ return $result;
+ }
+
+ /**
+ * Removes a share from the shares system permanently.
+ *
+ * @param Horde_Share_Object $share The share to remove.
+ *
+ * @throws Horde_Share_Exception
+ */
+ public function removeShare($share)
+ {
+ if (!is_a($share, 'Horde_Share_Object')) {
+ throw new Horde_Share_Exception('Shares must be Horde_Share_Object objects or extend that class.');
+ }
+
+ try {
+ Horde::callHook('share_remove', array($share));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ /* Remove share from the caches. */
+ $id = $share->getId();
+ unset($this->_shareMap[$id]);
+ unset($this->_cache[$share->getName()]);
+
+ /* Reset caches that depend on unknown criteria. */
+ $this->_listCache = array();
+
+ return $this->_removeShare($share);
+ }
+
+ /**
+ * Checks if a share exists in the system.
+ *
+ * @param string $share The share to check.
+ *
+ * @return boolean True if the share exists.
+ */
+ public function exists($share)
+ {
+ if (isset($this->_cache[$share])) {
+ return true;
+ }
+
+ return $this->_exists($share);
+ }
+
+ /**
+ * Finds out what rights the given user has to this object.
+ *
+ * @see Horde_Perms::getPermissions
+ *
+ * @param mixed $share The share that should be checked for the users
+ * permissions.
+ * @param string $user The user to check for.
+ *
+ * @return mixed A bitmask of permissions, a permission value, or an array
+ * of permission values the user has, depending on the
+ * permission type and whether the permission value is
+ * ambiguous. False if there is no such permsission.
+ */
+ public function getPermissions($share, $user = null)
+ {
+ if (!is_a($share, 'Horde_Share_Object')) {
+ $share = $this->getShare($share);
+ }
+
+ $perm = $share->getPermission();
+ return $GLOBALS['injector']->getInstance('Horde_Perms')->getPermissions($perm, $user);
+ }
+
+ /**
+ * Returns the Identity for a particular share owner.
+ *
+ * @deprecated
+ *
+ * @param mixed $share The share to fetch the Identity for - either the
+ * string name, or the Horde_Share_Object object.
+ *
+ * @return Identity An Identity instance.
+ */
+ public function getIdentityByShare($share)
+ {
+ if (!is_a($share, 'Horde_Share_Object')) {
+ $share = $this->getShare($share);
+ }
+
+ // TODO: Need to inject this into this method instead of using injector
+ return $GLOBALS['injector']->getInstance('Horde_Prefs_Identity')->getIdentity($share->get('owner'));
+ }
+
+ /**
+ * Set the class type to use for creating share objects.
+ *
+ * @var string $classname The classname to use.
+ */
+ public function setShareClass($classname)
+ {
+ $this->_shareObject = $classname;
+ }
+
+ /**
+ * Utility function to be used with uasort() for sorting arrays of
+ * Horde_Share objects.
+ *
+ * Example:
+ * <code>
+ * uasort($list, array('Horde_Share', '_sortShares'));
+ * </code>
+ *
+ * @access protected
+ */
+ protected function _sortShares($a, $b)
+ {
+ $aParts = explode(':', $a->getName());
+ $bParts = explode(':', $b->getName());
+
+ $min = min(count($aParts), count($bParts));
+ $idA = '';
+ $idB = '';
+ for ($i = 0; $i < $min; $i++) {
+ if ($idA) {
+ $idA .= ':';
+ $idB .= ':';
+ }
+ $idA .= $aParts[$i];
+ $idB .= $bParts[$i];
+
+ if ($idA != $idB) {
+ $curA = isset($this->_sortList[$idA]) ? $this->_sortList[$idA]->get('name') : '';
+ $curB = isset($this->_sortList[$idB]) ? $this->_sortList[$idB]->get('name') : '';
+ return strnatcasecmp($curA, $curB);
+ }
+ }
+
+ return count($aParts) > count($bParts);
+ }
+
+}
--- /dev/null
+<?php
+
+require_once 'Horde/DataTree.php';
+
+/**
+ * Horde_Share_datatree:: provides the datatree backend for the horde share
+ * driver.
+ *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ * Copyright 2002-2007 Infoteck Internet <webmaster@infoteck.qc.ca>
+ *
+ * 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 Joel Vandal <joel@scopserv.com>
+ * @author Mike Cochrame <mike@graftonhall.co.nz>
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Jan Schneider <jan@horde.org>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share_Datatree extends Horde_Share
+{
+ /**
+ * The Horde_Share_Object subclass to instantiate objects as
+ *
+ * @var string
+ */
+ protected $_shareObject = 'Horde_Share_Object_Datatree';
+
+ /**
+ * Pointer to a DataTree instance to manage/store shares
+ *
+ * @var DataTree
+ */
+ protected $_datatree;
+
+ /**
+ * Initializes the object.
+ *
+ * @throws Horde_Exception
+ */
+ public function __wakeup()
+ {
+ // TODO: Remove GLOBAL config access
+ if (empty($GLOBALS['conf']['datatree']['driver'])) {
+ throw new Horde_Exception('You must configure a DataTree backend to use Shares.');
+ }
+
+ $driver = $GLOBALS['conf']['datatree']['driver'];
+ $this->_datatree = &DataTree::singleton(
+ $driver,
+ array_merge(Horde::getDriverConfig('datatree', $driver),
+ array('group' => 'horde.shares.' . $this->_app))
+ );
+
+ foreach (array_keys($this->_cache) as $name) {
+ if (!is_a($this->_datatree, 'PEAR_Error')) {
+ $this->_cache[$name]->setShareOb($this);
+ $this->_cache[$name]->datatreeObject->setDataTree($this->_datatree);
+ }
+ }
+
+ parent::__wakeup();
+ }
+
+ /**
+ * Returns a Horde_Share_Object_datatree object corresponding to the given
+ * share name, with the details retrieved appropriately.
+ *
+ * @param string $name The name of the share to retrieve.
+ *
+ * @return Horde_Share_Object_datatree The requested share.
+ * @throws Horde_Share_Exception
+ */
+ public function _getShare($name)
+ {
+ $datatreeObject = $this->_datatree->getObject($name, 'DataTreeObject_Share');
+ if ($datatreeObject instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($datatreeObject->getMessage());
+ }
+ $share = new $this->_shareObject($datatreeObject);
+
+ return $share;
+ }
+
+ /**
+ * Returns a Horde_Share_Object_datatree object corresponding to the given
+ * unique ID, with the details retrieved appropriately.
+ *
+ * @param string $cid The id of the share to retrieve.
+ *
+ * @return Horde_Share_Object_datatree The requested share.
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShareById($id)
+ {
+ $datatreeObject = $this->_datatree->getObjectById($id, 'DataTreeObject_Share');
+ if (is_a($datatreeObject, 'PEAR_Error')) {
+ throw new Horde_Share_Exception($datatreeObject->getMessage());
+ }
+ $share = new $this->_shareObject($datatreeObject);
+
+ return $share;
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object_datatree objects corresponding
+ * to the given set of unique IDs, with the details retrieved
+ * appropriately.
+ *
+ * @param array $cids The array of ids to retrieve.
+ *
+ * @return array The requested shares.
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShares($ids)
+ {
+ $shares = array();
+ $objects = &$this->_datatree->getObjects($ids, 'DataTreeObject_Share');
+ if (is_a($objects, 'PEAR_Error')) {
+ throw new Horde_Share_Exception($objects->getMessage());
+ }
+ foreach (array_keys($objects) as $key) {
+ if (is_a($objects[$key], 'PEAR_Error')) {
+ return $objects[$key];
+ }
+ $shares[$key] = new $this->_shareObject($objects[$key]);
+ }
+ return $shares;
+ }
+
+ /**
+ * Lists *all* shares for the current app/share, regardless of
+ * permissions.
+ *
+ * @return array All shares for the current app/share.
+ * @throws Horde_Share_Exception
+ */
+ function _listAllShares()
+ {
+ $sharelist = $this->_datatree->get(DATATREE_FORMAT_FLAT, DATATREE_ROOT, true);
+ if ($sharelist instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($sharelist->getMessage());
+ }
+ if (!count($sharelist)) {
+ return $sharelist;
+ }
+ unset($sharelist[DATATREE_ROOT]);
+
+ return $this->getShares(array_keys($sharelist));
+ }
+
+ /**
+ * Returns an array of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return array The shares the user has access to.
+ * @throws Horde_Share_Exception
+ */
+ function _listShares($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null, $from = 0, $count = 0,
+ $sort_by = null, $direction = 0)
+ {
+ $key = serialize(array($userid, $perm, $attributes));
+ if (empty($this->_listCache[$key])) {
+ $criteria = $this->getShareCriteria($userid, $perm, $attributes);
+ $sharelist = $this->_datatree->getByAttributes($criteria,
+ DATATREE_ROOT,
+ true, 'id', $from,
+ $count, $sort_by,
+ null, $direction);
+ if ($sharelist instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($sharelist->getMessage());
+ }
+ $this->_listCache[$key] = array_keys($sharelist);
+ }
+
+ return $this->_listCache[$key];
+ }
+
+ /**
+ * Returns the number of shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return integer The number of shares
+ */
+ protected function _countShares($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null)
+ {
+ $criteria = $this->getShareCriteria($userid, $perm, $attributes);
+ return $this->_datatree->countByAttributes($criteria, DATATREE_ROOT, true, 'id');
+ }
+
+ /**
+ * Returns a new share object.
+ *
+ * @param string $name The share's name.
+ *
+ * @return Horde_Share_Object_datatree A new share object.
+ */
+ protected function &_newShare($name)
+ {
+ $datatreeObject = new Horde_Share_Object_DataTree_Share($name);
+ $datatreeObject->setDataTree($this->_datatree);
+ $share = new $this->_shareObject($datatreeObject);
+
+ return $share;
+ }
+
+ /**
+ * Adds a share to the shares system.
+ *
+ * The share must first be created with
+ * Horde_Share_datatreee::_newShare(), and have any initial details added
+ * to it, before this function is called.
+ *
+ * @param Horde_Share_Object_datatree $share The new share object.
+ */
+ protected function _addShare(&$share)
+ {
+ return $this->_datatree->add($share->datatreeObject);
+ }
+
+ /**
+ * Removes a share from the shares system permanently.
+ *
+ * @param Horde_Share_Object_datatree $share The share to remove.
+ */
+ protected function _removeShare(&$share)
+ {
+ return $this->_datatree->remove($share->datatreeObject);
+ }
+
+ /**
+ * Checks if a share exists in the system.
+ *
+ * @param string $share The share to check.
+ *
+ * @return boolean True if the share exists.
+ */
+ protected function _exists($share)
+ {
+ return $this->_datatree->exists($share);
+ }
+
+ /**
+ * Returns an array of criteria for querying shares.
+ * @access protected
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares returned to those who
+ * have these attribute values.
+ *
+ * @return array The criteria tree for fetching this user's shares.
+ */
+ public function getShareCriteria($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null)
+ {
+ if (!empty($userid)) {
+ $criteria = array(
+ 'OR' => array(
+ // (owner == $userid)
+ array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'owner'),
+ array('field' => 'value', 'op' => '=', 'test' => $userid))),
+
+ // (name == perm_users and key == $userid and val & $perm)
+ array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'perm_users'),
+ array('field' => 'key', 'op' => '=', 'test' => $userid),
+ array('field' => 'value', 'op' => '&', 'test' => $perm))),
+
+ // (name == perm_creator and val & $perm)
+ array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'perm_creator'),
+ array('field' => 'value', 'op' => '&', 'test' => $perm))),
+
+ // (name == perm_default and val & $perm)
+ array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'perm_default'),
+ array('field' => 'value', 'op' => '&', 'test' => $perm)))));
+
+ // If the user has any group memberships, check for those also.
+ // @TODO: inject
+ require_once 'Horde/Group.php';
+ $group = &Group::singleton();
+ $groups = $group->getGroupMemberships($userid, true);
+ if (!($groups instanceof PEAR_Error) && $groups) {
+ // (name == perm_groups and key in ($groups) and val & $perm)
+ $criteria['OR'][] = array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'perm_groups'),
+ array('field' => 'key', 'op' => 'IN', 'test' => array_keys($groups)),
+ array('field' => 'value', 'op' => '&', 'test' => $perm)));
+ }
+ } else {
+ $criteria = array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'perm_guest'),
+ array('field' => 'value', 'op' => '&', 'test' => $perm)));
+ }
+
+ if (is_array($attributes)) {
+ // Build attribute/key filter.
+ foreach ($attributes as $key => $value) {
+ $criteria = array(
+ 'AND' => array(
+ $criteria,
+ array(
+ 'JOIN' => array(
+ 'AND' => array(
+ array('field' => 'name', 'op' => '=', 'test' => $key),
+ array('field' => 'value', 'op' => '=', 'test' => $value))))));
+ }
+ } elseif (!is_null($attributes)) {
+ // Restrict to shares owned by the user specified in the
+ // $attributes string.
+ $criteria = array(
+ 'AND' => array(
+ $criteria,
+ array(
+ 'JOIN' => array(
+ array('field' => 'name', 'op' => '=', 'test' => 'owner'),
+ array('field' => 'value', 'op' => '=', 'test' => $attributes)))));
+ }
+
+ return $criteria;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Horde_Share_Exception
+ *
+ *
+ */
+class Horde_Share_Exception extends Exception
+{
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * @package Horde_Share
+ */
+
+/**
+ * Horde_Share_kolab:: provides the kolab backend for the horde share driver.
+ *
+ * Copyright 2004-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 Stuart Binge <omicron@mighty.co.za>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share_kolab extends Horde_Share
+{
+ /**
+ * Our Kolab folder list handler
+ *
+ * @var Kolab_List
+ */
+ protected $_list;
+
+ /**
+ * The share type
+ *
+ * @var string
+ */
+ protected $_type;
+
+ /**
+ * A marker for the validity of the list cache
+ *
+ * @var int
+ */
+ protected $_listCacheValidity;
+
+ /**
+ * The session handler.
+ *
+ * @var Horde_Kolab_Session
+ */
+ protected $_session;
+
+ /**
+ * Initializes the object.
+ *
+ * @throws Horde_Exception
+ */
+ public function __wakeup()
+ {
+ if (empty($GLOBALS['conf']['kolab']['enabled'])) {
+ throw new Horde_Exception('You must enable the kolab settings to use the Kolab Share driver.');
+ }
+
+ $this->_type = $this->_getFolderType($this->_app);
+ if ($this->_type instanceof PEAR_Error) {
+ return $this->_type;
+ }
+
+ $this->_list = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
+
+ parent::__wakeup();
+ }
+
+ private function _getFolderType($app)
+ {
+ switch ($app) {
+ case 'mnemo':
+ return 'note';
+ case 'kronolith':
+ return 'event';
+ case 'turba':
+ return 'contact';
+ case 'nag':
+ return 'task';
+ default:
+ throw new Horde_Share_Exception(sprintf(_("The Horde/Kolab integration engine does not support \"%s\""), $app));
+ }
+ }
+
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['_sortList'], $properties['_list']);
+ $properties = array_keys($properties);
+ return $properties;
+ }
+
+ /**
+ * Returns a Horde_Share_Object_kolab object of the request folder.
+ *
+ * @param string $object The share to fetch.
+ *
+ * @return Horde_Share_Object_kolab The share object.
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShare($object)
+ {
+ if (empty($object)) {
+ throw new Horde_Share_Exception('No object requested.');
+ }
+
+ /** Get the corresponding folder for this share ID */
+ $folder = $this->_list->getByShare($object, $this->_type);
+
+ /** Does the folder exist? */
+ if (!$folder->exists()) {
+ throw new Horde_Share_Exception(sprintf(_("Share \"%s\" does not exist."), $object));
+ }
+
+ /** Create the object from the folder */
+ $share = new Horde_Share_Object_Kolab($object, $this->_type);
+ $share->setFolder($folder);
+
+ return $share;
+ }
+
+ /**
+ * Returns a Horde_Share_Object_kolab object of the requested folder.
+ *
+ * @param string $id The id of the share to fetch.
+ *
+ * @return Horde_Share_Object_kolab The share object.
+ */
+ protected function &_getShareById($id)
+ {
+ return $this->_getShare($id);
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object_kolab objects corresponding to
+ * the requested folders.
+ *
+ * @param string $ids The ids of the shares to fetch.
+ *
+ * @return array An array of Horde_Share_Object_kolab objects.
+ */
+ protected function &_getShares($ids)
+ {
+ $objects = array();
+ foreach ($ids as $id) {
+ $result = &$this->_getShare($id);
+ if ($result instanceof PEAR_Error) {
+ return $result;
+ }
+ $objects[$id] = &$result;
+ }
+ return $objects;
+ }
+
+ /**
+ * Lists *all* shares for the current app/share, regardless of
+ * permissions.
+ *
+ * Currently not implemented in this class.
+ *
+ * @return array All shares for the current app/share.
+ */
+ protected function &_listAllShares()
+ {
+ $shares = array();
+ return $shares;
+ }
+
+ /**
+ * Returns an array of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return array The shares the user has access to.
+ */
+ protected function _listShares($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null, $from = 0, $count = 0,
+ $sort_by = null, $direction = 0)
+ {
+ $key = serialize(array($this->_type, $userid, $perm, $attributes));
+ if ($this->_list === false) {
+ $this->_listCache[$key] = array();
+ } else if (empty($this->_listCache[$key])
+ || $this->_list->validity != $this->_listCacheValidity) {
+ $sharelist = $this->_list->getByType($this->_type);
+ if ($sharelist instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($sharelist->getMessage());
+ }
+
+ $shares = array();
+ foreach ($sharelist as $folder) {
+ $id = $folder->getShareId();
+ $share = &$this->getShare($id);
+ $keep = true;
+ if (!$share->hasPermission($userid, $perm)) {
+ $keep = false;
+ }
+ if (isset($attributes) && $keep) {
+ if (is_array($attributes)) {
+ foreach ($attributes as $key => $value) {
+ if (!$share->get($key) == $value) {
+ $keep = false;
+ break;
+ }
+ }
+ } elseif (!$share->get('owner') == $attributes) {
+ $keep = false;
+ }
+ }
+ if ($keep) {
+ $shares[] = $id;
+ }
+ }
+ $this->_listCache[$key] = $shares;
+ $this->_listCacheValidity = $this->_list->validity;
+ }
+
+ return $this->_listCache[$key];
+ }
+
+ /**
+ * Returns the number of shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return integer The number of shares
+ */
+ protected function _countShares($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null)
+ {
+ $shares = $this->_listShares($userid, $perm, $attributes);
+ return count($shares);
+ }
+
+ /**
+ * Returns a new share object.
+ *
+ * @param string $name The share's name.
+ *
+ * @return Horde_Share_Object_kolab A new share object.
+ */
+ protected function &_newShare($name)
+ {
+ $storageObject = new Horde_Share_Object_Kolab($name, $this->_type);
+ return $storageObject;
+ }
+
+ /**
+ * Adds a share to the shares system.
+ *
+ * The share must first be created with Horde_Share_kolab::_newShare(),
+ * and have any initial details added to it, before this function is
+ * called.
+ *
+ * @param Horde_Share_Object_kolab $share The new share object.
+ */
+ protected function _addShare(&$share)
+ {
+ return $share->save();
+ }
+
+ /**
+ * Removes a share from the shares system permanently.
+ *
+ * @param Horde_Share_Object_Kolab $share The share to remove.
+ */
+ protected function _removeShare(Horde_Share_Object $share)
+ {
+ $share_id = $share->getName();
+ $result = $share->delete();
+ }
+
+ /**
+ * Checks if a share exists in the system.
+ *
+ * @param string $share The share to check.
+ *
+ * @return boolean True if the share exists.
+ */
+ protected function _exists($object)
+ {
+ if (empty($object)) {
+ return false;
+ }
+
+ /** Get the corresponding folder for this share ID */
+ $folder = $this->_list->getByShare($object, $this->_type);
+ if ($folder instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($folder->getMessage());
+ }
+
+ return $folder->exists();
+ }
+
+ /**
+ * Create a default share for the current app
+ *
+ * @return string The share ID of the new default share.
+ */
+ public function getDefaultShare()
+ {
+ $default = $this->_list->getDefault($this->_type);
+ if ($default instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($default->getMessage());
+ }
+ if ($default !== false) {
+ return $this->getShare($default->getShareId());
+ }
+
+ /** Okay, no default folder yet */
+ $share = $this->newShare(Horde_Auth::getAuth());
+
+ /** The value does not matter here as the share will rewrite it */
+ $share->set('name', '');
+ $result = $this->addShare($share);
+
+ return $share;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Abstract class for storing Share information.
+ *
+ * This class should be extended for the more specific drivers.
+ *
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Jan Schneider <jan@horde.org>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share_Object
+{
+ /**
+ * The Horde_Share object which this share came from - needed for updating
+ * data in the backend to make changes stick, etc.
+ *
+ * @var Horde_Share
+ */
+ protected $_shareOb;
+
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['_shareOb']);
+ $properties = array_keys($properties);
+ return $properties;
+ }
+
+ /**
+ * Associates a Share object with this share.
+ *
+ * @param Horde_Share $shareOb The Share object.
+ */
+ public function setShareOb($shareOb)
+ {
+ if (!($shareOb instanceof Horde_Share)) {
+ throw new Horde_Share_Exception('This object needs a Horde_Share instance as storage handler!');
+ }
+ $this->_shareOb = $shareOb;
+ }
+
+ /**
+ * Sets an attribute value in this object.
+ *
+ * @param string $attribute The attribute to set.
+ * @param mixed $value The value for $attribute.
+ *
+ * @return mixed True if setting the attribute did succeed, a PEAR_Error
+ * otherwise.
+ */
+ public function set($attribute, $value)
+ {
+ return $this->_set($attribute, $value);
+ }
+
+ /**
+ * Returns an attribute value from this object.
+ *
+ * @param string $attribute The attribute to return.
+ *
+ * @return mixed The value for $attribute.
+ */
+ public function get($attribute)
+ {
+ return $this->_get($attribute);
+ }
+
+ /**
+ * Returns the ID of this share.
+ *
+ * @return string The share's ID.
+ */
+ public function getId()
+ {
+ return $this->_getId();
+ }
+
+ /**
+ * Returns the name of this share.
+ *
+ * @return string The share's name.
+ */
+ public function getName()
+ {
+ return $this->_getName();
+ }
+
+ /**
+ * Saves the current attribute values.
+ *
+ * @return boolean
+ * @throws Horde_Exception
+ */
+ public function save()
+ {
+ try {
+ Horde::callHook('share_modify', array($this));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ return $this->_save();
+ }
+
+ /**
+ * Gives a user a certain privilege for this share.
+ *
+ * @param string $userid The userid of the user.
+ * @param integer $permission A Horde_Perms::* constant.
+ */
+ public function addUserPermission($userid, $permission)
+ {
+ $perm = $this->getPermission();
+ $perm->addUserPermission($userid, $permission, false);
+ $this->setPermission($perm);
+ }
+
+ /**
+ * Removes a certain privilege for a user from this share.
+ *
+ * @param string $userid The userid of the user.
+ * @param integer $permission A Horde_Perms::* constant.
+ */
+ public function removeUserPermission($userid, $permission)
+ {
+ $perm = $this->getPermission();
+ $perm->removeUserPermission($userid, $permission, false);
+ $this->setPermission($perm);
+ }
+
+ /**
+ * Gives a group certain privileges for this share.
+ *
+ * @param string $group The group to add permissions for.
+ * @param integer $permission A Horde_Perms::* constant.
+ */
+ public function addGroupPermission($group, $permission)
+ {
+ $perm = $this->getPermission();
+ $perm->addGroupPermission($group, $permission, false);
+ $this->setPermission($perm);
+ }
+
+ /**
+ * Removes a certain privilege from a group.
+ *
+ * @param string $group The group to remove permissions from.
+ * @param constant $permission A Horde_Perms::* constant.
+ */
+ public function removeGroupPermission($group, $permission)
+ {
+ $perm = $this->getPermission();
+ $perm->removeGroupPermission($group, $permission, false);
+ $this->setPermission($perm);
+ }
+
+ /**
+ * Removes a user from this share.
+ *
+ * @param string $userid The userid of the user to remove.
+ */
+ public function removeUser($userid)
+ {
+ /* Remove all $userid's permissions. */
+ $perm = $this->getPermission();
+ $perm->removeUserPermission($userid, Horde_Perms::SHOW, false);
+ $perm->removeUserPermission($userid, Horde_Perms::READ, false);
+ $perm->removeUserPermission($userid, Horde_Perms::EDIT, false);
+ $perm->removeUserPermission($userid, Horde_Perms::DELETE, false);
+
+ return $this->setPermission($perm);
+ }
+
+ /**
+ * Removes a group from this share.
+ *
+ * @param integer $groupId The group to remove.
+ */
+ public function removeGroup($groupId)
+ {
+ /* Remove all $groupId's permissions. */
+ $perm = $this->getPermission();
+ $perm->removeGroupPermission($groupId, Horde_Perms::SHOW, false);
+ $perm->removeGroupPermission($groupId, Horde_Perms::READ, false);
+ $perm->removeGroupPermission($groupId, Horde_Perms::EDIT, false);
+ $perm->removeGroupPermission($groupId, Horde_Perms::DELETE, false);
+
+ return $this->setPermission($perm);
+ }
+
+ /**
+ * Returns an array containing all the userids of the users with access to
+ * this share.
+ *
+ * @param integer $perm_level List only users with this permission level.
+ * Defaults to all users.
+ *
+ * @return array The users with access to this share.
+ */
+ public function listUsers($perm_level = null)
+ {
+ $perm = $this->getPermission();
+ $results = array_keys($perm->getUserPermissions($perm_level));
+ // Always return the share's owner.
+ if ($this->get('owner')) {
+ array_push($results, $this->get('owner'));
+ }
+ return $results;
+ }
+
+ /**
+ * Returns an array containing all the groupids of the groups with access
+ * to this share.
+ *
+ * @param integer $perm_level List only users with this permission level.
+ * Defaults to all users.
+ *
+ * @return array The IDs of the groups with access to this share.
+ */
+ public function listGroups($perm_level = null)
+ {
+ $perm = $this->getPermission();
+ return array_keys($perm->getGroupPermissions($perm_level));
+ }
+
+ /**
+ * Locks an item from this share, or the entire share if no item defined.
+ *
+ * @param string $item_uid A uid of an item from this share.
+ *
+ * @return mixed A lock ID on success, PEAR_Error on failure, false if:
+ * - The share is already locked
+ * - The item is already locked
+ * - A share lock was requested and an item is already
+ * locked in the share
+ * @throws Horde_Share_Exception
+ */
+ public function lock($item_uid = null)
+ {
+ try {
+ // TODO: Pass this in as a parameter, don't use the injector directly in
+ // a library
+ $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
+ } catch (Horde_Lock_Exception $e) {
+ Horde::logMessage($e, 'ERR');
+ throw new Horde_Share_Exception($e);
+ }
+
+ $shareid = $this->getId();
+
+ // Default parameters.
+ $locktype = Horde_Lock::TYPE_EXCLUSIVE;
+ $timeout = 600;
+ $itemscope = $this->_shareOb->getApp() . ':' . $shareid;
+
+ if (!empty($item_uid)) {
+ // Check if the share is locked. Share locks are placed at app
+ // scope.
+ try {
+ $result = $locks->getLocks($this->_shareOb->getApp(), $shareid, $locktype);
+ } catch (Horde_Lock_Exception $e) {
+ throw new Horde_Share_Exception($e);
+ }
+ if (!empty($result)) {
+ // Lock found.
+ return false;
+ }
+ // Try to place the item lock at app:shareid scope.
+ return $locks->setLock(Horde_Auth::getAuth(), $itemscope, $item_uid,
+ $timeout, $locktype);
+ } else {
+ // Share lock requested. Check for locked items.
+ try {
+ $result = $locks->getLocks($itemscope, null, $locktype);
+ } catch (Horde_Lock_Exception $e) {
+ throw new Horde_Share_Exception($e);
+ }
+ if (!empty($result)) {
+ // Lock found.
+ return false;
+ }
+ // Try to place the share lock
+ return $locks->setLock(Horde_Auth::getAuth(), $this->_shareOb->getApp(),
+ $shareid, $timeout, $locktype);
+ }
+ }
+
+ /**
+ * Removes the lock for a lock ID.
+ *
+ * @param string $lockid The lock ID as generated by a previous call
+ * to lock().
+ *
+ * @return mixed True on success, PEAR_Error on failure.
+ */
+ public function unlock($lockid)
+ {
+ try {
+ // TODO: pass in method, do not use injector in library
+ $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
+ } catch (Horde_Lock_Exception $e) {
+ Horde::logMessage($e, 'ERR');
+ throw new Horde_Share_Exception($e);
+ }
+
+ return $locks->clearLock($lockid);
+ }
+
+ /**
+ * Checks for existing locks.
+ *
+ * First this checks for share locks and if none exists, checks for item
+ * locks (if item_uid defined). It will return the first lock found.
+ *
+ * @param string $item_uid A uid of an item from this share.
+ *
+ * @return mixed Hash with the found lock information in 'lock' and the
+ * lock type ('share' or 'item') in 'type', or an empty
+ * array if there are no locks, or a PEAR_Error on failure.
+ */
+ public function checkLocks($item_uid = null)
+ {
+ // TODO: Inject lock object, do not use injector in library
+ try {
+ $locks = $GLOBALS['injector']->getInstance('Horde_Lock');
+ } catch (Horde_Lock_Exception $e) {
+ Horde::logMessage($e, 'ERR');
+ throw new Horde_Share_Exception($e);
+ }
+
+ $shareid = $this->getId();
+ $locktype = Horde_Lock::TYPE_EXCLUSIVE;
+
+ // Check for share locks
+ try {
+ $result = $locks->getLocks($this->_shareOb->getApp(), $shareid, $locktype);
+ } catch (Horde_Lock_Exception $e) {
+ Horde::logMessage($e, 'ERR');
+ throw new Horde_Share_Exception($e);
+ }
+
+ if (empty($result) && !empty($item_uid)) {
+ // Check for item locks
+ $locktargettype = 'item';
+ try {
+ $result = $locks->getLocks($this->_shareOb->getApp() . ':' . $shareid, $item_uid, $locktype);
+ } catch (Horde_Lock_Exception $e) {
+ Horde::logMessage($e, 'ERR');
+ throw new Horde_Share_Exception($e->getMessage());
+ }
+ } else {
+ $locktargettype = 'share';
+ }
+
+ if (empty($result)) {
+ return array();
+ }
+
+ return array('type' => $locktargettype,
+ 'lock' => reset($result));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Extension of the Horde_Share_Object class for storing share information in
+ * the DataTree driver.
+ *
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Jan Schneider <jan@horde.org>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share_Object_Datatree extends Horde_Share_Object
+{
+ /**
+ * The actual storage object that holds the data.
+ *
+ * @var mixed
+ */
+ public $datatreeObject;
+
+ /**
+ * Constructor.
+ *
+ * @param DataTreeObject_Share $datatreeObject A DataTreeObject_Share
+ * instance.
+ */
+ public function __construct(Horde_Share_Object_Datatree_Share $datatreeObject)
+ {
+ $this->datatreeObject = $datatreeObject;
+ }
+
+ /**
+ * Sets an attribute value in this object.
+ *
+ * @param string $attribute The attribute to set.
+ * @param mixed $value The value for $attribute.
+ *
+ * @return mixed True if setting the attribute did succeed, a PEAR_Error
+ * otherwise.
+ */
+ public function _set($attribute, $value)
+ {
+ return $this->datatreeObject->set($attribute, $value);
+ }
+
+ /**
+ * Returns one of the attributes of the object, or null if it isn't
+ * defined.
+ *
+ * @param string $attribute The attribute to retrieve.
+ *
+ * @return mixed The value of the attribute, or an empty string.
+ */
+ public function _get($attribute)
+ {
+ return $this->datatreeObject->get($attribute);
+ }
+
+ /**
+ * Returns the ID of this share.
+ *
+ * @return string The share's ID.
+ */
+ protected function _getId()
+ {
+ return $this->datatreeObject->getId();
+ }
+
+ /**
+ * Returns the name of this share.
+ *
+ * @return string The share's name.
+ */
+ protected function _getName()
+ {
+ return $this->datatreeObject->getName();
+ }
+
+ /**
+ * Saves the current attribute values.
+ */
+ protected function _save()
+ {
+ return $this->datatreeObject->save();
+ }
+
+ /**
+ * Checks to see if a user has a given permission.
+ *
+ * @param string $userid The userid of the user.
+ * @param integer $permission A Horde_Perms::* constant to test for.
+ * @param string $creator The creator of the event.
+ *
+ * @return boolean Whether or not $userid has $permission.
+ */
+ public function hasPermission($userid, $permission, $creator = null)
+ {
+ if ($userid && $userid == $this->datatreeObject->get('owner')) {
+ return true;
+ }
+ // TODO: inject
+ return $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($this->getPermission(), $userid, $permission, $creator);
+ }
+
+ /**
+ * Sets the permission of this share.
+ *
+ * @param Horde_Perms_Permission $perm Permission object.
+ * @param boolean $update Should the share be saved
+ * after this operation?
+ *
+ * @return boolean True if no error occured, PEAR_Error otherwise
+ */
+ public function setPermission(&$perm, $update = true)
+ {
+ $this->datatreeObject->data['perm'] = $perm->getData();
+ if ($update) {
+ return $this->datatreeObject->save();
+ }
+ return true;
+ }
+
+ /**
+ * Returns the permission of this share.
+ *
+ * @return Horde_Perms_Permission Permission object that represents the
+ * permissions on this share
+ */
+ function getPermission()
+ {
+ $perm = new Horde_Perms_Permission($this->datatreeObject->getName());
+ $perm->data = isset($this->datatreeObject->data['perm'])
+ ? $this->datatreeObject->data['perm']
+ : array();
+
+ return $perm;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * Extension of the DataTreeObject class for storing Share information in the
+ * DataTree driver. If you want to store specialized Share information, you
+ * should extend this class instead of extending DataTreeObject directly.
+ *
+ * @author Mike Cochrane <mike@graftonhall.co.nz>
+ * @author Jan Schneider <jan@horde.org>
+ * @package Horde_Share
+ */
+class Horde_Share_Object_DataTree_Share extends DataTreeObject
+{
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['datatree']);
+ $properties = array_keys($properties);
+ return $properties;
+ }
+
+ /**
+ * Maps this object's attributes from the data array into a format that we
+ * can store in the attributes storage backend.
+ *
+ * @access protected
+ *
+ * @param boolean $permsonly Only process permissions? Lets subclasses
+ * override part of this method while handling
+ * their additional attributes seperately.
+ *
+ * @return array The attributes array.
+ */
+ protected function _toAttributes($permsonly = false)
+ {
+ // Default to no attributes.
+ $attributes = array();
+
+ foreach ($this->data as $key => $value) {
+ if ($key == 'perm') {
+ foreach ($value as $type => $perms) {
+ if (is_array($perms)) {
+ foreach ($perms as $member => $perm) {
+ $attributes[] = array('name' => 'perm_' . $type,
+ 'key' => $member,
+ 'value' => $perm);
+ }
+ } else {
+ $attributes[] = array('name' => 'perm_' . $type,
+ 'key' => '',
+ 'value' => $perms);
+ }
+ }
+ } elseif (!$permsonly) {
+ $attributes[] = array('name' => $key,
+ 'key' => '',
+ 'value' => $value);
+ }
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Takes in a list of attributes from the backend and maps it to our
+ * internal data array.
+ *
+ * @access protected
+ *
+ * @param array $attributes The list of attributes from the backend
+ * (attribute name, key, and value).
+ * @param boolean $permsonly Only process permissions? Lets subclasses
+ * override part of this method while handling
+ * their additional attributes seperately.
+ */
+ protected function _fromAttributes($attributes, $permsonly = false)
+ {
+ // Initialize data array.
+ $this->data['perm'] = array();
+
+ foreach ($attributes as $attr) {
+ if (substr($attr['name'], 0, 4) == 'perm') {
+ if (!empty($attr['key'])) {
+ $this->data['perm'][substr($attr['name'], 5)][$attr['key']] = $attr['value'];
+ } else {
+ $this->data['perm'][substr($attr['name'], 5)] = $attr['value'];
+ }
+ } elseif (!$permsonly) {
+ $this->data[$attr['name']] = $attr['value'];
+ }
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Extension of the Horde_Share_Object class for handling Kolab share
+ * information.
+ *
+ * @author Stuart Binge <omicron@mighty.co.za>
+ * @author Gunnar Wrobel <wrobel@pardus.de>
+ * @package Horde_Share
+ */
+class Horde_Share_Object_Kolab extends Horde_Share_Object
+{
+ /**
+ * The Kolab folder this share is based on.
+ *
+ * @var Kolab_Folder
+ */
+ protected $_folder;
+
+ /**
+ * The Kolab folder name.
+ *
+ * @var string
+ */
+ protected $_folder_name;
+
+ /**
+ * A cache for the share attributes.
+ *
+ * @var array
+ */
+ protected $_data;
+
+ /**
+ * Our Kolab folder list handler
+ *
+ * @var Kolab_List
+ */
+ protected $_list;
+
+ /**
+ * The session handler.
+ *
+ * @var Horde_Kolab_Session
+ */
+ private $_session;
+
+ /**
+ * Constructor.
+ *
+ * Sets the folder name.
+ *
+ * @param string $id The share id.
+ */
+ public function __construct($id, $type)
+ {
+ // We actually ignore the random id string that all horde apps provide
+ // as initial name and wait for a set('name', 'xyz') call. But we want
+ // to know if we should create a default share.
+ if ($id == Horde_Auth::getAuth()) {
+ $this->_data['default'] = true;
+ } else {
+ $this->_data['default'] = false;
+ }
+ $this->_type = $type;
+ $this->__wakeup();
+ }
+
+ /**
+ * Associates a Share object with this share.
+ *
+ * @param Horde_Share $shareOb The Share object.
+ */
+ public function setShareOb($shareOb)
+ {
+ /** Ignore the parent as we don't need it */
+ }
+
+ /**
+ * Initializes the object.
+ */
+ public function __wakeup()
+ {
+ $this->_list = $GLOBALS['injector']->getInstance('Horde_Kolab_Storage');
+ if (isset($this->_folder_name)) {
+ $this->_folder = $this->_list->getFolder($this->_folder_name);
+ }
+ }
+
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['_shareOb'], $properties['_list'],
+ $properties['_folder']);
+ $properties = array_keys($properties);
+ return $properties;
+ }
+
+ /**
+ * Returns the default share name for the current application.
+ *
+ * @return string The default share name.
+ */
+ public function getDefaultShareName()
+ {
+ switch ($this->_type) {
+ case 'contact':
+ return _("Contacts");
+ case 'note':
+ return _("Notes");
+ case 'event':
+ return _("Calendar");
+ case 'task':
+ return _("Tasks");
+ case 'filter':
+ return _("Filters");
+ case 'h-prefs':
+ return _("Preferences");
+ }
+ }
+
+ /**
+ * Sets the folder for this storage object.
+ *
+ * @param string $folder Name of the Kolab folder.
+ * @param array $perms The permissions of the folder if they are known.
+ */
+ public function setFolder(&$folder)
+ {
+ if (!isset($this->_folder)) {
+ $this->_folder = &$folder;
+ $this->_folder_name = $folder->name;
+ } else {
+ throw new Horde_Share_Exception(_("The share has already been initialized!"));
+ }
+ }
+
+ /**
+ * Returns the ID of this share.
+ *
+ * @return string The share's ID.
+ */
+ protected function _getId()
+ {
+ return $this->_folder->getShareId();
+ }
+
+ /**
+ * Returns the name of this share.
+ *
+ * @return string The share's name.
+ */
+ protected function _getName()
+ {
+ return $this->_folder->getShareId();
+ }
+
+ /**
+ * Returns an attribute value from this object.
+ *
+ * @param string $attribute The attribute to return.
+ *
+ * @return mixed The value for $attribute.
+ */
+ protected function _get($attribute)
+ {
+ if (isset($this->_data[$attribute])) {
+ return $this->_data[$attribute];
+ }
+
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+
+ switch ($attribute) {
+ case 'owner':
+ $this->_data['owner'] = $this->_folder->getOwner();
+ break;
+
+ case 'name':
+ $this->_data['name'] = $this->_folder->getTitle();
+ break;
+
+ case 'type':
+ $this->_data['type'] = $this->_folder->getType();
+ break;
+
+ case 'params':
+ $params = @unserialize($this->_folder->getAttribute('params'));
+ $default = array('source' => 'kolab',
+ 'default' => $this->get('default'),
+ 'name' => $this->get('name'));
+ $type = $this->get('type');
+ if (!($type instanceof PEAR_Error) && $type == 'event') {
+ $default = array_merge($default, array(
+ 'fbrelevance' => $this->_folder->getFbrelevance(),
+ 'xfbaccess' => $this->_folder->getXfbaccess()
+ ));
+ }
+ if ($params instanceof PEAR_Error || $params == '') {
+ $params = $default;
+ }
+ $this->_data['params'] = serialize(array_merge($default, $params));
+ break;
+
+ case 'default':
+ $this->_data['default'] = $this->_folder->isDefault();
+ break;
+
+ default:
+ $annotation = $this->_folder->getAttribute($attribute);
+ if ($annotation instanceof PEAR_Error || empty($annotation)) {
+ $annotation = '';
+ }
+ $this->_data[$attribute] = $annotation;
+ break;
+ }
+
+ return $this->_data[$attribute];
+ }
+
+ /**
+ * Sets an attribute value in this object.
+ *
+ * @param string $attribute The attribute to set.
+ * @param mixed $value The value for $attribute.
+ *
+ * @return mixed True if setting the attribute did succeed, a PEAR_Error
+ * otherwise.
+ */
+ protected function _set($attribute, $value)
+ {
+ switch ($attribute) {
+ case 'name':
+ /* On folder creation of default shares we wish to ignore
+ * the names provided by the Horde applications. We use
+ * the Kolab default names. */
+ if (!isset($this->_folder)) {
+ if ($this->get('default')) {
+ $value = $this->getDefaultShareName();
+ }
+ $this->setFolder($this->_list->getNewFolder());
+ }
+ $this->_folder->setName($value);
+ $this->_data['name'] = $this->_folder->getTitle();
+ break;
+
+ case 'params':
+ $value = unserialize($value);
+ if (isset($value['default'])) {
+ $this->_data['default'] = $value['default'];
+ unset($value['default']);
+ }
+ $value = serialize($value);
+
+ default:
+ $this->_data[$attribute] = $value;
+ }
+ }
+
+ /**
+ * Saves the current attribute values.
+ */
+ protected function _save()
+ {
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+
+ $data = $this->_data;
+ /** The name is handled immediately when set */
+ unset($data['name']);
+ $data['type'] = $this->_type;
+
+ $result = $this->_folder->save($data);
+ if ($result instanceof PEAR_Error) {
+ return $result;
+ }
+
+ /** The name may have changed */
+ $this->_data['name'] = $this->_folder->getTitle();
+ $this->_folder_name = $this->_folder->name;
+ return true;
+ }
+
+ /**
+ * Delete this share.
+ *
+ * @return boolean|PEAR_Error True on success.
+ */
+ public function delete()
+ {
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+ return $this->_folder->delete();
+ }
+
+ /**
+ * Checks to see if a user has a given permission.
+ *
+ * @param string $userid The userid of the user.
+ * @param integer $permission A Horde_Perms::* constant to test for.
+ * @param string $creator The creator of the shared object.
+ *
+ * @return boolean|PEAR_Error Whether or not $userid has $permission.
+ */
+ public function hasPermission($userid, $permission, $creator = null)
+ {
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+ return $this->_folder->hasPermission($userid, $permission, $creator);
+ }
+
+ /**
+ * Returns the permissions from this storage object.
+ *
+ * @return Horde_Perms_Permission_Kolab|PEAR_Error The permissions on the share.
+ */
+ public function getPermission()
+ {
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+ return $this->_folder->getPermission();
+ }
+
+ /**
+ * Sets the permissions on the share.
+ *
+ * @param Horde_Perms_Permission_Kolab $perms Permission object to folder on the
+ * object.
+ * @param boolean $update Save the updated information?
+ *
+ * @return boolean|PEAR_Error True on success.
+ */
+ public function setPermission($perms, $update = true)
+ {
+ if (!isset($this->_folder)) {
+ return $this->_folderError();
+ }
+ return $this->_folder->setPermission($perms, $update);
+ }
+
+ /**
+ * Return a standard error in case the share has not been
+ * correctly initialized.
+ *
+ * @throws Horde_Share_Exception
+ */
+ protected function _folderError()
+ {
+ throw new Horde_Share_Exception(_("The Kolab share object has not been initialized yet!"));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Extension of the Horde_Share_Object class for storing share information in
+ * the sql driver.
+ *
+ * @author Duck <duck@obala.net>
+ * @package Horde_Share
+ */
+class Horde_Share_Object_Sql extends Horde_Share_Object
+{
+ /**
+ * The actual storage object that holds the data.
+ *
+ * @TODO: Check visibility - should be protected/private
+ * @var mixed
+ */
+ public $data = array();
+
+ /**
+ * Constructor.
+ *
+ * @param array $data Share data array.
+ */
+ public function __construct($data)
+ {
+ if (!isset($data['perm']) || !is_array($data['perm'])) {
+ $this->data['perm'] = array(
+ 'users' => array(),
+ 'type' => 'matrix',
+ 'default' => isset($data['perm_default'])
+ ? (int)$data['perm_default'] : 0,
+ 'guest' => isset($data['perm_guest'])
+ ? (int)$data['perm_guest'] : 0,
+ 'creator' => isset($data['perm_creator'])
+ ? (int)$data['perm_creator'] : 0,
+ 'groups' => array());
+
+ unset($data['perm_creator'], $data['perm_guest'],
+ $data['perm_default']);
+ }
+ $this->data = array_merge($data, $this->data);
+ }
+
+ /**
+ * Sets an attribute value in this object.
+ *
+ * @param string $attribute The attribute to set.
+ * @param mixed $value The value for $attribute.
+ *
+ * @return mixed True if setting the attribute did succeed, a PEAR_Error
+ * otherwise.
+ */
+ public function _set($attribute, $value)
+ {
+ if ($attribute == 'owner') {
+ return $this->data['share_owner'] = $value;
+ } else {
+ return $this->data['attribute_' . $attribute] = $value;
+ }
+ }
+
+ /**
+ * Returns one of the attributes of the object, or null if it isn't
+ * defined.
+ *
+ * @param string $attribute The attribute to retrieve.
+ *
+ * @return mixed The value of the attribute, or an empty string.
+ */
+ protected function _get($attribute)
+ {
+ if ($attribute == 'owner') {
+ return $this->data['share_owner'];
+ } elseif (isset($this->data['attribute_' . $attribute])) {
+ return $this->data['attribute_' . $attribute];
+ }
+ }
+
+ /**
+ * Returns the ID of this share.
+ *
+ * @return string The share's ID.
+ */
+ protected function _getId()
+ {
+ return isset($this->data['share_id']) ? $this->data['share_id'] : null;
+ }
+
+ /**
+ * Returns the name of this share.
+ *
+ * @return string The share's name.
+ */
+ protected function _getName()
+ {
+ return $this->data['share_name'];
+ }
+
+ /**
+ * Saves the current attribute values.
+ */
+ protected function _save()
+ {
+ $db = $this->_shareOb->getWriteDb();
+ $table = $this->_shareOb->getTable();
+
+ $fields = array();
+ $params = array();
+
+ foreach ($this->_shareOb->_toDriverCharset($this->data) as $key => $value) {
+ if ($key != 'share_id' && $key != 'perm' && $key != 'share_flags') {
+ $fields[] = $key;
+ $params[] = $value;
+ }
+ }
+
+ $fields[] = 'perm_creator';
+ $params[] = isset($this->data['perm']['creator']) ? (int)$this->data['perm']['creator'] : 0;
+
+ $fields[] = 'perm_default';
+ $params[] = isset($this->data['perm']['default']) ? (int)$this->data['perm']['default'] : 0;
+
+ $fields[] = 'perm_guest';
+ $params[] = isset($this->data['perm']['guest']) ? (int)$this->data['perm']['guest'] : 0;
+
+ $fields[] = 'share_flags';
+ $flags = 0;
+ if (!empty($this->data['perm']['users'])) {
+ $flags |= Horde_Share_Sql::SQL_FLAG_USERS;
+ }
+ if (!empty($this->data['perm']['groups'])) {
+ $flags |= Horde_Share_Sql::SQL_FLAG_GROUPS;
+ }
+ $params[] = $flags;
+
+ if (empty($this->data['share_id'])) {
+ $share_id = $db->nextId($table);
+ if ($share_id instanceof PEAR_Error) {
+ Horde::logMessage($share_id, 'ERR');
+ throw new Horde_Share_Exception($share_id->getMessage());
+ }
+
+ $this->data['share_id'] = $share_id;
+ $fields[] = 'share_id';
+ $params[] = $this->data['share_id'];
+
+ $query = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (?' . str_repeat(', ?', count($fields) - 1) . ')';
+ } else {
+ $query = 'UPDATE ' . $table . ' SET ' . implode(' = ?, ', $fields) . ' = ? WHERE share_id = ?';
+ $params[] = $this->data['share_id'];
+ }
+ $stmt = $db->prepare($query, null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute($params);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+
+ // Update the share's user permissions
+ $stmt = $db->prepare('DELETE FROM ' . $table . '_users WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($this->data['share_id']));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+
+ if (!empty($this->data['perm']['users'])) {
+ $data = array();
+ foreach ($this->data['perm']['users'] as $user => $perm) {
+ $stmt = $db->prepare('INSERT INTO ' . $table . '_users (share_id, user_uid, perm) VALUES (?, ?, ?)', null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($this->data['share_id'], $user, $perm));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+ }
+ }
+
+ // Update the share's group permissions
+ $stmt = $db->prepare('DELETE FROM ' . $table . '_groups WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($this->data['share_id']));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+
+ if (!empty($this->data['perm']['groups'])) {
+ $data = array();
+ foreach ($this->data['perm']['groups'] as $group => $perm) {
+ $stmt = $db->prepare('INSERT INTO ' . $table . '_groups (share_id, group_uid, perm) VALUES (?, ?, ?)', null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($this->data['share_id'], $group, $perm));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks to see if a user has a given permission.
+ *
+ * @param string $userid The userid of the user.
+ * @param integer $permission A Horde_Perms::* constant to test for.
+ * @param string $creator The creator of the event.
+ *
+ * @return boolean Whether or not $userid has $permission.
+ */
+ public function hasPermission($userid, $permission, $creator = null)
+ {
+ if ($userid == $this->data['share_owner']) {
+ return true;
+ }
+ // @TODO: inject perms, don't use the injector here
+ return $GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission($this->getPermission(), $userid, $permission, $creator);
+ }
+
+ /**
+ * Sets the permission of this share.
+ *
+ * @param Horde_Perms_Permission $perm Permission object.
+ * @param boolean $update Should the share be saved
+ * after this operation?
+ *
+ * @TODO: Look at storing the Perm object itself, instead of the data
+ * (Make it easier to inject the perm object instead of instantiating
+ * it in the library).
+ *
+ * @return boolean True if no error occured, PEAR_Error otherwise
+ */
+ public function setPermission($perm, $update = true)
+ {
+ $this->data['perm'] = $perm->getData();
+ if ($update) {
+ return $this->save();
+ }
+ return true;
+ }
+
+ /**
+ * Returns the permission of this share.
+ *
+ * @return Horde_Perms_Permission Permission object that represents the
+ * permissions on this share.
+ */
+ public function getPermission()
+ {
+ $perm = new Horde_Perms_Permission($this->getName());
+ $perm->data = isset($this->data['perm'])
+ ? $this->data['perm']
+ : array();
+
+ return $perm;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Extension of the Horde_Share_Object class for storing share information in
+ * the sql driver.
+ *
+ * @author Duck <duck@obala.net>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ *
+ * @package Horde_Share
+ */
+class Horde_Share_Object_Sql_Hierarchical extends Horde_Share_Object_Sql
+{
+ /**
+ * Constructor. This is here primarily to make calling the parent
+ * constructor(s) from any subclasses cleaner.
+ *
+ * @param unknown_type $data
+ * @return Horde_Share_Object_sql_hierarchical
+ */
+ public function __construct($data)
+ {
+ if (!isset($data['share_parents'])) {
+ $data['share_parents'] = null;
+ }
+ parent::__construct($data);
+ }
+
+ public function inheritPermissions()
+ {
+ throw new Horde_Share_Exception('Not implemented.');
+ }
+
+ /**
+ * Return a count of the number of children this share has
+ *
+ * @param integer $perm A Horde_Perms::* constant
+ * @param boolean $allLevels Count grandchildren or just children
+ *
+ * @return mixed The number of child shares || PEAR_Error
+ */
+ public function countChildren($perm = Horde_Perms::SHOW, $allLevels = true)
+ {
+ return $this->_shareOb->countShares(Horde_Auth::getAuth(), $perm, null, $this, $allLevels);
+ }
+
+ /**
+ * Get all children of this share.
+ *
+ * @param int $perm Horde_Perms::* constant. If NULL will return
+ * all shares regardless of permissions.
+ * @param boolean $allLevels Return all levels.
+ *
+ * @return mixed An array of Horde_Share_Object objects || PEAR_Error
+ */
+ public function getChildren($perm = Horde_Perms::SHOW, $allLevels = true)
+ {
+ return $this->_shareOb->listShares(Horde_Auth::getAuth(), $perm, null, 0, 0,
+ null, 1, $this, $allLevels, is_null($perm));
+
+ }
+
+ /**
+ * Returns a child's direct parent
+ *
+ * @return mixed The direct parent Horde_Share_Object or PEAR_Error
+ */
+ public function getParent()
+ {
+ return $this->_shareOb->getParent($this);
+ }
+
+ /**
+ * Get all of this share's parents.
+ *
+ * @return array() An array of Horde_Share_Objects
+ */
+ public function getParents()
+ {
+ $parents = array();
+ $share = $this->getParent();
+ while (is_a($share, 'Horde_Share_Object')) {
+ $parents[] = $share;
+ $share = $share->getParent();
+ }
+ return array_reverse($parents);
+ }
+
+ /**
+ * Set the parent object for this share.
+ *
+ * @param mixed $parent A Horde_Share object or share id for the parent.
+ *
+ * @return mixed true || PEAR_Error
+ */
+ public function setParent($parent)
+ {
+ if (!is_null($parent) && !is_a($parent, 'Horde_Share_Object')) {
+ $parent = $this->_shareOb->getShareById($parent);
+ if ($parent instanceof PEAR_Error) {
+ Horde::logMessage($parent, 'ERR');
+ throw new Horde_Share_Exception($parent->getMessage());
+ }
+ }
+
+ /* If we are an existing share, check for any children */
+ if ($this->getId()) {
+ $children = $this->_shareOb->listShares(
+ Horde_Auth::getAuth(), Horde_Perms::EDIT, null, 0, 0, null, 0,
+ $this->getId());
+ } else {
+ $children = array();
+ }
+
+ /* Can't set a child share as a parent */
+ if (!empty($parent) && in_array($parent->getId(), array_keys($children))) {
+ throw new Horde_Share_Exception('Cannot set an existing child as the parent');
+ }
+
+ if (!is_null($parent)) {
+ $parent_string = $parent->get('parents') . ':' . $parent->getId();
+ } else {
+ $parent_string = null;
+ }
+ $this->data['share_parents'] = $parent_string;
+ $query = $this->_shareOb->_write_db->prepare('UPDATE ' . $this->_shareOb->_table . ' SET share_parents = ? WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
+ $result = $query->execute(array($this->data['share_parents'], $this->getId()));
+ $query->free();
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+
+ /* Now we can reset the children's parent */
+ foreach($children as $child) {
+ $child->setParent($this);
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the permission of this share.
+ *
+ * @return Horde_Perms_Permission Permission object that represents the
+ * permissions on this share.
+ */
+ public function getPermission()
+ {
+ $perm = new Horde_Perms_Permission('');
+ $perm->data = isset($this->data['perm'])
+ ? $this->data['perm']
+ : array();
+
+ return $perm;
+ }
+
+ /**
+ * Returns one of the attributes of the object, or null if it isn't
+ * defined.
+ *
+ * @param string $attribute The attribute to retrieve.
+ *
+ * @return mixed The value of the attribute, or an empty string.
+ */
+ protected function _get($attribute)
+ {
+ if ($attribute == 'owner' || $attribute == 'parents') {
+ return $this->data['share_' . $attribute];
+ } elseif (isset($this->data['attribute_' . $attribute])) {
+ return $this->data['attribute_' . $attribute];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Hierarchical shares do not have share names.
+ *
+ * @return unknown
+ */
+ protected function _getName()
+ {
+ return '';
+ }
+
+}
+
--- /dev/null
+<?php
+/**
+ * Horde_Share_sql:: provides the sql backend for the horde share
+ * driver.
+ *
+ * Copyright 2008-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 Duck <duck@obala.net>
+ * @package Horde_Share
+ */
+
+/**
+ * @package Horde_Share
+ */
+class Horde_Share_Sql extends Horde_Share
+{
+ /* Share has user perms */
+ const SQL_FLAG_USERS = 1;
+
+ /* Share has group perms */
+ const SQL_FLAG_GROUPS = 2;
+
+ /**
+ * Handle for the current database connection.
+ * @TODO: port to Horde_Db
+ *
+ * @var MDB2
+ */
+ protected $_db;
+
+ /**
+ * Handle for the current database connection, used for writing. Defaults
+ * to the same handle as $db if a separate write database is not required.
+ *
+ * @var MDB2
+ */
+ protected $_write_db;
+
+ /**
+ * SQL connection parameters
+ */
+ protected $_params = array();
+
+ /**
+ * Main share table for the current scope.
+ *
+ * @var string
+ */
+ protected $_table;
+
+ /**
+ * The Horde_Share_Object subclass to instantiate objects as
+ *
+ * @var string
+ */
+ protected $_shareObject = 'Horde_Share_Object_Sql';
+
+ /**
+ * Initializes the object.
+ */
+ public function __wakeup()
+ {
+ $this->_table = $this->_app . '_shares';
+ $this->_connect();
+
+ foreach (array_keys($this->_cache) as $name) {
+ $this->_cache[$name]->setShareOb($this);
+ }
+
+ parent::__wakeup();
+ }
+
+ /**
+ * Returns the properties that need to be serialized.
+ *
+ * @return array List of serializable properties.
+ */
+ public function __sleep()
+ {
+ $properties = get_object_vars($this);
+ unset($properties['_sortList'],
+ $properties['_db'],
+ $properties['_write_db']);
+ return array_keys($properties);
+ }
+
+ /**
+ * Get storage table
+ */
+ public function getTable()
+ {
+ return $this->_table;
+ }
+
+ /**
+ * Refetence to write db
+ */
+ public function getWriteDb()
+ {
+ return $this->_write_db;
+ }
+
+ public function getReadDb()
+ {
+ return $this->_db;
+ }
+
+ /**
+ * Finds out if the share has user set
+ */
+ public function _hasUsers($share)
+ {
+ return $share['share_flags'] & self::SQL_FLAG_USERS;
+ }
+
+ /**
+ * Finds out if the share has user set
+ */
+ public function _hasGroups($share)
+ {
+ return $share['share_flags'] & self::SQL_FLAG_GROUPS;
+ }
+
+ /**
+ * Get users permissions
+ *
+ * @param array $share Share data array
+ *
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShareUsers(&$share)
+ {
+ if ($this->_hasUsers($share)) {
+ $stmt = $this->_db->prepare('SELECT user_uid, perm FROM ' . $this->_table . '_users WHERE share_id = ?');
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($share['share_id']));
+ if ( $result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $share['perm']['users'][$row['user_uid']] = (int)$row['perm'];
+ }
+ }
+ $stmt->free();
+ $result->free();
+ }
+ }
+
+ /**
+ * Get groups permissions
+ *
+ * @param array $share Share data array
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShareGroups(&$share)
+ {
+ if ($this->_hasGroups($share)) {
+ // Get groups permissions
+ $stmt = $this->_db->prepare('SELECT group_uid, perm FROM ' . $this->_table . '_groups WHERE share_id = ?');
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($share['share_id']));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $share['perm']['groups'][$row['group_uid']] = (int)$row['perm'];
+ }
+ }
+ $stmt->free();
+ $result->free();
+ }
+ }
+
+ /**
+ * Returns a Horde_Share_Object_sql object corresponding to the given
+ * share name, with the details retrieved appropriately.
+ *
+ * @param string $name The name of the share to retrieve.
+ *
+ * @return Horde_Share_Object_sql The requested share.
+ */
+ protected function _getShare($name)
+ {
+ $stmt = $this->_db->prepare('SELECT * FROM ' . $this->_table . ' WHERE share_name = ?');
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $results = $stmt->execute(array($name));
+ if ($results instanceof PEAR_Error) {
+ Horde::logMessage($results, 'ERR');
+ throw new Horde_Share_Exception($results->getMessage());
+ }
+ $data = $results->fetchRow(MDB2_FETCHMODE_ASSOC);
+ if ($data instanceof PEAR_Error) {
+ Horde::logMessage($data, 'ERR');
+ throw new Horde_Share_Exception($data->getMessage());
+ } elseif (empty($data)) {
+ throw new Horde_Share_Exception(sprintf(_("Share \"%s\" does not exist."), $name));
+ }
+ $stmt->free();
+ $results->free();
+
+ // Convert charset
+ $data = $this->_fromDriverCharset($data);
+
+ // Populate the perms array
+ $this->_loadPermissions($data);
+
+ return new $this->_shareObject($data);
+ }
+
+ /**
+ * Helper function to load the permissions data into the share data
+ *
+ * @param array $data Array of share attributes
+ */
+ protected function _loadPermissions(&$data)
+ {
+ $this->_getShareUsers($data);
+ $this->_getShareGroups($data);
+ $this->_getSharePerms($data);
+ }
+
+ protected function _getSharePerms(&$data)
+ {
+ $data['perm']['type'] = 'matrix';
+ $data['perm']['default'] = isset($data['perm_default']) ? (int)$data['perm_default'] : 0;
+ $data['perm']['guest'] = isset($data['perm_guest']) ? (int)$data['perm_guest'] : 0;
+ $data['perm']['creator'] = isset($data['perm_creator']) ? (int)$data['perm_creator'] : 0;
+ unset($data['perm_creator'], $data['perm_guest'], $data['perm_default']);
+ }
+
+ /**
+ * Returns a Horde_Share_Object_sql object corresponding to the given
+ * unique ID, with the details retrieved appropriately.
+ *
+ * @param integer $cid The id of the share to retrieve.
+ *
+ * @return Horde_Share_Object_sql The requested share.
+ * @throws Horde_Share_Exception
+ */
+ protected function _getShareById($id)
+ {
+ $params = array($id);
+ $stmt = $this->_db->prepare('SELECT * FROM ' . $this->_table . ' WHERE share_id = ?');
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $results = $stmt->execute($params);
+ if ($results instanceof PEAR_Error) {
+ Horde::logMessage($results, 'ERR');
+ throw new Horde_Share_Exception($results->getMessage());
+ }
+ $data = $results->fetchRow(MDB2_FETCHMODE_ASSOC);
+ if ($data instanceof PEAR_Error) {
+ Horde::logMessage($data, 'ERR');
+ throw new Horde_Share_Exception($data->getMessage());
+ } elseif (empty($data)) {
+ throw new Horde_Share_Exception(sprintf(_("Share ID %d does not exist."), $id));
+ }
+
+ $stmt->free();
+ $results->free();
+
+ // Convert charset
+ $data = $this->_fromDriverCharset($data);
+
+ // Get permissions
+ $this->_loadPermissions($data);
+
+ return new $this->_shareObject($data);
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object_sql objects corresponding
+ * to the given set of unique IDs, with the details retrieved
+ * appropriately.
+ *
+ * @param array $cids The array of ids to retrieve.
+ *
+ * @return array The requested shares.
+ */
+ protected function _getShares($ids)
+ {
+ $shares = array();
+ $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_id IN (' . implode(', ', $ids) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ $groups = array();
+ $users = array();
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
+ if ($this->_hasUsers($share)) {
+ $users[] = (int)$share['share_id'];
+ }
+ if ($this->_hasGroups($share)) {
+ $groups[] = (int)$share['share_id'];
+ }
+ }
+ $result->free();
+
+ // Get users permissions
+ if (!empty($users)) {
+ $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users '
+ . ' WHERE share_id IN (' . implode(', ', $users) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ // Get groups permissions
+ if (!empty($groups)) {
+ $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups'
+ . ' WHERE share_id IN (' . implode(', ', $groups) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ $sharelist = array();
+ foreach ($shares as $id => $data) {
+ $this->_getSharePerms($data);
+ $sharelist[$data['share_name']] = new $this->_shareObject($data);
+ }
+
+ return $sharelist;
+ }
+
+ /**
+ * Lists *all* shares for the current app/share, regardless of
+ * permissions.
+ *
+ * This is for admin functionality and scripting tools, and shouldn't be
+ * called from user-level code!
+ *
+ * @return array All shares for the current app/share.
+ * @throws Horde_Share_Exception
+ */
+ public function listAllShares()
+ {
+ return $this->_listAllShares();
+ }
+
+ /**
+ * Lists *all* shares for the current app/share, regardless of
+ * permissions.
+ *
+ * @return array All shares for the current app/share.
+ */
+ protected function _listAllShares()
+ {
+ $shares = array();
+ $query = 'SELECT * FROM ' . $this->_table . ' ORDER BY share_name ASC';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
+ }
+ $result->free();
+
+ // Get users permissions
+ $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ return $result;
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+
+ // Get groups permissions
+ $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+
+ $sharelist = array();
+ foreach ($shares as $id => $data) {
+ $this->_getSharePerms($data);
+ $sharelist[$data['share_name']] = new $this->_shareObject($data);
+ $sharelist[$data['share_name']]->setShareOb($this);
+ }
+
+ return $sharelist;
+ }
+
+ /**
+ * Returns an array of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return array The shares the user has access to.
+ * @throws Horde_Share_Exception
+ */
+ public function listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
+ $from = 0, $count = 0, $sort_by = null, $direction = 0)
+ {
+ $shares = array();
+ if (is_null($sort_by)) {
+ $sortfield = 's.share_name';
+ } elseif ($sort_by == 'owner' || $sort_by == 'id') {
+ $sortfield = 's.share_' . $sort_by;
+ } else {
+ $sortfield = 's.attribute_' . $sort_by;
+ }
+
+ $query = 'SELECT DISTINCT s.* '
+ . $this->getShareCriteria($userid, $perm, $attributes)
+ . ' ORDER BY ' . $sortfield
+ . (($direction == 0) ? ' ASC' : ' DESC');
+ if ($from > 0 || $count > 0) {
+ $this->_db->setLimit($count, $from);
+ }
+
+ // Fix field names for sqlite. MDB2 tries to handle this with
+ // MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES, but it doesn't stick.
+ if ($this->_db->phptype == 'sqlite') {
+ $connection = $this->_db->getConnection();
+ @sqlite_query('PRAGMA full_column_names=0', $connection);
+ @sqlite_query('PRAGMA short_column_names=1', $connection);
+ }
+
+ Horde::logMessage(sprintf("SQL Query by Horde_Share_sql::listShares: %s", $query), 'DEBUG');
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ $users = array();
+ $groups = array();
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
+ if ($this->_hasUsers($share)) {
+ $users[] = (int)$share['share_id'];
+ }
+ if ($this->_hasGroups($share)) {
+ $groups[] = (int)$share['share_id'];
+ }
+ }
+ $result->free();
+
+ // Get users permissions
+ if (!empty($users)) {
+ $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table
+ . '_users WHERE share_id IN (' . implode(', ', $users)
+ . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ // Get groups permissions
+ if (!empty($groups)) {
+ $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table
+ . '_groups WHERE share_id IN (' . implode(', ', $groups)
+ . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ $sharelist = array();
+ foreach ($shares as $id => $data) {
+ $this->_getSharePerms($data);
+ $sharelist[$data['share_name']] = new $this->_shareObject($data);
+ $sharelist[$data['share_name']]->setShareOb($this);
+ }
+ unset($shares);
+
+ try {
+ return Horde::callHook('share_list', array($userid, $perm, $attributes, $sharelist));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ return $sharelist;
+ }
+
+ /**
+ * Returns an array of all system shares.
+ *
+ * @return array All system shares.
+ * @throws Horde_Share_Exception
+ */
+ public function listSystemShares()
+ {
+ // Fix field names for sqlite. MDB2 tries to handle this with
+ // MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES, but it doesn't stick.
+ if ($this->_db->phptype == 'sqlite') {
+ $connection = $this->_db->getConnection();
+ @sqlite_query('PRAGMA full_column_names=0', $connection);
+ @sqlite_query('PRAGMA short_column_names=1', $connection);
+ }
+
+ $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_owner IS NULL';
+ Horde::logMessage('SQL Query by Horde_Share_sql::listSystemShares: ' . $query, 'DEBUG');
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());;
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ $sharelist = array();
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $data = $this->_fromDriverCharset($share);
+ $this->_getSharePerms($data);
+ $sharelist[$data['share_name']] = new $this->_shareObject($data);
+ $sharelist[$data['share_name']]->setShareOb($this);
+ }
+ $result->free();
+
+ return $sharelist;
+ }
+
+ /**
+ * Returns the number of shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ *
+ * @return integer The number of shares
+ */
+ protected function _countShares($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null)
+ {
+ $query = $this->getShareCriteria($userid, $perm, $attributes);
+ $query = 'SELECT COUNT(DISTINCT s.share_id) ' . $query;
+ Horde::logMessage(sprintf("SQL Query by Horde_Share_sql::_countShares: %s", $query), 'DEBUG');
+ return $this->_db->queryOne($query);
+ }
+
+ /**
+ * Returns a new share object.
+ *
+ * @param string $name The share's name.
+ *
+ * @return Horde_Share_Object_sql A new share object.
+ */
+ protected function _newShare($name)
+ {
+ return new $this->_shareObject(array('share_name' => $name));
+ }
+
+ /**
+ * Adds a share to the shares system.
+ *
+ * The share must first be created with
+ * Horde_Share_sql::_newShare(), and have any initial details added
+ * to it, before this function is called.
+ *
+ * @param Horde_Share_Object_sql $share The new share object.
+ */
+ protected function _addShare($share)
+ {
+ return $share->save();
+ }
+
+ /**
+ * Removes a share from the shares system permanently.
+ *
+ * @param Horde_Share_Object_sql $share The share to remove.
+ *
+ * @return boolean
+ * @throws Horde_Share_Exception
+ */
+ protected function _removeShare($share)
+ {
+ $params = array($share->getId());
+ $tables = array($this->_table,
+ $this->_table . '_users',
+ $this->_table . '_groups');
+ foreach ($tables as $table) {
+
+ /* Remove the share entry */
+ $stmt = $this->_write_db->prepare('DELETE FROM ' . $table . ' WHERE share_id = ?', null, MDB2_PREPARE_MANIP);
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute($params);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ $stmt->free();
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a share exists in the system.
+ *
+ * @param string $share The share to check.
+ *
+ * @return boolean True if the share exists.
+ * @throws Horde_Share_Exception
+ */
+ protected function _exists($share)
+ {
+ $stmt = $this->_db->prepare('SELECT 1 FROM ' . $this->_table
+ . ' WHERE share_name = ?');
+
+ if ($stmt instanceof PEAR_Error) {
+ Horde::logMessage($stmt, 'ERR');
+ throw new Horde_Share_Exception($stmt->getMessage());
+ }
+ $result = $stmt->execute(array($share));
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+
+ $exists = (bool)$result->fetchOne();
+ $stmt->free();
+ $result->free();
+
+ return $exists;
+ }
+
+ /**
+ * Returns an array of criteria for querying shares.
+ * @access protected
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares returned to those who
+ * have these attribute values.
+ *
+ * @return string The criteria string for fetching this user's shares.
+ */
+ public function getShareCriteria($userid, $perm = Horde_Perms::SHOW,
+ $attributes = null)
+ {
+ $query = ' FROM ' . $this->_table . ' s ';
+ $where = '';
+
+ if (!empty($userid)) {
+ // (owner == $userid)
+ $where .= 's.share_owner = ' . $this->_write_db->quote($userid);
+
+ // (name == perm_creator and val & $perm)
+ $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_creator', '&', $perm) . ')';
+
+ // (name == perm_creator and val & $perm)
+ $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_default', '&', $perm) . ')';
+
+ // (name == perm_users and key == $userid and val & $perm)
+ $query .= ' LEFT JOIN ' . $this->_table . '_users u ON u.share_id = s.share_id';
+ $where .= ' OR ( u.user_uid = ' . $this->_write_db->quote($userid)
+ . ' AND (' . Horde_SQL::buildClause($this->_db, 'u.perm', '&', $perm) . '))';
+
+ // If the user has any group memberships, check for those also.
+ // @TODO: Inject the group driver
+ require_once 'Horde/Group.php';
+ $group = Group::singleton();
+ $groups = $group->getGroupMemberships($userid, true);
+ if (!is_a($groups, 'PEAR_Error') && $groups) {
+ // (name == perm_groups and key in ($groups) and val & $perm)
+ $ids = array_keys($groups);
+ $group_ids = array();
+ foreach ($ids as $id) {
+ $group_ids[] = $this->_db->quote((string)$id);
+ }
+ $query .= ' LEFT JOIN ' . $this->_table . '_groups g ON g.share_id = s.share_id';
+ $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')'
+ . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))';
+ } elseif ($groups instanceof PEAR_Error) {
+ Horde::logMessage($groups, 'ERR');
+ }
+ } else {
+ $where = '(' . Horde_SQL::buildClause($this->_db, 's.perm_guest', '&', $perm) . ')';
+ }
+
+ $attributes = $this->_toDriverKeys($attributes);
+ $attributes = $this->_toDriverCharset($attributes);
+
+ if (is_array($attributes)) {
+ // Build attribute/key filter.
+ $where = ' (' . $where . ') ';
+ foreach ($attributes as $key => $value) {
+ $where .= ' AND ' . $key . ' = ' . $this->_db->quote($value);
+ }
+ } elseif (!empty($attributes)) {
+ // Restrict to shares owned by the user specified in the
+ // $attributes string.
+ $where = ' (' . $where . ') AND s.share_owner = ' . $this->_db->quote($attributes);
+ }
+
+ return $query . ' WHERE ' . $where;
+ }
+
+ /**
+ * Resets the current database name so that MDB2 is always selecting the
+ * database before sending a query.
+ *
+ * @TODO: This needs to be public since it's used as a callback in MDB2.
+ * Remove when refactored to use Horde_Db
+ */
+ public function _selectDB($db, $scope, $message, $is_manip = null)
+ {
+ if ($scope == 'query') {
+ $db->connected_database_name = '';
+ }
+ }
+
+ /**
+ * Set the SQL table name to use for the current scope's share storage.
+ *
+ * @var string $table The table name
+ */
+ public function setShareTable($table) {
+ $this->_table = $table;
+ }
+
+ /**
+ * Attempts to open a connection to the sql server.
+ *
+ * @return boolean True on success.
+ * @throws Horde_Share_Exception
+ */
+ protected function _connect()
+ {
+ $this->_params = $GLOBALS['conf']['sql'];
+ if (!isset($this->_params['database'])) {
+ $this->_params['database'] = '';
+ }
+ if (!isset($this->_params['username'])) {
+ $_params['username'] = '';
+ }
+ if (!isset($this->_params['hostspec'])) {
+ $this->_params['hostspec'] = '';
+ }
+
+ /* Connect to the sql server using the supplied parameters. */
+ $params = $this->_params;
+ unset($params['charset']);
+ $this->_write_db = MDB2::factory($params);
+ if ($this->_write_db instanceof PEAR_Error) {
+ throw new Horde_Share_Excetion($this->_write_db->getMessage());
+ }
+
+ /* Attach debug handler. */
+ $this->_write_db->setOption('debug', true);
+ $this->_write_db->setOption('debug_handler', array($this, '_selectDB'));
+ $this->_write_db->setOption('seqcol_name', 'id');
+
+ /* Set DB portability options. */
+ switch ($this->_write_db->phptype) {
+ case 'mssql':
+ $this->_write_db->setOption('field_case', CASE_LOWER);
+ $this->_write_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_RTRIM | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
+ break;
+
+ case 'pgsql':
+ /* The debug handler breaks PostgreSQL. In most cases it shouldn't
+ * be necessary, but this may mean we simply can't support use of
+ * multiple Postgres databases right now. See
+ * http://bugs.horde.org/ticket/7825 */
+ $this->_write_db->setOption('debug', false);
+ // Fall through
+
+ default:
+ $this->_write_db->setOption('field_case', CASE_LOWER);
+ $this->_write_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
+ }
+
+ /* Check if we need to set up the read DB connection seperately. */
+ if (!empty($this->_params['splitread'])) {
+ $params = array_merge($params, $this->_params['read']);
+ unset($params['charset']);
+ $this->_db = MDB2::singleton($params);
+ if ($this->_db instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($this->_db);
+ }
+
+ $this->_db->setOption('seqcol_name', 'id');
+ /* Set DB portability options. */
+ switch ($this->_db->phptype) {
+ case 'mssql':
+ $this->_db->setOption('field_case', CASE_LOWER);
+ $this->_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_RTRIM | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
+ break;
+
+ case 'pgsql':
+ /* The debug handler breaks PostgreSQL. In most cases it shouldn't
+ * be necessary, but this may mean we simply can't support use of
+ * multiple Postgres databases right now. See
+ * http://bugs.horde.org/ticket/7825 */
+ $this->_write_db->setOption('debug', false);
+ // Fall through
+
+ default:
+ $this->_db->setOption('field_case', CASE_LOWER);
+ $this->_db->setOption('portability', MDB2_PORTABILITY_FIX_CASE | MDB2_PORTABILITY_ERRORS | MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES);
+ }
+ } else {
+ /* Default to the same DB handle as the writer for reading too */
+ $this->_db = $this->_write_db;
+ }
+
+ return true;
+ }
+
+ /**
+ * Utility function to convert from the SQL server's charset.
+ */
+ protected function _fromDriverCharset($data)
+ {
+ foreach ($data as $key => $value) {
+ if (substr($key, 0, 9) == 'attribute') {
+ $data[$key] = Horde_String::convertCharset(
+ $data[$key], $this->_params['charset']);
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Utility function to convert TO the SQL server's charset.
+ *
+ * @TODO: This needs to be public since it's called by the share object.
+ * Look at making this outright public or maybe moving it to the object.
+ */
+ public function _toDriverCharset($data)
+ {
+ if (!is_array($data)) {
+ return $data;
+ }
+
+ foreach ($data as $key => $value) {
+ if (substr($key, 0, 9) == 'attribute') {
+ $data[$key] = Horde_String::convertCharset(
+ $data[$key], Horde_Nls::getCharset(), $this->_params['charset']);
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Convert an array keyed on client keys to an array keyed on the driver
+ * keys.
+ *
+ * @param array $data The client code keyed array.
+ *
+ * @return array The driver keyed array.
+ */
+ protected function _toDriverKeys($data)
+ {
+ if (!is_array($data)) {
+ return $data;
+ }
+
+ $driver_keys = array();
+ foreach ($data as $key => $value) {
+ if ($key == 'owner') {
+ $driver_keys['share_owner'] = $value;
+ } else {
+ $driver_keys['attribute_' . $key] = $value;
+ }
+ }
+
+ return $driver_keys;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Implementation of Horde_Share class for shared objects that are hierarchical
+ * in nature.
+ *
+ * @author Duck <duck@obala.net>
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ * @package Horde_Share
+ */
+class Horde_Share_Sql_Hierarchical extends Horde_Share_Sql
+{
+ /**
+ * The Horde_Share_Object subclass to instantiate objects as
+ *
+ * @var string
+ */
+ protected $_shareObject = 'Horde_Share_Object_Sql_Hierarchical';
+
+ /**
+ * Override new share creation so we can allow for shares with empty
+ * share_names.
+ *
+ */
+ public function newShare($name = '')
+ {
+ $share = $this->_newShare();
+ $share->setShareOb($this);
+ //@TODO: inject the Auth object
+ $share->set('owner', Horde_Auth::getAuth());
+
+ return $share;
+ }
+
+ /**
+ * Returns a new share object.
+ *
+ * @param string $name The share's name.
+ *
+ * @return Horde_Share_Object_sql A new share object.
+ */
+ protected function _newShare()
+ {
+ $share = new $this->_shareObject();
+ return $share;
+ }
+
+ /**
+ * Returns an array of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ * @param integer $from The share to start listing from.
+ * @param integer $count The number of shares to return.
+ * @param string $sort_by The field to sort by
+ * @param integer $direction The sort direction
+ * @param mixed $parent Either a share_id, Horde_Share_Object or null.
+ * @param boolean $alllevels List all levels or just the direct children
+ * of $parent?
+ *
+ * @return mixed The shares the user has access to
+ * @throws Horde_Share_Exception
+ */
+ public function &listShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
+ $from = 0, $count = 0, $sort_by = null,
+ $direction = 0, $parent = null,
+ $allLevels = true, $ignorePerms = false)
+ {
+ $shares = array();
+ if (is_null($sort_by)) {
+ $sortfield = 's.share_id';
+ } elseif ($sort_by == 'owner' || $sort_by == 'id') {
+ $sortfield = 's.share_' . $sort_by;
+ } else {
+ $sortfield = 's.attribute_' . $sort_by;
+ }
+
+ $query = 'SELECT DISTINCT s.* '
+ . $this->getShareCriteria($userid, $perm, $attributes,
+ $parent, $allLevels, $ignorePerms)
+ . ' ORDER BY ' . $sortfield
+ . (($direction == 0) ? ' ASC' : ' DESC');
+ if ($from > 0 || $count > 0) {
+ $this->_db->setLimit($count, $from);
+ }
+
+ Horde::logMessage('Query By Horde_Share_sql_hierarchical: ' . $query, 'DEBUG');
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ $users = array();
+ $groups = array();
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
+ if ($this->_hasUsers($share)) {
+ $users[] = (int)$share['share_id'];
+ }
+ if ($this->_hasGroups($share)) {
+ $groups[] = (int)$share['share_id'];
+ }
+ }
+ $result->free();
+
+ // Get users permissions
+ if (!empty($users)) {
+ $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table
+ . '_users WHERE share_id IN (' . implode(', ', $users)
+ . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ // Get groups permissions
+ if (!empty($groups)) {
+ $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table
+ . '_groups WHERE share_id IN (' . implode(', ', $groups)
+ . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ $sharelist = array();
+ foreach ($shares as $id => $data) {
+ $this->_getSharePerms($data);
+ $sharelist[$id] = new $this->_shareObject($data);
+ $sharelist[$id]->setShareOb($this);
+ }
+ unset($shares);
+
+ try {
+ return Horde::callHook('share_list', array($userid, $perm, $attributes, $sharelist));
+ } catch (Horde_Exception_HookNotSet $e) {}
+
+ return $sharelist;
+ }
+
+ /**
+ * Returns an array of criteria for querying shares.
+ * @access protected
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares returned to those who
+ * have these attribute values.
+ * @param mixed $parent The share to start searching in.
+ * (A Horde_Share_Object, share_id or null)
+ * @param boolean $allLevels Return all levels, or just the direct
+ * children of $parent? Defaults to all levels.
+ *
+ * @return string The criteria string for fetching this user's shares.
+ * @throws Horde_Share_Exception
+ */
+ public function getShareCriteria($userid, $perm = Horde_Perms::SHOW, $attributes = null,
+ $parent = null, $allLevels = true,
+ $ignorePerms = false)
+ {
+ static $criteria;
+
+ if ($parent instanceof Horde_Share_Object) {
+ $parent_id = $parent->getId();
+ } else {
+ $parent_id = $parent;
+ }
+ $key = $userid . $perm . $parent_id . $allLevels
+ . (is_array($attributes) ? serialize($attributes) : $attributes);
+ if (isset($criteria[$key])) {
+ return $criteria[$key];
+ }
+
+ $query = ' FROM ' . $this->_table . ' s ';
+ $where = '';
+
+ if (!$ignorePerms) {
+ if (empty($userid)) {
+ $where = '(' . Horde_SQL::buildClause($this->_db, 's.perm_guest', '&', $perm) . ')';
+ } else {
+ // (owner == $userid)
+ $where = 's.share_owner = ' . $this->_db->quote($userid);
+
+ // (name == perm_creator and val & $perm)
+ $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_creator', '&', $perm) . ')';
+
+ // (name == perm_creator and val & $perm)
+ $where .= ' OR (' . Horde_SQL::buildClause($this->_db, 's.perm_default', '&', $perm) . ')';
+
+ // (name == perm_users and key == $userid and val & $perm)
+ $query .= ' LEFT JOIN ' . $this->_table . '_users AS u ON u.share_id = s.share_id';
+ $where .= ' OR ( u.user_uid = ' . $this->_write_db->quote($userid)
+ . ' AND (' . Horde_SQL::buildClause($this->_db, 'u.perm', '&', $perm) . '))';
+
+ // If the user has any group memberships, check for those also.
+ // @TODO: Inject the group driver
+ require_once 'Horde/Group.php';
+ $group = &Group::singleton();
+ $groups = $group->getGroupMemberships($userid, true);
+ if (!($groups instanceof PEAR_Error) && $groups) {
+ // (name == perm_groups and key in ($groups) and val & $perm)
+ $ids = array_keys($groups);
+ $group_ids = array();
+ foreach ($ids as $id) {
+ $group_ids[] = $this->_db->quote((string)$id);
+ }
+ $query .= ' LEFT JOIN ' . $this->_table . '_groups AS g ON g.share_id = s.share_id';
+ $where .= ' OR (g.group_uid IN (' . implode(',', $group_ids) . ')'
+ . ' AND (' . Horde_SQL::buildClause($this->_db, 'g.perm', '&', $perm) . '))';
+ }
+ }
+ }
+
+ /* Convert to driver's keys */
+ $attributes = $this->_toDriverKeys($attributes);
+
+ /* ...and to driver charset */
+ $attributes = $this->_toDriverCharset($attributes);
+
+ if (is_array($attributes)) {
+ // Build attribute/key filter.
+ if (!empty($where)) {
+ $where = ' (' . $where . ') ';
+ }
+ foreach ($attributes as $key => $value) {
+ $where .= ' AND ' . $key;
+ if (is_array($value)) {
+ $where .= ' ' . $value[0]. ' ' . $this->_db->quote($value[1]);
+ } else {
+ $where .= ' = ' . $this->_db->quote($value);
+ }
+ }
+ } elseif (!empty($attributes)) {
+ // Restrict to shares owned by the user specified
+ $where = (!empty($where) ? ' (' . $where . ') AND ' : ' ') . 's.share_owner = ' . $this->_db->quote($attributes);
+ }
+
+ // See if we need to filter by parent or get the parent object
+ if ($parent != null) {
+ if (!($parent instanceof Horde_Share_Object)) {
+ $parent = $this->getShareById($parent);
+ if ($parent instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($parent->getMessage());
+ }
+ }
+
+ // Need to append the parent's share id to the list of parents in
+ // order to search the share_parents field.
+ $parents = $parent->get('parents') . ':' . $parent->getId();
+ if ($allLevels) {
+ $where_parent = '(share_parents = ' . $this->_db->quote($parents)
+ . ' OR share_parents LIKE ' . $this->_db->quote($parents . ':%') . ')';
+ } else {
+ $where_parent = 's.share_parents = ' . $this->_db->quote($parents);
+ }
+ } elseif (!$allLevels) {
+ // No parents, and we only want the root.
+ $where_parent = "(s.share_parents = '' OR s.share_parents IS NULL)";
+ }
+
+ if (empty($where_parent)) {
+ $criteria[$key] = $query . ' WHERE ' . $where;
+ } else {
+ if (!empty($where)) {
+ $criteria[$key] = $query . ' WHERE (' . $where . ') AND ' . $where_parent;
+ } else {
+ $criteria[$key] = $query . ' WHERE ' . $where_parent;
+ }
+ }
+
+ return $criteria[$key];
+ }
+
+ /**
+ * Return a list of users who have shares with the given permissions
+ * for the current user.
+ *
+ * @param integer $perm The level of permissions required.
+ * @param mixed $parent The parent share to start looking in.
+ * (Horde_Share_Object, share_id, or null)
+ * @param boolean $allLevels Return all levels, or just the direct
+ * children of $parent? Defaults to all levels.
+ * @param integer $from The user to start listing at.
+ * @param integer $count The number of users to return.
+ *
+ * @return array List of users.
+ */
+ public function listOwners($perm = Horde_Perms::SHOW, $parent = null, $allLevels = true,
+ $from = 0, $count = 0)
+ {
+ $sql = 'SELECT DISTINCT(s.share_owner) '
+ . $this->getShareCriteria(Horde_Auth::getAuth(), $perm, null,
+ $parent, $allLevels);
+
+ if ($count) {
+ $this->_db->setLimit($count, $from);
+ }
+
+ $allowners = $this->_db->queryCol($sql);
+ if ($allowners instanceof PEAR_Error) {
+ Horde::logMessage($allowners, 'ERR');
+ throw new Horde_Share_Exception($allowners->getMessage());
+ }
+
+ $owners = array();
+ foreach ($allowners as $owner) {
+ if ($this->countShares(Horde_Auth::getAuth(), $perm, $owner, $parent,
+ $allLevels)) {
+
+ $owners[] = $owner;
+ }
+ }
+
+ return $owners;
+ }
+
+ /**
+ * Count the number of users who have shares with the given permissions
+ * for the current user.
+ *
+ * @param integer $perm The level of permissions required.
+ * @param mixed $parent The parent share to start looking in.
+ * (Horde_Share_Object, share_id, or null).
+ * @param boolean $allLevels Return all levels, or just the direct
+ * children of $parent?
+ *
+ * @return integer Number of users.
+ */
+ public function countOwners($perm = Horde_Perms::SHOW, $parent = null, $allLevels = true)
+ {
+ $sql = 'SELECT COUNT(DISTINCT(s.share_owner)) '
+ . $this->getShareCriteria(Horde_Auth::getAuth(), $perm, null, $parent,
+ $allLevels);
+
+ return $this->_db->queryOne($sql);
+ }
+
+ /**
+ * Returns a share's direct parent object.
+ *
+ * @param Horde_Share_Object $share The share to get parent for.
+ *
+ * @return Horde_Share_Object The parent share, if it exists.
+ */
+ public function getParent($child)
+ {
+ $parents = $child->get('parents');
+
+ // No parents, this is at the root.
+ if (empty($parents)) {
+ return null;
+ }
+ $parents = explode(':', $parents);
+ return $this->getShareById(array_pop($parents));
+ }
+
+ /**
+ * Returns a Horde_Share_Object object corresponding to the given unique
+ * ID, with the details retrieved appropriately.
+ *
+ * @param string $cid The id of the share to retrieve.
+ *
+ * @return Horde_Share_Object The requested share.
+ */
+ public function getShareById($cid)
+ {
+ if (!isset($this->_cache[$cid])) {
+ $share = &$this->_getShareById($cid);
+ if ($share instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($share->getMessage());
+ }
+ $share->setShareOb($this);
+ $this->_cache[$cid] = &$share;
+ }
+
+ return $this->_cache[$cid];
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object objects corresponding to the
+ * given set of unique IDs, with the details retrieved appropriately.
+ *
+ * @param array $cids The array of ids to retrieve.
+ *
+ * @return array The requested shares keyed by share_id.
+ * @throws Horde_Share_Exception
+ */
+ public function getShares($cids)
+ {
+ $all_shares = array();
+ $missing_ids = array();
+ foreach ($cids as $cid) {
+ if (isset($this->_cache[$cid])) {
+ $all_shares[] = &$this->_cache[$cid];
+ } else {
+ $missing_ids[] = $cid;
+ }
+ }
+
+ if (count($missing_ids)) {
+ $shares = &$this->_getShares($missing_ids);
+ if ($shares instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($shares->getMessage());
+ }
+
+ foreach (array_keys($shares) as $key) {
+ $this->_cache[$key] = &$shares[$key];
+ $this->_cache[$key]->setShareOb($this);
+ $all_shares[$key] = &$this->_cache[$key];
+ }
+ }
+
+ return $all_shares;
+ }
+
+ /**
+ * Removes a share from the shares system permanently. This will recursively
+ * delete all child shares as well.
+ *
+ * @param Horde_Share_Object $share The share to remove.
+ * @throws Horde_Exception
+ */
+ public function removeShare(Horde_Share_Object $share)
+ {
+ try {
+ Horde::callHook('share_remove', array($share));
+ } catch (Horde_Share_Exception_HookNotSet $e) {}
+
+ /* Get the list of all $share's children */
+ $children = $share->getChildren(null, true);
+
+ /* Remove share from the caches. */
+ $id = $share->getId();
+ $this->_cache = array();
+ $this->_listCache = array();
+
+ foreach ($children as $child) {
+ $result = $this->_removeShare($child);
+ if ($result instanceof PEAR_Error) {
+ throw new Horde_Share_Exception($result->getMessage());
+ }
+ }
+
+ return $this->_removeShare($share);
+ }
+
+ /**
+ * Returns an array of Horde_Share_Object_sql objects corresponding
+ * to the given set of unique IDs, with the details retrieved
+ * appropriately.
+ *
+ * @param array $cids The array of ids to retrieve.
+ *
+ * @return array The requested shares keyed by share_id.
+ */
+ protected function _getShares($ids)
+ {
+ $shares = array();
+ $query = 'SELECT * FROM ' . $this->_table . ' WHERE share_id IN (' . implode(', ', $ids) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (empty($result)) {
+ return array();
+ }
+
+ $groups = array();
+ $users = array();
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[(int)$share['share_id']] = $this->_fromDriverCharset($share);
+ if ($this->_hasUsers($share)) {
+ $users[] = (int)$share['share_id'];
+ }
+ if ($this->_hasGroups($share)) {
+ $groups[] = (int)$share['share_id'];
+ }
+ }
+ $result->free();
+
+ // Get users permissions
+ if (!empty($users)) {
+ $query = 'SELECT share_id, user_uid, perm FROM ' . $this->_table . '_users '
+ . ' WHERE share_id IN (' . implode(', ', $users) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['users'][$share['user_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ // Get groups permissions
+ if (!empty($groups)) {
+ $query = 'SELECT share_id, group_uid, perm FROM ' . $this->_table . '_groups'
+ . ' WHERE share_id IN (' . implode(', ', $groups) . ')';
+ $result = $this->_db->query($query);
+ if ($result instanceof PEAR_Error) {
+ Horde::logMessage($result, 'ERR');
+ throw new Horde_Share_Exception($result->getMessage());
+ } elseif (!empty($result)) {
+ while ($share = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
+ $shares[$share['share_id']]['perm']['groups'][$share['group_uid']] = (int)$share['perm'];
+ }
+ $result->free();
+ }
+ }
+
+ $sharelist = array();
+ foreach ($shares as $id => $data) {
+ $sharelist[$id] = new $this->_shareObject($data);
+ }
+
+ return $sharelist;
+ }
+
+ /**
+ * Override the Horde_Share base class to avoid any confusion
+ *
+ * @throws Horde_Share_Exception
+ */
+ public function getShare($name)
+ {
+ throw new Horde_Share_Exception(_("Share names are not supported in this driver"));
+ }
+
+ /**
+ * Returns the count of all shares that $userid has access to.
+ *
+ * @param string $userid The userid of the user to check access for.
+ * @param integer $perm The level of permissions required.
+ * @param mixed $attributes Restrict the shares counted to those
+ * matching $attributes. An array of
+ * attribute/values pairs or a share owner
+ * username.
+ * @param mixed $parent The share to start searching from
+ * (Horde_Share_Object, share_id, or null)
+ * @param boolean $allLevels Return all levels, or just the direct
+ * children of $parent?
+ *
+ * @return integer Number of shares the user has access to.
+ */
+ public function countShares($userid, $perm = Horde_Perms::SHOW, $attributes = null,
+ $parent = null, $allLevels = true)
+ {
+ $query = 'SELECT COUNT(DISTINCT s.share_id) '
+ . $this->getShareCriteria($userid, $perm, $attributes,
+ $parent, $allLevels);
+
+ return $this->_db->queryOne($query);
+ }
+
+}
<?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
-http://pear.php.net/dtd/tasks-1.0.xsd
-http://pear.php.net/dtd/package-2.0
-http://pear.php.net/dtd/package-2.0.xsd">
+<package packagerversion="1.9.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
<name>Horde_Share</name>
<channel>pear.horde.org</channel>
<summary>Horde Shared Permissions System</summary>
<description>Horde_Share:: This class provides an interface to all shared
-resources a user owns or has access to.
- </description>
+resources a user owns or has access to.</description>
<lead>
<name>Chuck Hagenbuch</name>
<user>chuck</user>
<email>chuck@horde.org</email>
<active>yes</active>
</lead>
- <date>2006-05-08</date>
- <time>23:21:27</time>
+ <date>2010-05-17</date>
+ <time>13:26:30</time>
<version>
- <release>0.0.3</release>
- <api>0.0.3</api>
+ <release>0.0.4</release>
+ <api>0.0.4</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>* Converted to package.xml 2.0 for pear.horde.org.
-* Split into a driver pattern.
-* Simplified the API greatly, removing unused functions.
-* Add a method for counting the number of shares at a certain access level.
-* Add native SQL driver (duck@obala.net, Request #6109).
-* Implemented extended free/busy access concept in the Kolab driver.
+ <notes>
+* Converted to Horde 4 coding standards
</notes>
<contents>
- <dir name="/">
- <file baseinstalldir="/Horde" name="Share.php" role="php"/>
- <dir name="Share">
- <file baseinstalldir="/Horde" name="datatree.php" role="php"/>
- <file baseinstalldir="/Horde" name="kolab.php" role="php"/>
- <file baseinstalldir="/Horde" name="sql.php" role="php"/>
- <file baseinstalldir="/Horde" name="sql_hierarchical.php" role="php"/>
- </dir>
+ <dir baseinstalldir="/" name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <dir name="Share">
+ <dir name="Object">
+ <dir name="Datatree">
+ <file baseinstalldir="/" name="Share.php" role="php" />
+ </dir> <!-- /lib/Horde/Share/Object/Datatree -->
+ <dir name="Sql">
+ <file baseinstalldir="/" name="Hierarchical.php" role="php" />
+ </dir> <!-- /lib/Horde/Share/Object/Sql -->
+ <file baseinstalldir="/" name="Datatree.php" role="php" />
+ <file baseinstalldir="/" name="Kolab.php" role="php" />
+ <file baseinstalldir="/" name="Sql.php" role="php" />
+ </dir> <!-- /lib/Horde/Share/Object -->
+ <dir name="Sql">
+ <file baseinstalldir="/" name="Hierarchical.php" role="php" />
+ </dir> <!-- /lib/Horde/Share/Sql -->
+ <file baseinstalldir="/" name="Datatree.php" role="php" />
+ <file baseinstalldir="/" name="Exception.php" role="php" />
+ <file baseinstalldir="/" name="Kolab.php" role="php" />
+ <file baseinstalldir="/" name="Object.php" role="php" />
+ <file baseinstalldir="/" name="Sql.php" role="php" />
+ </dir> <!-- /lib/Horde/Share -->
+ <file baseinstalldir="/" name="Share.php" role="php" />
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib -->
+ <dir name="tests">
+ <dir name="Horde">
+ <dir name="Share">
+ <file baseinstalldir="/" name="AllTests.php" role="php" />
+ <file baseinstalldir="/" name="KolabScenarioTest.php" role="php" />
+ </dir> <!-- /tests/Horde/Share -->
+ </dir> <!-- /tests/Horde -->
+ <file baseinstalldir="/" name="kolab_createdefault.phpt" role="data" />
+ <file baseinstalldir="/" name="kolab_list.phpt" role="data" />
+ <file baseinstalldir="/" name="kolab_simple.phpt" role="data" />
+ </dir> <!-- /tests -->
</dir> <!-- / -->
</contents>
<dependencies>
<required>
<php>
- <min>4.0.0</min>
+ <min>5.2.0</min>
</php>
<pearinstaller>
- <min>1.4.0b1</min>
+ <min>1.5.0</min>
</pearinstaller>
<package>
<name>Perms</name>
</package>
</required>
</dependencies>
- <phprelease />
+ <phprelease>
+ <filelist>
+ <install as="Horde/Share.php" name="lib/Horde/Share.php" />
+ <install as="Horde/Share/Datatree.php" name="lib/Horde/Share/Datatree.php" />
+ <install as="Horde/Share/Exception.php" name="lib/Horde/Share/Exception.php" />
+ <install as="Horde/Share/Kolab.php" name="lib/Horde/Share/Kolab.php" />
+ <install as="Horde/Share/Object.php" name="lib/Horde/Share/Object.php" />
+ <install as="Horde/Share/Sql.php" name="lib/Horde/Share/Sql.php" />
+ <install as="Horde/Share/Object/Datatree.php" name="lib/Horde/Share/Object/Datatree.php" />
+ <install as="Horde/Share/Object/Kolab.php" name="lib/Horde/Share/Object/Kolab.php" />
+ <install as="Horde/Share/Object/Sql.php" name="lib/Horde/Share/Object/Sql.php" />
+ <install as="Horde/Share/Object/Datatree/Share.php" name="lib/Horde/Share/Object/Datatree/Share.php" />
+ <install as="Horde/Share/Object/Sql/Hierarchical.php" name="lib/Horde/Share/Object/Sql/Hierarchical.php" />
+ <install as="Horde/Share/Sql/Hierarchical.php" name="lib/Horde/Share/Sql/Hierarchical.php" />
+ </filelist>
+ </phprelease>
<changelog>
<release>
<version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2003-07-05</date>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>
+Initial release as a PEAR package
+ </notes>
+ </release>
+ <release>
+ <version>
<release>0.0.2</release>
<api>0.0.2</api>
</version>
</stability>
<date>2004-10-29</date>
<license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>- Added countShares().
+ <notes>
+- Added countShares().
- listShares() and countShares() now treat the $owner argument
as an optional username restricting the returned shares, not
a modifier to the initial $userid. Now $userid is the user
</release>
<release>
<version>
- <release>0.0.1</release>
- <api>0.0.1</api>
+ <release>0.0.3</release>
+ <api>0.0.3</api>
</version>
<stability>
- <release>alpha</release>
- <api>alpha</api>
+ <release>beta</release>
+ <api>beta</api>
</stability>
- <date>2003-07-05</date>
+ <date>2006-05-08</date>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>
+* Converted to package.xml 2.0 for pear.horde.org.
+ * Split into a driver pattern.
+ * Simplified the API greatly, removing unused functions.
+ * Add a method for counting the number of shares at a certain access level.
+ * Add native SQL driver (duck@obala.net, Request #6109).
+ * Implemented extended free/busy access concept in the Kolab driver.
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>0.0.4</release>
+ <api>0.0.4</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2010-05-17</date>
<license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
- <notes>Initial release as a PEAR package
+ <notes>
+* Converted to Horde 4 coding standards
</notes>
</release>
</changelog>
$actionID = Horde_Util::getFormData('actionID', 'edit');
switch ($actionID) {
case 'edit':
- $share = &$shares->getShareById(Horde_Util::getFormData('cid'));
- if (!$share instanceof PEAR_Error) {
+ try {
+ $share = &$shares->getShareById(Horde_Util::getFormData('cid'));
$form = 'edit.inc';
$perm = &$share->getPermission();
- } elseif (($category = Horde_Util::getFormData('share')) !== null) {
- $share = &$shares->getShare($category);
- if (!$share instanceof PEAR_Error) {
- $form = 'edit.inc';
- $perm = &$share->getPermission();
+ } catch (Horde_Share_Exception $e) {
+ if (($category = Horde_Util::getFormData('share')) !== null) {
+ try {
+ $share = $shares->getShare($category);
+ $form = 'edit.inc';
+ $perm = &$share->getPermission();
+ } catch (Horde_Share_Exception $e) {
+ $notification->push($e->getMessage(), 'horde.error');
+ }
}
}
- if ($share instanceof PEAR_Error) {
- $notification->push($share, 'horde.error');
- } elseif (!Horde_Auth::getAuth() ||
+ if (!Horde_Auth::getAuth() ||
(isset($share) &&
!Horde_Auth::isAdmin() &&
Horde_Auth::getAuth() != $share->get('owner'))) {
break;
case 'editform':
- $share = &$shares->getShareById(Horde_Util::getFormData('cid'));
- if ($share instanceof PEAR_Error) {
+ try {
+ $share = &$shares->getShareById(Horde_Util::getFormData('cid'));
+ } catch (Horde_Share_Exception $e) {
$notification->push(_("Attempt to edit a non-existent share."), 'horde.error');
- } else {
+ }
+
+ if (!empty($share)) {
if (!Horde_Auth::getAuth() ||
(!Horde_Auth::isAdmin() &&
Horde_Auth::getAuth() != $share->get('owner'))) {
// has permissions to do so.
try {
$sourceShare = Kronolith::getInternalCalendar($source);
- if (!($share instanceof PEAR_Error) &&
- $sourceShare->hasPermission(Horde_Auth::getAuth(), Horde_Perms::DELETE) &&
+ if ($sourceShare->hasPermission(Horde_Auth::getAuth(), Horde_Perms::DELETE) &&
(($user == Horde_Auth::getAuth() &&
$share->hasPermission(Horde_Auth::getAuth(), Horde_Perms::EDIT)) ||
($user != Horde_Auth::getAuth() &&
// Remove share and all groups/permissions.
$share = $GLOBALS['kronolith_shares']->getShare($calendarId);
$result = $GLOBALS['kronolith_shares']->removeShare($share);
- if ($result instanceof PEAR_Error) {
- throw new Kronolith_Exception($result);
- }
} catch (Exception $e) {
throw new Kronolith_Exception(sprintf(_("Unable to delete calendar \"%s\": %s"), $calendarId, $e->getMessage()));
}
$tagger->replaceTags($event->uid, $event->tags, $event->creator, 'event');
/* Add tags again, but as the share owner (replaceTags removes ALL tags). */
- $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
- if ($cal instanceof PEAR_Error) {
- throw new Kronolith_Exception($cal);
+ try {
+ $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
+ } catch (Horde_Share_Exception $e) {
+ throw new Kronolith_Exception($e);
}
$tagger->tag($event->uid, $event->tags, $cal->get('owner'), 'event');
/* Add tags again, but as the share owner (replaceTags removes ALL
* tags). */
- $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
- $this->handleError($cal);
+ try {
+ $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
+ } catch (Horde_Share_Exception $e) {
+ Horde::logMessage($e->getMessage(), 'ERR');
+ throw new Kronolith_Exception($e);
+ }
$tagger->tag($event->uid, $event->tags, $cal->get('owner'), 'event');
/* Update Geolocation */
throw new Horde_Exception_PermissionDenied();
}
- $shares = $GLOBALS['kronolith_shares']->listShares($user, Horde_Perms::EDIT);
- $this->handleError($shares);
+ try {
+ $shares = $GLOBALS['kronolith_shares']->listShares($user, Horde_Perms::EDIT);
+ } catch (Horde_Share_Exception $e) {
+ Horde::logMessage($shares, 'ERR');
+ throw new Kronolith_Exception($shares);
+ }
foreach (array_keys($shares) as $calendar) {
$ids = Kronolith::listEventIds(null, null, $calendar);
}
/* Fetch the appropriate share and check permissions. */
- $share = $kronolith_shares->getShare($calendar[0]);
- if ($share instanceof PEAR_Error) {
+ try {
+ $share = $kronolith_shares->getShare($calendar[0]);
+ $owner = $share->get('owner');
+ } catch (Horde_Share_Exception $e) {
// Might be a Kronolith_Resource
try {
$resource = Kronolith_Resource::isResourceCalendar($calendar[0]);
} catch (Horde_Exception $e) {
return $returnObj ? $share : '';
}
- } else {
- $owner = $share->get('owner');
}
/* Default the start date to today. */
$actionID = Horde_Util::getFormData('actionID', 'edit');
switch ($actionID) {
case 'edit':
- $share = $shares->getShareById(Horde_Util::getFormData('cid'));
- if (!($share instanceof PEAR_Error)) {
+ try {
+ $share = $shares->getShareById(Horde_Util::getFormData('cid'));
$perm = $share->getPermission();
- } elseif (($category = Horde_Util::getFormData('share')) !== null) {
- try {
- $share = $shares->getShare($category);
+ } catch (Horde_Share_Exception $e) {
+ if (($category = Horde_Util::getFormData('share')) !== null) {
+ try {
+ $share = $shares->getShare($category);
+ $perm = $share->getPermission();
+ } catch (Exception $e) {
+ $notification->push($e, 'horde.error');
+ }
$perm = $share->getPermission();
- } catch (Exception $e) {
- $notification->push($e, 'horde.error');
}
}
+
if (!Horde_Auth::getAuth() ||
(isset($share) &&
!Horde_Auth::isAdmin() &&
break;
case 'editform':
- $share = $shares->getShareById(Horde_Util::getFormData('cid'));
- if ($share instanceof PEAR_Error) {
- $notification->push(_("Attempt to edit a non-existent share."), 'horde.error');
- } else {
+ try {
+ $share = $shares->getShareById(Horde_Util::getFormData('cid'));
if (!Horde_Auth::getAuth() ||
(!Horde_Auth::isAdmin() &&
Horde_Auth::getAuth() != $share->get('owner'))) {
$notification->push($e, 'horde.error');
}
$perm = $share->getPermission();
+ } catch (Horde_Share_Exception $e) {
+ $notification->push(_("Attempt to edit a non-existent share."), 'horde.error');
}
+
break;
}
-if ($share instanceof PEAR_Error) {
+if (empty($share)) {
$title = _("Edit Permissions");
} else {
$title = sprintf(_("Edit Permissions for %s"), $share->get('name'));
* @package Whups
*/
-/** Horde_Share */
-require_once 'Horde/Share.php';
-
/** Horde_Form_Action */
require_once 'Horde/Form/Action.php';