mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-17 21:43:22 +01:00
1029 lines
34 KiB
PHP
1029 lines
34 KiB
PHP
|
<?php
|
||
|
|
||
|
/** Do not start a session. */
|
||
|
define('HORDE_SESSION_NONE', 1);
|
||
|
|
||
|
/** Do not write changes to session. */
|
||
|
define('HORDE_SESSION_READONLY', 2);
|
||
|
|
||
|
/**
|
||
|
* The Registry:: class provides a set of methods for communication
|
||
|
* between Horde applications and keeping track of application
|
||
|
* configuration information.
|
||
|
*
|
||
|
* $Horde: framework/Horde/Horde/Registry.php,v 1.249 2005/02/14 18:00:59 jan Exp $
|
||
|
*
|
||
|
* Copyright 1999-2005 Chuck Hagenbuch <chuck@horde.org>
|
||
|
* Copyright 1999-2005 Jon Parise <jon@horde.org>
|
||
|
* Copyright 1999-2005 Anil Madhavapeddy <anil@recoil.org>
|
||
|
*
|
||
|
* See the enclosed file COPYING for license information (LGPL). If you
|
||
|
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
|
||
|
*
|
||
|
* @author Chuck Hagenbuch <chuck@horde.org>
|
||
|
* @author Jon Parise <jon@horde.org>
|
||
|
* @author Anil Madhavapeddy <anil@recoil.org>
|
||
|
* @since Horde 1.3
|
||
|
* @package Horde_Framework
|
||
|
*/
|
||
|
class Registry {
|
||
|
|
||
|
/**
|
||
|
* Hash storing all of the known services and callbacks.
|
||
|
*
|
||
|
* @var array $_apiCache
|
||
|
*/
|
||
|
var $_apiCache = array();
|
||
|
|
||
|
/**
|
||
|
* Hash storing all known data types.
|
||
|
*
|
||
|
* @var array $_typeCache
|
||
|
*/
|
||
|
var $_typeCache = array();
|
||
|
|
||
|
/**
|
||
|
* Hash storing all of the registered interfaces that applications
|
||
|
* provide.
|
||
|
*
|
||
|
* @var array $_interfaces
|
||
|
*/
|
||
|
var $_interfaces = array();
|
||
|
|
||
|
/**
|
||
|
* Hash storing information on each registry-aware application.
|
||
|
*
|
||
|
* @var array $applications
|
||
|
*/
|
||
|
var $applications = array();
|
||
|
|
||
|
/**
|
||
|
* Stack of in-use applications.
|
||
|
*
|
||
|
* @var array $_appStack
|
||
|
*/
|
||
|
var $_appStack = array();
|
||
|
|
||
|
/**
|
||
|
* Quick pointer to the current application.
|
||
|
*
|
||
|
* @var $_currentApp
|
||
|
*/
|
||
|
var $_currentApp = null;
|
||
|
|
||
|
/**
|
||
|
* Cache of $prefs objects
|
||
|
*
|
||
|
* @var array $_prefsCache
|
||
|
*/
|
||
|
var $_prefsCache = array();
|
||
|
|
||
|
/**
|
||
|
* Cache of application configurations.
|
||
|
*
|
||
|
* @var array $_confCache
|
||
|
*/
|
||
|
var $_confCache = array();
|
||
|
|
||
|
/**
|
||
|
* Returns a reference to the global Registry object, only
|
||
|
* creating it if it doesn't already exist.
|
||
|
*
|
||
|
* This method must be invoked as: $registry = &Registry::singleton()
|
||
|
*
|
||
|
* @param optional integer $session_flags Any session flags.
|
||
|
*
|
||
|
* @return object Registry The Horde Registry instance.
|
||
|
*/
|
||
|
function &singleton($session_flags = 0)
|
||
|
{
|
||
|
static $registry;
|
||
|
|
||
|
if (!isset($registry)) {
|
||
|
$registry = new Registry($session_flags);
|
||
|
}
|
||
|
|
||
|
return $registry;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a new registry instance. Should never be called except
|
||
|
* by &Registry::singleton().
|
||
|
*
|
||
|
* @param optional integer $session_flags Any session flags.
|
||
|
*
|
||
|
* @access private
|
||
|
*/
|
||
|
function Registry($session_flags = 0)
|
||
|
{
|
||
|
/* Import and global Horde's configuration values. */
|
||
|
$this->importConfig('horde');
|
||
|
|
||
|
/* Start a session. */
|
||
|
if ($session_flags & HORDE_SESSION_NONE) {
|
||
|
/* Never start a session if the session flags include
|
||
|
HORDE_SESSION_NONE. */
|
||
|
$_SESSION = array();
|
||
|
} else {
|
||
|
Horde::setupSessionHandler();
|
||
|
@session_start();
|
||
|
if ($session_flags & HORDE_SESSION_READONLY) {
|
||
|
/* Close the session immediately so no changes can be
|
||
|
made but values are still available. */
|
||
|
@session_write_close();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Read the registry configuration file. */
|
||
|
require_once HORDE_BASE . '/config/registry.php';
|
||
|
|
||
|
/* Initialize the localization routines and variables. */
|
||
|
# NLS::setLang();
|
||
|
# NLS::setTextdomain('horde', HORDE_BASE . '/locale', NLS::getCharset());
|
||
|
# String::setDefaultCharset(NLS::getCharset());
|
||
|
|
||
|
/* Stop system if Horde is inactive. */
|
||
|
if ($this->applications['horde']['status'] == 'inactive') {
|
||
|
Horde::fatal(_("This system is currently deactivated."), __FILE__, __LINE__);
|
||
|
}
|
||
|
|
||
|
/* Scan for all APIs provided by each app, and set other
|
||
|
* common defaults like templates and graphics. */
|
||
|
$appList = array_keys($this->applications);
|
||
|
foreach ($appList as $appName) {
|
||
|
$app = &$this->applications[$appName];
|
||
|
if (($app['status'] == 'heading') ||
|
||
|
($app['status'] == 'inactive') ||
|
||
|
($app['status'] == 'admin' && !Auth::isAdmin())) {
|
||
|
continue;
|
||
|
}
|
||
|
if (isset($app['provides'])) {
|
||
|
if (is_array($app['provides'])) {
|
||
|
foreach ($app['provides'] as $interface) {
|
||
|
$this->_interfaces[$interface] = $appName;
|
||
|
}
|
||
|
} else {
|
||
|
$this->_interfaces[$app['provides']] = $appName;
|
||
|
}
|
||
|
}
|
||
|
if (!isset($app['templates']) && isset($app['fileroot'])) {
|
||
|
$app['templates'] = $app['fileroot'] . '/templates';
|
||
|
}
|
||
|
if (!isset($app['jsuri']) && isset($app['webroot'])) {
|
||
|
$app['jsuri'] = $app['webroot'] . '/js';
|
||
|
}
|
||
|
if (!isset($app['jsfs']) && isset($app['fileroot'])) {
|
||
|
$app['jsfs'] = $app['fileroot'] . '/js';
|
||
|
}
|
||
|
if (!isset($app['themesuri']) && isset($app['webroot'])) {
|
||
|
$app['themesuri'] = $app['webroot'] . '/themes';
|
||
|
}
|
||
|
if (!isset($app['themesfs']) && isset($app['fileroot'])) {
|
||
|
$app['themesfs'] = $app['fileroot'] . '/themes';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# /* Create the global Perms object. */
|
||
|
# $GLOBALS['perms'] = &Perms::singleton();
|
||
|
|
||
|
# /* Attach javascript notification listener. */
|
||
|
# $notification = &Notification::singleton();
|
||
|
# $notification->attach('javascript');
|
||
|
|
||
|
/* Register access key logger for translators. */
|
||
|
if (@$GLOBALS['conf']['log_accesskeys']) {
|
||
|
register_shutdown_function(create_function('', 'Horde::getAccessKey(null, null, true);'));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a list of the installed and registered applications.
|
||
|
*
|
||
|
* @since Horde 2.2
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param array $filter (optional) An array of the statuses that
|
||
|
* should be returned. Defaults to non-hidden.
|
||
|
* @param boolean $assoc (optional) Associative array with app names
|
||
|
* as keys.
|
||
|
* @param integer $permission (optional) The permission level to check
|
||
|
* for in the list. Defaults to PERMS_SHOW.
|
||
|
*
|
||
|
* @return array List of apps registered with Horde. If no
|
||
|
* applications are defined returns an empty array.
|
||
|
*/
|
||
|
function listApps($filter = null, $assoc = false, $permission = PERMS_SHOW)
|
||
|
{
|
||
|
$apps = array();
|
||
|
if (is_null($filter)) {
|
||
|
$filter = array('notoolbar', 'active');
|
||
|
}
|
||
|
|
||
|
foreach ($this->applications as $app => $params) {
|
||
|
if (in_array($params['status'], $filter) &&
|
||
|
(defined('AUTH_HANDLER') || $this->hasPermission($app, $permission))) {
|
||
|
$assoc ? $apps[$app] = $app : $apps[] = $app;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $apps;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns all available registry APIs.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @return array The API list.
|
||
|
*/
|
||
|
function listAPIs()
|
||
|
{
|
||
|
$apis = array();
|
||
|
|
||
|
foreach (array_keys($this->_interfaces) as $interface) {
|
||
|
@list($api, ) = explode('/', $interface);
|
||
|
$apis[] = $api;
|
||
|
}
|
||
|
|
||
|
return array_unique($apis);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns all of the available registry methods, or alternately
|
||
|
* only those for a specified API.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param optional string $api Defines the API for which the methods
|
||
|
* shall be returned.
|
||
|
*
|
||
|
* @return array The method list.
|
||
|
*/
|
||
|
function listMethods($api = null)
|
||
|
{
|
||
|
$methods = array();
|
||
|
|
||
|
$this->_fillAPICache();
|
||
|
|
||
|
foreach (array_keys($this->applications) as $app) {
|
||
|
if (isset($this->applications[$app]['provides'])) {
|
||
|
$provides = $this->applications[$app]['provides'];
|
||
|
if (!is_array($provides)) {
|
||
|
$provides = array($provides);
|
||
|
}
|
||
|
} else {
|
||
|
$provides = array();
|
||
|
}
|
||
|
|
||
|
foreach ($provides as $method) {
|
||
|
if (strpos($method, '/') !== false) {
|
||
|
if (is_null($api) ||
|
||
|
(substr($method, 0, strlen($api)) == $api)) {
|
||
|
$methods[] = $method;
|
||
|
}
|
||
|
} elseif (is_null($api) || ($method == $api)) {
|
||
|
if (isset($this->_apiCache[$app])) {
|
||
|
foreach (array_keys($this->_apiCache[$app]) as $service) {
|
||
|
$methods[] = $method . '/' . $service;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return array_unique($methods);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns all of the available registry data types.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @return array The data type list.
|
||
|
*/
|
||
|
function listTypes()
|
||
|
{
|
||
|
$this->_fillAPICache();
|
||
|
return $this->_typeCache;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a method's signature.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $method The full name of the method to check for.
|
||
|
*
|
||
|
* @return array A two dimensional array. The first element contains an
|
||
|
* array with the parameter names, the second one the return
|
||
|
* type.
|
||
|
*/
|
||
|
function getSignature($method)
|
||
|
{
|
||
|
if (!($app = $this->hasMethod($method))) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$this->_fillAPICache();
|
||
|
|
||
|
@list(, $function) = explode('/', $method);
|
||
|
if (isset($this->_apiCache[$app][$function]['type']) &&
|
||
|
isset($this->_apiCache[$app][$function]['args'])) {
|
||
|
return array($this->_apiCache[$app][$function]['args'], $this->_apiCache[$app][$function]['type']);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if an interface is implemented by an active
|
||
|
* application.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $interface The interface to check for.
|
||
|
*
|
||
|
* @return mixed The application implementing $interface if we have it,
|
||
|
* false if the interface is not implemented.
|
||
|
*/
|
||
|
function hasInterface($interface)
|
||
|
{
|
||
|
return !empty($this->_interfaces[$interface]) ?
|
||
|
$this->_interfaces[$interface] :
|
||
|
false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Determine if a method has been registered with the registry.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $method The full name of the method to check for.
|
||
|
* @param string $app (optional) Only check this application.
|
||
|
*
|
||
|
* @return mixed The application implementing $method if we have it,
|
||
|
* false if the method doesn't exist.
|
||
|
*/
|
||
|
function hasMethod($method, $app = null)
|
||
|
{
|
||
|
if (is_null($app)) {
|
||
|
@list($interface, $call) = explode('/', $method);
|
||
|
if (!empty($this->_interfaces[$method])) {
|
||
|
$app = $this->_interfaces[$method];
|
||
|
} elseif (!empty($this->_interfaces[$interface])) {
|
||
|
$app = $this->_interfaces[$interface];
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
$call = $method;
|
||
|
}
|
||
|
|
||
|
$this->_fillAPICache();
|
||
|
|
||
|
return !empty($this->_apiCache[$app][$call]) ? $app : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the hook corresponding to the default package that
|
||
|
* provides the functionality requested by the $method
|
||
|
* parameter. $method is a string consisting of
|
||
|
* "packagetype/methodname".
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $method The method to call.
|
||
|
* @param optional array $args Arguments to the method.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function call($method, $args = array())
|
||
|
{
|
||
|
@list($interface, $call) = explode('/', $method);
|
||
|
|
||
|
if (!empty($this->_interfaces[$method])) {
|
||
|
$app = $this->_interfaces[$method];
|
||
|
} elseif (!empty($this->_interfaces[$interface])) {
|
||
|
$app = $this->_interfaces[$interface];
|
||
|
} else {
|
||
|
return PEAR::raiseError('The method "' . $method . '" is not defined in the Horde Registry.');
|
||
|
}
|
||
|
|
||
|
return $this->callByPackage($app, $call, $args);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Output the hook corresponding to the specific package named.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app The application being called.
|
||
|
* @param string $call The method to call.
|
||
|
* @param optional array $args Arguments to the method.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function callByPackage($app, $call, $args = array())
|
||
|
{
|
||
|
/* Note: calling hasMethod() makes sure that we've cached
|
||
|
* $app's services and included the API file, so we don't try
|
||
|
* to do it again explicitly in this method. */
|
||
|
if (!$this->hasMethod($call, $app)) {
|
||
|
return PEAR::raiseError(sprintf('The method "%s" is not defined in the API for %s.', $call, $app));
|
||
|
}
|
||
|
|
||
|
/* Make sure that the function actually exists. */
|
||
|
$function = '_' . $app . '_' . $call;
|
||
|
if (!function_exists($function)) {
|
||
|
return PEAR::raiseError('The function implementing ' . $call . ' (' . $function . ') is not defined in ' . $app . '\'s API.');
|
||
|
}
|
||
|
|
||
|
$checkPerms = isset($this->_apiCache[$app][$call]['checkperms']) ?
|
||
|
$this->_apiCache[$app][$call]['checkperms'] : true;
|
||
|
|
||
|
/* Switch application contexts now, if necessary, before
|
||
|
* including any files which might do it for us. Return an
|
||
|
* error immediately if pushApp() fails. */
|
||
|
$pushed = $this->pushApp($app, $checkPerms);
|
||
|
if (is_a($pushed, 'PEAR_Error')) {
|
||
|
return $pushed;
|
||
|
}
|
||
|
|
||
|
$res = call_user_func_array($function, $args);
|
||
|
|
||
|
/* If we changed application context in the course of this
|
||
|
* call, undo that change now. */
|
||
|
if ($pushed === true) {
|
||
|
$this->popApp();
|
||
|
}
|
||
|
|
||
|
return $res;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the hook corresponding to the default package that
|
||
|
* provides the functionality requested by the $method
|
||
|
* parameter. $method is a string consisting of
|
||
|
* "packagetype/methodname".
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $method The method to link to.
|
||
|
* @param optional array $args Arguments to the method.
|
||
|
* @param optional mixed $extra Extra, non-standard arguments to the
|
||
|
* method.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function link($method, $args = array(), $extra = '')
|
||
|
{
|
||
|
@list($interface, $call) = explode('/', $method);
|
||
|
|
||
|
if (!empty($this->_interfaces[$method])) {
|
||
|
$app = $this->_interfaces[$method];
|
||
|
} elseif (!empty($this->_interfaces[$interface])) {
|
||
|
$app = $this->_interfaces[$interface];
|
||
|
} else {
|
||
|
return PEAR::raiseError('The method "' . $method . '" is not defined in the Horde Registry.');
|
||
|
}
|
||
|
|
||
|
return $this->linkByPackage($app, $call, $args, $extra);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Output the hook corresponding to the specific package named.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app The application being called.
|
||
|
* @param string $call The method to link to.
|
||
|
* @param optional array $args Arguments to the method.
|
||
|
* @param optional mixed $extra Extra, non-standard arguments to the
|
||
|
* method.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function linkByPackage($app, $call, $args = array(), $extra = '')
|
||
|
{
|
||
|
/* Note: calling hasMethod makes sure that we've cached $app's
|
||
|
* services and included the API file, so we don't try to do
|
||
|
* it it again explicitly in this method. */
|
||
|
if (!$this->hasMethod($call, $app)) {
|
||
|
return PEAR::raiseError('The method "' . $call . '" is not defined in ' . $app . '\'s API.');
|
||
|
}
|
||
|
|
||
|
/* Make sure the link is defined. */
|
||
|
if (empty($this->_apiCache[$app][$call]['link'])) {
|
||
|
return PEAR::raiseError('The link ' . $call . ' is not defined in ' . $app . '\'s API.');
|
||
|
}
|
||
|
|
||
|
/* Initial link value. */
|
||
|
$link = $this->_apiCache[$app][$call]['link'];
|
||
|
|
||
|
/* Fill in html-encoded arguments. */
|
||
|
foreach ($args as $key => $val) {
|
||
|
$link = str_replace('%' . $key . '%', htmlentities($val), $link);
|
||
|
}
|
||
|
if (isset($this->applications[$app]['webroot'])) {
|
||
|
$link = str_replace('%application%', $this->get('webroot', $app), $link);
|
||
|
}
|
||
|
|
||
|
/* Replace htmlencoded arguments that haven't been specified with
|
||
|
an empty string (this is where the default would be substituted
|
||
|
in a stricter registry implementation). */
|
||
|
$link = preg_replace('|%.+%|U', '', $link);
|
||
|
|
||
|
/* Fill in urlencoded arguments. */
|
||
|
foreach ($args as $key => $val) {
|
||
|
$link = str_replace('|' . String::lower($key) . '|', urlencode($val), $link);
|
||
|
}
|
||
|
|
||
|
/* Append any extra, non-standard arguments. */
|
||
|
if (is_array($extra)) {
|
||
|
$extra_args = '';
|
||
|
foreach ($extra as $key => $val) {
|
||
|
$extra_args .- '&' . urlencode($key) . '=' . urlencode($val);
|
||
|
}
|
||
|
} else {
|
||
|
$extra_args = $extra;
|
||
|
}
|
||
|
$link = str_replace('|extra|', $extra_args, $link);
|
||
|
|
||
|
/* Replace html-encoded arguments that haven't been specified with
|
||
|
an empty string (this is where the default would be substituted
|
||
|
in a stricter registry implementation). */
|
||
|
$link = preg_replace('|\|.+\||U', '', $link);
|
||
|
|
||
|
return $link;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replace any %application% strings with the filesystem path to
|
||
|
* the application.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $path The application string.
|
||
|
* @param optional string $app The application being called.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function applicationFilePath($path, $app = null)
|
||
|
{
|
||
|
if (is_null($app)) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
if (!isset($this->applications[$app])) {
|
||
|
return PEAR::raiseError(sprintf(_("'%s' is not configured in the Horde Registry."), $app));
|
||
|
}
|
||
|
|
||
|
return str_replace('%application%', $this->applications[$app]['fileroot'], $path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Replace any %application% strings with the web path to the
|
||
|
* application.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $path The application string.
|
||
|
* @param optional string $app The application being called.
|
||
|
*
|
||
|
* @return TODO
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function applicationWebPath($path, $app = null)
|
||
|
{
|
||
|
if (!isset($app)) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
return str_replace('%application%', $this->applications[$app]['webroot'], $path);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the current application, adding it to the top of the Horde
|
||
|
* application stack. If this is the first application to be
|
||
|
* pushed, retrieve session information as well.
|
||
|
*
|
||
|
* pushApp() also reads the application's configuration file and
|
||
|
* sets up its global $conf hash.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app The name of the application to push.
|
||
|
* @param boolean $checkPerms (optional) Make sure that the current user
|
||
|
* has permissions to the application being
|
||
|
* loaded. Defaults to true. Should ONLY
|
||
|
* be disabled by system scripts (cron jobs,
|
||
|
* etc.) and scripts that handle login.
|
||
|
*
|
||
|
* @return boolean Whether or not the _appStack was modified.
|
||
|
* Return PEAR_Error on error.
|
||
|
*/
|
||
|
function pushApp($app, $checkPerms = true)
|
||
|
{
|
||
|
if ($app == $this->_currentApp) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* Bail out if application is not present or inactive. */
|
||
|
if (!isset($this->applications[$app]) ||
|
||
|
$this->applications[$app]['status'] == 'inactive' ||
|
||
|
($this->applications[$app]['status'] == 'admin' && !Auth::isAdmin())) {
|
||
|
Horde::fatal($app . ' is not activated', __FILE__, __LINE__);
|
||
|
}
|
||
|
|
||
|
/* If permissions checking is requested, return an error if
|
||
|
* the current user does not have read perms to the
|
||
|
* application being loaded. We allow access:
|
||
|
*
|
||
|
* - To all admins.
|
||
|
* - To all authenticated users if no permission is set on $app.
|
||
|
* - To anyone who is allowed by an explicit ACL on $app. */
|
||
|
if ($checkPerms && !$this->hasPermission($app)) {
|
||
|
Horde::logMessage(sprintf('User %s does not have READ permission for %s', Auth::getAuth(), $app), __FILE__, __LINE__, PEAR_LOG_DEBUG);
|
||
|
return PEAR::raiseError(sprintf(_("User %s is not authorised for %s."), Auth::getAuth(), $this->applications[$app]['name']), 'permission_denied');
|
||
|
}
|
||
|
|
||
|
/* Import this application's configuration values. */
|
||
|
$success = $this->importConfig($app);
|
||
|
if (is_a($success, 'PEAR_Error')) {
|
||
|
return $success;
|
||
|
}
|
||
|
|
||
|
/* Load preferences after the configuration has been loaded to
|
||
|
* make sure the prefs file has all the information it needs. */
|
||
|
$this->loadPrefs($app);
|
||
|
|
||
|
/* Reset the language in case there is a different one
|
||
|
* selected in the preferences. */
|
||
|
$language = '';
|
||
|
if (isset($this->_prefsCache[$app]) &&
|
||
|
isset($this->_prefsCache[$app]->_prefs['language'])) {
|
||
|
$language = $this->_prefsCache[$app]->getValue('language');
|
||
|
}
|
||
|
NLS::setLang($language);
|
||
|
NLS::setTextdomain($app, $this->applications[$app]['fileroot'] . '/locale', NLS::getCharset());
|
||
|
String::setDefaultCharset(NLS::getCharset());
|
||
|
|
||
|
/* Once we know everything succeeded and is in a consistent
|
||
|
* state again, push the new application onto the stack. */
|
||
|
array_push($this->_appStack, $app);
|
||
|
$this->_currentApp = $app;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove the current app from the application stack, setting the
|
||
|
* current app to whichever app was current before this one took
|
||
|
* over.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @return string The name of the application that was popped.
|
||
|
*/
|
||
|
function popApp()
|
||
|
{
|
||
|
/* Pop the current application off of the stack. */
|
||
|
$previous = array_pop($this->_appStack);
|
||
|
|
||
|
/* Import the new active application's configuration values
|
||
|
* and set the gettext domain and the preferred language. */
|
||
|
$this->_currentApp = count($this->_appStack) ? end($this->_appStack) : null;
|
||
|
if ($this->_currentApp) {
|
||
|
$this->importConfig($this->_currentApp);
|
||
|
$this->loadPrefs($this->_currentApp);
|
||
|
#$language = $GLOBALS['prefs']->getValue('language');
|
||
|
#if (isset($language)) {
|
||
|
# NLS::setLang($language);
|
||
|
#}
|
||
|
NLS::setTextdomain($this->_currentApp, $this->applications[$this->_currentApp]['fileroot'] . '/locale', NLS::getCharset());
|
||
|
String::setDefaultCharset(NLS::getCharset());
|
||
|
}
|
||
|
|
||
|
return $previous;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the current application - the app at the top of the
|
||
|
* application stack.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @return string The current application.
|
||
|
*/
|
||
|
function getApp()
|
||
|
{
|
||
|
return $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check permissions on an application.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @return boolean Whether or not access is allowed.
|
||
|
*/
|
||
|
function hasPermission($app, $permission = PERMS_READ)
|
||
|
{
|
||
|
return true;
|
||
|
#return Auth::isAdmin() || ($GLOBALS['perms']->exists($app) ?
|
||
|
# $GLOBALS['perms']->hasPermission($app, Auth::getAuth(), $permission) :
|
||
|
# (bool)Auth::getAuth());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads the configuration values for the given application and
|
||
|
* imports them into the global $conf variable.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app The name of the application.
|
||
|
*
|
||
|
* @return boolean True on success, PEAR_Error on error.
|
||
|
*/
|
||
|
function importConfig($app)
|
||
|
{
|
||
|
/* Don't make config files global $registry themselves. */
|
||
|
global $registry;
|
||
|
|
||
|
/* Cache config values so that we don't re-read files on every
|
||
|
* popApp() call. */
|
||
|
if (!isset($this->_confCache[$app])) {
|
||
|
if (!isset($this->_confCache['horde'])) {
|
||
|
$conf = array();
|
||
|
ob_start();
|
||
|
$success = include HORDE_BASE . '/config/conf.php';
|
||
|
$errors = ob_get_contents();
|
||
|
ob_end_clean();
|
||
|
if (!empty($errors)) {
|
||
|
return PEAR::raiseError(sprintf('Failed to import Horde configuration: %s', strip_tags($errors)));
|
||
|
}
|
||
|
if (!$success) {
|
||
|
return PEAR::raiseError('Failed to import Horde configuration.');
|
||
|
}
|
||
|
|
||
|
/* Initial Horde-wide settings. */
|
||
|
|
||
|
/* Set the error reporting level in accordance with
|
||
|
* the config settings. */
|
||
|
error_reporting($conf['debug_level']);
|
||
|
|
||
|
/* Set the maximum execution time in accordance with
|
||
|
* the config settings. */
|
||
|
@set_time_limit($conf['max_exec_time']);
|
||
|
|
||
|
/* Set the umask according to config settings. */
|
||
|
if (isset($conf['umask'])) {
|
||
|
umask($conf['umask']);
|
||
|
}
|
||
|
} else {
|
||
|
$conf = $this->_confCache['horde'];
|
||
|
}
|
||
|
|
||
|
if ($app !== 'horde') {
|
||
|
$success = @include $this->applications[$app]['fileroot'] . '/config/conf.php';
|
||
|
if (!$success) {
|
||
|
return PEAR::raiseError('Failed to import application configuration for ' . $app);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$this->_confCache[$app] = &$conf;
|
||
|
}
|
||
|
|
||
|
$GLOBALS['conf'] = &$this->_confCache[$app];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Loads the preferences for the current user for the current
|
||
|
* application and imports them into the global $prefs variable.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app The name of the application.
|
||
|
*/
|
||
|
function loadPrefs($app = null)
|
||
|
{
|
||
|
return array();
|
||
|
|
||
|
static $prefs_default = false;
|
||
|
|
||
|
require_once 'Horde/Prefs.php';
|
||
|
|
||
|
if ($app === null) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
/* If there is no logged in user, return an empty Prefs::
|
||
|
* object with just default preferences. */
|
||
|
# if (!Auth::getAuth()) {
|
||
|
# $prefs = &Prefs::factory('none', $app, '', '', null, false);
|
||
|
# $prefs->retrieve();
|
||
|
# $this->_prefsCache[$app] = &$prefs;
|
||
|
# $GLOBALS['prefs'] = &$this->_prefsCache[$app];
|
||
|
# $prefs_default = true;
|
||
|
# return;
|
||
|
# }
|
||
|
|
||
|
/* Cache prefs objects so that we don't re-load them on every
|
||
|
* popApp() call. */
|
||
|
# if (!isset($this->_prefsCache[$app]) ||
|
||
|
# !empty($prefs_default)) {
|
||
|
# $prefs = &Prefs::factory($GLOBALS['conf']['prefs']['driver'], $app,
|
||
|
# Auth::getAuth(), Auth::getCredential('password'));
|
||
|
# $prefs->retrieve();
|
||
|
# $this->_prefsCache[$app] = &$prefs;
|
||
|
# }
|
||
|
|
||
|
$GLOBALS['prefs'] = &$this->_prefsCache[$app];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unload preferences from an application or (if no application is
|
||
|
* specified) from ALL applications. Useful when a user has logged
|
||
|
* out but you need to continue on the same page, etc.
|
||
|
*
|
||
|
* After unloading, if there is an application on the app stack to
|
||
|
* load preferences from, then we reload a fresh set.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $app (optional) The application to unload prefrences for.
|
||
|
* If null, ALL preferences are reset.
|
||
|
*/
|
||
|
function unloadPrefs($app = null)
|
||
|
{
|
||
|
if ($app === null) {
|
||
|
$this->_prefsCache = array();
|
||
|
} elseif (isset($this->_prefsCache[$app])) {
|
||
|
unset($this->_prefsCache[$app]);
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ($this->_currentApp) {
|
||
|
$this->loadPrefs();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the requested configuration parameter for the specified
|
||
|
* application. If no application is specified, the value of
|
||
|
* $this->_currentApp (the current application) is used. However,
|
||
|
* if the parameter is not present for that application, the
|
||
|
* Horde-wide value is used instead. If that is not present, we
|
||
|
* return null.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param string $parameter The configuration value to retrieve.
|
||
|
* @param optional string $app The application to get the value for.
|
||
|
*
|
||
|
* @return string The requested parameter, or null if it is not set.
|
||
|
*/
|
||
|
function get($parameter, $app = null)
|
||
|
{
|
||
|
if (is_null($app)) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
if (isset($this->applications[$app][$parameter])) {
|
||
|
$pval = $this->applications[$app][$parameter];
|
||
|
} else {
|
||
|
if ($parameter == 'icon') {
|
||
|
$pval = $this->_getIcon($app);
|
||
|
} else {
|
||
|
$pval = isset($this->applications['horde'][$parameter]) ? $this->applications['horde'][$parameter] : null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($parameter == 'name') {
|
||
|
return _($pval);
|
||
|
} else {
|
||
|
return $pval;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function to work out an application's graphics URI, taking into
|
||
|
* account any themes directories that may be set up.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param optional string $app The application for which to get the
|
||
|
* image directory. If blank will default
|
||
|
* to current application.
|
||
|
*
|
||
|
* @return string The image directory uri path.
|
||
|
*/
|
||
|
function getImageDir($app = null)
|
||
|
{
|
||
|
if (empty($app)) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
static $img_dir = array();
|
||
|
if (isset($img_dir[$app])) {
|
||
|
return $img_dir[$app];
|
||
|
}
|
||
|
|
||
|
/* This is the default location for the graphics. */
|
||
|
$img_dir[$app] = $this->get('themesuri', $app) . '/graphics';
|
||
|
|
||
|
/* Figure out if this is going to be overridden by any theme
|
||
|
* settings. */
|
||
|
if (isset($GLOBALS['prefs']) && ($theme = $GLOBALS['prefs']->getValue('theme')) &&
|
||
|
(@include $this->get('themesfs', 'horde') . '/' . $theme . '/info.php') &&
|
||
|
isset($theme_icons) &&
|
||
|
in_array($app, $theme_icons)) {
|
||
|
$img_dir[$app] = $this->get('themesuri', $app) . '/' . $theme . '/graphics';
|
||
|
}
|
||
|
|
||
|
return $img_dir[$app];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the path to an application's icon, respecting whether the
|
||
|
* current theme has its own icons.
|
||
|
*
|
||
|
* @access private
|
||
|
*
|
||
|
* @param string $app The application for which to get the icon.
|
||
|
*/
|
||
|
function _getIcon($app)
|
||
|
{
|
||
|
return $this->getImageDir($app) . '/' . $app . '.png';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Query the initial page for an application - the webroot, if
|
||
|
* there is no initial_page set, and the initial_page, if it is
|
||
|
* set.
|
||
|
*
|
||
|
* @access public
|
||
|
*
|
||
|
* @param optional string $app The name of the application.
|
||
|
*
|
||
|
* @return string URL pointing to the inital page of the application.
|
||
|
* Returns PEAR_Error on error.
|
||
|
*/
|
||
|
function getInitialPage($app = null)
|
||
|
{
|
||
|
if (is_null($app)) {
|
||
|
$app = $this->_currentApp;
|
||
|
}
|
||
|
|
||
|
if (!isset($this->applications[$app])) {
|
||
|
return PEAR::raiseError(sprintf(_("'%s' is not configured in the Horde Registry."), $app));
|
||
|
}
|
||
|
return $this->applications[$app]['webroot'] . '/' . (isset($this->applications[$app]['initial_page']) ? $this->applications[$app]['initial_page'] : '');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Fills the registry's API cache with the available services.
|
||
|
*
|
||
|
* @access private
|
||
|
*/
|
||
|
function _fillAPICache()
|
||
|
{
|
||
|
if (!empty($this->_apiCache)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$status = array('active', 'notoolbar', 'hidden');
|
||
|
# if (Auth::isAdmin()) {
|
||
|
# $status[] = 'admin';
|
||
|
# }
|
||
|
$apps = $this->listApps($status);
|
||
|
foreach ($apps as $app) {
|
||
|
$_services = $_types = null;
|
||
|
$api = $this->get('fileroot', $app) . '/lib/api.php';
|
||
|
if (is_readable($api)) {
|
||
|
include_once $api;
|
||
|
}
|
||
|
if (!isset($_services)) {
|
||
|
$this->_apiCache[$app] = array();
|
||
|
} else {
|
||
|
$this->_apiCache[$app] = $_services;
|
||
|
}
|
||
|
if (isset($_types)) {
|
||
|
foreach ($_types as $type => $params) {
|
||
|
/* Prefix non-Horde types with the application
|
||
|
* name. */
|
||
|
$prefix = $app == 'horde' ? '' : "${app}_";
|
||
|
$this->_typeCache[$prefix . $type] = $params;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|