<?xml version="1.0"?>
<!-- $Id$ -->
<configuration>
+ <configtab name="storage" desc="Storage">
+ <configsection name="storage">
+ <configheader>Context Storage</configheader>
+ <configswitch name="driver" desc="What backend should we use for storing the list of valid contexts/customers?">Sql
+ <case name="Sql" desc="SQL">
+ <configsection name="params">
+ <configsql switchname="driverconfig" />
+ <configstring name="table" desc="Table to hold the list of contexts/customers" required="true">contexts</configstring>
+ </configsection>
+ </case>
+ </configswitch>
+ </configsection>
+ </configtab>
<configtab name="extensions" desc="Extensions">
<configsection name="extensions">
<configheader>Extension Storage</configheader>
- <configswitch name="driver" desc="What backend should we use for storing Asterisk phone user configuration?">ldap
- <case name="ldap" desc="LDAP">
+ <configswitch name="driver" desc="What backend should we use for storing Asterisk phone user configuration?">Ldap
+ <case name="Ldap" desc="LDAP">
<configsection name="params">
- <configldap switchname="driver" />
+ <configldap switchname="driverconfig" />
</configsection>
</case>
- <case name="sql" desc="SQL">
+ <case name="Sql" desc="SQL">
<configsection name="params">
- <configsql switchname="driver" />
+ <configsql switchname="driverconfig" />
+ <configstring name="table" desc="Table to hold the list of extensions" required="true"></configstring>
</configsection>
</case>
</configswitch>
<configtab name="devices" desc="VoIP Devices">
<configsection name="devices">
<configheader>Device Storage</configheader>
- <configswitch name="driver" desc="What backend should we use for storing Asterisk phone user configuration?">ldap
- <case name="ldap" desc="LDAP">
+ <configswitch name="driver" desc="What backend should we use for storing Asterisk phone user configuration?">Ldap
+ <case name="Ldap" desc="LDAP">
<configsection name="params">
- <configldap switchname="driver" />
+ <configldap switchname="driverconfig" />
</configsection>
</case>
- <case name="sql" desc="SQL">
+ <case name="Sql" desc="SQL">
<configsection name="params">
- <configsql switchname="driver" />
+ <configsql switchname="driverconfig" />
+ <configstring name="table" desc="Table to hold the device configuration data" required="true">sip_peers</configstring>
</configsection>
</case>
</configswitch>
+++ /dev/null
-<?php
-/**
- * $Id$
- *
- * Copyright 2005 Ben Klang <ben@alkaloid.net>
- *
- * See the enclosed file LICENSE for license information (GPL). If you
- * did not receive this file, see http://www.horde.org/licenses/gpl.php.
- */
-@define('SHOUT_BASE', dirname(__FILE__) . '/..');
-
-require SHOUT_BASE . '/users/edit.php';
\ No newline at end of file
+++ /dev/null
-<?php
-/**
- * $Id$
- *
- * Copyright 2005-2006 Ben Klang <ben@alkaloid.net>
- *
- * See the enclosed file LICENSE for license information (GPL). If you
- * did not receive this file, see http://www.horde.org/licenses/gpl.php.
- *
- * @package shout
- */
-@define('SHOUT_BASE', dirname(__FILE__) . '/..');
-//require_once 'Horde/Variables.php';
-
-$context = Horde_Util::getFormData('context');
-$extension = Horde_Util::getFormData('extension');
-
-$res = $shout->deleteUser($context, $extension);
-
-if (!$res) {
- echo "Failed!";
- print_r($res);
-}
-$notification->push("User Deleted.");
-$notification->notify();
-require SHOUT_TEMPLATES . '/common-footer.inc';
\ No newline at end of file
+++ /dev/null
-<?php
-/**
- * $Id$
- *
- * Copyright 2005-2006 Ben Klang <ben@alkaloid.net>
- *
- * See the enclosed file LICENSE for license information (GPL). If you
- * did not receive this file, see http://www.horde.org/licenses/gpl.php.
- *
- * @package shout
- */
-if (!isset($SHOUT_RUNNING) || !$SHOUT_RUNNING) {
- header('Location: /');
- exit();
-}
-
-require_once SHOUT_BASE . '/lib/User.php';
-require_once 'Horde/Variables.php';
-
-$RENDERER = &new Horde_Form_Renderer();
-
-$empty = '';
-$beendone = 0;
-$wereerrors = 0;
-
-$vars = &Variables::getDefaultVariables($empty);
-
-$FormName = 'UserDetailsForm';
-$Form = &Horde_Form::singleton($FormName, $vars);
-if (is_a($Form, 'PEAR_Error')) {
- $notification->push($Form);
-} else {
- $FormValid = $Form->validate($vars, true);
- if (is_a($FormValid, 'PEAR_Error')) {
- $notification->push($FormValid);
- } else {
- $Form->fillUserForm(&$vars, $extension);
- }
-}
-
-
-$notification->notify();
-
-if (!$FormValid || !$Form->isSubmitted()) {
- # Display the form for editing
- $Form->open($RENDERER, $vars, 'index.php', 'post');
- $Form->preserveVarByPost(&$vars, 'extension');
- $Form->preserveVarByPost(&$vars, 'context');
- $Form->preserveVarByPost(&$vars, 'section');
- $RENDERER->beginActive($Form->getTitle());
- $RENDERER->renderFormActive($Form, $vars);
- $RENDERER->submit();
- $RENDERER->end();
- $Form->close($RENDERER);
-} else {
- # Process the Valid and Submitted form
-$notification->push("How did we get HERE?!", 'horde.error');
-$notification->notify();
-// $info = array();
-// $Form->getInfo($vars, $info);
-//
-// $name = $info['name'];
-// $extension = $info['extension'];
-// $newextension = $info['newextension'];
-// $email = $info['email'];
-// $pin = $info['pin'];
-//
-//
-// $limits = $shout->getLimits($context, $extension);
-//
-// $userdetails = array("newextension" => $newextension,
-// "name" => $name,
-// "pin" => $pin,
-// "email" => $email);
-//
-// $i = 1;
-// $userdetails['telephonenumbers'] = array();
-// while ($i <= $limits['telephonenumbersmax']) {
-// $tmp = $info['telephone'.$i];
-// if (!empty($tmp)) {
-// $userdetails['telephonenumbers'][] = $tmp;
-// }
-// $i++;
-// }
-//
-// $userdetails['dialopts'] = array();
-// if ($info['moh']) {
-// $userdetails['dialopts'][] = 'm';
-// }
-// if ($info['transfer']) {
-// $userdetails['dialopts'][] = 't';
-// }
-}
\ No newline at end of file
+++ /dev/null
-<?php
-/**
- * $Id$
- *
- * Copyright 2005-2006 Ben Klang <ben@alkaloid.net>
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @package shout
- */
-
-if (!isset($SHOUT_RUNNING) || !$SHOUT_RUNNING) {
- header('Location: /');
- exit();
-}
-
-$users = &$shout->getUsers($context);
+++ /dev/null
-<?php
-/**
- * $Id$
- *
- * Copyright 2005-2006 Ben Klang <ben@alkaloid.net>
- *
- * See the enclosed file LICENSE for license information (GPL). If you
- * did not receive this file, see http://www.horde.org/licenses/gpl.php.
- *
- * @package shout
- */
-if (!isset($SHOUT_RUNNING) || !$SHOUT_RUNNING) {
- header('Location: /');
- exit();
-}
-
-require_once SHOUT_BASE . '/lib/User.php';
-require_once 'Horde/Variables.php';
-
-$RENDERER = &new Horde_Form_Renderer();
-
-$vars = &Variables::getDefaultVariables();
-$FormName = $vars->get('formname');
-
-$Form = &Horde_Form::singleton($FormName, $vars);
-
-$FormValid = $Form->validate($vars, true);
-
-if (!$FormValid || !$Form->isSubmitted()) {
- require SHOUT_BASE . '/usermgr/edit.php';
-} else {
- # Form is Valid and Submitted
- $extension = $vars->get('extension');
-
- $limits = $shout->getLimits($context, $extension);
-
- # FIXME: Input Validation (Text::??)
- $userdetails = array(
- "newextension" => $vars->get('newextension'),
- "name" => $vars->get('name'),
- "mailboxpin" => $vars->get('mailboxpin'),
- "email" => $vars->get('email'),
- "uid" => $vars->get('uid'),
- );
-
- $userdetails['telephonenumber'] = array();
- $telephonenumber = $vars->get("telephonenumber");
- if (!empty($telephonenumber) && is_array($telephonenumber)) {
- $i = 1;
- while ($i <= $limits['telephonenumbersmax']) {
- if (!empty($telephonenumber[$i])) {
- $userdetails['telephonenumber'][] = $telephonenumber[$i++];
- } else {
- $i++;
- }
- }
- }
-
- $userdetails['dialopts'] = array();
-
- if ($vars->get('moh')) {
- $userdetails['dialopts'][] = 'm';
- }
- if ($vars->get('transfer')) {
- $userdetails['dialopts'][] = 't';
- }
- if ($vars->get('eca')) {
- $userdetails['dialopts'][] = 'e';
- }
- $res = $shout->saveUser($context, $extension, $userdetails);
- if (is_a($res, 'PEAR_Error')) {
- $notification->push($res);
- } else {
- $notification->push('User information updated. '.
- 'Changes will take effect within 10 minutes',
- 'horde.success');
- }
-
- $notification->notify();
-}
*/
@define('SHOUT_BASE', dirname(__FILE__));
-$shout_configured = (is_readable(SHOUT_BASE . '/config/conf.php') &&
- is_readable(SHOUT_BASE . '/config/applist.xml') &&
- is_readable(SHOUT_BASE . '/config/defines.php'));
+$shout_configured = (is_readable(SHOUT_BASE . '/config/conf.php'));
if (!$shout_configured) {
require SHOUT_BASE . '/../lib/Test.php';
Horde_Test::configFilesMissing('Shout', SHOUT_BASE,
- array('conf.php', 'applist.xml', 'defines.php'));
+ array('conf.php'));
}
require_once SHOUT_BASE . '/lib/base.php';
-header('Location: ' . Horde::applicationUrl('usermgr.php'));
+header('Location: ' . Horde::applicationUrl('extensions.php'));
* @return mixed The newly created concrete Shout_Driver instance, or
* false on an error.
*/
- function &factory($driver = null, $params = null)
+ function &factory($class, $driver = null, $params = null)
{
if (is_null($driver)) {
- $driver = $GLOBALS['conf']['storage']['driver'];
+ $driver = $GLOBALS['conf'][$class]['driver'];
}
$driver = basename($driver);
if (is_null($params)) {
- $params = Horde::getDriverConfig('storage', $driver);
+ if ($GLOBALS['conf'][$class]['params']['driverconfig'] == 'horde') {
+ $params = array_merge($GLOBALS['conf'][$class]['params'],
+ Horde::getDriverConfig('storage', $driver));
+ } else {
+ $params = $GLOBALS['conf'][$class]['params'];
+ }
}
+ $params['class'] = $class;
+
require_once dirname(__FILE__) . '/Driver/' . $driver . '.php';
$class = 'Shout_Driver_' . $driver;
if (class_exists($class)) {
- $shout = new $class($params);
- return $shout;
+ return new $class($params);
} else {
return false;
}
}
- /**
- * Attempts to return a reference to a concrete Shout_Driver
- * instance based on $driver. It will only create a new instance
- * if no Shout_Driver instance with the same parameters currently
- * exists.
- *
- * This method must be invoked as: $var = &Shout_Driver::singleton()
- *
- * @param string $driver The type of concrete Shout_Driver subclass
- * to return. The is based on the storage
- * driver ($driver). The code is dynamically
- * included.
- * @param array $params (optional) A hash containing any additional
- * configuration or connection parameters a
- * subclass might need.
- *
- * @return mixed The created concrete Shout_Driver instance, or false
- * on error.
- */
- function &singleton($driver = null, $params = null)
- {
- static $instances;
-
- if (is_null($driver)) {
- $driver = $GLOBALS['conf']['storage']['driver'];
- }
-
- if (is_null($params)) {
- $params = Horde::getDriverConfig('storage', $driver);
- }
-
- if (!isset($instances)) {
- $instances = array();
- }
-
- $signature = serialize(array($driver, $params));
- if (!isset($instances[$signature])) {
- $instances[$signature] = &Shout_Driver::factory($driver, $params);
- }
-
- return $instances[$signature];
- }
}
-// }}}
<?php
-# Make Shout methods available
-require_once SHOUT_BASE . '/lib/Shout.php';
-
-class Shout_Driver_ldap extends Shout_Driver
+class Shout_Driver_Ldap extends Shout_Driver
{
var $_ldapKey; // Index used for storing objects
var $_appKey; // Index used for moving info to/from the app
* Handle for the current database connection.
* @var object LDAP $_LDAP
*/
- var $_LDAP;
+ private $_LDAP;
/**
* Boolean indicating whether or not we're connected to the LDAP
* server.
* @var boolean $_connected
*/
- var $_connected = false;
+ private $_connected = false;
/**
*
* @param array $params A hash containing connection parameters.
*/
- function Shout_Driver_ldap($params = array())
+ function __construct($params = array())
{
- parent::Shout_Driver($params);
+ parent::__construct($params);
$this->_connect();
/* These next lines will translate between indexes used in the
}
/**
- * Get a list of contexts from the backend
- *
- * @param string $filter Search filter
- *
- * @return array Contexts valid for this system
- *
- * @access private
- */
- function &getContexts($searchfilters = SHOUT_CONTEXT_ALL,
- $filterperms = null)
- {
- static $entries = array();
- if (isset($entries[$searchfilters])) {
- return $entries[$searchfilters];
- }
-
- if ($filterperms === null) {
- $filterperms = PERMS_SHOW|PERMS_READ;
- }
-
- # TODO Add caching mechanism here. Possibly cache results per
- # filter $this->contexts['customer'] and return either data
- # or possibly a reference to that data
-
- # Determine which combination of contexts need to be returned
- if ($searchfilters == SHOUT_CONTEXT_ALL) {
- $searchfilter="(objectClass=asteriskObject)";
- } else {
- $searchfilter = "(&";
- # FIXME Change this to non-V-Office specific objectClass
- if ($searchfilters & SHOUT_CONTEXT_CUSTOMERS) {
- # FIXME what does this objectClass really do for us?
- $searchfilter.="(objectClass=vofficeCustomer)";
- }
- if ($searchfilters & SHOUT_CONTEXT_EXTENSIONS) {
- $searchfilter.="(objectClass=asteriskExtensions)";
- }
- if ($searchfilters & SHOUT_CONTEXT_MOH) {
- $searchfilter.="(objectClass=asteriskMusicOnHold)";
- }
- if ($searchfilters & SHOUT_CONTEXT_CONFERENCE) {
- $searchfilter.="(objectClass=asteriskMeetMe)";
- }
- $searchfilter .= ")";
- }
-
- $attributes = array(SHOUT_ACCOUNT_ID_ATTRIBUTE, 'objectClass', 'context');
-
- # Collect all the possible contexts from the backend
- $res = @ldap_search($this->_LDAP,
- SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
- "$searchfilter");
- #array('context', 'associatedDomain'));
- if (!$res) {
- return PEAR::raiseError("Unable to locate any contexts " .
- "underneath ".SHOUT_ASTERISK_BRANCH.",".$this->_params['basedn'] .
- " matching those search filters" . ldap_error($this->_LDAP));
- }
-
- $res = ldap_get_entries($this->_LDAP, $res);
- $i = 0;
- $entries[$searchfilters] = array();
- while ($i < $res['count']) {
- $context = $res[$i]['context'][0];
- $type = SHOUT_CONTEXT_NONE;
- foreach ($res[$i][strtolower('objectClass')] as $objectClass) {
- switch ($objectClass) {
- case SHOUT_CONTEXT_CUSTOMERS_OBJECTCLASS:
- # FIXME What does this objectClass really get us?
- $type = $type | SHOUT_CONTEXT_CUSTOMERS;
- break;
- case SHOUT_CONTEXT_EXTENSIONS_OBJECTCLASS:
- $type = $type | SHOUT_CONTEXT_EXTENSIONS;
- break;
- case SHOUT_CONTEXT_MOH_OBJECTCLASS:
- $type = $type | SHOUT_CONTEXT_MOH;
- break;
- case SHOUT_CONTEXT_CONFERENCE_OBJECTCLASS:
- $type = $type | SHOUT_CONTEXT_CONFERENCE;
- break;
- case SHOUT_CONTEXT_VOICEMAIL_OBJECTCLASS:
- $type = $type | SHOUT_CONTEXT_VOICEMAIL;
- break;
- }
- }
- if (Shout::checkRights("shout:contexts:$context", $filterperms)) {
- $entries[$searchfilters][$context] =
- array(
- 'custid' => SHOUT_ACCOUNT_ID_ATTRIBUTE,
- 'type' => $type,
- );
- }
- $i++;
- }
- # return the array
- return $entries[$searchfilters];
- }
-
- /**
- * For the given context and type, make sure the context has the
- * appropriate properties, that it is effectively of that "type"
- *
- * @param string $context the context to check type for
- *
- * @param string $type the type to verify the context is of
- *
- * @return boolean true of the context is of type, false if not
- *
- * @access public
- */
- function checkContextType($context, $type) {
- switch ($type) {
- case "users":
- $searchfilter = '(objectClass='.SHOUT_CONTEXT_VOICEMAIL_OBJECTCLASS.')';
- break;
- case "dialplan":
- $searchfilter = '(objectClass='.SHOUT_CONTEXT_EXTENSIONS_OBJECTCLASS.')';
- break;
- case "moh":
- $searchfilter='(objectClass='.SHOUT_CONTEXT_MOH_OBJECTCLASS.')';
- break;
- case "conference":
- $searchfilter='(objectClass='.SHOUT_CONTEXT_CONFERENCE_OBJECTCLASS.')';
- break;
- case "all":
- default:
- $searchfilter="";
- break;
- }
-
- $res = @ldap_search($this->_LDAP,
- SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
- "(&(objectClass=asteriskObject)$searchfilter(context=$context))",
- array("context"));
- if (!$res) {
- return PEAR::raiseError("Unable to search directory for context
-type");
- }
-
- $res = ldap_get_entries($this->_LDAP, $res);
- if (!$res) {
- return PEAR::raiseError("Unable to get results from LDAP query");
- }
-
- if ($res['count'] == 1) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
* Get a list of users valid for the contexts
*
- * @param string $context Context on which to search
+ * @param string $context Context in which to search
*
* @return array User information indexed by voice mailbox number
*/
- function getUsers($context)
+ public function getExtensions($context)
{
static $entries = array();
return $entries[$context];
}
- $basedn = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
+ $this->_params['basedn'];
$filter = '(&';
- $filter .= '(objectClass='.SHOUT_USER_OBJECTCLASS.')';
- $filter .= '(context='.$context.')';
+ $filter .= '(objectClass=AsteriskVoiceMail)';
+ $filter .= '(AstContext='.$context.')';
$filter .= ')';
$attributes = array(
- 'voiceMailbox',
- 'asteriskUserDialOptions',
- 'asteriskVoiceMailboxOptions',
- 'voiceMailboxPin',
'cn',
- 'telephoneNumber',
- 'asteriskUserDialTimeout',
'mail',
- 'asteriskPager',
+ 'AstVoicemailMailbox',
+ 'AstVoicemailPassword',
+ 'AstVoicemailOptions',
+ 'AstVoicemailPager'
);
- $search = @ldap_search($this->_LDAP, $basedn, $filter, $attributes);
-
- if (!$search) {
- return PEAR::raiseError("Unable to search directory: " .
- ldap_error($this->_LDAP));
+ $search = ldap_search($this->_LDAP, $this->_params['basedn'], $filter, $attributes);
+ if ($search === false) {
+ throw new Shout_Exception("Unable to search directory: " .
+ ldap_error($this->_LDAP), ldap_errno($this->_LDAP));
}
$res = ldap_get_entries($this->_LDAP, $search);
- #
- # ATTRIBUTES RETURNED FROM ldap_get_entries ARE ALL LOWER CASE!!
- #
+ if ($res === false) {
+ throw new Shout_Exception("Unable to fetch results from directory: " .
+ ldap_error($this->_LDAP), ldap_errno($this->_LDAP));
+ }
+
+ // ATTRIBUTES RETURNED FROM ldap_get_entries ARE ALL LOWER CASE!!
+ // It's a PHP thing.
$entries[$context] = array();
$i = 0;
while ($i < $res['count']) {
- $extension = $res[$i]['voicemailbox'][0];
- $uid = md5($res[$i]['dn']);
+ list($extension) = explode('@', $res[$i]['AstVoicemailMailbox'][0]);
$entries[$context][$extension] = array();
- $entries[$context][$extension]['uid'] = $uid;
-
- $j = 0;
- $entries[$context][$extension]['dialopts'] = array();
- while ($j < @$res[$i]['asteriskuserdialoptions']['count']) {
- $entries[$context][$extension]['dialopts'][] =
- $res[$i]['asteriskuserdialoptions'][$j];
- $j++;
- }
$j = 0;
$entries[$context][$extension]['mailboxopts'] = array();
- while ($j < @$res[$i]['asteriskvoicemailboxoptions']['count']) {
+ while ($j < @$res[$i]['astvoicemailoptions']['count']) {
$entries[$context][$extension]['mailboxopts'][] =
- $res[$i]['asteriskvoicemailboxoptions'][$j];
+ $res[$i]['astvoicemailoptions'][$j];
$j++;
}
$entries[$context][$extension]['mailboxpin'] =
- $res[$i]['voicemailboxpin'][0];
+ $res[$i]['astvoicemailpassword'][0];
- @$entries[$context][$extension]['name'] =
+ $entries[$context][$extension]['name'] =
$res[$i]['cn'][0];
- $j = 0;
- $entries[$context][$extension]['telephonenumber'] = array();
- while ($j < @$res[$i]['telephonenumber']['count']) {
- // Start with 1 for telephone numbers for user convenience
- $entries[$context][$extension]['telephonenumber'][$j+1] =
- $res[$i]['telephonenumber'][$j];
- $j++;
- }
-
- # FIXME Do some sanity checking here. Also set a default?
- @$entries[$context][$extension]['dialtimeout'] =
- $res[$i]['asteriskuserdialtimeout'][0];
-
@$entries[$context][$extension]['email'] =
$res[$i]['mail'][0];
@$entries[$context][$extension]['pageremail'] =
- $res[$i]['asteriskpager'][0];
+ $res[$i]['astvoicemailpager'][0];
$i++;
}
/**
- * Returns the name of the user's default context
- *
- * @return string User's default context
- */
- function getHomeContext()
- {
- # FIXME Cache this lookup?
-
- $basedn = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
- $filter = '(&';
- $filter .= '(mail='.Auth::getAuth().')';
- $filter .= '(objectClass='.SHOUT_USER_OBJECTCLASS.')';
- $filter .= ')';
- $attributes = array('context');
-
- $res = @ldap_search($this->_LDAP, $basedn, $filter, $attributes);
- if (!$res) {
- return PEAR::raiseError("Unable to locate any customers " .
- "underneath ".SHOUT_ASTERISK_BRANCH.",".$this->_params['basedn'] .
- " matching those search filters");
- # FIXME Better error string above
- }
-
- $res = ldap_get_entries($this->_LDAP, $res);
-
- # Assume the user only has one context. The schema enforces this
- # FIXME: Handle cases where the managing user isn't a valid telephone
- # system user
- # FIXME: Do we want to warn? If so, how? This PEAR::Error shows up
- # in unfavorable places (ie. perms screen)
- if ($res['count'] != 1) {
- //return PEAR::raiseError(_("Unable to determine default context"));
- return '';
- }
- return $res[0]['context'][0];
- }
-
- /**
* Get a context's properties
*
* @param string $context Context to get properties for
*
* @return integer Bitfield of properties valid for this context
*/
- function getContextProperties($context)
+ public function getContextProperties($context)
{
$res = @ldap_search($this->_LDAP,
* @return array Multi-dimensional associative array of extensions data
*
*/
- function &getDialplan($context, $preprocess = false)
+ public function getDialplan($context, $preprocess = false)
{
# FIXME Implement preprocess functionality. Don't forget to cache!
static $dialplans = array();
* @return array Array with elements indicating various limits
*/
# FIXME Figure out how this fits into Shout/Congregation better
- function &getLimits($context = null, $extension = null)
+ public function getLimits($context = null, $extension = null)
{
$limits = array('telephonenumbersmax',
*
* @return TRUE on success, PEAR::Error object on error
*/
- function saveUser($context, $extension, $userdetails)
+ public function saveUser($context, $extension, $userdetails)
{
$ldapKey = &$this->_ldapKey;
$appKey = &$this->_appKey;
*
* @return boolean True on success, PEAR::Error object on error
*/
- function deleteUser($context, $extension)
+ public function deleteUser($context, $extension)
{
$ldapKey = &$this->_ldapKey;
$appKey = &$this->_appKey;
/* Needed because uksort can't take a classed function as its callback arg */
- function _sortexten($e1, $e2)
+ protected function _sortexten($e1, $e2)
{
print "$e1 and $e2\n";
$ret = Shout::extensort($e1, $e2);
*
* @access private
*/
- function _connect()
+ protected function _connect()
{
- if (!$this->_connected) {
- # FIXME What else is needed for this assert?
- Horde::assertDriverConfig($this->_params, 'storage',
- array('hostspec', 'basedn', 'binddn', 'password'));
-
- # FIXME Add other sane defaults here (mostly objectClass related)
- if (!isset($this->_params['userObjectclass'])) {
- $this->_params['userObjectclass'] = 'asteriskUser';
+ if ($this->_connected) {
+ return;
+ }
+
+ if (!Horde_Util::extensionExists('ldap')) {
+ throw new Horde_Exception('Required LDAP extension not found.');
+ }
+
+ Horde::assertDriverConfig($this->_params, $this->_params['class'],
+ array('hostspec', 'basedn', 'writedn'));
+
+ /* Open an unbound connection to the LDAP server */
+ $conn = ldap_connect($this->_params['hostspec'], $this->_params['port']);
+ if (!$conn) {
+ Horde::logMessage(
+ sprintf('Failed to open an LDAP connection to %s.',
+ $this->_params['hostspec']),
+ __FILE__, __LINE__, PEAR_LOG_ERR);
+ throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.');
+ }
+
+ /* Set hte LDAP protocol version. */
+ if (isset($this->_params['version'])) {
+ $result = ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION,
+ $this->_params['version']);
+ if ($result === false) {
+ Horde::logMessage(
+ sprintf('Set LDAP protocol version to %d failed: [%d] %s',
+ $this->_params['version'],
+ ldap_errno($conn),
+ ldap_error($conn)),
+ __FILE__, __LINE__, PEAR_LOG_WARNING);
+ throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
}
+ }
- $this->_LDAP = ldap_connect($this->_params['hostspec'], 389); #FIXME
- if (!$this->_LDAP) {
- Horde::fatal("Unable to connect to LDAP server $hostname on
-$port", __FILE__, __LINE__); #FIXME: $port
- }
- $res = ldap_set_option($this->_LDAP, LDAP_OPT_PROTOCOL_VERSION,
-$this->_params['version']);
- if (!$res) {
- return PEAR::raiseError("Unable to set LDAP protocol version");
- }
- $res = ldap_bind($this->_LDAP, $this->_params['binddn'],
-$this->_params['password']);
- if (!$res) {
- return PEAR::raiseError("Unable to bind to the LDAP server.
-Check authentication credentials.");
+ /* Start TLS if we're using it. */
+ if (!empty($this->_params['tls'])) {
+ if (!@ldap_start_tls($conn)) {
+ Horde::logMessage(
+ sprintf('STARTTLS failed: [%d] %s',
+ @ldap_errno($this->_ds),
+ @ldap_error($this->_ds)),
+ __FILE__, __LINE__, PEAR_LOG_ERR);
}
+ }
- $this->_connected = true;
+ /* If necessary, bind to the LDAP server as the user with search
+ * permissions. */
+ if (!empty($this->_params['searchdn'])) {
+ $bind = ldap_bind($conn, $this->_params['searchdn'],
+ $this->_params['searchpw']);
+ if ($bind === false) {
+ Horde::logMessage(
+ sprintf('Bind to server %s:%d with DN %s failed: [%d] %s',
+ $this->_params['hostspec'],
+ $this->_params['port'],
+ $this->_params['searchdn'],
+ @ldap_errno($conn),
+ @ldap_error($conn)),
+ __FILE__, __LINE__, PEAR_LOG_ERR);
+ throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
+ }
}
- return true;
+
+ /* Store the connection handle at the instance level. */
+ $this->_LDAP = $conn;
}
+
}
--- /dev/null
+<?php
+
+class Shout_Driver_Sql extends Shout_Driver
+{
+ /**
+ * Handle for the current database connection.
+ * @var object $_db
+ */
+ protected $_db = null;
+
+ /**
+ * Boolean indicating whether or not we're connected to the LDAP
+ * server.
+ * @var boolean $_connected
+ */
+ protected $_connected = false;
+
+
+ /**
+ * Constructs a new Shout LDAP driver object.
+ *
+ * @param array $params A hash containing connection parameters.
+ */
+ function __construct($params = array())
+ {
+ parent::__construct($params);
+ $this->_connect();
+ }
+
+ public function getContexts()
+ {
+ $this->_connect();
+
+ $sql = 'SELECT context FROM %s';
+ $sql = sprintf($sql, $this->_params['table']);
+ $vars = array();
+
+ $result = $this->_db->query($sql, $vars);
+ if ($result instanceof PEAR_Error) {
+ throw Shout_Exception($result);
+ }
+
+ $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+ if ($row instanceof PEAR_Error) {
+ throw Shout_Exception($row);
+ }
+
+ $contexts = array();
+ while ($row && !($row instanceof PEAR_Error)) {
+ /* Add this new foo to the $_foo list. */
+ $contexts[] = $row['context'];
+
+ /* Advance to the new row in the result set. */
+ $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+ }
+
+ $result->free();
+ return $contexts;
+ }
+
+ /**
+ * Get a list of devices for a given context
+ *
+ * @param string $context Context in which to search for devices
+ * @param string $extension Extension in which to search for devices
+ *
+ * @return array Array of devices within this context with their information
+ *
+ * @access private
+ */
+ public function getDevices($context, $extension)
+ {
+ $sql = 'SELECT id, name, callerid, context, host, permit, nat, ' .
+ 'secret, disallow, allow FROM %s WHERE mailbox = ?';
+ $sql = sprintf($sql, $this->_params['table']);
+ $args = array($extension . '@' . $context);
+
+ $result = $this->_db->query($sql, $args);
+ if (is_a($result instanceof PEAR_Error)) {
+ throw Shout_Exception($result);
+ }
+
+ $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+ if ($row instanceof PEAR_Error) {
+ throw Shout_Exception($row);
+ }
+
+ $devices = array();
+ while ($row && !($row instanceof PEAR_Error)) {
+ /* Add this new foo to the $_foo list. */
+ $devices[] = $row;
+
+ /* Advance to the new row in the result set. */
+ $row = $result->fetchRow(DB_FETCHMODE_ASSOC);
+ }
+
+ $result->free();
+
+ }
+
+ /**
+ * Get a list of users valid for the contexts
+ *
+ * @param string $context Context on which to search
+ *
+ * @return array User information indexed by voice mailbox number
+ */
+ public function getExtensions($context)
+ {
+ throw new Shout_Exception("Not implemented yet.");
+ }
+
+ /**
+ * Save a user to the LDAP tree
+ *
+ * @param string $context Context to which the user should be added
+ *
+ * @param string $extension Extension to be saved
+ *
+ * @param array $userdetails Phone numbers, PIN, options, etc to be saved
+ *
+ * @return TRUE on success, PEAR::Error object on error
+ */
+ public function saveExtension($context, $extension, $userdetails)
+ {
+ throw new Shout_Exception("Not implemented.");
+ }
+
+ /**
+ * Deletes a user from the LDAP tree
+ *
+ * @param string $context Context to delete the user from
+ * @param string $extension Extension of the user to be deleted
+ *
+ * @return boolean True on success, PEAR::Error object on error
+ */
+ public function deleteExtension($context, $extension)
+ {
+ throw new Shout_Exception("Not implemented.");
+ }
+
+ /**
+ * Attempts to open a persistent connection to the SQL server.
+ *
+ * @throws Horde_Exception
+ */
+ protected function _connect()
+ {
+ if ($this->_connected) {
+ return;
+ }
+
+ Horde::assertDriverConfig($this->_params, $this->_params['class'],
+ array('phptype', 'charset', 'table'));
+
+ if (!isset($this->_params['database'])) {
+ $this->_params['database'] = '';
+ }
+ if (!isset($this->_params['username'])) {
+ $this->_params['username'] = '';
+ }
+ if (!isset($this->_params['hostspec'])) {
+ $this->_params['hostspec'] = '';
+ }
+
+ /* Connect to the SQL server using the supplied parameters. */
+ $this->_write_db = DB::connect($this->_params,
+ array('persistent' => !empty($this->_params['persistent'])));
+ if ($this->_write_db instanceof PEAR_Error) {
+ throw Horde_Exception($this->_write_db);
+ }
+
+ // Set DB portability options.
+ switch ($this->_write_db->phptype) {
+ case 'mssql':
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+
+ default:
+ $this->_write_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ /* Check if we need to set up the read DB connection seperately. */
+ if (!empty($this->_params['splitread'])) {
+ $params = array_merge($this->_params, $this->_params['read']);
+ $this->_db = DB::connect($params,
+ array('persistent' => !empty($params['persistent'])));
+ if ($this->_db instanceof PEAR_Error) {
+ throw Horde_Exception($this->_db);
+ }
+
+ // Set DB portability options.
+ switch ($this->_db->phptype) {
+ case 'mssql':
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+
+ default:
+ $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+ }
+
+ } else {
+ /* Default to the same DB handle for the writer too. */
+ $this->_db = $this->_write_db;
+ }
+
+ $this->_connected = true;
+ }
+
+ /**
+ * Disconnects from the SQL server and cleans up the connection.
+ */
+ protected function _disconnect()
+ {
+ if ($this->_connected) {
+ $this->_connected = false;
+ $this->_db->disconnect();
+ $this->_write_db->disconnect();
+ }
+ }
+
+}
--- /dev/null
+<?php
+class Shout_Exception extends Horde_Exception
+{
+}
\ No newline at end of file
$tabs = new Horde_UI_Tabs('section', $vars);
- if (Shout::checkRights($permprefix . ':users', null, 1) &&
- $shout->checkContextType($context, 'users')) {
-
- $url = Horde::applicationUrl('usermgr.php');
+ if (Shout::checkRights($permprefix . ':extensions', null, 1)) {
+ $url = Horde::applicationUrl('extensions.php');
$url = Horde_Util::addParameter($url, 'context', $context);
- $tabs->addTab(_("_User Manager"), $url, 'usermgr');
+ $tabs->addTab(_("_Extensions"), $url, 'usermgr');
}
- if (Shout::checkRights($permprefix . ':dialplan', null, 1) &&
- $shout->checkContextType($context, 'dialplan')) {
-
+ if (Shout::checkRights($permprefix . ':dialplan', null, 1)) {
$url = Horde::applicationUrl('dialplan.php');
$url = Horde_Util::addParameter($url, 'context', $context);
- $tabs->addTab(_("_Dial Plan"), $url, 'dialplan');
+ $tabs->addTab(_("_Automated Attendant"), $url, 'dialplan');
}
- if (Shout::checkRights($permprefix . ':conference', null, 1) &&
- $shout->checkContextType($context, 'conference')) {
-
+ if (Shout::checkRights($permprefix . ':conference', null, 1)) {
$url = Horde::applicationUrl('conference.php');
$url = Horde_Util::addParameter($url, 'context', $context);
$tabs->addTab(_("_Conference Rooms"), $url, 'conference');
}
- if (Shout::checkRights($permprefix . ':moh', null, 1) &&
- $shout->checkContextType($context, "moh")) {
-
+ if (Shout::checkRights($permprefix . ':moh', null, 1)) {
$url = Horde::applicationUrl('moh.php');
$url = Horde_Util::addParameter($url, 'context', $context);
$tabs->addTab(_("_Music on Hold"), $url, 'moh');
}
- if ($perms->hasPermission('shout:superadmin', Horde_Auth::getAuth(), PERMS_SHOW|PERMS_READ)) {
- $url = Horde::applicationUrl('security.php');
- $url = Horde_Util::addParameter($url, 'context', $context);
- $tabs->addTab(_("_Security"), $url, 'security');
- }
-
return $tabs;
}
print "Shout::checkRights() returning $ret";
return ($test & $permmask) == $permmask;
}
-
- static public function getContextTypes()
- {
- return array(SHOUT_CONTEXT_CUSTOMERS => _("Customers"),
- SHOUT_CONTEXT_EXTENSIONS => _("Dialplan"),
- SHOUT_CONTEXT_MOH => _("Music On Hold"),
- SHOUT_CONTEXT_CONFERENCE => _("Conference Calls"));
- }
}
// Ensure Shout is properly configured before use
$shout_configured = (@is_readable(SHOUT_BASE . '/config/conf.php'));
if (!$shout_configured) {
- require SHOUT_BASE . '/../lib/Test.php';
Horde_Test::configFilesMissing('Shout', SHOUT_BASE, array('conf.php'));
}
//// UI classes.
//require_once 'Horde/UI/Tabs.php';
-$shout = Shout_Driver::singleton();
-
-//// Horde libraries.
-//require_once 'Horde/Help.php';
+$shout_storage = Shout_Driver::factory('storage');
+$shout_extensions = Shout_Driver::factory('extensions');
+$shout_devices = Shout_Driver::factory('devices');
$context = Horde_Util::getFormData('context');
$section = Horde_Util::getFormData('section');
try {
- $contexts = $shout->getContexts();
+ $contexts = $shout_storage->getContexts();
} catch (Shout_Exception $e) {
$notification->push($e);
$contexts = false;
if (count($contexts) == 1) {
// Default to the user's only context
$context = $contexts[0];
-} elseif (!$context) {
- try {
- // Attempt to locate the user's "home" context
- $context = $shout->getHomeContext();
- } catch (Shout_Exception $e) {
- $notification->push($e);
- }
+} elseif (!empty($context) && !in_array($context, $contexts)) {
+ $notification->push('You do not have permission to access that context.', 'horde.error');
+ $context = false;
+} elseif (!empty($context)) {
+ $notification->push("Please select a context to continue.", 'horde.info');
$context = false;
-}
\ No newline at end of file
+}
+
+$_SESSION['shout']['context'] = $context;
\ No newline at end of file
</tr>
<?php
$line = 0;
- foreach ($users as $extension => $user) {
+ foreach ($extensions as $extension => $user) {
$rowcolor = $line % 2;
$line++;
$url = Horde::applicationUrl("index.php");