Overview

Packages

  • Auth
  • Core
  • Horde
    • Imsp
  • None
  • Notification

Classes

  • Horde
  • Horde_Config
  • Horde_Config_Form
  • Horde_Core_ActiveSync_Connector
  • Horde_Core_ActiveSync_Driver
  • Horde_Core_Ajax_Application
  • Horde_Core_Ajax_Imple
  • Horde_Core_Ajax_Imple_AutoCompleter
  • Horde_Core_Ajax_Imple_Geocoder_Geonames
  • Horde_Core_Ajax_Imple_SpellChecker
  • Horde_Core_Alarm_Handler_Notify
  • Horde_Core_Auth_Application
  • Horde_Core_Auth_Composite
  • Horde_Core_Auth_Ldap
  • Horde_Core_Auth_Msad
  • Horde_Core_Auth_Shibboleth
  • Horde_Core_Auth_Signup_Base
  • Horde_Core_Auth_Signup_Form
  • Horde_Core_Auth_Signup_Null
  • Horde_Core_Auth_Signup_Sql
  • Horde_Core_Auth_Signup_SqlObject
  • Horde_Core_Autoloader_Callback_Mime
  • Horde_Core_Autoloader_Callback_Nls
  • Horde_Core_Block
  • Horde_Core_Block_Collection
  • Horde_Core_Block_Layout
  • Horde_Core_Block_Layout_Manager
  • Horde_Core_Block_Layout_View
  • Horde_Core_Block_Upgrade
  • Horde_Core_Browser
  • Horde_Core_Bundle
  • Horde_Core_Cli
  • Horde_Core_Controller_NotFound
  • Horde_Core_Controller_RequestConfiguration
  • Horde_Core_Controller_RequestMapper
  • Horde_Core_Controller_SettingsFinder
  • Horde_Core_Db_Migration
  • Horde_Core_Factory_ActiveSyncBackend
  • Horde_Core_Factory_ActiveSyncServer
  • Horde_Core_Factory_ActiveSyncState
  • Horde_Core_Factory_Ajax
  • Horde_Core_Factory_Alarm
  • Horde_Core_Factory_Auth
  • Horde_Core_Factory_AuthSignup
  • Horde_Core_Factory_Base
  • Horde_Core_Factory_BlockCollection
  • Horde_Core_Factory_Browser
  • Horde_Core_Factory_Cache
  • Horde_Core_Factory_Crypt
  • Horde_Core_Factory_Data
  • Horde_Core_Factory_Db
  • Horde_Core_Factory_DbBase
  • Horde_Core_Factory_DbPear
  • Horde_Core_Factory_Dns
  • Horde_Core_Factory_Editor
  • Horde_Core_Factory_Facebook
  • Horde_Core_Factory_Group
  • Horde_Core_Factory_History
  • Horde_Core_Factory_HttpClient
  • Horde_Core_Factory_Identity
  • Horde_Core_Factory_Image
  • Horde_Core_Factory_Imple
  • Horde_Core_Factory_Imsp
  • Horde_Core_Factory_ImspAuth
  • Horde_Core_Factory_Injector
  • Horde_Core_Factory_KolabServer
  • Horde_Core_Factory_KolabSession
  • Horde_Core_Factory_KolabStorage
  • Horde_Core_Factory_Ldap
  • Horde_Core_Factory_Lock
  • Horde_Core_Factory_Logger
  • Horde_Core_Factory_LoginTasks
  • Horde_Core_Factory_Mail
  • Horde_Core_Factory_Mapper
  • Horde_Core_Factory_Matcher
  • Horde_Core_Factory_Memcache
  • Horde_Core_Factory_MimeViewer
  • Horde_Core_Factory_Notification
  • Horde_Core_Factory_Perms
  • Horde_Core_Factory_PermsCore
  • Horde_Core_Factory_Prefs
  • Horde_Core_Factory_Request
  • Horde_Core_Factory_Secret
  • Horde_Core_Factory_SessionHandler
  • Horde_Core_Factory_Share
  • Horde_Core_Factory_ShareBase
  • Horde_Core_Factory_Template
  • Horde_Core_Factory_TextFilter
  • Horde_Core_Factory_ThemesCache
  • Horde_Core_Factory_Token
  • Horde_Core_Factory_Tree
  • Horde_Core_Factory_Twitter
  • Horde_Core_Factory_UrlShortener
  • Horde_Core_Factory_Vfs
  • Horde_Core_Factory_View
  • Horde_Core_Factory_Weather
  • Horde_Core_Group_Ldap
  • Horde_Core_Log_Logger
  • Horde_Core_LoginTasks
  • Horde_Core_LoginTasks_Backend_Horde
  • Horde_Core_LoginTasks_SystemTask_Upgrade
  • Horde_Core_Mime_Viewer_Syntaxhighlighter
  • Horde_Core_Mime_Viewer_Vcard
  • Horde_Core_Notification_Event_Status
  • Horde_Core_Notification_Handler_Decorator_Hordelog
  • Horde_Core_Notification_Storage_Session
  • Horde_Core_Perms
  • Horde_Core_Perms_Ui
  • Horde_Core_Prefs_Cache_Session
  • Horde_Core_Prefs_Identity
  • Horde_Core_Prefs_Storage_Configuration
  • Horde_Core_Prefs_Storage_Hooks
  • Horde_Core_Prefs_Storage_Upgrade
  • Horde_Core_Prefs_Ui
  • Horde_Core_Prefs_Ui_Widgets
  • Horde_Core_Share_Driver
  • Horde_Core_Share_FactoryCallback
  • Horde_Core_Sidebar
  • Horde_Core_Text_Filter_Bbcode
  • Horde_Core_Text_Filter_Emails
  • Horde_Core_Text_Filter_Emoticons
  • Horde_Core_Text_Filter_Highlightquotes
  • Horde_Core_Translation
  • Horde_Core_Tree_Html
  • Horde_Core_Tree_Javascript
  • Horde_Core_Tree_Simplehtml
  • Horde_Core_Ui_FlagImage
  • Horde_Core_Ui_JsCalendar
  • Horde_Core_Ui_Language
  • Horde_Core_Ui_Layout
  • Horde_Core_Ui_ModalFormRenderer
  • Horde_Core_Ui_Pager
  • Horde_Core_Ui_Tabs
  • Horde_Core_Ui_TagCloud
  • Horde_Core_Ui_VarRenderer
  • Horde_Core_Ui_VarRenderer_Html
  • Horde_Core_Ui_VarRenderer_TablesetHtml
  • Horde_Core_Ui_Widget
  • Horde_ErrorHandler
  • Horde_Help
  • Horde_Menu
  • Horde_Registry
  • Horde_Registry_Api
  • Horde_Registry_Application
  • Horde_Registry_Caller
  • Horde_Registry_Nlsconfig
  • Horde_Script_Files
  • Horde_Session
  • Horde_Session_Null
  • Horde_Themes
  • Horde_Themes_Cache
  • Horde_Themes_Css
  • Horde_Themes_Element
  • Horde_Themes_Image
  • Horde_Themes_Sound

Exceptions

  • Horde_Exception_HookNotSet
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * The Horde_Config:: package provides a framework for managing the
   4:  * configuration of Horde applications, writing conf.php files from
   5:  * conf.xml source files, generating user interfaces, etc.
   6:  *
   7:  * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
   8:  *
   9:  * See the enclosed file COPYING for license information (LGPL). If you
  10:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
  11:  *
  12:  * @author   Chuck Hagenbuch <chuck@horde.org>
  13:  * @category Horde
  14:  * @package  Core
  15:  */
  16: class Horde_Config
  17: {
  18:     /**
  19:      * The name of the configured application.
  20:      *
  21:      * @var string
  22:      */
  23:     protected $_app;
  24: 
  25:     /**
  26:      * The XML tree of the configuration file traversed to an
  27:      * associative array.
  28:      *
  29:      * @var array
  30:      */
  31:     protected $_xmlConfigTree = null;
  32: 
  33:     /**
  34:      * The content of the generated configuration file.
  35:      *
  36:      * @var string
  37:      */
  38:     protected $_phpConfig;
  39: 
  40:     /**
  41:      * The content of the old configuration file.
  42:      *
  43:      * @var string
  44:      */
  45:     protected $_oldConfig;
  46: 
  47:     /**
  48:      * The manual configuration in front of the generated configuration.
  49:      *
  50:      * @var string
  51:      */
  52:     protected $_preConfig;
  53: 
  54:     /**
  55:      * The manual configuration after the generated configuration.
  56:      *
  57:      * @var string
  58:      */
  59:     protected $_postConfig;
  60: 
  61:     /**
  62:      * The current $conf array of the configured application.
  63:      *
  64:      * @var array
  65:      */
  66:     protected $_currentConfig = array();
  67: 
  68:     /**
  69:      * The version tag of the conf.xml file which will be copied into the
  70:      * conf.php file.
  71:      *
  72:      * @var string
  73:      */
  74:     protected $_versionTag = '';
  75: 
  76:     /**
  77:      * The line marking the begin of the generated configuration.
  78:      *
  79:      * @var string
  80:      */
  81:     protected $_configBegin = "/* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */\n";
  82: 
  83:     /**
  84:      * The line marking the end of the generated configuration.
  85:      *
  86:      * @var string
  87:      */
  88:     protected $_configEnd = "/* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */\n";
  89: 
  90:     /**
  91:      * Horde URL to check version information.
  92:      *
  93:      * @var string
  94:      */
  95:     protected $_versionUrl = 'http://www.horde.org/versions.php';
  96: 
  97:     /**
  98:      * Constructor.
  99:      *
 100:      * @param string $app  The name of the application to be configured.
 101:      */
 102:     public function __construct($app = 'horde')
 103:     {
 104:         $this->_app = $app;
 105:     }
 106: 
 107:     /**
 108:      * Contact Horde servers and get version information.
 109:      *
 110:      * @return array  Keys are app names, values are arrays with two keys:
 111:      *                'version' and 'url'.
 112:      * @throws Horde_Exception
 113:      * @throws Horde_Http_Client_Exception
 114:      */
 115:     public function checkVersions()
 116:     {
 117:         if (!Horde_Util::extensionExists('SimpleXML')) {
 118:             throw new Horde_Exception('SimpleXML not available.');
 119:         }
 120: 
 121:         $http = $GLOBALS['injector']->getInstance('Horde_Core_Factory_HttpClient')->create();
 122:         $response = $http->get($this->_versionUrl);
 123:         if ($response->code != 200) {
 124:             throw new Horde_Exception('Unexpected response from server.');
 125:         }
 126: 
 127:         $xml = new SimpleXMLElement($response->getBody());
 128:         $versions = array();
 129: 
 130:         foreach ($xml->stable->application as $app) {
 131:             $versions[strval($app['name'])] = array(
 132:                 'version' => $app->version,
 133:                 'url' => $app->url
 134:             );
 135:         }
 136: 
 137:         return $versions;
 138:     }
 139: 
 140:     /**
 141:      * @since Horde_Core 1.1.0
 142:      */
 143:     public function configFile()
 144:     {
 145:         $path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
 146:         $configFile = $path . '/conf.php';
 147:         if (is_link($configFile)) {
 148:             $configFile = readlink($configFile);
 149:         }
 150:         return $configFile;
 151:     }
 152: 
 153:     /**
 154:      * Reads the application's conf.xml file and builds an associative array
 155:      * from its XML tree.
 156:      *
 157:      * @param array $custom_conf  Any settings that shall be included in the
 158:      *                            generated configuration.
 159:      *
 160:      * @return array  An associative array representing the configuration
 161:      *                tree.
 162:      */
 163:     public function readXMLConfig($custom_conf = null)
 164:     {
 165:         if (!is_null($this->_xmlConfigTree) && !$custom_conf) {
 166:             return $this->_xmlConfigTree;
 167:         }
 168: 
 169:         $path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
 170: 
 171:         if ($custom_conf) {
 172:             $this->_currentConfig = $custom_conf;
 173:         } else {
 174:             /* Fetch the current conf.php contents. */
 175:             @eval($this->getPHPConfig());
 176:             if (isset($conf)) {
 177:                 $this->_currentConfig = $conf;
 178:             }
 179:         }
 180: 
 181:         /* Load the DOM object. */
 182:         $dom = new DOMDocument();
 183:         $dom->load($path . '/conf.xml');
 184: 
 185:         /* Check if there is a CVS/Git version tag and store it. */
 186:         $node = $dom->firstChild;
 187:         while (!empty($node)) {
 188:             if (($node->nodeType == XML_COMMENT_NODE) &&
 189:                 ($vers_tag = $this->getVersion($node->nodeValue))) {
 190:                 $this->_versionTag = $vers_tag . "\n";
 191:                 break;
 192:             }
 193:             $node = $node->nextSibling;
 194:         }
 195: 
 196:         /* Parse the config file. */
 197:         $this->_xmlConfigTree = array();
 198:         $root = $dom->documentElement;
 199:         if ($root->hasChildNodes()) {
 200:             $this->_parseLevel($this->_xmlConfigTree, $root->childNodes, '');
 201:         }
 202: 
 203:         /* Parse additional config files. */
 204:         foreach (glob($path . '/conf.d/*.xml') as $additional) {
 205:             $dom->load($additional);
 206:             $root = $dom->documentElement;
 207:             if ($root->hasChildNodes()) {
 208:                 $tree = array();
 209:                 $this->_parseLevel($tree, $root->childNodes, '');
 210:                 $this->_xmlConfigTree = Horde_Array::replaceRecursive($this->_xmlConfigTree, $tree);
 211:             }
 212:         }
 213: 
 214:         return $this->_xmlConfigTree;
 215:     }
 216: 
 217:     /**
 218:      * Get the Horde version string for a config file.
 219:      *
 220:      * @param string $text  The text to parse.
 221:      *
 222:      * @return string  The version string or false if not found.
 223:      */
 224:     public function getVersion($text)
 225:     {
 226:         // Old CVS tag
 227:         if (preg_match('/\$.*?conf\.xml,v .*? .*\$/', $text, $match) ||
 228:             // New Git tag
 229:             preg_match('/\$Id:\s*[0-9a-f]+\s*\$/', $text, $match)) {
 230:             return $match[0];
 231:         }
 232: 
 233:         return false;
 234:     }
 235: 
 236:     /**
 237:      * Returns the file content of the current configuration file.
 238:      *
 239:      * @return string  The unparsed configuration file content.
 240:      */
 241:     public function getPHPConfig()
 242:     {
 243:         if (!is_null($this->_oldConfig)) {
 244:             return $this->_oldConfig;
 245:         }
 246: 
 247:         $path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
 248:         if (file_exists($path . '/conf.php')) {
 249:             $this->_oldConfig = file_get_contents($path . '/conf.php');
 250:             if (!empty($this->_oldConfig)) {
 251:                 $this->_oldConfig = preg_replace('/<\?php\n?/', '', $this->_oldConfig);
 252:                 $pos = strpos($this->_oldConfig, $this->_configBegin);
 253:                 if ($pos !== false) {
 254:                     $this->_preConfig = substr($this->_oldConfig, 0, $pos);
 255:                     $this->_oldConfig = substr($this->_oldConfig, $pos);
 256:                 }
 257:                 $pos = strpos($this->_oldConfig, $this->_configEnd);
 258:                 if ($pos !== false) {
 259:                     $this->_postConfig = substr($this->_oldConfig, $pos + strlen($this->_configEnd));
 260:                     $this->_oldConfig = substr($this->_oldConfig, 0, $pos);
 261:                 }
 262:             }
 263:         } else {
 264:             $this->_oldConfig = '';
 265:         }
 266: 
 267:         return $this->_oldConfig;
 268:     }
 269: 
 270:     /**
 271:      * Generates and writes the content of the application's configuration
 272:      * file.
 273:      *
 274:      * @since Horde_Core 1.1.0
 275:      *
 276:      * @param Horde_Variables $formvars  The processed configuration form
 277:      *                                   data.
 278:      * @param string $php                The content of the generated
 279:      *                                   configuration file.
 280:      *
 281:      * @return boolean  True if the configuration file could be written
 282:      *                  immediately to the file system.
 283:      */
 284:     public function writePHPConfig($formvars, &$php = null)
 285:     {
 286:         $php = $this->generatePHPConfig($formvars);
 287:         $path = $GLOBALS['registry']->get('fileroot', $this->_app) . '/config';
 288:         $configFile = $this->configFile();
 289:         if (file_exists($configFile)) {
 290:             if (@copy($configFile, $path . '/conf.bak.php')) {
 291:                 $GLOBALS['notification']->push(sprintf(_("Successfully saved the backup configuration file %s."), Horde_Util::realPath($path . '/conf.bak.php')), 'horde.success');
 292:             } else {
 293:                 $GLOBALS['notification']->push(sprintf(_("Could not save the backup configuration file %s."), Horde_Util::realPath($path . '/conf.bak.php')), 'horde.warning');
 294:             }
 295:         }
 296:         if ($fp = @fopen($configFile, 'w')) {
 297:             /* Can write, so output to file. */
 298:             fwrite($fp, $php);
 299:             fclose($fp);
 300:             $GLOBALS['registry']->rebuild();
 301:             return true;
 302:         }
 303: 
 304:         /* Cannot write. Save to session. */
 305:         $GLOBALS['session']->set('horde', 'config/' . $this->_app, $php);
 306: 
 307:         return false;
 308:     }
 309: 
 310:     /**
 311:      * Generates the content of the application's configuration file.
 312:      *
 313:      * @param Horde_Variables $formvars  The processed configuration form
 314:      *                                   data.
 315:      * @param array $custom_conf         Any settings that shall be included
 316:      *                                   in the generated configuration.
 317:      *
 318:      * @return string  The content of the generated configuration file.
 319:      */
 320:     public function generatePHPConfig($formvars, $custom_conf = null)
 321:     {
 322:         $this->readXMLConfig($custom_conf);
 323:         $this->getPHPConfig();
 324: 
 325:         $this->_phpConfig = "<?php\n" . $this->_preConfig . $this->_configBegin;
 326:         if (!empty($this->_versionTag)) {
 327:             $this->_phpConfig .= '// ' . $this->_versionTag;
 328:         }
 329:         $this->_generatePHPConfig($this->_xmlConfigTree, '', $formvars);
 330:         $this->_phpConfig .= $this->_configEnd . $this->_postConfig;
 331: 
 332:         return $this->_phpConfig;
 333:     }
 334: 
 335:     /**
 336:      * Generates the configuration file items for a part of the configuration
 337:      * tree.
 338:      *
 339:      * @param array $section             An associative array containing the
 340:      *                                   part of the traversed XML
 341:      *                                   configuration tree that should be
 342:      *                                   processed.
 343:      * @param string $prefix             A configuration prefix determining
 344:      *                                   the current position inside the
 345:      *                                   configuration file. This prefix will
 346:      *                                   be translated to keys of the $conf
 347:      *                                   array in the generated configuration
 348:      *                                   file.
 349:      * @param Horde_Variables $formvars  The processed configuration form
 350:      *                                   data.
 351:      */
 352:     protected function _generatePHPConfig($section, $prefix, $formvars)
 353:     {
 354:         if (!is_array($section)) {
 355:             return;
 356:         }
 357: 
 358:         foreach ($section as $name => $configitem) {
 359:             $prefixedname = empty($prefix)
 360:                 ? $name
 361:                 : $prefix . '|' . $name;
 362:             $configname = str_replace('|', '__', $prefixedname);
 363:             $quote = (!isset($configitem['quote']) || $configitem['quote'] !== false);
 364: 
 365:             if ($configitem == 'placeholder') {
 366:                 $this->_phpConfig .= '$conf[\'' . str_replace('|', '\'][\'', $prefix) . "'] = array();\n";
 367:             } elseif (isset($configitem['switch'])) {
 368:                 $val = $formvars->getExists($configname, $wasset);
 369:                 if (!$wasset) {
 370:                     $val = isset($configitem['default']) ? $configitem['default'] : null;
 371:                 }
 372:                 if (isset($configitem['switch'][$val])) {
 373:                     $value = $val;
 374:                     if ($quote && $value != 'true' && $value != 'false') {
 375:                         $value = "'" . $value . "'";
 376:                     }
 377:                     $this->_generatePHPConfig($configitem['switch'][$val]['fields'], $prefix, $formvars);
 378:                 }
 379:             } elseif (isset($configitem['_type'])) {
 380:                 $val = $formvars->getExists($configname, $wasset);
 381:                 if (!$wasset &&
 382:                     ((array_key_exists('is_default', $configitem) && $configitem['is_default'])
 383:                      || !array_key_exists('is_default', $configitem))) {
 384: 
 385:                     $val = isset($configitem['default']) ? $configitem['default'] : null;
 386:                 }
 387: 
 388:                 $type = $configitem['_type'];
 389:                 switch ($type) {
 390:                 case 'multienum':
 391:                     if (is_array($val)) {
 392:                         $encvals = array();
 393:                         foreach ($val as $v) {
 394:                             $encvals[] = $this->_quote($v);
 395:                         }
 396:                         $arrayval = "'" . implode('\', \'', $encvals) . "'";
 397:                         if ($arrayval == "''") {
 398:                             $arrayval = '';
 399:                         }
 400:                     } else {
 401:                         $arrayval = '';
 402:                     }
 403:                     $value = 'array(' . $arrayval . ')';
 404:                     break;
 405: 
 406:                 case 'boolean':
 407:                     if (is_bool($val)) {
 408:                         $value = $val ? 'true' : 'false';
 409:                     } else {
 410:                         $value = ($val == 'on') ? 'true' : 'false';
 411:                     }
 412:                     break;
 413: 
 414:                 case 'stringlist':
 415:                     $values = explode(',', $val);
 416:                     if (!is_array($values)) {
 417:                         $value = "array('" . $this->_quote(trim($values)) . "')";
 418:                     } else {
 419:                         $encvals = array();
 420:                         foreach ($values as $v) {
 421:                             $encvals[] = $this->_quote(trim($v));
 422:                         }
 423:                         $arrayval = "'" . implode('\', \'', $encvals) . "'";
 424:                         if ($arrayval == "''") {
 425:                             $arrayval = '';
 426:                         }
 427:                         $value = 'array(' . $arrayval . ')';
 428:                     }
 429:                     break;
 430: 
 431:                 case 'int':
 432:                     if (strlen($val)) {
 433:                         $value = (int)$val;
 434:                     }
 435:                     break;
 436: 
 437:                 case 'octal':
 438:                     $value = sprintf('0%o', octdec($val));
 439:                     break;
 440: 
 441:                 case 'header':
 442:                 case 'description':
 443:                     break;
 444: 
 445:                 default:
 446:                     if ($val != '') {
 447:                         $value = $val;
 448:                         if ($quote && $value != 'true' && $value != 'false') {
 449:                             $value = "'" . $this->_quote($value) . "'";
 450:                         }
 451:                     }
 452:                     break;
 453:                 }
 454:             } else {
 455:                 $this->_generatePHPConfig($configitem, $prefixedname, $formvars);
 456:             }
 457: 
 458:             if (isset($value)) {
 459:                 $this->_phpConfig .= '$conf[\'' . str_replace('__', '\'][\'', $configname) . '\'] = ' . $value . ";\n";
 460:             }
 461:             unset($value);
 462:         }
 463:     }
 464: 
 465:     /**
 466:      * Parses one level of the configuration XML tree into the associative
 467:      * array containing the traversed configuration tree.
 468:      *
 469:      * @param array &$conf           The already existing array where the
 470:      *                               processed XML tree portion should be
 471:      *                               appended to.
 472:      * @param DOMNodeList $children  The XML nodes of the level that should
 473:      *                               be parsed.
 474:      * @param string $ctx            A string representing the current
 475:      *                               position (context prefix) inside the
 476:      *                               configuration XML file.
 477:      */
 478:     protected function _parseLevel(&$conf, $children, $ctx)
 479:     {
 480:         foreach ($children as $node) {
 481:             if ($node->nodeType != XML_ELEMENT_NODE) {
 482:                 continue;
 483:             }
 484:             $name = $node->getAttribute('name');
 485:             $desc = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($node->getAttribute('desc'), 'linkurls');
 486:             $required = !($node->getAttribute('required') == 'false');
 487:             $quote = !($node->getAttribute('quote') == 'false');
 488: 
 489:             $curctx = empty($ctx)
 490:                 ? $name
 491:                 : $ctx . '|' . $name;
 492: 
 493:             switch ($node->tagName) {
 494:             case 'configdescription':
 495:                 if (empty($name)) {
 496:                     $name = uniqid(mt_rand());
 497:                 }
 498: 
 499:                 $conf[$name] = array(
 500:                     '_type' => 'description',
 501:                     'desc' => $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($this->_default($curctx, $this->_getNodeOnlyText($node)), 'linkurls')
 502:                 );
 503:                 break;
 504: 
 505:             case 'configheader':
 506:                 if (empty($name)) {
 507:                     $name = uniqid(mt_rand());
 508:                 }
 509: 
 510:                 $conf[$name] = array(
 511:                     '_type' => 'header',
 512:                     'desc' => $this->_default($curctx, $this->_getNodeOnlyText($node))
 513:                 );
 514:                 break;
 515: 
 516:             case 'configswitch':
 517:                 $values = $this->_getSwitchValues($node, $ctx);
 518:                 list($default, $isDefault) = $quote
 519:                     ? $this->__default($curctx, $this->_getNodeOnlyText($node))
 520:                     : $this->__defaultRaw($curctx, $this->_getNodeOnlyText($node));
 521: 
 522:                 if ($default === '') {
 523:                     $default = key($values);
 524:                 }
 525: 
 526:                 if (is_bool($default)) {
 527:                     $default = $default ? 'true' : 'false';
 528:                 }
 529: 
 530:                 $conf[$name] = array(
 531:                     'desc' => $desc,
 532:                     'switch' => $values,
 533:                     'default' => $default,
 534:                     'is_default' => $isDefault
 535:                 );
 536:                 break;
 537: 
 538:             case 'configenum':
 539:                 $values = $this->_getEnumValues($node);
 540:                 list($default, $isDefault) = $quote
 541:                     ? $this->__default($curctx, $this->_getNodeOnlyText($node))
 542:                     : $this->__defaultRaw($curctx, $this->_getNodeOnlyText($node));
 543: 
 544:                 if ($default === '') {
 545:                     $default = key($values);
 546:                 }
 547: 
 548:                 if (is_bool($default)) {
 549:                     $default = $default ? 'true' : 'false';
 550:                 }
 551: 
 552:                 $conf[$name] = array(
 553:                     '_type' => 'enum',
 554:                     'required' => $required,
 555:                     'quote' => $quote,
 556:                     'values' => $values,
 557:                     'desc' => $desc,
 558:                     'default' => $default,
 559:                     'is_default' => $isDefault
 560:                 );
 561:                 break;
 562: 
 563:             case 'configlist':
 564:                 list($default, $isDefault) = $this->__default($curctx, null);
 565: 
 566:                 if (is_null($default)) {
 567:                     $default = $this->_getNodeOnlyText($node);
 568:                 } elseif (is_array($default)) {
 569:                     $default = implode(', ', $default);
 570:                 }
 571: 
 572:                 $conf[$name] = array(
 573:                     '_type' => 'stringlist',
 574:                     'required' => $required,
 575:                     'desc' => $desc,
 576:                     'default' => $default,
 577:                     'is_default' => $isDefault
 578:                 );
 579:                 break;
 580: 
 581:             case 'configmultienum':
 582:                 $default = $this->_getNodeOnlyText($node);
 583:                 if (strlen($default)) {
 584:                     $default = explode(',', $default);
 585:                 } else {
 586:                     $default = array();
 587:                 }
 588:                 list($default, $isDefault) = $this->__default($curctx, $default);
 589: 
 590:                 $conf[$name] = array(
 591:                     '_type' => 'multienum',
 592:                     'required' => $required,
 593:                     'values' => $this->_getEnumValues($node),
 594:                     'desc' => $desc,
 595:                     'default' => Horde_Array::valuesToKeys($default),
 596:                     'is_default' => $isDefault
 597:                 );
 598:                 break;
 599: 
 600:             case 'configpassword':
 601:                 $conf[$name] = array(
 602:                     '_type' => 'password',
 603:                     'required' => $required,
 604:                     'desc' => $desc,
 605:                     'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
 606:                     'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
 607:                 );
 608:                 break;
 609: 
 610:             case 'configstring':
 611:                 $conf[$name] = array(
 612:                     '_type' => 'text',
 613:                     'required' => $required,
 614:                     'desc' => $desc,
 615:                     'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
 616:                     'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
 617:                 );
 618: 
 619:                 if ($conf[$name]['default'] === false) {
 620:                     $conf[$name]['default'] = 'false';
 621:                 } elseif ($conf[$name]['default'] === true) {
 622:                     $conf[$name]['default'] = 'true';
 623:                 }
 624:                 break;
 625: 
 626:             case 'configboolean':
 627:                 $default = $this->_getNodeOnlyText($node);
 628:                 $default = !(empty($default) || $default === 'false');
 629: 
 630:                 $conf[$name] = array(
 631:                     '_type' => 'boolean',
 632:                     'required' => $required,
 633:                     'desc' => $desc,
 634:                     'default' => $this->_default($curctx, $default),
 635:                     'is_default' => $this->_isDefault($curctx, $default)
 636:                 );
 637:                 break;
 638: 
 639:             case 'configinteger':
 640:                 $values = $this->_getEnumValues($node);
 641: 
 642:                 $conf[$name] = array(
 643:                     '_type' => 'int',
 644:                     'required' => $required,
 645:                     'values' => $values,
 646:                     'desc' => $desc,
 647:                     'default' => $this->_default($curctx, $this->_getNodeOnlyText($node)),
 648:                     'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
 649:                 );
 650: 
 651:                 if ($node->getAttribute('octal') == 'true' &&
 652:                     $conf[$name]['default'] != '') {
 653:                     $conf[$name]['_type'] = 'octal';
 654:                     $conf[$name]['default'] = sprintf('0%o', $this->_default($curctx, octdec($this->_getNodeOnlyText($node))));
 655:                 }
 656:                 break;
 657: 
 658:             case 'configldap':
 659:                 $conf[$node->getAttribute('switchname')] = $this->_configLDAP($ctx, $node);
 660:                 break;
 661: 
 662:             case 'configphp':
 663:                 $conf[$name] = array(
 664:                     '_type' => 'php',
 665:                     'required' => $required,
 666:                     'quote' => false,
 667:                     'desc' => $desc,
 668:                     'default' => $this->_defaultRaw($curctx, $this->_getNodeOnlyText($node)),
 669:                     'is_default' => $this->_isDefaultRaw($curctx, $this->_getNodeOnlyText($node))
 670:                 );
 671:                 break;
 672: 
 673:             case 'configsecret':
 674:                 $conf[$name] = array(
 675:                     '_type' => 'text',
 676:                     'required' => true,
 677:                     'desc' => $desc,
 678:                     'default' => $this->_default($curctx, strval(new Horde_Support_Uuid())),
 679:                     'is_default' => $this->_isDefault($curctx, $this->_getNodeOnlyText($node))
 680:                 );
 681:                 break;
 682: 
 683:             case 'configsql':
 684:                 $conf[$node->getAttribute('switchname')] = $this->configSQL($ctx, $node);
 685:                 break;
 686: 
 687:             case 'configvfs':
 688:                 $conf[$node->getAttribute('switchname')] = $this->_configVFS($ctx, $node);
 689:                 break;
 690: 
 691:             case 'configsection':
 692:                 $conf[$name] = array();
 693:                 $cur = &$conf[$name];
 694:                 if ($node->hasChildNodes()) {
 695:                     $this->_parseLevel($cur, $node->childNodes, $curctx);
 696:                 }
 697:                 break;
 698: 
 699:             case 'configtab':
 700:                 $key = uniqid(mt_rand());
 701: 
 702:                 $conf[$key] = array(
 703:                     'tab' => $name,
 704:                     'desc' => $desc
 705:                 );
 706: 
 707:                 if ($node->hasChildNodes()) {
 708:                     $this->_parseLevel($conf, $node->childNodes, $ctx);
 709:                 }
 710:                 break;
 711: 
 712:             case 'configplaceholder':
 713:                 $conf[uniqid(mt_rand())] = 'placeholder';
 714:                 break;
 715: 
 716:             default:
 717:                 $conf[$name] = array();
 718:                 $cur = &$conf[$name];
 719:                 if ($node->hasChildNodes()) {
 720:                     $this->_parseLevel($cur, $node->childNodes, $curctx);
 721:                 }
 722:                 break;
 723:             }
 724:         }
 725:     }
 726: 
 727:     /**
 728:      * Returns the configuration tree for an LDAP backend configuration to
 729:      * replace a <configldap> tag.
 730:      * Subnodes will be parsed and added to both the Horde defaults and the
 731:      * Custom configuration parts.
 732:      *
 733:      * @param string $ctx         The context of the <configldap> tag.
 734:      * @param DomNode $node       The DomNode representation of the
 735:      *                            <configldap> tag.
 736:      * @param string $switchname  If DomNode is not set, the value of the
 737:      *                            tag's switchname attribute.
 738:      *
 739:      * @return array  An associative array with the LDAP configuration tree.
 740:      */
 741:     protected function _configLDAP($ctx, $node = null,
 742:                                    $switchname = 'driverconfig')
 743:     {
 744:         $fields = array(
 745:             'hostspec' => array(
 746:                 '_type' => 'text',
 747:                 'required' => true,
 748:                 'desc' => 'LDAP server/hostname',
 749:                 'default' => $this->_default($ctx . '|hostspec', '')
 750:             ),
 751: 
 752:             'port' => array(
 753:                 '_type' => 'int',
 754:                 'required' => false,
 755:                 'desc' => 'Port on which LDAP is listening, if non-standard',
 756:                 'default' => $this->_default($ctx . '|port', null)
 757:             ),
 758: 
 759:             'tls' => array(
 760:                 '_type' => 'boolean',
 761:                 'required' => false,
 762:                 'desc' => 'Use TLS to connect to the server?',
 763:                 'default' => $this->_default($ctx . '|tls', false)
 764:             ),
 765: 
 766:             'version' => array(
 767:                 '_type' => 'int',
 768:                 'required' => true,
 769:                 'quote' => false,
 770:                 'desc' => 'LDAP protocol version',
 771:                 'switch' => array(
 772:                     '2' => array(
 773:                         'desc' => '2 (deprecated)',
 774:                         'fields' => array()
 775:                     ),
 776:                     '3' => array(
 777:                         'desc' => '3',
 778:                         'fields' => array()
 779:                     )
 780:                 ),
 781:                 'default' => $this->_default($ctx . '|version', 3)
 782:             ),
 783: 
 784:             'bindas' => array(
 785:                 'desc' => 'Bind to LDAP as which user?',
 786:                 'default' => $this->_default($ctx . '|bindas', 'admin'),
 787:                 'switch' => array(
 788:                     'anon' => array(
 789:                         'desc' => 'Bind anonymously',
 790:                         'fields' => array()
 791:                     ),
 792:                     'user' => array(
 793:                         'desc' => 'Bind as the currently logged-in user',
 794:                         'fields' => array(
 795:                             'user' => array(
 796:                                 'binddn' => array(
 797:                                     '_type' => 'text',
 798:                                     'required' => false,
 799:                                     'desc' => 'DN used to bind for searching the user\'s DN (leave empty for anonymous bind)',
 800:                                     'default' => $this->_default($ctx . '|binddn', '')
 801:                                 ),
 802:                                 'bindpw' => array(
 803:                                     '_type' => 'text',
 804:                                     'required' => false,
 805:                                     'desc' => 'Password for bind DN',
 806:                                     'default' => $this->_default($ctx . '|bindpw', '')
 807:                                 ),
 808:                                 'uid' => array(
 809:                                     '_type' => 'text',
 810:                                     'required' => true,
 811:                                     'desc' => 'The username search key (set to samaccountname for AD).',
 812:                                     'default' => $this->_default($ctx . '|user|uid', 'uid')
 813:                                 ),
 814:                                 'filter_type' => array(
 815:                                     'required' => false,
 816:                                     'desc' => 'How to specify a filter for the user lists.',
 817:                                     'default' => $this->_default($ctx . '|user|filter_type', 'objectclass'),
 818:                                     'switch' => array(
 819:                                         'filter' => array(
 820:                                             'desc' => 'LDAP filter string',
 821:                                             'fields' => array(
 822:                                                 'filter' => array(
 823:                                                     '_type' => 'text',
 824:                                                     'required' => true,
 825:                                                     'desc' => 'The LDAP filter string used to search for users.',
 826:                                                     'default' => $this->_default($ctx . '|user|filter', '(objectClass=*)')
 827:                                                 ),
 828:                                             ),
 829:                                         ),
 830:                                         'objectclass' => array(
 831:                                             'desc' => 'List of objectClasses',
 832:                                             'fields' => array(
 833:                                                 'objectclass' => array(
 834:                                                     '_type' => 'stringlist',
 835:                                                     'required' => true,
 836:                                                     'desc' => 'The objectclass filter used to search for users. Can be a single objectclass or a comma-separated list.',
 837:                                                     'default' => implode(', ', $this->_default($ctx . '|user|objectclass', array('*')))
 838:                                                 ),
 839:                                             ),
 840:                                         ),
 841:                                     ),
 842:                                 ),
 843:                             ),
 844:                         ),
 845:                     ),
 846:                     'admin' => array(
 847:                         'desc' => 'Bind with administrative/system credentials',
 848:                         'fields' => array(
 849:                             'binddn' => array(
 850:                                 '_type' => 'text',
 851:                                 'required' => true,
 852:                                 'desc' => 'DN used to bind to LDAP',
 853:                                 'default' => $this->_default($ctx . '|binddn', '')
 854:                             ),
 855:                             'bindpw' => array(
 856:                                 '_type' => 'text',
 857:                                 'required' => true,
 858:                                 'desc' => 'Password for bind DN',
 859:                                 'default' => $this->_default($ctx . '|bindpw', '')
 860:                             )
 861:                         )
 862:                     ),
 863:                 )
 864:             ),
 865:         );
 866: 
 867:         if (isset($node) && $node->getAttribute('excludebind')) {
 868:             $excludes = explode(',', $node->getAttribute('excludebind'));
 869:             foreach ($excludes as $exclude) {
 870:                 unset($fields['bindas']['switch'][$exclude]);
 871:             }
 872:         }
 873: 
 874:         if (isset($node) && $node->getAttribute('baseconfig') == 'true') {
 875:             return array(
 876:                 'desc' => 'Use LDAP?',
 877:                 'default' => $this->_default($ctx . '|' . $node->getAttribute('switchname'), false),
 878:                 'switch' => array(
 879:                     'false' => array(
 880:                         'desc' => 'No',
 881:                         'fields' => array()
 882:                     ),
 883:                     'true' => array(
 884:                         'desc' => 'Yes',
 885:                         'fields' => $fields
 886:                     ),
 887:                 )
 888:             );
 889:         }
 890: 
 891:         $standardFields = array(
 892:             'basedn' => array(
 893:                 '_type' => 'text',
 894:                 'required' => true,
 895:                 'desc' => 'Base DN',
 896:                 'default' => $this->_default($ctx . '|basedn', '')
 897:             ),
 898:             'scope' => array(
 899:                 '_type' => 'enum',
 900:                 'required' => true,
 901:                 'desc' => 'Search scope',
 902:                 'default' => $this->_default($ctx . '|scope', ''),
 903:                 'values' => array(
 904:                     'sub' => 'Subtree search',
 905:                     'one' => 'One level'),
 906:             ),
 907:         );
 908: 
 909:         list($default, $isDefault) = $this->__default($ctx . '|' . (isset($node) ? $node->getAttribute('switchname') : $switchname), 'horde');
 910:         $config = array(
 911:             'desc' => 'Driver configuration',
 912:             'default' => $default,
 913:             'is_default' => $isDefault,
 914:             'switch' => array(
 915:                 'horde' => array(
 916:                     'desc' => 'Horde defaults',
 917:                     'fields' => $standardFields,
 918:                 ),
 919:                 'custom' => array(
 920:                     'desc' => 'Custom parameters',
 921:                     'fields' => $fields + $standardFields,
 922:                 )
 923:             )
 924:         );
 925: 
 926:         if (isset($node) && $node->hasChildNodes()) {
 927:             $cur = array();
 928:             $this->_parseLevel($cur, $node->childNodes, $ctx);
 929:             $config['switch']['horde']['fields'] = array_merge($config['switch']['horde']['fields'], $cur);
 930:             $config['switch']['custom']['fields'] = array_merge($config['switch']['custom']['fields'], $cur);
 931:         }
 932: 
 933:         return $config;
 934:     }
 935: 
 936:     /**
 937:      * Returns the configuration tree for an SQL backend configuration to
 938:      * replace a <configsql> tag.
 939:      * Subnodes will be parsed and added to both the Horde defaults and the
 940:      * Custom configuration parts.
 941:      *
 942:      * @param string $ctx         The context of the <configsql> tag.
 943:      * @param DomNode $node       The DomNode representation of the <configsql>
 944:      *                            tag.
 945:      * @param string $switchname  If DomNode is not set, the value of the
 946:      *                            tag's switchname attribute.
 947:      *
 948:      * @return array  An associative array with the SQL configuration tree.
 949:      */
 950:     public function configSQL($ctx, $node = null, $switchname = 'driverconfig')
 951:     {
 952:         $persistent = array(
 953:             '_type' => 'boolean',
 954:             'required' => false,
 955:             'desc' => 'Request persistent connections?',
 956:             'default' => $this->_default($ctx . '|persistent', false)
 957:         );
 958: 
 959:         $hostspec = array(
 960:             '_type' => 'text',
 961:             'required' => true,
 962:             'desc' => 'Database server/host',
 963:             'default' => $this->_default($ctx . '|hostspec', '')
 964:         );
 965: 
 966:         $username = array(
 967:             '_type' => 'text',
 968:             'required' => true,
 969:             'desc' => 'Username to connect to the database as',
 970:             'default' => $this->_default($ctx . '|username', '')
 971:         );
 972: 
 973:         $password = array(
 974:             '_type' => 'text',
 975:             'required' => false,
 976:             'desc' => 'Password to connect with',
 977:             'default' => $this->_default($ctx . '|password', '')
 978:         );
 979: 
 980:         $database = array(
 981:             '_type' => 'text',
 982:             'required' => true,
 983:             'desc' => 'Database name to use',
 984:             'default' => $this->_default($ctx . '|database', '')
 985:         );
 986: 
 987:         $socket = array(
 988:             '_type' => 'text',
 989:             'required' => false,
 990:             'desc' => 'Location of UNIX socket',
 991:             'default' => $this->_default($ctx . '|socket', '')
 992:         );
 993: 
 994:         $port = array(
 995:             '_type' => 'int',
 996:             'required' => false,
 997:             'desc' => 'Port the DB is running on, if non-standard',
 998:             'default' => $this->_default($ctx . '|port', null)
 999:         );
1000: 
1001:         $protocol = array(
1002:             'desc' => 'How should we connect to the database?',
1003:             'default' => $this->_default($ctx . '|protocol', 'unix'),
1004:             'switch' => array(
1005:                 'unix' => array(
1006:                     'desc' => 'UNIX Sockets',
1007:                     'fields' => array(
1008:                         'socket' => $socket
1009:                     )
1010:                 ),
1011:                 'tcp' => array(
1012:                     'desc' => 'TCP/IP',
1013:                     'fields' => array(
1014:                         'hostspec' => $hostspec,
1015:                         'port' => $port
1016:                     )
1017:                 )
1018:             )
1019:         );
1020: 
1021:         $mysql_protocol = $protocol;
1022:         $mysql_protocol['switch']['tcp']['fields']['port']['default'] = $this->_default($ctx . '|port', 3306);
1023: 
1024:         $charset = array(
1025:             '_type' => 'text',
1026:             'required' => true,
1027:             'desc' => 'Internally used charset',
1028:             'default' => $this->_default($ctx . '|charset', 'utf-8')
1029:         );
1030: 
1031:         $ssl = array(
1032:             '_type' => 'boolean',
1033:             'required' => false,
1034:             'desc' => 'Use SSL to connect to the server?',
1035:             'default' => $this->_default($ctx . '|ssl', false)
1036:         );
1037: 
1038:         $ca = array(
1039:             '_type' => 'text',
1040:             'required' => false,
1041:             'desc' => 'Certification Authority to use for SSL connections',
1042:             'default' => $this->_default($ctx . '|ca', '')
1043:         );
1044: 
1045:         $read_hostspec = array(
1046:             '_type' => 'text',
1047:             'required' => true,
1048:             'desc' => 'Read database server/host',
1049:             'default' => $this->_default($ctx . '|read|hostspec', '')
1050:         );
1051: 
1052:         $read_port = array(
1053:             '_type' => 'int',
1054:             'required' => false,
1055:             'desc' => 'Port the read DB is running on, if non-standard',
1056:             'default' => $this->_default($ctx . '|read|port', null)
1057:         );
1058: 
1059:         $splitread = array(
1060:             '_type' => 'boolean',
1061:             'required' => false,
1062:             'desc' => 'Split reads to a different server?',
1063:             'default' => $this->_default($ctx . '|splitread', 'false'),
1064:             'switch' => array(
1065:                 'false' => array(
1066:                     'desc' => 'Disabled',
1067:                     'fields' => array()
1068:                 ),
1069:                 'true' => array(
1070:                     'desc' => 'Enabled',
1071:                     'fields' => array(
1072:                         'read' => array(
1073:                             'persistent' => $persistent,
1074:                             'username' => $username,
1075:                             'password' => $password,
1076:                             'protocol' => $protocol,
1077:                             'database' => $database,
1078:                             'charset' => $charset
1079:                         )
1080:                     )
1081:                 )
1082:             )
1083:         );
1084: 
1085:         $custom_fields = array(
1086:             'required' => true,
1087:             'desc' => 'What database backend should we use?',
1088:             'default' => $this->_default($ctx . '|phptype', ''),
1089:             'switch' => array(
1090:                 'false' => array(
1091:                     'desc' => '[None]',
1092:                     'fields' => array()
1093:                 ),
1094:                 'mysql' => array(
1095:                     'desc' => 'MySQL / PDO',
1096:                     'fields' => array(
1097:                         'persistent' => $persistent,
1098:                         'username' => $username,
1099:                         'password' => $password,
1100:                         'protocol' => $mysql_protocol,
1101:                         'database' => $database,
1102:                         'charset' => $charset,
1103:                         'ssl' => $ssl,
1104:                         'ca' => $ca,
1105:                         'splitread' => Horde_Array::replaceRecursive(
1106:                             $splitread,
1107:                             array(
1108:                                 'switch' => array(
1109:                                     'true' => array(
1110:                                         'fields' => array(
1111:                                             'read' => array(
1112:                                                 'protocol' => $mysql_protocol,
1113:                                             )
1114:                                         )
1115:                                     )
1116:                                 )
1117:                             )
1118:                         )
1119:                     )
1120:                 ),
1121:                 'mysqli' => array(
1122:                     'desc' => 'MySQL (mysqli)',
1123:                     'fields' => array(
1124:                         'username' => $username,
1125:                         'password' => $password,
1126:                         'protocol' => $mysql_protocol,
1127:                         'database' => $database,
1128:                         'charset' => $charset,
1129:                         'ssl' => $ssl,
1130:                         'ca' => $ca,
1131:                         'splitread' => Horde_Array::replaceRecursive(
1132:                             $splitread,
1133:                             array(
1134:                                 'switch' => array(
1135:                                     'true' => array(
1136:                                         'fields' => array(
1137:                                             'read' => array(
1138:                                                 'protocol' => $mysql_protocol,
1139:                                             )
1140:                                         )
1141:                                     )
1142:                                 )
1143:                             )
1144:                         )
1145:                     )
1146:                 ),
1147:                 'pgsql' => array(
1148:                     'desc' => 'PostgreSQL',
1149:                     'fields' => array(
1150:                         'persistent' => $persistent,
1151:                         'username' => $username,
1152:                         'password' => $password,
1153:                         'protocol' => $protocol,
1154:                         'database' => $database,
1155:                         'charset' => $charset,
1156:                         'splitread' => $splitread,
1157:                     )
1158:                 ),
1159:                 'sqlite' => array(
1160:                     'desc' => 'SQLite',
1161:                     'fields' => array(
1162:                         'database' => array(
1163:                             '_type' => 'text',
1164:                             'required' => true,
1165:                             'desc' => 'Absolute path to the database file',
1166:                             'default' => $this->_default($ctx . '|database', '')
1167:                         ),
1168:                         'charset' => $charset
1169:                     )
1170:                 )
1171:             )
1172:         );
1173: 
1174:         if (isset($node) && $node->getAttribute('baseconfig') == 'true') {
1175:             return $custom_fields;
1176:         }
1177: 
1178:         list($default, $isDefault) = $this->__default($ctx . '|' . (isset($node) ? $node->getAttribute('switchname') : $switchname), 'horde');
1179:         $config = array(
1180:             'desc' => 'Driver configuration',
1181:             'default' => $default,
1182:             'is_default' => $isDefault,
1183:             'switch' => array(
1184:                 'horde' => array(
1185:                     'desc' => 'Horde defaults',
1186:                     'fields' => array()
1187:                 ),
1188:                 'custom' => array(
1189:                     'desc' => 'Custom parameters',
1190:                     'fields' => array(
1191:                         'phptype' => $custom_fields
1192:                     )
1193:                 )
1194:             )
1195:         );
1196: 
1197:         if (isset($node) && $node->hasChildNodes()) {
1198:             $cur = array();
1199:             $this->_parseLevel($cur, $node->childNodes, $ctx);
1200:             $config['switch']['horde']['fields'] = array_merge($config['switch']['horde']['fields'], $cur);
1201:             $config['switch']['custom']['fields'] = array_merge($config['switch']['custom']['fields'], $cur);
1202:         }
1203: 
1204:         return $config;
1205:     }
1206: 
1207:     /**
1208:      * Returns the configuration tree for a VFS backend configuration to
1209:      * replace a <configvfs> tag.
1210:      * Subnodes will be parsed and added to both the Horde defaults and the
1211:      * Custom configuration parts.
1212:      *
1213:      * @param string $ctx    The context of the <configvfs> tag.
1214:      * @param DomNode $node  The DomNode representation of the <configvfs>
1215:      *                       tag.
1216:      *
1217:      * @return array  An associative array with the VFS configuration tree.
1218:      */
1219:     protected function _configVFS($ctx, $node)
1220:     {
1221:         $sql = $this->configSQL($ctx . '|params');
1222:         $default = $node->getAttribute('default');
1223:         $default = empty($default) ? 'horde' : $default;
1224:         list($default, $isDefault) = $this->__default($ctx . '|' . $node->getAttribute('switchname'), $default);
1225: 
1226:         $config = array(
1227:             'desc' => 'What VFS driver should we use?',
1228:             'default' => $default,
1229:             'is_default' => $isDefault,
1230:             'switch' => array(
1231:                 'File' => array(
1232:                     'desc' => 'Files on the local system',
1233:                     'fields' => array(
1234:                         'params' => array(
1235:                             'vfsroot' => array(
1236:                                 '_type' => 'text',
1237:                                 'desc' => 'Where on the real filesystem should Horde use as root of the virtual filesystem?',
1238:                                 'default' => $this->_default($ctx . '|params|vfsroot', '/tmp')
1239:                             )
1240:                         )
1241:                     )
1242:                 ),
1243:                 'Sql' => array(
1244:                     'desc' => 'SQL database',
1245:                     'fields' => array(
1246:                         'params' => array(
1247:                             'driverconfig' => $sql
1248:                         )
1249:                     )
1250:                 ),
1251:                 'Ssh2' => array(
1252:                     'desc' => 'SSH2 (SFTP)',
1253:                     'fields' => array(
1254:                         'params' => array(
1255:                             'hostspec' => array(
1256:                                 '_type' => 'text',
1257:                                 'required' => true,
1258:                                 'desc' => 'SSH server/host',
1259:                                 'default' => $this->_default($ctx . '|hostspec', '')
1260:                             ),
1261:                             'port' => array(
1262:                                 '_type' => 'text',
1263:                                 'required' => false,
1264:                                 'desc' => 'Port number on which SSH listens',
1265:                                 'default' => $this->_default($ctx . '|port', '22')
1266:                             ),
1267:                             'username' => array(
1268:                                 '_type' => 'text',
1269:                                 'required' => true,
1270:                                 'desc' => 'Username to connect to the SSH server',
1271:                                 'default' => $this->_default($ctx . '|username', '')
1272:                             ),
1273:                             'password' => array(
1274:                                 '_type' => 'text',
1275:                                 'required' => true,
1276:                                 'desc' => 'Password with which to connect',
1277:                                 'default' => $this->_default($ctx . '|password', '')
1278:                             ),
1279:                             'vfsroot' => array(
1280:                                 '_type' => 'text',
1281:                                 'desc' => 'Where on the real filesystem should Horde use as root of the virtual filesystem?',
1282:                                 'default' => $this->_default($ctx . '|vfsroot', '/tmp')
1283:                             )
1284:                         )
1285:                     )
1286:                 )
1287:             )
1288:         );
1289: 
1290:         if (isset($node) && $node->getAttribute('baseconfig') != 'true') {
1291:             $config['switch']['horde'] = array(
1292:                 'desc' => 'Horde defaults',
1293:                 'fields' => array()
1294:             );
1295:         }
1296:         $cases = $this->_getSwitchValues($node, $ctx . '|params');
1297:         foreach ($cases as $case => $fields) {
1298:             if (isset($config['switch'][$case])) {
1299:                 $config['switch'][$case]['fields']['params'] = array_merge($config['switch'][$case]['fields']['params'], $fields['fields']);
1300:             }
1301:         }
1302: 
1303:         return $config;
1304:     }
1305: 
1306:     /**
1307:      * Returns a certain value from the current configuration array or
1308:      * a default value, if not found.
1309:      *
1310:      * @param string $ctx     A string representing the key of the
1311:      *                        configuration array to return.
1312:      * @param mixed $default  The default value to return if the key wasn't
1313:      *                        found.
1314:      *
1315:      * @return mixed  Either the value of the configuration array's requested
1316:      *                key or the default value if the key wasn't found.
1317:      */
1318:     protected function _default($ctx, $default)
1319:     {
1320:         list ($ptr,) = $this->__default($ctx, $default);
1321:         return $ptr;
1322:     }
1323: 
1324:     /**
1325:      * Returns whether a certain value from the current configuration array
1326:      * exists or a default value will be used.
1327:      *
1328:      * @param string $ctx     A string representing the key of the
1329:      *                        configuration array to return.
1330:      * @param mixed $default  The default value to return if the key wasn't
1331:      *                        found.
1332:      *
1333:      * @return boolean  Whether the default value will be used.
1334:      */
1335:     protected function _isDefault($ctx, $default)
1336:     {
1337:         list (,$isDefault) = $this->__default($ctx, $default);
1338:         return $isDefault;
1339:     }
1340: 
1341:     /**
1342:      * Returns a certain value from the current configuration array or a
1343:      * default value, if not found, and which of the values have been
1344:      * returned.
1345:      *
1346:      * @param string $ctx     A string representing the key of the
1347:      *                        configuration array to return.
1348:      * @param mixed $default  The default value to return if the key wasn't
1349:      *                        found.
1350:      *
1351:      * @return array  First element: either the value of the configuration
1352:      *                array's requested key or the default value if the key
1353:      *                wasn't found.
1354:      *                Second element: whether the returned value was the
1355:      *                default value.
1356:      */
1357:     protected function __default($ctx, $default)
1358:     {
1359:         $ctx = explode('|', $ctx);
1360:         $ptr = $this->_currentConfig;
1361: 
1362:         for ($i = 0, $ctx_count = count($ctx); $i < $ctx_count; ++$i) {
1363:             if (!isset($ptr[$ctx[$i]])) {
1364:                 return array($default, true);
1365:             }
1366: 
1367:             $ptr = $ptr[$ctx[$i]];
1368:         }
1369: 
1370:         return array($ptr, false);
1371:     }
1372: 
1373:     /**
1374:      * Returns a certain value from the current configuration file or
1375:      * a default value, if not found.
1376:      * It does NOT return the actual value, but the PHP expression as used
1377:      * in the configuration file.
1378:      *
1379:      * @param string $ctx     A string representing the key of the
1380:      *                        configuration array to return.
1381:      * @param mixed $default  The default value to return if the key wasn't
1382:      *                        found.
1383:      *
1384:      * @return mixed  Either the value of the configuration file's requested
1385:      *                key or the default value if the key wasn't found.
1386:      */
1387:     protected function _defaultRaw($ctx, $default)
1388:     {
1389:         list ($ptr,) = $this->__defaultRaw($ctx, $default);
1390:         return $ptr;
1391:     }
1392: 
1393:     /**
1394:      * Returns whether a certain value from the current configuration array
1395:      * exists or a default value will be used.
1396:      *
1397:      * @param string $ctx     A string representing the key of the
1398:      *                        configuration array to return.
1399:      * @param mixed $default  The default value to return if the key wasn't
1400:      *                        found.
1401:      *
1402:      * @return boolean  Whether the default value will be used.
1403:      */
1404:     protected function _isDefaultRaw($ctx, $default)
1405:     {
1406:         list (,$isDefault) = $this->__defaultRaw($ctx, $default);
1407:         return $isDefault;
1408:     }
1409: 
1410:     /**
1411:      * Returns a certain value from the current configuration file or
1412:      * a default value, if not found, and which of the values have been
1413:      * returned.
1414:      *
1415:      * It does NOT return the actual value, but the PHP expression as used
1416:      * in the configuration file.
1417:      *
1418:      * @param string $ctx     A string representing the key of the
1419:      *                        configuration array to return.
1420:      * @param mixed $default  The default value to return if the key wasn't
1421:      *                        found.
1422:      *
1423:      * @return array  First element: either the value of the configuration
1424:      *                array's requested key or the default value if the key
1425:      *                wasn't found.
1426:      *                Second element: whether the returned value was the
1427:      *                default value.
1428:      */
1429:     protected function __defaultRaw($ctx, $default)
1430:     {
1431:         $ctx = explode('|', $ctx);
1432:         $pattern = '/^\$conf\[\'' . implode("'\]\['", $ctx) . '\'\] = (.*);\r?$/m';
1433: 
1434:         return preg_match($pattern, $this->getPHPConfig(), $matches)
1435:             ? array($matches[1], false)
1436:             : array($default, true);
1437:     }
1438: 
1439:     /**
1440:      * Returns the content of all text node children of the specified node.
1441:      *
1442:      * @param DomNode $node  A DomNode object whose text node children to
1443:      *                       return.
1444:      *
1445:      * @return string  The concatenated values of all text nodes.
1446:      */
1447:     protected function _getNodeOnlyText($node)
1448:     {
1449:         $text = '';
1450: 
1451:         if (!$node->hasChildNodes()) {
1452:             return $node->textContent;
1453:         }
1454: 
1455:         foreach ($node->childNodes as $tnode) {
1456:             if ($tnode->nodeType == XML_TEXT_NODE) {
1457:                 $text .= $tnode->textContent;
1458:             }
1459:         }
1460: 
1461:         return trim($text);
1462:     }
1463: 
1464:     /**
1465:      * Returns an associative array containing all possible values of the
1466:      * specified <configenum> tag.
1467:      *
1468:      * The keys contain the actual enum values while the values contain their
1469:      * corresponding descriptions.
1470:      *
1471:      * @param DomNode $node  The DomNode representation of the <configenum>
1472:      *                       tag whose values should be returned.
1473:      *
1474:      * @return array  An associative array with all possible enum values.
1475:      */
1476:     protected function _getEnumValues($node)
1477:     {
1478:         $values = array();
1479: 
1480:         if (!$node->hasChildNodes()) {
1481:             return $values;
1482:         }
1483: 
1484:         foreach ($node->childNodes as $vnode) {
1485:             if ($vnode->nodeType == XML_ELEMENT_NODE &&
1486:                 $vnode->tagName == 'values') {
1487:                 if (!$vnode->hasChildNodes()) {
1488:                     return array();
1489:                 }
1490: 
1491:                 foreach ($vnode->childNodes as $value) {
1492:                     if ($value->nodeType == XML_ELEMENT_NODE) {
1493:                         if ($value->tagName == 'configspecial') {
1494:                             return $this->_handleSpecials($value);
1495:                         }
1496:                         if ($value->tagName == 'value') {
1497:                             $text = $value->textContent;
1498:                             $desc = $value->getAttribute('desc');
1499:                             $values[$text] = empty($desc) ? $text : $desc;
1500:                         }
1501:                     }
1502:                 }
1503:             }
1504:         }
1505: 
1506:         return $values;
1507:     }
1508: 
1509:     /**
1510:      * Returns a multidimensional associative array representing the specified
1511:      * <configswitch> tag.
1512:      *
1513:      * @param DomNode &$node  The DomNode representation of the <configswitch>
1514:      *                        tag to process.
1515:      *
1516:      * @return array  An associative array representing the node.
1517:      */
1518:     protected function _getSwitchValues(&$node, $curctx)
1519:     {
1520:         $values = array();
1521: 
1522:         if (!$node->hasChildNodes()) {
1523:             return $values;
1524:         }
1525: 
1526:         foreach ($node->childNodes as $case) {
1527:             if ($case->nodeType == XML_ELEMENT_NODE) {
1528:                 $name = $case->getAttribute('name');
1529:                 $values[$name] = array(
1530:                     'desc' => $case->getAttribute('desc'),
1531:                     'fields' => array()
1532:                 );
1533:                 if ($case->hasChildNodes()) {
1534:                     $this->_parseLevel($values[$name]['fields'], $case->childNodes, $curctx);
1535:                 }
1536:             }
1537:         }
1538: 
1539:         return $values;
1540:     }
1541: 
1542:     /**
1543:      * Returns an associative array containing the possible values of a
1544:      * <configspecial> tag as used inside of enum configurations.
1545:      *
1546:      * @param DomNode $node  The DomNode representation of the <configspecial>
1547:      *                       tag.
1548:      *
1549:      * @return array  An associative array with the possible values.
1550:      */
1551:     protected function _handleSpecials($node)
1552:     {
1553:         $app = $node->getAttribute('application');
1554:         if (!in_array($app, $GLOBALS['registry']->listApps())) {
1555:             $app = $GLOBALS['registry']->hasInterface($app);
1556:         }
1557:         if (!$app) {
1558:             return array();
1559:         }
1560:         return $GLOBALS['registry']->callAppMethod($app, 'configSpecialValues', array('args' => array($node->getAttribute('name')), 'noperms' => true));
1561:     }
1562: 
1563:     /**
1564:      * Returns the specified string with escaped single quotes
1565:      *
1566:      * @param string $string  A string to escape.
1567:      *
1568:      * @return string  The specified string with single quotes being escaped.
1569:      */
1570:     protected function _quote($string)
1571:     {
1572:         return str_replace("'", "\'", $string);
1573:     }
1574: 
1575: }
1576: 
API documentation generated by ApiGen