diff --git a/.gitattributes b/.gitattributes index e4504cf21..35002d0cb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,5 @@ +# Exclude files related to git when generating an archive .git* export-ignore + +# Normalize puppet manifests' line endings to LF on checkin and prevent conversion to CRLF when the files are checked out +.vagrant-puppet/* eol=lf diff --git a/.gitignore b/.gitignore index 55580cae9..3cc377b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,14 @@ # Exclude all hidden files .* -# But not .gitignore, .gitattributes, .vagrant-puppet, .htaccess and .gitkeep -!.gitignore -!.gitattributes -!.vagrant-puppet -!public/.htaccess -!packages/rhel/usr/share/icingaweb/public/.htaccess -!public/.htaccess.in -!.gitkeep -build/ +# Except those related to git and vagrant +!.git* +!.vagrant-puppet/* -development/ +# Exclude application log files +var/log/* -# ./configure output -config.log -autom4te.cache -autoscan* -config.status -Makefile - -# cmd tester -modules/test/bin/extcmd_test - -# misc test output -test/php/library/Icinga/Protocol/Statusdat/.cache - -# Generated API documentation -doc/api - -# Enabled modules -config/enabledModules/ - -# User preferences -config/preferences/*.ini - -# Application logfiles -var/log/*.log - -# Packaging +# Exclude symlink you need for packaging /debian -*.tar.gz -*.komodoproject - +build/* diff --git a/.vagrant-puppet/.gitattributes b/.vagrant-puppet/.gitattributes deleted file mode 100644 index af67531d8..000000000 --- a/.vagrant-puppet/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* -crlf diff --git a/.vagrant-puppet/files/etc/icinga2/conf.d/test-config.conf b/.vagrant-puppet/files/etc/icinga2/conf.d/test-config.conf index f25df325b..560fc6a1c 100644 --- a/.vagrant-puppet/files/etc/icinga2/conf.d/test-config.conf +++ b/.vagrant-puppet/files/etc/icinga2/conf.d/test-config.conf @@ -76,7 +76,7 @@ __function createService(service_type, num) { enable_active_checks = (service_type != "pending") vars.check_type = service_type - assign where match("*" + service_type + "*", host.vars.check_config) + assign where service_type in host.vars.check_config } } @@ -102,12 +102,12 @@ __function createHost(checkType, checkConfig, num, checkEnabled) { } __for (num in range(10)) { - createHost("ok", "ok", num, true) - createHost("random", "random,flapping", num, true) - createHost("down", "warning,critical", num, true) - createHost("unreachable", "unknown", num, true) - createHost("pending", "pending", num, false) - createHost("flap", "flapping", num, true) + createHost("ok", [ "ok" ], num, true) + createHost("random", [ "random", "flapping" ], num, true) + createHost("down", [ "warning", "critical" ], num, true) + createHost("unreachable", [ "unknown" ], num, true) + createHost("pending", [ "pending" ], num, false) + createHost("flap", [ "flapping" ], num, true) } // EOF diff --git a/.vagrant-puppet/manifests/default.pp b/.vagrant-puppet/manifests/default.pp index 39b0d967c..c728d80ec 100644 --- a/.vagrant-puppet/manifests/default.pp +++ b/.vagrant-puppet/manifests/default.pp @@ -601,27 +601,15 @@ exec { 'create-pgsql-icingaweb-db': require => Service['postgresql'] } -exec { 'populate-icingaweb-mysql-db-accounts': - unless => 'mysql -uicingaweb -picingaweb icingaweb -e "SELECT * FROM account;" &> /dev/null', - command => 'mysql -uicingaweb -picingaweb icingaweb < /vagrant/etc/schema/accounts.mysql.sql', +exec { 'populate-icingaweb-mysql-db-tables': + unless => 'mysql -uicingaweb -picingaweb icingaweb -e "SELECT * FROM icingaweb_group;" &> /dev/null', + command => 'mysql -uicingaweb -picingaweb icingaweb < /vagrant/etc/schema/mysql.schema.sql', require => [ Exec['create-mysql-icingaweb-db'] ] } -exec { 'populate-icingweba-pgsql-db-accounts': - unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM account;" &> /dev/null', - command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/accounts.pgsql.sql', - require => [ Exec['create-pgsql-icingaweb-db'] ] -} - -exec { 'populate-icingaweb-mysql-db-preferences': - unless => 'mysql -uicingaweb -picingaweb icingaweb -e "SELECT * FROM preference;" &> /dev/null', - command => 'mysql -uicingaweb -picingaweb icingaweb < /vagrant/etc/schema/preferences.mysql.sql', - require => [ Exec['create-mysql-icingaweb-db'] ] -} - -exec { 'populate-icingweba-pgsql-db-preferences': - unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM preference;" &> /dev/null', - command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/preferences.pgsql.sql', +exec { 'populate-icingweba-pgsql-db-tables': + unless => 'psql -U icingaweb -d icingaweb -c "SELECT * FROM icingaweb_group;" &> /dev/null', + command => 'sudo -u postgres psql -U icingaweb -d icingaweb -f /vagrant/etc/schema/pgsql.schema.sql', require => [ Exec['create-pgsql-icingaweb-db'] ] } diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index d97040cc3..000000000 --- a/Makefile.in +++ /dev/null @@ -1,158 +0,0 @@ -SHELL=/bin/sh - -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -bindir=@bindir@ - -HTTPD_CONFIG_PATH=@httpd_config_path@ -ICINGAWEB_CONFIG_PATH=@icingaweb_config_path@ -ICINGAWEB_LOG_PATH=@icingaweb_log_path@ - -INSTALL=@INSTALL@ -INSTALL_OPTS=@INSTALL_OPTS@ -INSTALL_OPTS_WEB=@INSTALL_OPTS_WEB@ - -default: - @echo "IcingaWeb make targets: " - @printf "%b" " -install:\t\t\tInstall the application and overwrite configs\n" - @printf "%b" " -update:\t\t\tInstall the application without touching the configs\n" - @printf "%b" " -install-apache-config:\tInstall the apache configuration\n" - -# -# Installs the whole application w\o httpd configurations -# -install: install-config install-basic ensure-writable-folders install-cli - -# -# Install icingacli bin -# - -install-cli: - $(INSTALL) -m 755 -d $(INSTALL_OPTS) $(bindir) - $(INSTALL) -m 755 $(INSTALL_OPTS) "./bin/icingacli" $(bindir)/icingacli; - -# -# Installs the whole application w\o configuration -# -install-basic: install-static-files install-runtime-dirs ensure-writable-folders - -# -# Updates only the application -# -update: install-application - -# -# Removes files created by ./configure -# -clean: - if [ -f ./Makefile ];then \ - rm ./Makefile; \ - fi; \ - if [ -f ./etc/apache/icingaweb.conf ];then \ - rm ./etc/apache/icingaweb.conf; \ - fi; - -# -# Installs/copies all static files (executables, scripts, html, etc) -# -install-static-files: install-application copy-web-files-public copy-web-files-modules - -# -# Installs all configuration files -# -install-config: - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_CONFIG_PATH) - - @dirs=`cd ./config ; find . -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_CONFIG_PATH)/"$$dir"; \ - done; - - @files=`cd ./config ; find . -mindepth 1 -type f \ - -and ! -name ".*" -and ! -name "*.in"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS_WEB) "./config/$$file" $(DESTDIR)$(ICINGAWEB_CONFIG_PATH)/"$$file"; \ - done - - -# -# Installs runtime directories like the application cache -# -install-runtime-dirs: - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/application/cache - -# -# Copies the tests into the installation directory -# -install-tests: copy-folder-tests - -# -# Install configurations for apache2 -# -install-apache-config: - $(INSTALL) -m 755 -d $(INSTALL_OPTS) $(DESTDIR)$(HTTPD_CONFIG_PATH) - $(INSTALL) -m 644 $(INSTALL_OPTS) "./etc/apache/icingaweb.conf" $(DESTDIR)$(HTTPD_CONFIG_PATH)/icingaweb.conf; - -# -# Installs the php files to the prefix -# -install-application: copy-web-files-application copy-web-files-library install-cli - -# -# Rule for copying folders and containing files (arbitary types), hidden files are excluded -# -copy-folder-%: - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/$* - - @dirs=`find ./$* -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/"$$dir"; \ - done; - - @files=`find ./$* -mindepth 1 -type f \ - -and ! -name ".*"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS) "$$file" $(DESTDIR)$(prefix)/"$$file"; \ - done - - -ensure-writable-folders: - $(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/var/ - $(INSTALL) -m 775 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(ICINGAWEB_LOG_PATH) - chmod -R 775 $(DESTDIR)$(ICINGAWEB_CONFIG_PATH) - - -# -# Rule for copying only php, *html, js and ini files. Hidden files are ignored -# -copy-web-files-%: - $(INSTALL) -m 755 $(INSTALL_OPTS) -d $(DESTDIR)$(prefix)/$* - - @dirs=`find ./$* -mindepth 1 -type d `;\ - for dir in $$dirs; do \ - $(INSTALL) -m 755 $(INSTALL_OPTS_WEB) -d $(DESTDIR)$(prefix)/"$$dir"; \ - done; - - @files=`find ./$* -mindepth 1 -type f \ - -name "*.php" -or -name "*.ini" -or -name "*.*html" \ - -or -name "*.js" -or -name "*.css" -or -name "*.less" \ - -or -name "*.otf" -or -name "*.ttf" -or -name "*.otf" \ - -or -name "*.svg" -or -name "*.woff" -or -name "*.png" \ - -and ! -name ".*"`; \ - for file in $$files; do \ - $(INSTALL) -m 644 $(INSTALL_OPTS_WEB) "$$file" $(DESTDIR)$(prefix)/"$$file"; \ - done - -# -# Create release or snapshot tarball -# -# TODO: Use git-archive -# create-tarball: -# @./bin/make-tarball --prefix $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)/ -# -# create-tarball-nightly: -# ./bin/make-tarball --prefix $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-`date +%Y%m%d`-`git rev-parse --short HEAD`/ diff --git a/Vagrantfile b/Vagrantfile index f01fd7360..d73944173 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -54,7 +54,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. - config.vm.synced_folder "./config", "/vagrant/config" config.vm.synced_folder "./var/log", "/vagrant/var/log" # Provider-specific configuration so you can fine-tune various diff --git a/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index ed4703fd0..000000000 --- a/aclocal.m4 +++ /dev/null @@ -1,84 +0,0 @@ -AC_DEFUN([AC_USER_GUESS],[ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if user $x exists]) - AS_IF([ $GREP -q "^$x:" /etc/passwd ], - [ AC_MSG_RESULT([found]); $2=$x ; break], - [ AC_MSG_RESULT([not found]) ]) - done - ]) - -AC_DEFUN([AC_CHECK_PHP_MODULE],[ - for x in $1;do - AC_MSG_CHECKING([if php has $x module]) - AS_IF([ php -m | $GREP -iq "^$x$" ], - [ AC_MSG_RESULT([found]) ], - [ AC_MSG_ERROR([not found])]) - done -]) - -AC_DEFUN([AC_CHECK_PHP_VERSION],[ - AC_MSG_CHECKING([if php has at least version $1.$2.$3]) - AS_IF([ test $1 -le `php -r 'echo PHP_MAJOR_VERSION;'` && \ - test $2 -le `php -r 'echo PHP_MINOR_VERSION;'` && \ - test $3 -le `php -r 'echo PHP_RELEASE_VERSION;'`], - [ AC_MSG_RESULT([PHP version is correct])], - [ AC_MSG_ERROR([You need at least PHP version $1.$2.$3])]) -]) - -AC_DEFUN([AC_CHECK_PHP_INCLUDE],[ - AC_MSG_CHECKING([if PHP runtime dependency '$2' is available]) - AS_IF([ php -r 'require "$1";' ], - [ AC_MSG_RESULT([PHP runtime dependency fulfilled])], - [ AC_MSG_ERROR([PHP runtime dependency '$2' is missing])]) -]) - -AC_DEFUN([AC_GROUP_GUESS],[ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if group $x exists]) - AS_IF([ $GREP -q "^$x:" /etc/group ], - [ AC_MSG_RESULT([found]); $2=$x ; break], - [ AC_MSG_RESULT([not found]) ]) - done -]) - -AC_DEFUN([AC_CHECK_BIN], [ - AC_PATH_PROG([$1],[$2],[not found]) - - AS_IF([ test "XX${$1}" == "XXnot found" ], - [ AC_MSG_WARN([binary $2 not found in PATH]) ]) - - test "XX${$1}" == "XXnot found" && $1="" -]) - -AC_DEFUN([AC_PATH_GUESS], [ - $2=$3 - for x in $1; do - AC_MSG_CHECKING([if path $x exists]) - AS_IF([test -d $x], - [AC_MSG_RESULT([found]); $2=$x; break], - [AC_MSG_RESULT([not found])] - ) - done -]) - -# ICINGA_CHECK_DBTYPE(DBTYPE, ARGUMENT_NAME) -# ------------------------------------------ -AC_DEFUN([ICINGA_CHECK_DBTYPE], [ - AC_MSG_CHECKING([Testing database type for $2]) - AS_IF(echo "$1" | $GREP -q "^\(my\|pg\)sql$", - AC_MSG_RESULT([OK ($1)]), - AC_MSG_ERROR([$1]) - ) -]) - -# ICINGA_CHECK_BACKENDTYPE(BACKENDTYPE, ARGUMENT_NAME) -# ------------------------------------------ -AC_DEFUN([ICINGA_CHECK_BACKENDTYPE], [ - AC_MSG_CHECKING([Testing backend type for $2]) - AS_IF(echo "$1" | $GREP -q "^\(ido\|statusdat\|livestatus\)$", - AC_MSG_RESULT([OK ($1)]), - AC_MSG_ERROR([$1]) - ) -]) diff --git a/application/clicommands/WebCommand.php b/application/clicommands/WebCommand.php index 11e7f002a..12ed9e1a4 100644 --- a/application/clicommands/WebCommand.php +++ b/application/clicommands/WebCommand.php @@ -4,6 +4,7 @@ namespace Icinga\Clicommands; +use Icinga\Application\Icinga; use Icinga\Cli\Command; use Icinga\Exception\IcingaException; @@ -30,7 +31,7 @@ class WebCommand extends Command // throw new IcingaException('Socket is required'); } if ($basedir === null) { - $basedir = dirname(ICINGAWEB_APPDIR) . '/public'; + $basedir = Icinga::app()->getBaseDir('public'); if (! file_exists($basedir) || ! is_dir($basedir)) { throw new IcingaException('Basedir is required'); } @@ -46,7 +47,7 @@ class WebCommand extends Command readlink('/proc/self/exe'), $socket, $basedir, - ICINGA_LIBDIR . '/Icinga/Application/webrouter.php' + Icinga::app()->getLibraryDir('/Icinga/Application/webrouter.php') ); // TODO: Store webserver log, switch uid, log index.php includes, pid file diff --git a/application/controllers/AuthenticationController.php b/application/controllers/AuthenticationController.php index 1d47a7d41..00dae1c6d 100644 --- a/application/controllers/AuthenticationController.php +++ b/application/controllers/AuthenticationController.php @@ -6,7 +6,7 @@ use Icinga\Authentication\Backend\AutoLoginBackend; use Icinga\Web\Controller\ActionController; -use Icinga\Form\Authentication\LoginForm; +use Icinga\Forms\Authentication\LoginForm; use Icinga\Authentication\AuthChain; use Icinga\Application\Config; use Icinga\Application\Logger; @@ -33,6 +33,10 @@ class AuthenticationController extends ActionController */ public function loginAction() { + if (@file_exists(Config::resolvePath('setup.token')) && !@file_exists(Config::resolvePath('config.ini'))) { + $this->redirectNow(Url::fromPath('setup')); + } + $auth = $this->Auth(); $this->view->form = $form = new LoginForm(); $this->view->title = $this->translate('Icingaweb Login'); @@ -53,7 +57,7 @@ class AuthenticationController extends ActionController $config = Config::app('authentication'); } catch (NotReadableError $e) { throw new ConfigurationError( - $this->translate('Could not read your authentiction.ini, no authentication methods are available.'), + $this->translate('Could not read your authentication.ini, no authentication methods are available.'), 0, $e ); @@ -93,30 +97,30 @@ class AuthenticationController extends ActionController } } if ($backendsTried === 0) { - throw new ConfigurationError( + $this->view->form->addError( $this->translate( 'No authentication methods available. Did you create' - . ' authentication.ini when installing Icinga Web 2?' + . ' authentication.ini when setting up Icinga Web 2?' ) ); - } - if ($backendsTried === $backendsWithError) { - throw new ConfigurationError( + } else if ($backendsTried === $backendsWithError) { + $this->view->form->addError( $this->translate( 'All configured authentication methods failed.' . ' Please check the system log or Icinga Web 2 log for more information.' ) ); - } - if ($backendsWithError) { - $this->view->form->getElement('username')->addError( + } elseif ($backendsWithError) { + $this->view->form->addError( $this->translate( 'Please note that not all authentication methods were available.' . ' Check the system log or Icinga Web 2 log for more information.' ) ); } - $this->view->form->getElement('password')->addError($this->translate('Incorrect username or password')); + if ($backendsTried > 0 && $backendsTried !== $backendsWithError) { + $this->view->form->getElement('password')->addError($this->translate('Incorrect username or password')); + } } elseif ($request->isGet()) { $user = new User(''); foreach ($chain as $backend) { @@ -134,6 +138,8 @@ class AuthenticationController extends ActionController } catch (Exception $e) { $this->view->errorInfo = $e->getMessage(); } + + $this->view->configMissing = is_dir(Config::$configDir) === false; } /** diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index c12860e72..8f5f9eb42 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -7,12 +7,12 @@ use Icinga\Web\Notification; use Icinga\Application\Modules\Module; use Icinga\Web\Widget; use Icinga\Application\Icinga; -use Icinga\Application\Config as IcingaConfig; -use Icinga\Form\Config\GeneralConfigForm; -use Icinga\Form\Config\AuthenticationBackendReorderForm; -use Icinga\Form\Config\AuthenticationBackendConfigForm; -use Icinga\Form\Config\ResourceConfigForm; -use Icinga\Form\ConfirmRemovalForm; +use Icinga\Application\Config; +use Icinga\Forms\Config\GeneralConfigForm; +use Icinga\Forms\Config\AuthenticationBackendReorderForm; +use Icinga\Forms\Config\AuthenticationBackendConfigForm; +use Icinga\Forms\Config\ResourceConfigForm; +use Icinga\Forms\ConfirmRemovalForm; use Icinga\Data\ResourceFactory; @@ -46,7 +46,7 @@ class ConfigController extends ActionController public function indexAction() { $form = new GeneralConfigForm(); - $form->setIniConfig(IcingaConfig::app()); + $form->setIniConfig(Config::app()); $form->handleRequest(); $this->view->form = $form; @@ -99,7 +99,7 @@ class ConfigController extends ActionController Notification::success(sprintf($this->translate('Module "%s" enabled'), $module)); $this->rerenderLayout()->reloadCss()->redirectNow('config/modules'); } catch (Exception $e) { - $this->view->exceptionMesssage = $e->getMessage(); + $this->view->exceptionMessage = $e->getMessage(); $this->view->moduleName = $module; $this->view->action = 'enable'; $this->render('module-configuration-error'); @@ -131,7 +131,7 @@ class ConfigController extends ActionController public function authenticationAction() { $form = new AuthenticationBackendReorderForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->handleRequest(); $this->view->form = $form; @@ -145,7 +145,7 @@ class ConfigController extends ActionController public function createauthenticationbackendAction() { $form = new AuthenticationBackendConfigForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setRedirectUrl('config/authentication'); $form->handleRequest(); @@ -161,7 +161,7 @@ class ConfigController extends ActionController public function editauthenticationbackendAction() { $form = new AuthenticationBackendConfigForm(); - $form->setIniConfig(IcingaConfig::app('authentication')); + $form->setIniConfig(Config::app('authentication')); $form->setResourceConfig(ResourceFactory::getResourceConfigs()); $form->setRedirectUrl('config/authentication'); $form->handleRequest(); @@ -177,10 +177,10 @@ class ConfigController extends ActionController public function removeauthenticationbackendAction() { $form = new ConfirmRemovalForm(array( - 'onSuccess' => function ($request) { + 'onSuccess' => function ($form) { $configForm = new AuthenticationBackendConfigForm(); - $configForm->setIniConfig(IcingaConfig::app('authentication')); - $authBackend = $request->getQuery('auth_backend'); + $configForm->setIniConfig(Config::app('authentication')); + $authBackend = $form->getRequest()->getQuery('auth_backend'); try { $configForm->remove($authBackend); @@ -212,7 +212,7 @@ class ConfigController extends ActionController */ public function resourceAction() { - $this->view->resources = IcingaConfig::app('resources', true)->toArray(); + $this->view->resources = Config::app('resources', true)->keys(); $this->view->tabs->activate('resources'); } @@ -222,7 +222,7 @@ class ConfigController extends ActionController public function createresourceAction() { $form = new ResourceConfigForm(); - $form->setIniConfig(IcingaConfig::app('resources')); + $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -236,7 +236,7 @@ class ConfigController extends ActionController public function editresourceAction() { $form = new ResourceConfigForm(); - $form->setIniConfig(IcingaConfig::app('resources')); + $form->setIniConfig(Config::app('resources')); $form->setRedirectUrl('config/resource'); $form->handleRequest(); @@ -250,10 +250,10 @@ class ConfigController extends ActionController public function removeresourceAction() { $form = new ConfirmRemovalForm(array( - 'onSuccess' => function ($request) { + 'onSuccess' => function ($form) { $configForm = new ResourceConfigForm(); - $configForm->setIniConfig(IcingaConfig::app('resources')); - $resource = $request->getQuery('resource'); + $configForm->setIniConfig(Config::app('resources')); + $resource = $form->getRequest()->getQuery('resource'); try { $configForm->remove($resource); @@ -274,9 +274,9 @@ class ConfigController extends ActionController // Check if selected resource is currently used for authentication $resource = $this->getRequest()->getQuery('resource'); - $authConfig = IcingaConfig::app('authentication')->toArray(); + $authConfig = Config::app('authentication'); foreach ($authConfig as $backendName => $config) { - if (array_key_exists('resource', $config) && $config['resource'] === $resource) { + if ($config->get('resource') === $resource) { $form->addError(sprintf( $this->translate( 'The resource "%s" is currently in use by the authentication backend "%s". ' . diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 0ae931c18..e1e9e14c2 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -8,7 +8,7 @@ use Icinga\Exception\ConfigurationError; use Icinga\Exception\IcingaException; use Icinga\Exception\NotReadableError; use Icinga\File\Ini\IniWriter; -use Icinga\Form\Dashboard\AddUrlForm; +use Icinga\Forms\Dashboard\AddUrlForm; use Icinga\Web\Controller\ActionController; use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; @@ -37,7 +37,7 @@ class DashboardController extends ActionController $dashboard = new Dashboard(); try { $dashboardConfig = Config::app($config); - if (count($dashboardConfig) === 0) { + if ($dashboardConfig->isEmpty()) { return null; } $dashboard->readConfig($dashboardConfig); @@ -93,7 +93,7 @@ class DashboardController extends ActionController ); $configFile = Config::app('dashboard/dashboard')->getConfigFile(); - if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) { + if ($this->writeConfiguration(Config::fromArray($dashboard->toArray()), $configFile)) { $this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane')))); } else { $this->render('showConfiguration'); @@ -151,12 +151,12 @@ class DashboardController extends ActionController /** * Store the given configuration as INI file * - * @param Zend_Config $config The configuration to store - * @param string $target The path where to store the configuration + * @param Config $config The configuration to store + * @param string $target The path where to store the configuration * * @return bool Whether the configuartion has been successfully stored */ - protected function writeConfiguration(Zend_Config $config, $target) + protected function writeConfiguration(Config $config, $target) { $writer = new IniWriter(array('config' => $config, 'filename' => $target)); diff --git a/application/controllers/ListController.php b/application/controllers/ListController.php index 8f9a39e1b..f8b0ed1d6 100644 --- a/application/controllers/ListController.php +++ b/application/controllers/ListController.php @@ -3,9 +3,9 @@ // {{{ICINGA_LICENSE_HEADER}}} use Icinga\Module\Monitoring\Controller; -use Icinga\Web\Hook; use Icinga\Web\Url; use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Protocol\File\FileReader; use \Zend_Controller_Action_Exception as ActionError; @@ -48,7 +48,7 @@ class ListController extends Controller . ' - (?.*)$/'; // message $loggerWriter = Logger::getInstance()->getWriter(); - $resource = new FileReader(new Zend_Config(array( + $resource = new FileReader(new ConfigObject(array( 'filename' => $loggerWriter->getPath(), 'fields' => $pattern ))); diff --git a/application/controllers/PreferenceController.php b/application/controllers/PreferenceController.php index bd76b2466..7acab7c25 100644 --- a/application/controllers/PreferenceController.php +++ b/application/controllers/PreferenceController.php @@ -6,7 +6,7 @@ use Icinga\Web\Controller\BasePreferenceController; use Icinga\Web\Url; use Icinga\Web\Widget\Tab; use Icinga\Application\Config; -use Icinga\Form\PreferenceForm; +use Icinga\Forms\PreferenceForm; use Icinga\Exception\ConfigurationError; use Icinga\User\Preferences\PreferencesStore; @@ -25,9 +25,9 @@ class PreferenceController extends BasePreferenceController public static function createProvidedTabs() { return array( - 'general' => new Tab( + 'preferences' => new Tab( array( - 'title' => 'General settings', + 'title' => t('Preferences'), 'url' => Url::fromPath('/preference') ) ) @@ -39,8 +39,8 @@ class PreferenceController extends BasePreferenceController */ public function indexAction() { - $storeConfig = Config::app()->preferences; - if ($storeConfig === null) { + $storeConfig = Config::app()->getSection('preferences'); + if ($storeConfig->isEmpty()) { throw new ConfigurationError(t('You need to configure how to store preferences first.')); } @@ -51,6 +51,6 @@ class PreferenceController extends BasePreferenceController $form->handleRequest(); $this->view->form = $form; - $this->getTabs()->activate('general'); + $this->getTabs()->activate('preferences'); } } diff --git a/application/fonts/fontanello-ifont/LICENSE.txt b/application/fonts/fontanello-ifont/LICENSE.txt new file mode 100644 index 000000000..29b99c574 --- /dev/null +++ b/application/fonts/fontanello-ifont/LICENSE.txt @@ -0,0 +1,39 @@ +Font license info + + +## Font Awesome + + Copyright (C) 2012 by Dave Gandy + + Author: Dave Gandy + License: SIL () + Homepage: http://fortawesome.github.com/Font-Awesome/ + + +## Iconic + + Copyright (C) 2012 by P.J. Onori + + Author: P.J. Onori + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://somerandomdude.com/work/iconic/ + + +## MFG Labs + + Copyright (C) 2012 by Daniel Bruce + + Author: MFG Labs + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://www.mfglabs.com/ + + +## Entypo + + Copyright (C) 2012 by Daniel Bruce + + Author: Daniel Bruce + License: SIL (http://scripts.sil.org/OFL) + Homepage: http://www.entypo.com + + diff --git a/application/fonts/fontanello-ifont/README.txt b/application/fonts/fontanello-ifont/README.txt new file mode 100644 index 000000000..43e23f283 --- /dev/null +++ b/application/fonts/fontanello-ifont/README.txt @@ -0,0 +1,75 @@ +This webfont is generated by http://fontello.com open source project. + + +================================================================================ +Please, note, that you should obey original font licences, used to make this +webfont pack. Details available in LICENSE.txt file. + +- Usually, it's enough to publish content of LICENSE.txt file somewhere on your + site in "About" section. + +- If your project is open-source, usually, it will be ok to make LICENSE.txt + file publically available in your repository. + +- Fonts, used in Fontello, don't require to make clickable links on your site. + But any kind of additional authors crediting is welcome. +================================================================================ + + +Comments on archive content +--------------------------- + +- /font/* - fonts in different formats + +- /css/* - different kinds of css, for all situations. Should be ok with + twitter bootstrap. Also, you can skip style and assign icon classes + directly to text elements, if you don't mind about IE7. + +- demo.html - demo file, to show your webfont content + +- LICENSE.txt - license info about source fonts, used to build your one. + +- config.json - keeps your settings. You can import it back to fontello anytime, + to continue your work + + +Why so many CSS files ? +----------------------- + +Because we like to fit all your needs :) + +- basic file, .css - is usually enougth, in contains @font-face + and character codes definition + +- *-ie7.css - if you need IE7 support, but still don't wish to put char codes + directly into html + +- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face + rules, but still wish to benefit of css generation. That can be very + convenient for automated assets build systems. When you need to update font - + no needs to manually edit files, just override old version with archive + content. See fontello source codes for example. + +- *-embedded.css - basic css file, but with embedded WOFF font, to avoid + CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain. + We strongly recommend to resolve this issue by `Access-Control-Allow-Origin` + server headers. But if you ok with dirty hack - this file is for you. Note, + that data url moved to separate @font-face to avoid problems with + + + + + + + + +
+

+ ifont + font demo +

+ +
+
+
+
icon-dashboard0xe800
+
icon-user0xe801
+
icon-users0xe802
+
icon-ok0xe803
+
+
+
icon-cancel0xe804
+
icon-plus0xe805
+
icon-minus0xe806
+
icon-folder-empty0xe807
+
+
+
icon-download0xe808
+
icon-upload0xe809
+
icon-git0xe80a
+
icon-cubes0xe80b
+
+
+
icon-database0xe80c
+
icon-gauge0xe80d
+
icon-sitemap0xe80e
+
icon-sort-name-up0xe80f
+
+
+
icon-sort-name-down0xe810
+
icon-megaphone0xe811
+
icon-bug0xe812
+
icon-tasks0xe813
+
+
+
icon-filter0xe814
+
icon-off0xe815
+
icon-book0xe816
+
icon-paste0xe817
+
+
+
icon-scissors0xe818
+
icon-globe0xe819
+
icon-cloud0xe81a
+
icon-flash0xe81b
+
+
+
icon-service0xe81c
+
icon-down-dir0xe81d
+
icon-up-dir0xe81e
+
icon-left-dir0xe81f
+
+
+
icon-right-dir0xe820
+
icon-down-open0xe821
+
icon-right-open0xe822
+
icon-up-open0xe823
+
+
+
icon-left-open0xe824
+
icon-up-big0xe825
+
icon-right-big0xe826
+
icon-left-big0xe827
+
+
+
icon-down-big0xe828
+
icon-resize-full-alt0xe829
+
icon-resize-full0xe82a
+
icon-resize-small0xe82b
+
+
+
icon-move0xe82c
+
icon-resize-horizontal0xe82d
+
icon-resize-vertical0xe82e
+
icon-zoom-in0xe82f
+
+
+
icon-block0xe830
+
icon-zoom-out0xe831
+
icon-lightbulb0xe832
+
icon-clock0xe833
+
+
+
icon-volume-up0xe834
+
icon-volume-down0xe835
+
icon-volume-off0xe836
+
icon-mute0xe837
+
+
+
icon-mic0xe838
+
icon-endtime0xe839
+
icon-starttime0xe83a
+
icon-calendar-empty0xe83b
+
+
+
icon-calendar0xe83c
+
icon-wrench0xe83d
+
icon-sliders0xe83e
+
icon-conf-alt0xe83f
+
+
+
icon-conf0xe840
+
icon-phone0xe841
+
icon-file-pdf0xe842
+
icon-file-word0xe843
+
+
+
icon-file-excel0xe844
+
icon-doc-text0xe845
+
icon-trash0xe846
+
icon-comment-empty0xe847
+
+
+
icon-comment0xe848
+
icon-chat0xe849
+
icon-chat-empty0xe84a
+
icon-bell0xe84b
+
+
+
icon-bell-alt0xe84c
+
icon-attention-alt0xe84d
+
icon-print0xe84e
+
icon-edit0xe84f
+
+
+
icon-forward0xe850
+
icon-reply0xe851
+
icon-reply-all0xe852
+
icon-eye0xe853
+
+
+
icon-tag0xe854
+
icon-tags0xe855
+
icon-lock-open-alt0xe856
+
icon-lock-open0xe857
+
+
+
icon-lock0xe858
+
icon-home0xe859
+
icon-info0xe85a
+
icon-help0xe85b
+
+
+
icon-search0xe85c
+
icon-flapping0xe85d
+
icon-rewind0xe85e
+
icon-chart-line0xe85f
+
+
+
icon-bell-off0xe860
+
icon-bell-off-empty0xe861
+
icon-plug0xe862
+
icon-eye-off0xe863
+
+
+
icon-reschedule0xe864
+
icon-cw0xe865
+
icon-host0xe866
+
icon-thumbs-up0xe867
+
+
+
icon-thumbs-down0xe868
+
+
+ + + \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/font/ifont.eot b/application/fonts/fontanello-ifont/font/ifont.eot new file mode 100644 index 000000000..b8cec1252 Binary files /dev/null and b/application/fonts/fontanello-ifont/font/ifont.eot differ diff --git a/application/fonts/fontanello-ifont/font/ifont.svg b/application/fonts/fontanello-ifont/font/ifont.svg new file mode 100644 index 000000000..6e385b6f0 --- /dev/null +++ b/application/fonts/fontanello-ifont/font/ifont.svg @@ -0,0 +1,116 @@ + + + +Copyright (C) 2014 by original authors @ fontello.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/font/ifont.ttf b/application/fonts/fontanello-ifont/font/ifont.ttf new file mode 100644 index 000000000..470c1997a Binary files /dev/null and b/application/fonts/fontanello-ifont/font/ifont.ttf differ diff --git a/application/fonts/fontanello-ifont/font/ifont.woff b/application/fonts/fontanello-ifont/font/ifont.woff new file mode 100644 index 000000000..6f08975f5 Binary files /dev/null and b/application/fonts/fontanello-ifont/font/ifont.woff differ diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index 0afc56749..41107be18 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Authentication; +namespace Icinga\Forms\Authentication; use Icinga\Web\Form; use Icinga\Web\Url; @@ -32,7 +32,7 @@ class LoginForm extends Form array( 'required' => true, 'label' => t('Username'), - 'placeholder' => t('Please enter your username...'), + 'placeholder' => t(''), 'class' => false === isset($formData['username']) ? 'autofocus' : '' ) ); @@ -42,7 +42,7 @@ class LoginForm extends Form array( 'required' => true, 'label' => t('Password'), - 'placeholder' => t('...and your password'), + 'placeholder' => t(''), 'class' => isset($formData['username']) ? 'autofocus' : '' ) ); diff --git a/application/forms/Config/Authentication/AutologinBackendForm.php b/application/forms/Config/Authentication/AutologinBackendForm.php index 4f4df73e3..a21d2c006 100644 --- a/application/forms/Config/Authentication/AutologinBackendForm.php +++ b/application/forms/Config/Authentication/AutologinBackendForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Zend_Validate_Callback; use Icinga\Web\Form; @@ -31,7 +31,9 @@ class AutologinBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication backend'), + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ), 'validators' => array( array( 'Regex', @@ -50,9 +52,8 @@ class AutologinBackendForm extends Form 'text', 'strip_username_regexp', array( - 'required' => true, - 'label' => t('Backend Domain Pattern'), - 'description' => t('The domain pattern of this authentication backend'), + 'label' => t('Filter Pattern'), + 'description' => t('The regular expression to use to strip specific parts off from usernames. Leave empty if you do not want to strip off anything'), 'value' => '/\@[^$]+$/', 'validators' => array( new Zend_Validate_Callback(function ($value) { @@ -65,7 +66,7 @@ class AutologinBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'autologin' ) ); @@ -82,7 +83,7 @@ class AutologinBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { return true; } diff --git a/application/forms/Config/Authentication/DbBackendForm.php b/application/forms/Config/Authentication/DbBackendForm.php index 23335f8fa..572a09c2e 100644 --- a/application/forms/Config/Authentication/DbBackendForm.php +++ b/application/forms/Config/Authentication/DbBackendForm.php @@ -2,11 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Web\Form; -use Icinga\Web\Request; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Authentication\Backend\DbUserBackend; @@ -54,7 +54,9 @@ class DbBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication provider'), + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ), ) ); $this->addElement( @@ -73,7 +75,7 @@ class DbBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'db' ) ); @@ -86,9 +88,9 @@ class DbBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidAuthenticationBackend($this)) { + if (false === static::isValidAuthenticationBackend($this)) { return false; } } @@ -100,21 +102,29 @@ class DbBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { - $element = $form->getElement('resource'); - try { - $dbUserBackend = new DbUserBackend(ResourceFactory::create($element->getValue())); + $dbUserBackend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig())); if ($dbUserBackend->count() < 1) { - $element->addError(t('No users found under the specified database backend')); + $form->addError(t('No users found under the specified database backend')); return false; } } catch (Exception $e) { - $element->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); + $form->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage())); return false; } return true; } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index 6056b0911..9b48c3dbc 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -2,12 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Web\Form; -use Icinga\Web\Request; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; +use Icinga\Exception\AuthenticationException; use Icinga\Authentication\Backend\LdapUserBackend; /** @@ -54,7 +55,9 @@ class LdapBackendForm extends Form array( 'required' => true, 'label' => t('Backend Name'), - 'description' => t('The name of this authentication backend') + 'description' => t( + 'The name of this authentication provider that is used to differentiate it from others' + ) ) ); $this->addElement( @@ -93,11 +96,20 @@ class LdapBackendForm extends Form 'hidden', 'backend', array( - 'required' => true, + 'disabled' => true, 'value' => 'ldap' ) ); - + $this->addElement( + 'text', + 'base_dn', + array( + 'required' => false, + 'label' => t('Base DN'), + 'description' => t('The path where users can be found on the ldap server. ' . + ' Leave empty to select all users available on the specified resource.') + ) + ); return $this; } @@ -106,9 +118,9 @@ class LdapBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidAuthenticationBackend($this)) { + if (false === static::isValidAuthenticationBackend($this)) { return false; } } @@ -120,22 +132,34 @@ class LdapBackendForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidAuthenticationBackend(Form $form) + public static function isValidAuthenticationBackend(Form $form) { - $element = $form->getElement('resource'); - try { $ldapUserBackend = new LdapUserBackend( - ResourceFactory::create($element->getValue()), + ResourceFactory::createResource($form->getResourceConfig()), $form->getElement('user_class')->getValue(), - $form->getElement('user_name_attribute')->getValue() + $form->getElement('user_name_attribute')->getValue(), + $form->getElement('base_dn')->getValue() ); $ldapUserBackend->assertAuthenticationPossible(); + } catch (AuthenticationException $e) { + $form->addError($e->getMessage()); + return false; } catch (Exception $e) { - $element->addError(sprintf(t('Connection validation failed: %s'), $e->getMessage())); + $form->addError(sprintf(t('Unable to validate authentication: %s'), $e->getMessage())); return false; } return true; } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/AuthenticationBackendConfigForm.php b/application/forms/Config/AuthenticationBackendConfigForm.php index e81382cd4..12f407c69 100644 --- a/application/forms/Config/AuthenticationBackendConfigForm.php +++ b/application/forms/Config/AuthenticationBackendConfigForm.php @@ -2,18 +2,19 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; use Icinga\Web\Notification; use Icinga\Application\Config; use Icinga\Application\Platform; +use Icinga\Data\ConfigObject; +use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; -use Icinga\Form\Config\Authentication\DbBackendForm; -use Icinga\Form\Config\Authentication\LdapBackendForm; -use Icinga\Form\Config\Authentication\AutologinBackendForm; +use Icinga\Forms\Config\Authentication\DbBackendForm; +use Icinga\Forms\Config\Authentication\LdapBackendForm; +use Icinga\Forms\Config\Authentication\AutologinBackendForm; class AuthenticationBackendConfigForm extends ConfigForm { @@ -39,8 +40,6 @@ class AuthenticationBackendConfigForm extends ConfigForm * @param Config $resources The resource configuration * * @return self - * - * @throws ConfigurationError In case no resources are available for authentication */ public function setResourceConfig(Config $resourceConfig) { @@ -49,10 +48,6 @@ class AuthenticationBackendConfigForm extends ConfigForm $resources[strtolower($resource->type)][] = $name; } - if (empty($resources)) { - throw new ConfigurationError(t('Could not find any resources for authentication')); - } - $this->resources = $resources; return $this; } @@ -97,12 +92,12 @@ class AuthenticationBackendConfigForm extends ConfigForm $name = isset($values['name']) ? $values['name'] : ''; if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif ($this->config->get($name) !== null) { + } elseif ($this->config->hasSection($name)) { throw new InvalidArgumentException(t('Authentication backend already exists')); } unset($values['name']); - $this->config->{$name} = $values; + $this->config->setSection($name, $values); return $this; } @@ -122,18 +117,19 @@ class AuthenticationBackendConfigForm extends ConfigForm throw new InvalidArgumentException(t('Old authentication backend name missing')); } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { throw new InvalidArgumentException(t('New authentication backend name missing')); - } elseif (($backendConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } + $backendConfig = $this->config->getSection($name); if ($newName !== $name) { // Only remove the old entry if it has changed as the order gets screwed when editing backend names - unset($this->config->{$name}); + $this->config->removeSection($name); } unset($values['name']); - $this->config->{$newName} = array_merge($backendConfig->toArray(), $values); - return $this->config->{$newName}; + $this->config->setSection($newName, $backendConfig->merge($values)); + return $backendConfig; } /** @@ -149,11 +145,12 @@ class AuthenticationBackendConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif (($backendConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } - unset($this->config->{$name}); + $backendConfig = $this->config->getSection($name); + $this->config->removeSection($name); return $backendConfig; } @@ -171,7 +168,7 @@ class AuthenticationBackendConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Authentication backend name missing')); - } elseif ($this->config->get($name) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown authentication backend provided')); } @@ -181,10 +178,10 @@ class AuthenticationBackendConfigForm extends ConfigForm $newConfig = array(); foreach ($backendOrder as $backendName) { - $newConfig[$backendName] = $this->config->get($backendName); + $newConfig[$backendName] = $this->config->getSection($backendName); } - $config = new Config($newConfig); + $config = Config::fromArray($newConfig); $this->config = $config->setConfigFile($this->config->getConfigFile()); return $this; } @@ -197,17 +194,17 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $backendForm = $this->getBackendForm($this->getElement('type')->getValue()); - if (false === $backendForm->isValidAuthenticationBackend($this)) { + if (false === $backendForm::isValidAuthenticationBackend($this)) { $this->addElement($this->getForceCreationCheckbox()); return false; } } - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); try { if ($authBackend === null) { // create new backend $this->add($this->getValues()); @@ -235,22 +232,33 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); if ($authBackend !== null) { if ($authBackend === '') { throw new ConfigurationError(t('Authentication backend name missing')); - } elseif (false === isset($this->config->{$authBackend})) { + } elseif (! $this->config->hasSection($authBackend)) { throw new ConfigurationError(t('Unknown authentication backend provided')); - } elseif (false === isset($this->config->{$authBackend}->backend)) { + } elseif ($this->config->getSection($authBackend)->backend === null) { throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend)); } - $configValues = $this->config->{$authBackend}->toArray(); + $configValues = $this->config->getSection($authBackend)->toArray(); $configValues['type'] = $configValues['backend']; $configValues['name'] = $authBackend; $this->populate($configValues); + } elseif (empty($this->resources)) { + $autologinBackends = array_filter( + $this->config->toArray(), + function ($authBackendCfg) { + return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin'; + } + ); + + if (false === empty($autologinBackends)) { + throw new ConfigurationError(t('Could not find any resources for authentication')); + } } } @@ -280,7 +288,7 @@ class AuthenticationBackendConfigForm extends ConfigForm public function createElements(array $formData) { $backendTypes = array(); - $backendType = isset($formData['type']) ? $formData['type'] : 'db'; + $backendType = isset($formData['type']) ? $formData['type'] : null; if (isset($this->resources['db'])) { $backendTypes['db'] = t('Database'); @@ -299,6 +307,10 @@ class AuthenticationBackendConfigForm extends ConfigForm $backendTypes['autologin'] = t('Autologin'); } + if ($backendType === null) { + $backendType = key($backendTypes); + } + $this->addElement( 'select', 'type', @@ -307,7 +319,7 @@ class AuthenticationBackendConfigForm extends ConfigForm 'required' => true, 'autosubmit' => true, 'label' => t('Backend Type'), - 'description' => t('The type of the resource to use for this authenticaton backend'), + 'description' => t('The type of the resource to use for this authenticaton provider'), 'multiOptions' => $backendTypes ) ); @@ -319,4 +331,14 @@ class AuthenticationBackendConfigForm extends ConfigForm $this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements()); } + + /** + * Return the configuration for the chosen resource + * + * @return ConfigObject + */ + public function getResourceConfig() + { + return ResourceFactory::getResourceConfig($this->getValue('resource')); + } } diff --git a/application/forms/Config/AuthenticationBackendReorderForm.php b/application/forms/Config/AuthenticationBackendReorderForm.php index 3b5e70866..07200827a 100644 --- a/application/forms/Config/AuthenticationBackendReorderForm.php +++ b/application/forms/Config/AuthenticationBackendReorderForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; class AuthenticationBackendReorderForm extends ConfigForm { @@ -30,17 +29,26 @@ class AuthenticationBackendReorderForm extends ConfigForm return $this->config->keys(); } + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + // This adds just a dummy element to be able to utilize Form::getValue as part of onSuccess() + $this->addElement('hidden', 'backend_newpos'); + } + /** * Update the authentication backend order and save the configuration * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - $formData = $this->getRequestData($request); - if (isset($formData['backend_newpos'])) { + $newPosData = $this->getValue('backend_newpos'); + if ($newPosData) { $configForm = $this->getConfigForm(); - list($backendName, $position) = explode('|', $formData['backend_newpos'], 2); + list($backendName, $position) = explode('|', $newPosData, 2); try { if ($configForm->move($backendName, $position)->save()) { diff --git a/application/forms/Config/General/ApplicationConfigForm.php b/application/forms/Config/General/ApplicationConfigForm.php index fda695886..95ad22071 100644 --- a/application/forms/Config/General/ApplicationConfigForm.php +++ b/application/forms/Config/General/ApplicationConfigForm.php @@ -2,12 +2,14 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use DateTimeZone; -use Icinga\Web\Form; -use Icinga\Util\Translator; +use Icinga\Application\Icinga; use Icinga\Data\ResourceFactory; +use Icinga\Util\Translator; +use Icinga\Web\Form; + /** * Form class to modify the general application configuration @@ -27,56 +29,18 @@ class ApplicationConfigForm extends Form */ public function createElements(array $formData) { - $languages = array(); - foreach (Translator::getAvailableLocaleCodes() as $language) { - $languages[$language] = $language; - } - - $this->addElement( - 'select', - 'global_language', - array( - 'label' => t('Default Language'), - 'required' => true, - 'multiOptions' => $languages, - 'description' => t( - 'Select the language to use by default. Can be overwritten by a user in his preferences.' - ) - ) - ); - - $tzList = array(); - foreach (DateTimeZone::listIdentifiers() as $tz) { - $tzList[$tz] = $tz; - } - - $this->addElement( - 'select', - 'global_timezone', - array( - 'label' => t('Default Application Timezone'), - 'required' => true, - 'multiOptions' => $tzList, - 'description' => t( - 'Select the timezone to be used as the default. User\'s can set their own timezone if' - . ' they like to, but this is the timezone to be used as the default setting .' - ), - 'value' => date_default_timezone_get() - ) - ); - $this->addElement( 'text', - 'global_modulePath', + 'global_module_path', array( 'label' => t('Module Path'), 'required' => true, + 'value' => implode(':', Icinga::app()->getModuleManager()->getModuleDirs()), 'description' => t( 'Contains the directories that will be searched for available modules, separated by ' . 'colons. Modules that don\'t exist in these directories can still be symlinked in ' . 'the module folder, but won\'t show up in the list of disabled modules.' - ), - 'value' => realpath(ICINGAWEB_APPDIR . '/../modules') + ) ) ); diff --git a/application/forms/Config/General/LoggingConfigForm.php b/application/forms/Config/General/LoggingConfigForm.php index 50b61d246..deed06011 100644 --- a/application/forms/Config/General/LoggingConfigForm.php +++ b/application/forms/Config/General/LoggingConfigForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use Icinga\Application\Icinga; use Icinga\Application\Logger; @@ -30,13 +30,13 @@ class LoggingConfigForm extends Form 'logging_log', array( 'required' => true, - 'class' => 'autosubmit', + 'autosubmit' => true, 'label' => t('Logging Type'), 'description' => t('The type of logging to utilize.'), 'multiOptions' => array( 'syslog' => 'Syslog', - 'file' => t('File'), - 'none' => t('None') + 'file' => t('File', 'app.config.logging.type'), + 'none' => t('None', 'app.config.logging.type') ) ) ); @@ -50,16 +50,16 @@ class LoggingConfigForm extends Form 'label' => t('Logging Level'), 'description' => t('The maximum logging level to emit.'), 'multiOptions' => array( - Logger::$levels[Logger::ERROR] => t('Error'), - Logger::$levels[Logger::WARNING] => t('Warning'), - Logger::$levels[Logger::INFO] => t('Information'), - Logger::$levels[Logger::DEBUG] => t('Debug') + Logger::$levels[Logger::ERROR] => t('Error', 'app.config.logging.level'), + Logger::$levels[Logger::WARNING] => t('Warning', 'app.config.logging.level'), + Logger::$levels[Logger::INFO] => t('Information', 'app.config.logging.level'), + Logger::$levels[Logger::DEBUG] => t('Debug', 'app.config.logging.level') ) ) ); } - if (isset($formData['logging_log']) && $formData['logging_log'] === 'syslog') { + if (false === isset($formData['logging_log']) || $formData['logging_log'] === 'syslog') { $this->addElement( 'text', 'logging_application', diff --git a/application/forms/Config/GeneralConfigForm.php b/application/forms/Config/GeneralConfigForm.php index 0b55704c2..0d81bb96b 100644 --- a/application/forms/Config/GeneralConfigForm.php +++ b/application/forms/Config/GeneralConfigForm.php @@ -2,13 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\General\LoggingConfigForm; -use Icinga\Form\Config\General\ApplicationConfigForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\General\LoggingConfigForm; +use Icinga\Forms\Config\General\ApplicationConfigForm; /** * Form class for application-wide and logging specific settings @@ -38,18 +37,18 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { $sections = array(); foreach ($this->getValues() as $sectionAndPropertyName => $value) { - list($section, $property) = explode('_', $sectionAndPropertyName); + list($section, $property) = explode('_', $sectionAndPropertyName, 2); if (! isset($sections[$section])) { $sections[$section] = array(); } $sections[$section][$property] = $value; } foreach ($sections as $section => $config) { - $this->config->{$section} = $config; + $this->config->setSection($section, $config); } if ($this->save()) { @@ -62,7 +61,7 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { $values = array(); foreach ($this->config as $section => $properties) { diff --git a/application/forms/Config/Resource/DbResourceForm.php b/application/forms/Config/Resource/DbResourceForm.php index 4fd7297d9..d5197c94e 100644 --- a/application/forms/Config/Resource/DbResourceForm.php +++ b/application/forms/Config/Resource/DbResourceForm.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; +use Icinga\Application\Platform; /** * Form class for adding/modifying database resources @@ -29,6 +28,23 @@ class DbResourceForm extends Form */ public function createElements(array $formData) { + $dbChoices = array(); + if (Platform::zendClassExists('Zend_Db_Adapter_Pdo_Mysql')) { + $dbChoices['mysql'] = 'MySQL'; + } + if (Platform::zendClassExists('Zend_Db_Adapter_Pdo_Pgsql')) { + $dbChoices['pgsql'] = 'PostgreSQL'; + } + + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'select', 'db', @@ -36,11 +52,7 @@ class DbResourceForm extends Form 'required' => true, 'label' => t('Database Type'), 'description' => t('The type of SQL database'), - 'multiOptions' => array( - 'mysql' => 'MySQL', - 'pgsql' => 'PostgreSQL' - //'oracle' => 'Oracle' - ) + 'multiOptions' => $dbChoices ) ); $this->addElement( @@ -54,14 +66,13 @@ class DbResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port to use'), - 'value' => 3306 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port to use'), + 'value' => 3306 ) ); $this->addElement( @@ -101,9 +112,9 @@ class DbResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -115,10 +126,10 @@ class DbResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); $resource->getConnection()->getConnection(); } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); diff --git a/application/forms/Config/Resource/FileResourceForm.php b/application/forms/Config/Resource/FileResourceForm.php index d1d33a749..8e2920313 100644 --- a/application/forms/Config/Resource/FileResourceForm.php +++ b/application/forms/Config/Resource/FileResourceForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Icinga\Web\Form; use Icinga\Web\Form\Validator\ReadablePathValidator; @@ -25,6 +25,15 @@ class FileResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'filename', diff --git a/application/forms/Config/Resource/LdapResourceForm.php b/application/forms/Config/Resource/LdapResourceForm.php index 6196f3a17..6641b96bb 100644 --- a/application/forms/Config/Resource/LdapResourceForm.php +++ b/application/forms/Config/Resource/LdapResourceForm.php @@ -2,13 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; /** @@ -29,6 +27,15 @@ class LdapResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'hostname', @@ -40,14 +47,13 @@ class LdapResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port of the LDAP server to use for authentication'), - 'value' => 389 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port of the LDAP server to use for authentication'), + 'value' => 389 ) ); $this->addElement( @@ -56,7 +62,7 @@ class LdapResourceForm extends Form array( 'required' => true, 'label' => t('Root DN'), - 'description' => t('The path where users can be found on the ldap server') + 'description' => t('Only the root and its child nodes will be accessible on this resource.') ) ); $this->addElement( @@ -87,9 +93,9 @@ class LdapResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -101,11 +107,17 @@ class LdapResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); - $resource->connect(); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); + if (false === $resource->testCredentials( + $form->getElement('bind_dn')->getValue(), + $form->getElement('bind_pw')->getValue() + ) + ) { + throw new Exception(); + } } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); return false; diff --git a/application/forms/Config/Resource/LivestatusResourceForm.php b/application/forms/Config/Resource/LivestatusResourceForm.php index 92534f220..d90600370 100644 --- a/application/forms/Config/Resource/LivestatusResourceForm.php +++ b/application/forms/Config/Resource/LivestatusResourceForm.php @@ -2,13 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; -use Zend_Config; use Icinga\Web\Form; -use Icinga\Web\Request; use Icinga\Application\Icinga; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; /** @@ -29,6 +28,15 @@ class LivestatusResourceForm extends Form */ public function createElements(array $formData) { + $this->addElement( + 'text', + 'name', + array( + 'required' => true, + 'label' => t('Resource Name'), + 'description' => t('The unique name of this resource') + ) + ); $this->addElement( 'text', 'socket', @@ -48,9 +56,9 @@ class LivestatusResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - if (false === $this->isValidResource($this)) { + if (false === static::isValidResource($this)) { return false; } } @@ -62,10 +70,10 @@ class LivestatusResourceForm extends Form * * @return bool Whether validation succeeded or not */ - public function isValidResource(Form $form) + public static function isValidResource(Form $form) { try { - $resource = ResourceFactory::createResource(new Zend_Config($form->getValues())); + $resource = ResourceFactory::createResource(new ConfigObject($form->getValues())); $resource->connect()->disconnect(); } catch (Exception $e) { $form->addError(t('Connectivity validation failed, connection to the given resource not possible.')); diff --git a/application/forms/Config/ResourceConfigForm.php b/application/forms/Config/ResourceConfigForm.php index 1aa7edc96..fe3b9957d 100644 --- a/application/forms/Config/ResourceConfigForm.php +++ b/application/forms/Config/ResourceConfigForm.php @@ -2,16 +2,15 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\Resource\DbResourceForm; -use Icinga\Form\Config\Resource\FileResourceForm; -use Icinga\Form\Config\Resource\LdapResourceForm; -use Icinga\Form\Config\Resource\LivestatusResourceForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\FileResourceForm; +use Icinga\Forms\Config\Resource\LdapResourceForm; +use Icinga\Forms\Config\Resource\LivestatusResourceForm; use Icinga\Application\Platform; use Icinga\Exception\ConfigurationError; @@ -64,12 +63,12 @@ class ResourceConfigForm extends ConfigForm $name = isset($values['name']) ? $values['name'] : ''; if (! $name) { throw new InvalidArgumentException(t('Resource name missing')); - } elseif ($this->config->{$name} !== null) { + } elseif ($this->config->hasSection($name)) { throw new InvalidArgumentException(t('Resource already exists')); } unset($values['name']); - $this->config->{$name} = $values; + $this->config->setSection($name, $values); return $this; } @@ -89,14 +88,15 @@ class ResourceConfigForm extends ConfigForm throw new InvalidArgumentException(t('Old resource name missing')); } elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) { throw new InvalidArgumentException(t('New resource name missing')); - } elseif (($resourceConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown resource provided')); } + $resourceConfig = $this->config->getSection($name); + $this->config->removeSection($name); unset($values['name']); - unset($this->config->{$name}); - $this->config->{$newName} = array_merge($resourceConfig->toArray(), $values); - return $this->config->{$newName}; + $this->config->setSection($newName, $resourceConfig->merge($values)); + return $resourceConfig; } /** @@ -112,11 +112,12 @@ class ResourceConfigForm extends ConfigForm { if (! $name) { throw new InvalidArgumentException(t('Resource name missing')); - } elseif (($resourceConfig = $this->config->get($name)) === null) { + } elseif (! $this->config->hasSection($name)) { throw new InvalidArgumentException(t('Unknown resource provided')); } - unset($this->config->{$name}); + $resourceConfig = $this->config->getSection($name); + $this->config->removeSection($name); return $resourceConfig; } @@ -128,17 +129,17 @@ class ResourceConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $resourceForm = $this->getResourceForm($this->getElement('type')->getValue()); - if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm->isValidResource($this)) { + if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm::isValidResource($this)) { $this->addElement($this->getForceCreationCheckbox()); return false; } } - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); try { if ($resource === null) { // create new resource $this->add($this->getValues()); @@ -166,17 +167,17 @@ class ResourceConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); if ($resource !== null) { if ($resource === '') { throw new ConfigurationError(t('Resource name missing')); - } elseif (false === isset($this->config->{$resource})) { + } elseif (! $this->config->hasSection($resource)) { throw new ConfigurationError(t('Unknown resource provided')); } - $configValues = $this->config->{$resource}->toArray(); + $configValues = $this->config->getSection($resource)->toArray(); $configValues['name'] = $resource; $this->populate($configValues); } @@ -220,15 +221,6 @@ class ResourceConfigForm extends ConfigForm $resourceTypes['db'] = t('SQL Database'); } - $this->addElement( - 'text', - 'name', - array( - 'required' => true, - 'label' => t('Resource Name'), - 'description' => t('The unique name of this resource') - ) - ); $this->addElement( 'select', 'type', diff --git a/application/forms/ConfigForm.php b/application/forms/ConfigForm.php index 585bd6914..28d3111ea 100644 --- a/application/forms/ConfigForm.php +++ b/application/forms/ConfigForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; use Zend_Form_Decorator_Abstract; diff --git a/application/forms/ConfirmRemovalForm.php b/application/forms/ConfirmRemovalForm.php index 86a2eb02a..02d7263df 100644 --- a/application/forms/ConfirmRemovalForm.php +++ b/application/forms/ConfirmRemovalForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Icinga\Web\Form; diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index 88195654d..7f5a217d1 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -2,9 +2,9 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Dashboard; +namespace Icinga\Forms\Dashboard; -use Icinga\Application\Config as IcingaConfig; +use Icinga\Application\Config; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; @@ -110,7 +110,7 @@ class AddUrlForm extends Form protected function getDashboardPaneSelectionValues() { $dashboard = new Dashboard(); - $dashboard->readConfig(IcingaConfig::app('dashboard/dashboard')); + $dashboard->readConfig(Config::app('dashboard/dashboard')); return $dashboard->getPaneKeyTitleArray(); } } diff --git a/application/forms/LdapDiscoveryForm.php b/application/forms/LdapDiscoveryForm.php new file mode 100644 index 000000000..0fd0ea0d3 --- /dev/null +++ b/application/forms/LdapDiscoveryForm.php @@ -0,0 +1,75 @@ +setName('form_ldap_discovery'); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'domain', + array( + 'required' => true, + 'label' => t('Search Domain'), + 'description' => t('Search this domain for records of available servers.'), + ) + ); + + if (false) { + $this->addElement( + 'note', + 'additional_description', + array( + 'value' => t('No Ldap servers found on this domain.' + . ' You can try to specify host and port and try again, or just skip this step and ' + . 'configure the server manually.' + ) + ) + ); + $this->addElement( + 'text', + 'hostname', + array( + 'required' => false, + 'label' => t('Host'), + 'description' => t('IP or host name to search.'), + ) + ); + + $this->addElement( + 'text', + 'port', + array( + 'required' => false, + 'label' => t('Port'), + 'description' => t('Port', 389), + ) + ); + } + return $this; + } + + public function isValid($data) + { + if (false === parent::isValid($data)) { + return false; + } + return true; + } +} diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php index 633e2183a..e3cfdf319 100644 --- a/application/forms/PreferenceForm.php +++ b/application/forms/PreferenceForm.php @@ -2,18 +2,18 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; use DateTimeZone; use Icinga\Application\Logger; +use Icinga\Authentication\Manager; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; use Icinga\Util\TimezoneDetect; use Icinga\Util\Translator; use Icinga\Web\Form; use Icinga\Web\Notification; -use Icinga\Web\Request; use Icinga\Web\Session; /** @@ -41,7 +41,6 @@ class PreferenceForm extends Form public function init() { $this->setName('form_config_preferences'); - $this->setSubmitLabel(t('Save Changes')); } /** @@ -76,7 +75,6 @@ class PreferenceForm extends Form */ public function save() { - $this->store->load(); // Necessary for patching existing preferences $this->store->save($this->preferences); return $this; } @@ -86,11 +84,13 @@ class PreferenceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { + $this->preferences = new Preferences($this->store->load()); + $webPreferences = $this->preferences->get('icingaweb', array()); foreach ($this->getValues() as $key => $value) { - if ($value === null) { + if ($value === null || $value === 'autodetect') { if (isset($webPreferences[$key])) { unset($webPreferences[$key]); } @@ -100,14 +100,15 @@ class PreferenceForm extends Form } $this->preferences->icingaweb = $webPreferences; - // TODO: Is this even necessary in case the session is written on response? - $session = Session::getSession(); - $session->user->setPreferences($this->preferences); - $session->write(); + Session::getSession()->user->setPreferences($this->preferences); try { - $this->save(); - Notification::success(t('Preferences successfully saved')); + if ($this->getElement('btn_submit_preferences')->isChecked()) { + $this->save(); + Notification::success(t('Preferences successfully saved')); + } else { + Notification::success(t('Preferences successfully saved for the current session')); + } } catch (Exception $e) { Logger::error($e); Notification::error($e->getMessage()); @@ -119,11 +120,19 @@ class PreferenceForm extends Form * * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { - $values = $this->preferences->get('icingaweb', array()); - $values['browser_language'] = false === isset($values['language']); - $values['local_timezone'] = false === isset($values['timezone']); + $auth = Manager::getInstance(); + $values = $auth->getUser()->getPreferences()->get('icingaweb'); + + if (! isset($values['language'])) { + $values['language'] = 'autodetect'; + } + + if (! isset($values['timezone'])) { + $values['timezone'] = 'autodetect'; + } + $this->populate($values); } @@ -133,72 +142,40 @@ class PreferenceForm extends Form public function createElements(array $formData) { $languages = array(); + $languages['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getLocale()); foreach (Translator::getAvailableLocaleCodes() as $language) { $languages[$language] = $language; } $tzList = array(); + $tzList['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone()); foreach (DateTimeZone::listIdentifiers() as $tz) { $tzList[$tz] = $tz; } $this->addElement( - 'checkbox', - 'browser_language', - array( - 'ignore' => true, - 'required' => true, - 'autosubmit' => true, - 'value' => true, - 'label' => t('Use your browser\'s language suggestions') - ) - ); - - $useBrowserLanguage = isset($formData['browser_language']) ? $formData['browser_language'] == 1 : true; - $languageSelection = $this->createElement( 'select', 'language', array( - 'required' => false === $useBrowserLanguage, + 'required' => true, 'label' => t('Your Current Language'), 'description' => t('Use the following language to display texts and messages'), 'multiOptions' => $languages, 'value' => substr(setlocale(LC_ALL, 0), 0, 5) ) ); - if ($useBrowserLanguage) { - $languageSelection->setAttrib('disabled', 'disabled'); - } - $this->addElement($languageSelection); $this->addElement( - 'checkbox', - 'local_timezone', - array( - 'ignore' => true, - 'required' => true, - 'autosubmit' => true, - 'value' => true, - 'label' => t('Use your local timezone') - ) - ); - - $useLocalTimezone = isset($formData['local_timezone']) ? $formData['local_timezone'] == 1 : true; - $timezoneSelection = $this->createElement( 'select', 'timezone', array( - 'required' => false === $useLocalTimezone, + 'required' => true, 'label' => t('Your Current Timezone'), 'description' => t('Use the following timezone for dates and times'), 'multiOptions' => $tzList, 'value' => $this->getDefaultTimezone() ) ); - if ($useLocalTimezone) { - $timezoneSelection->setAttrib('disabled', 'disabled'); - } - $this->addElement($timezoneSelection); $this->addElement( 'checkbox', @@ -208,6 +185,43 @@ class PreferenceForm extends Form 'label' => t('Use benchmark') ) ); + + $this->addElement( + 'submit', + 'btn_submit_preferences', + array( + 'ignore' => true, + 'label' => t('Save to the Preferences'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'div')) + ) + ) + ); + + $this->addElement( + 'submit', + 'btn_submit_session', + array( + 'ignore' => true, + 'label' => t('Save for the current Session'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'div')) + ) + ) + ); + + $this->addDisplayGroup( + array('btn_submit_preferences', 'btn_submit_session'), + 'submit_buttons', + array( + 'decorators' => array( + 'FormElements', + array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')) + ) + ) + ); } /** @@ -221,7 +235,18 @@ class PreferenceForm extends Form if ($detect->success()) { return $detect->getTimezoneName(); } else { - return date_default_timezone_get(); + return @date_default_timezone_get(); } } + + /** + * Return the preferred locale based on the given HTTP header and the available translations + * + * @return string + */ + protected function getLocale() + { + $locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']); + return $locale; + } } diff --git a/application/views/scripts/authentication/login.phtml b/application/views/scripts/authentication/login.phtml index fe3ab5e3b..e931d0448 100644 --- a/application/views/scripts/authentication/login.phtml +++ b/application/views/scripts/authentication/login.phtml @@ -1,11 +1,10 @@
-

translate('Icingaweb Login') ?>

errorInfo)): ?> @@ -14,6 +13,18 @@
form ?> - + + +
', // TODO: Documentation link + '', + '' + ); ?>
+
diff --git a/application/views/scripts/config/authentication/reorder.phtml b/application/views/scripts/config/authentication/reorder.phtml index 0ae7850eb..688d99f88 100644 --- a/application/views/scripts/config/authentication/reorder.phtml +++ b/application/views/scripts/config/authentication/reorder.phtml @@ -4,8 +4,8 @@ \ No newline at end of file + diff --git a/application/views/scripts/config/module.phtml b/application/views/scripts/config/module.phtml index c74cac80d..b7f6bf346 100644 --- a/application/views/scripts/config/module.phtml +++ b/application/views/scripts/config/module.phtml @@ -1,5 +1,6 @@
tabs ?> +

escape($module->getTitle()) ?>

@@ -12,7 +13,6 @@ $permissions = $module->getProvidedPermissions(); $state = $moduleData->enabled ? ($moduleData->loaded ? 'enabled' : 'failed') : 'disabled' ?> -

escape($module->getTitle()) ?>

diff --git a/application/views/scripts/config/modules.phtml b/application/views/scripts/config/modules.phtml index c0951d415..95c9fa731 100644 --- a/application/views/scripts/config/modules.phtml +++ b/application/views/scripts/config/modules.phtml @@ -11,9 +11,9 @@ @@ -37,4 +37,4 @@
escape('Name') ?>
enabled): ?> - icon('success.png', $this->translate('Module is enabled')) ?> + icon('thumbs-up', $this->translate('Module is enabled')) ?> - icon('remove.png', $this->translate('Module is disabled')) ?> + icon('thumbs-down', $this->translate('Module is disabled')) ?>

- icon('create.png'); ?> translate('Create A New Resource'); ?> + icon('plus'); ?> translate('Create A New Resource'); ?>

@@ -13,20 +13,20 @@ -resources as $name => $resource): ?> +resources as $name): ?>
translate('Remove'); ?>
- icon('edit.png'); ?> escape($name); ?> + icon('edit'); ?> escape($name); ?> - icon('remove.png'); ?> + icon('minus'); ?>
- \ No newline at end of file + diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml index 8153e17d2..e23df8b7a 100644 --- a/application/views/scripts/form/reorder-authbackend.phtml +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -11,23 +11,23 @@
- icon('edit.png'); ?> escape($backendNames[$i]); ?> + icon('edit'); ?> escape($backendNames[$i]); ?> - icon('remove.png', $this->translate('Remove')); ?> + icon('minus', $this->translate('Remove')); ?> 0): ?>
getElement($form->getTokenElementName()); ?> getElement($form->getUidElementName()); ?> - \ No newline at end of file + diff --git a/application/views/scripts/joystickPagination.phtml b/application/views/scripts/joystickPagination.phtml new file mode 100644 index 000000000..27cafa309 --- /dev/null +++ b/application/views/scripts/joystickPagination.phtml @@ -0,0 +1,99 @@ +count() <= 1 && $yAxisPaginator->count() <= 1) { + return; // Display this pagination only if there are multiple pages +} + +$fromTo = t('%s: %d to %d of %d'); +$xAxisPages = $xAxisPaginator->getPages('all'); +$yAxisPages = $yAxisPaginator->getPages('all'); + +$totalYAxisPages = $yAxisPaginator->count(); +$currentYAxisPage = $yAxisPaginator->getCurrentPageNumber(); +$prevYAxisPage = $currentYAxisPage > 1 ? $currentYAxisPage - 1 : null; +$nextYAxisPage = $currentYAxisPage < $totalYAxisPages ? $currentYAxisPage + 1 : null; + +$totalXAxisPages = $xAxisPaginator->count(); +$currentXAxisPage = $xAxisPaginator->getCurrentPageNumber(); +$prevXAxisPage = $currentXAxisPage > 1 ? $currentXAxisPage - 1 : null; +$nextXAxisPage = $currentXAxisPage < $totalXAxisPages ? $currentXAxisPage + 1 : null; + +?> + + + + + + + + + + + + + + + + + + + +
  + + icon('up-open'); ?> + + icon('up-open'); ?> + +  
+ + icon('left-open'); ?> + + icon('left-open'); ?> + +   + + icon('right-open'); ?> + + icon('right-open'); ?> + +
  + + icon('down-open'); ?> + + icon('down-open'); ?> + +  
diff --git a/bin/icingacli b/bin/icingacli index 1a0781222..c85777c9c 100755 --- a/bin/icingacli +++ b/bin/icingacli @@ -1,6 +1,8 @@ #!/usr/bin/php dispatch(); + +Icinga\Application\Cli::start()->dispatch(); diff --git a/config/.gitignore b/config/.gitignore deleted file mode 100644 index 0a2f13d0d..000000000 --- a/config/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -authentication.ini -config.ini -modules/monitoring/backends.ini -modules/monitoring/instances.ini -resources.ini - diff --git a/config/authentication.ini.in b/config/authentication.ini.in deleted file mode 100644 index 2a2d2a969..000000000 --- a/config/authentication.ini.in +++ /dev/null @@ -1,29 +0,0 @@ -; authentication.ini -; -; Each section listed in this configuration represents a backend used to authenticate users. The backend configurations -; must define a resource referring to a configured database or LDAP connection in the INI file resources.ini. -; -; The backends will be processed from top to bottom using the first backend for authentication which reports that -; the user trying to log in is available. - -[autologin] -backend = autologin -; -; If you want to strip the domain -; strip_username_regexp = /\@[^$]+$/ - -[internal_ldap_authentication] -@ldap_auth_disabled@ -backend = ldap -resource = internal_ldap -user_class = @ldap_user_objectclass@ -user_name_attribute = @ldap_attribute_username@ -group_base_dn = @ldap_group_base_dn@ -group_attribute = @ldap_group_attribute@ -group_member_attribute = @ldap_group_member_attribute@ -group_class = @ldap_group_class@ - -[internal_db_authentication] -@internal_auth_disabled@ -backend = db -resource = internal_db diff --git a/config/config.ini.in b/config/config.ini.in deleted file mode 100644 index 560acf527..000000000 --- a/config/config.ini.in +++ /dev/null @@ -1,41 +0,0 @@ -[global] -timezone = "Europe/Berlin" - -; Contains the directories that will be searched for available modules. Modules that -; don't exist in these directories can still be symlinked in the module folder, but -; won't show up in the list of disabled modules -; modulePath = "/vagrant/modules:/usr/share/icingaweb/modules" - -[logging] -enable = true -; Writing to a Stream -type = "file" -; Write data to the following file -target = "@icingaweb_log_path@/icingaweb.log" -; Write data to a PHP stream -;target = "php://output" - -; Writing to the System Log -;type = "syslog" -; Prefix all syslog messages generated with the string "icingaweb" -;application = "icingaweb" -;facility = "LOG_USER" - -level = 1 -; The default level is WARNING, which means that only events of this level and -; above will be tracked. Level numbers descend in order of importance where -; ERROR (0) is the most important level and DEBUG (3) is the least important -; level: -; -; ERROR = 0 - Error: error conditions -; WARNING = 1 - Warning: warning conditions -; INFO = 2 - Informational: informational messages -; DEBUG = 3 - Debug: debug messages - -[preferences] -; Use INI file storage to save preferences to a local disk -type = "ini" - -; Use database storage to save preferences in either a MySQL or PostgreSQL database -;type = db -;resource = icingaweb-mysql diff --git a/config/enabledModules/README b/config/enabledModules/README deleted file mode 100644 index 7a55ea091..000000000 --- a/config/enabledModules/README +++ /dev/null @@ -1 +0,0 @@ -Enabled modules shall be symlinked here. diff --git a/config/ldap/ldap_ca.conf.in b/config/ldap/ldap_ca.conf.in deleted file mode 100644 index 2682820b8..000000000 --- a/config/ldap/ldap_ca.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -# Use given CA file -TLS_REQCERT demand -TLS_CACERT @prefix@/config/ssl/cacerts/trusted.crt - diff --git a/config/ldap/ldap_nocert.conf b/config/ldap/ldap_nocert.conf deleted file mode 100644 index 768691479..000000000 --- a/config/ldap/ldap_nocert.conf +++ /dev/null @@ -1,4 +0,0 @@ -# This config file will allow TLS-based LDAP connections ignoring -# unknown certificates -TLS_REQCERT never - diff --git a/config/memberships.ini b/config/memberships.ini deleted file mode 100644 index c92fae47c..000000000 --- a/config/memberships.ini +++ /dev/null @@ -1,9 +0,0 @@ -[membership-set1] -backend = groupX -users = icingaadmin,tgelf -groups = admin,users - -[membership-set2] -backend = groupY -users = icingaadmin -groups = support1,support2 diff --git a/config/modules/monitoring/backends.ini.in b/config/modules/monitoring/backends.ini.in deleted file mode 100644 index 910f17f81..000000000 --- a/config/modules/monitoring/backends.ini.in +++ /dev/null @@ -1,19 +0,0 @@ -[localdb] -@ido_enabled@ -type = ido -resource = "ido" - -[locallive] -@livestatus_enabled@ -type = livestatus -resource = livestatus - -[localfile] -@statusdat_enabled@ -type = statusdat -resource = statusdat - -;[localfailsafe] -;enabled=false -;type = combo -;backends = localdb, locallive, localfile diff --git a/config/modules/monitoring/config.ini b/config/modules/monitoring/config.ini deleted file mode 100644 index 9b69fe86f..000000000 --- a/config/modules/monitoring/config.ini +++ /dev/null @@ -1,2 +0,0 @@ -[security] -protected_customvars = "*pw*,*pass*,community" diff --git a/config/modules/monitoring/instances.ini.in b/config/modules/monitoring/instances.ini.in deleted file mode 100644 index f129553d0..000000000 --- a/config/modules/monitoring/instances.ini.in +++ /dev/null @@ -1,2 +0,0 @@ -[icinga] -path = "@icinga_commandpipe@" diff --git a/config/permissions.ini b/config/permissions.ini deleted file mode 100644 index 3fec92f1c..000000000 --- a/config/permissions.ini +++ /dev/null @@ -1,11 +0,0 @@ -[test1] -users = icingaadmin,root,tgelf -groups = support2,support2 -permission_1 = monitoring, monitoring/log -permission_2 = monitoring/command/all - -[test2] -users = root -groups = admin -permission_2 = test/permission/1, test/permission/2 -permission_3 = test/permission/15, test/permission/7 \ No newline at end of file diff --git a/config/preferences/.gitkeep b/config/preferences/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/resources.ini.in b/config/resources.ini.in deleted file mode 100644 index d4c617c51..000000000 --- a/config/resources.ini.in +++ /dev/null @@ -1,55 +0,0 @@ -; resources.ini -; -; The configuration file *resources.ini* contains data sources that -; can be referenced in other configurations. This allows you to manage -; all connections to SQL databases in one single place, avoiding the need -; to edit several different configuration files, when the connection -; information of a resource change. -; -; Each section represents a resource, with the section name being the -; identifier used to reference this certain section. Depending on the -; resource type, each section contains different properties. The property -; *type* defines the resource type and thus how the properties are going to -; be interpreted. Currently only the resource type *db* is available. - - -[internal_db] -type = db -db = @internal_db_type@ -host = @internal_db_host@ -port = @internal_db_port@ -password = @internal_db_password@ -username = @internal_db_user@ -dbname = @internal_db_name@ - -[ido] -type = db -db = @ido_db_type@ -host = @ido_host@ -port = @ido_port@ -password = @ido_password@ -username = @ido_user@ -dbname = @ido_db_name@ - -[statusdat] -type = statusdat -status_file = @statusdat_file@ -object_file = @objects_cache_file@ - -[livestatus] -type = livestatus -socket = @livestatus_socket@ - -[internal_ldap] -type = ldap -hostname = @ldap_host@ -port = @ldap_port@ -root_dn = "@ldap_rootdn@" -bind_dn = "@ldap_binddn@" -bind_pw = @ldap_bindpass@ - -[logfile] -type = file -filename = "@icingaweb_log_path@/icingaweb.log" -fields = "/^(?[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) - (?[A-Za-z]+) - (?.*)$/" -; format: PCRE diff --git a/config/restrictions.ini b/config/restrictions.ini deleted file mode 100644 index d14a8a60f..000000000 --- a/config/restrictions.ini +++ /dev/null @@ -1,16 +0,0 @@ -[test1] -users = "user1" -groups = "no-such-group" -name = "monitoring/filter" -restriction = "hostgroup=lalala&service_description=*ping*" - -[test2] -users = "user2" -name = "monitoring/filter" -restriction = "hostgroup=kunden*&service_description=*ping*" - -[test3] -users = "user3" -name = "monitoring/filter" -restriction = "hostgroup=kunden*&service_description=*ping-ping*" - diff --git a/config/ssl/cacerts/trusted.crt.in b/config/ssl/cacerts/trusted.crt.in deleted file mode 100644 index e69de29bb..000000000 diff --git a/configure b/configure deleted file mode 100755 index a48f71506..000000000 --- a/configure +++ /dev/null @@ -1,4125 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for IcingaWeb2 1.0.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org and info@icinga.org -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='IcingaWeb2' -PACKAGE_TARNAME='icingaweb2' -PACKAGE_VERSION='1.0.0' -PACKAGE_STRING='IcingaWeb2 1.0.0' -PACKAGE_BUGREPORT='info@icinga.org' -PACKAGE_URL='' - -ac_default_prefix=/usr/local/icingaweb -ac_subst_vars='LTLIBOBJS -LIBOBJS -INSTALL_OPTS_WEB -INSTALL_OPTS -internal_auth_disabled -ldap_auth_disabled -icinga_commandpipe -livestatus_enabled -livestatus_socket -objects_cache_file -statusdat_file -statusdat_enabled -ido_password -ido_user -ido_db_name -ido_port -ido_host -ido_db_type -ido_enabled -icinga_backend -ldap_attribute_username -ldap_attribute_basedn -ldap_user_objectclass -ldap_bindpass -ldap_binddn -ldap_rootdn -ldap_port -ldap_host -internal_db_password -internal_db_user -internal_db_port -internal_db_host -internal_db_name -internal_db_type -icingaweb_log_path -icingaweb_config_path -bin_group -bin_user -httpd_config_path -web_path -web_group -web_user -app_name -PHP -SED -GREP -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -with_icingaweb_config_path -with_icingaweb_log_path -with_web_user -with_web_group -with_web_path -with_httpd_config_path -with_bin_user -with_bin_group -with_internal_db_type -with_internal_db_name -with_internal_db_host -with_internal_db_port -with_internal_db_password -with_internal_db_user -with_internal_authentication -with_ldap_authentication -with_ldap_host -with_ldap_port -with_ldap_binddn -with_ldap_bindpass -with_ldap_rootdn -with_ldap_user_objectclass -with_ldap_attribute_username -with_icinga_backend -with_ido_db_type -with_ido_host -with_ido_port -with_ido_db_name -with_ido_user -with_ido_password -with_statusdat_file -with_objects_cache_file -with_livestatus_socket -with_icinga_commandpipe -' - ac_precious_vars='build_alias -host_alias -target_alias -PHP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures IcingaWeb2 1.0.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/icingaweb2] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of IcingaWeb2 1.0.0:";; - esac - cat <<\_ACEOF - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-icingaweb-config-path=PATH - Configuration path for icinga web (default - $prefix/config) - --with-icingaweb-log-path=PATH - Log path for icinga web (default $prefix/var/log) - --with-web-user=USER username for web writable files (default www-data) - --with-web-group=GROUP group for web writable files (default www-data) - --with-web-path=PATH web sub path (default /icingaweb) - --with-httpd-config-path=PATH - Include folder apache2 (default /etc/apache2/conf.d) - --with-bin-user=USER user for all other files (default root) - --with-bin-group=GROUP group for all other files (default bin) - --with-internal-db-type=TYPE - database type to use for internal database (default - mysql, supported: pgsql, mysql) - --with-internal-db-name=NAME - database name to use for internal database (default - icingaweb) - --with-internal-db-host=HOST - database host to use for internal database (default - localhost) - --with-internal-db-port=PORT - database port to use for internal database (default: - 3306 for mysql, 5432 for pgsql) - --with-internal-db-password=PASS - database pass to use for internal database (default - icingaweb) - --with-internal-db-user=USER - database user to use for internal database (default - icingaweb) - --with-internal-authentication - use the internal database for authentication - (default: yes) - --with-ldap-authentication - use a ldap server for authentication (default: no) - --with-ldap-host=HOST host to use for authentication via ldap (default - localhost) - --with-ldap-port=PORT port to use for authentication via ldap (default - 389) - --with-ldap-binddn=DN dn to use for retrieving user information via ldap - (default cn=admin, cn=config) - --with-ldap-bindpass=PASS - password to use for retrieving user information via - ldap (default admin) - --with-ldap-rootdn=LDAP_ATTRIBUTE - root dn to use for user lookup (default ou=people, - dc=icinga, dc=org) - --with-ldap-user-objectclass=LDAP_OBJECT_CLASS - ldap object class to use for user authentication - (default: inetOrgPerson) - --with-ldap-attribute-username=LDAP_ATTRIBUTE - user attribute to use for the username (default: - uid) - --with-icinga-backend=(ido, statusdat, livestatus) - backend to use for rb (default: statusdat) - --with-ido-db-type=(mysql, pgsql) - database engine to use for retrieving data from the - ido db (default: mysql) - --with-ido-host=HOST host to use for retrieving data from the ido db - (default: localhost) - --with-ido-port=PORT backend to use for retrieving data from the ido db - (default: 3306 for mysql. 5432 for pgsql) - --with-ido-db-name=DATABASE - database name to use for retrieving data from the - ido db (default: icinga) - --with-ido-user=USER user to use for retrieving data from the ido db - (default: icinga) - --with-ido-password=PASSWORD - password to use for retrieving data from the ido db - (default: icinga) - --with-statusdat-file=FILE - location of the status.dat file when retrieving data - from status.dat (default: - /usr/local/icinga/var/status.dat) - --with-objects-cache-file=FILE - location of the objects.cache file when retrieving - data from status.dat (default: - /usr/local/icinga/var/objects.cache) - --with-livestatus-socket=FILE - location of the livestatus socket (default: - /usr/local/icinga/var/rw/live) - --with-icinga-commandpipe=FILE - location of the command pipe used for sending - commands (default: - /usr/local/icinga/var/rw/icinga.cmd) - --with-objects-file=FILE - location of the objects.cache file when retrieving - data from status.dat (default: - /usr/local/icinga/var/objects.cache) - -Some influential environment variables: - PHP php cli binary - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -IcingaWeb2 configure 1.0.0 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by IcingaWeb2 $as_me 1.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - -if test "x$prefix" = "xNONE" ; then - installDir="/usr/local/icingaweb" - prefix=$installDir -else - installDir=$prefix -fi - -# Checks for programs. -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - - -# Check for php - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework' is available... " >&6; } - if php -r 'require "Zend/Application.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework' is missing" "$LINENO" 5 -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has at least version 5.3.0" >&5 -$as_echo_n "checking if php has at least version 5.3.0... " >&6; } - if test 5 -le `php -r 'echo PHP_MAJOR_VERSION;'` && \ - test 3 -le `php -r 'echo PHP_MINOR_VERSION;'` && \ - test 0 -le `php -r 'echo PHP_RELEASE_VERSION;'`; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP version is correct" >&5 -$as_echo "PHP version is correct" >&6; } -else - as_fn_error $? "You need at least PHP version 5.3.0" "$LINENO" 5 -fi - - - # Extract the first word of "php", so it can be a program name with args. -set dummy php; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_path_PHP+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $PHP in - [\\/]* | ?:[\\/]*) - ac_cv_path_PHP="$PHP" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_PHP="$as_dir/$ac_word$ac_exec_ext" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_PHP" && ac_cv_path_PHP="not found" - ;; -esac -fi -PHP=$ac_cv_path_PHP -if test -n "$PHP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PHP" >&5 -$as_echo "$PHP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - if test "XX${PHP}" == "XXnot found" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: binary php not found in PATH" >&5 -$as_echo "$as_me: WARNING: binary php not found in PATH" >&2;} -fi - - test "XX${PHP}" == "XXnot found" && PHP="" - - -# Checks for libraries. - - for x in sockets json;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - -# -# Configuration files -# - -# Check whether --with-icingaweb_config_path was given. -if test "${with_icingaweb_config_path+set}" = set; then : - withval=$with_icingaweb_config_path; icingaweb_config_path=$withval -else - icingaweb_config_path=$prefix/config - -fi - - -# -# Log files -# - -# Check whether --with-icingaweb_log_path was given. -if test "${with_icingaweb_log_path+set}" = set; then : - withval=$with_icingaweb_log_path; icingaweb_log_path=$withval -else - icingaweb_log_path=$prefix/var/log - -fi - - -# -# Users for webfiles -# - - -# Check whether --with-web_user was given. -if test "${with_web_user+set}" = set; then : - withval=$with_web_user; web_user=$withval -else - - web_user=www-data - for x in www wwwrun www-data apache httpd nobody; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if user $x exists" >&5 -$as_echo_n "checking if user $x exists... " >&6; } - if $GREP -q "^$x:" /etc/passwd ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; web_user=$x ; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } -fi - done - - -fi - - - -# Check whether --with-web_group was given. -if test "${with_web_group+set}" = set; then : - withval=$with_web_group; web_group=$withval -else - - web_group=www-data - for x in www www-data apache httpd nogroup nobody; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if group $x exists" >&5 -$as_echo_n "checking if group $x exists... " >&6; } - if $GREP -q "^$x:" /etc/group ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; web_group=$x ; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } -fi - done - - -fi - - - -# Check whether --with-web_path was given. -if test "${with_web_path+set}" = set; then : - withval=$with_web_path; web_path=$withval -else - web_path=/icingaweb - -fi - - - -# Check whether --with-httpd_config_path was given. -if test "${with_httpd_config_path+set}" = set; then : - withval=$with_httpd_config_path; httpd_config_path=$withval -else - httpd_config_path= - httpd_config_path=/etc/apache2/conf.d - for x in /etc/httpd/conf.d /etc/apache2/conf-available /etc/apache2/conf.d /etc/apache/conf.d; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if path $x exists" >&5 -$as_echo_n "checking if path $x exists... " >&6; } - if test -d $x; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; }; httpd_config_path=$x; break -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - -fi - done - - -fi - - -# -# Users and groups for installation -# - - -# Check whether --with-bin_user was given. -if test "${with_bin_user+set}" = set; then : - withval=$with_bin_user; bin_user=$withval -else - bin_user=root - -fi - - - -# Check whether --with-bin_group was given. -if test "${with_bin_group+set}" = set; then : - withval=$with_bin_group; bin_group=$withval -else - bin_group=bin - -fi - - -# -# Internal database setup -# - - -# Check whether --with-internal_db_type was given. -if test "${with_internal_db_type+set}" = set; then : - withval=$with_internal_db_type; internal_db_type=$withval -else - internal_db_type=mysql - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing database type for --with-internal-db-type" >&5 -$as_echo_n "checking Testing database type for --with-internal-db-type... " >&6; } - if echo "$internal_db_type" | $GREP -q "^\(my\|pg\)sql$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($internal_db_type)" >&5 -$as_echo "OK ($internal_db_type)" >&6; } -else - as_fn_error $? "$internal_db_type" "$LINENO" 5 - -fi - - - -# Check whether --with-internal_db_name was given. -if test "${with_internal_db_name+set}" = set; then : - withval=$with_internal_db_name; internal_db_name=$withval -else - internal_db_name=icingaweb - -fi - - - -# Check whether --with-internal_db_host was given. -if test "${with_internal_db_host+set}" = set; then : - withval=$with_internal_db_host; internal_db_host=$withval -else - internal_db_host=localhost - -fi - - - -# Check whether --with-internal_db_port was given. -if test "${with_internal_db_port+set}" = set; then : - withval=$with_internal_db_port; internal_db_port=$withval -else - internal_db_port=db_default_port - -fi - - - -# Check whether --with-internal_db_password was given. -if test "${with_internal_db_password+set}" = set; then : - withval=$with_internal_db_password; internal_db_password=$withval -else - internal_db_password=icingaweb - -fi - - - -# Check whether --with-internal_db_user was given. -if test "${with_internal_db_user+set}" = set; then : - withval=$with_internal_db_user; internal_db_user=$withval -else - internal_db_user=icingaweb - -fi - - -# -# Authorization method -# - - -# Check whether --with-internal_authentication was given. -if test "${with_internal_authentication+set}" = set; then : - withval=$with_internal_authentication; internal_authentication=$withval -else - internal_authentication=yes - -fi - - - -# Check whether --with-ldap_authentication was given. -if test "${with_ldap_authentication+set}" = set; then : - withval=$with_ldap_authentication; ldap_authentication=$withval -else - ldap_authentication=no - -fi - - -# -# LDAP Authorization -# - - -# Check whether --with-ldap_host was given. -if test "${with_ldap_host+set}" = set; then : - withval=$with_ldap_host; ldap_host=$withval -else - ldap_host=localhost - -fi - - - -# Check whether --with-ldap_port was given. -if test "${with_ldap_port+set}" = set; then : - withval=$with_ldap_port; ldap_port=$withval -else - ldap_port=389 - -fi - - - -# Check whether --with-ldap_binddn was given. -if test "${with_ldap_binddn+set}" = set; then : - withval=$with_ldap_binddn; ldap_binddn=$withval -else - ldap_binddn="cn=admin,cn=config" - -fi - - - -# Check whether --with-ldap_bindpass was given. -if test "${with_ldap_bindpass+set}" = set; then : - withval=$with_ldap_bindpass; ldap_bindpass=$withval -else - ldap_bindpass="admin" - -fi - - - -# Check whether --with-ldap_rootdn was given. -if test "${with_ldap_rootdn+set}" = set; then : - withval=$with_ldap_rootdn; ldap_rootdn=$withval -else - ldap_rootdn="ou=people, dc=icinga, dc=org" - -fi - - - -# Check whether --with-ldap_user_objectclass was given. -if test "${with_ldap_user_objectclass+set}" = set; then : - withval=$with_ldap_user_objectclass; ldap_user_objectclass=$withval -else - ldap_user_objectclass="inetOrgPerson" - -fi - - - -# Check whether --with-ldap_attribute_username was given. -if test "${with_ldap_attribute_username+set}" = set; then : - withval=$with_ldap_attribute_username; ldap_attribute_username=$withval -else - ldap_attribute_username="uid" - -fi - - -# -# Icinga backend selection -# - - -# Check whether --with-icinga_backend was given. -if test "${with_icinga_backend+set}" = set; then : - withval=$with_icinga_backend; icinga_backend=$withval -else - icinga_backend="statusdat" - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing backend type for --with-icinga-backend" >&5 -$as_echo_n "checking Testing backend type for --with-icinga-backend... " >&6; } - if echo "$icinga_backend" | $GREP -q "^\(ido\|statusdat\|livestatus\)$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($icinga_backend)" >&5 -$as_echo "OK ($icinga_backend)" >&6; } -else - as_fn_error $? "$icinga_backend" "$LINENO" 5 - -fi - - -# -# Ido settings -# - - -# Check whether --with-ido_db_type was given. -if test "${with_ido_db_type+set}" = set; then : - withval=$with_ido_db_type; ido_db_type=$withval -else - ido_db_type="mysql" - -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Testing database type for --with-ido-db-type" >&5 -$as_echo_n "checking Testing database type for --with-ido-db-type... " >&6; } - if echo "$ido_db_type" | $GREP -q "^\(my\|pg\)sql$"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: OK ($ido_db_type)" >&5 -$as_echo "OK ($ido_db_type)" >&6; } -else - as_fn_error $? "$ido_db_type" "$LINENO" 5 - -fi - - - -# Check whether --with-ido_host was given. -if test "${with_ido_host+set}" = set; then : - withval=$with_ido_host; ido_host=$withval -else - ido_host="localhost" - -fi - - - -# Check whether --with-ido_port was given. -if test "${with_ido_port+set}" = set; then : - withval=$with_ido_port; ido_port=$withval -else - ido_port=db_default_port - -fi - - - -# Check whether --with-ido_db_name was given. -if test "${with_ido_db_name+set}" = set; then : - withval=$with_ido_db_name; ido_db_name=$withval -else - ido_db_name="icinga" - -fi - - - -# Check whether --with-ido_user was given. -if test "${with_ido_user+set}" = set; then : - withval=$with_ido_user; ido_user=$withval -else - ido_user="icinga" - -fi - - - -# Check whether --with-ido_password was given. -if test "${with_ido_password+set}" = set; then : - withval=$with_ido_password; ido_password=$withval -else - ido_password="icinga" - -fi - - -# -# Statusdat file location -# - - -# Check whether --with-statusdat_file was given. -if test "${with_statusdat_file+set}" = set; then : - withval=$with_statusdat_file; statusdat_file=$withval -else - statusdat_file="/usr/local/icinga/var/status.dat" - -fi - - - -# Check whether --with-objects_cache_file was given. -if test "${with_objects_cache_file+set}" = set; then : - withval=$with_objects_cache_file; objects_cache_file=$withval -else - objects_cache_file="/usr/local/icinga/var/objects.cache" - -fi - - -# -# Livestatus connection -# - - -# Check whether --with-livestatus_socket was given. -if test "${with_livestatus_socket+set}" = set; then : - withval=$with_livestatus_socket; livestatus_socket=$withval -else - livestatus_socket="/usr/local/icinga/var/rw/live" - -fi - - -# -# Icinga commandpipe -# - - -# Check whether --with-icinga_commandpipe was given. -if test "${with_icinga_commandpipe+set}" = set; then : - withval=$with_icinga_commandpipe; icinga_commandpipe=$withval -else - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" - -fi - - - -# Check whether --with-objects_cache_file was given. -if test "${with_objects_cache_file+set}" = set; then : - withval=$with_objects_cache_file; objects_cache_file=$withval -else - objects_cache_file="/usr/local/icinga/var/objects.cache" - -fi - - -# -# Livestatus connection -# - - -# Check whether --with-livestatus_socket was given. -if test "${with_livestatus_socket+set}" = set; then : - withval=$with_livestatus_socket; livestatus_socket=$withval -else - livestatus_socket="/usr/local/icinga/var/rw/live" - -fi - - -# -# Icinga commandpipe -# - - -# Check whether --with-icinga_commandpipe was given. -if test "${with_icinga_commandpipe+set}" = set; then : - withval=$with_icinga_commandpipe; icinga_commandpipe=$withval -else - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" - -fi - - -# Installation options -INSTALL_OPTS="-o $bin_user -g $bin_group" -INSTALL_OPTS_WEB="-o $web_user -g $web_group" - -if test "x$internal_db_type" = xmysql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Mysql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in mysql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$internal_db_port" == xdb_default_port; then : - internal_db_port=3306 -fi - -fi - -if test "x$ido_db_type" = xmysql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Mysql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - MySQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in mysql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$ido_port" = xdb_default_port; then : - ido_port=3306 -fi - -fi - -if test "x$internal_db_type" = xpgsql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Pgsql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in pgsql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$internal_db_port" = xdb_default_port; then : - internal_db_port=5432 -fi - -fi - -if test "x$ido_db_type" = xpgsql; then : - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available" >&5 -$as_echo_n "checking if PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is available... " >&6; } - if php -r 'require "Zend/Db/Adapter/Pdo/Pgsql.php";' ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: PHP runtime dependency fulfilled" >&5 -$as_echo "PHP runtime dependency fulfilled" >&6; } -else - as_fn_error $? "PHP runtime dependency 'Zend Framework - PostgreSQL PDO Adapter' is missing" "$LINENO" 5 -fi - - - for x in pgsql;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - if test "x$ido_port" = xdb_default_port; then : - ido_port=5432 -fi - -fi - -# -# Disable authentication backends -# - -ido_enabled="disabled = \"1\"" -statusdat_enabled="disabled = \"1\"" -livestatus_enabled="disabled = \"1\"" - -case $icinga_backend in #( - "ido") : - ido_enabled="" ;; #( - "statusdat") : - statusdat_enabled="" ;; #( - "livestatus") : - livestatus_enabled="" ;; #( - *) : - statusdat_enabled="" ;; -esac - -ldap_auth_disabled="disabled = \"1\"" -if test "x$ldap_authentication" != xno; then : - - for x in ldap;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - ldap_auth_disabled="" - -fi - -internal_auth_disabled="disabled = \"1\"" -if test "x$internal_authentication" != xno; then : - - for x in ldap;do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if php has $x module" >&5 -$as_echo_n "checking if php has $x module... " >&6; } - if php -m | $GREP -iq "^$x$" ; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } -else - as_fn_error $? "not found" "$LINENO" 5 -fi - done - - internal_auth_disabled="" - -fi - -# -# Substitution variables -# - -# Installation directives - - - - - - - - - - -# Internal db setup - - - - - - - -# ldap setup - - - - - - - - - -# backend setup - - -# ido backend variables - - - - - - - - -# status.dat backend - - - - -# livestatus backend - - - -# command pipe - - -# Comment placeholders for toggling backends - - - - -# Application and installation - - - - -# -# Create config files -# -ac_config_files="$ac_config_files Makefile config/authentication.ini config/config.ini config/resources.ini config/modules/monitoring/backends.ini config/modules/monitoring/instances.ini etc/apache/icingaweb.conf" - - -# -# Commit and write -# -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -ac_script=' -:mline -/\\$/{ - N - s,\\\n,, - b mline -} -t clear -:clear -s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g -t quote -s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g -t quote -b any -:quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g -s/\$/$$/g -H -:any -${ - g - s/^\n// - s/\n/ /g - p -} -' -DEFS=`sed -n "$ac_script" confdefs.h` - - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by IcingaWeb2 $as_me 1.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - -Configuration files: -$config_files - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -IcingaWeb2 config.status 1.0.0 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "config/authentication.ini") CONFIG_FILES="$CONFIG_FILES config/authentication.ini" ;; - "config/config.ini") CONFIG_FILES="$CONFIG_FILES config/config.ini" ;; - "config/resources.ini") CONFIG_FILES="$CONFIG_FILES config/resources.ini" ;; - "config/modules/monitoring/backends.ini") CONFIG_FILES="$CONFIG_FILES config/modules/monitoring/backends.ini" ;; - "config/modules/monitoring/instances.ini") CONFIG_FILES="$CONFIG_FILES config/modules/monitoring/instances.ini" ;; - "etc/apache/icingaweb.conf") CONFIG_FILES="$CONFIG_FILES etc/apache/icingaweb.conf" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - - -eval set X " :F $CONFIG_FILES " -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - - - - esac - -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 065c81a8f..000000000 --- a/configure.ac +++ /dev/null @@ -1,448 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ([2.61]) -AC_INIT([IcingaWeb2], [1.0.0], [info@icinga.org]) -AC_PREFIX_DEFAULT(/usr/local/icingaweb) - -if test "x$prefix" = "xNONE" ; then - installDir="/usr/local/icingaweb" - prefix=$installDir -else - installDir=$prefix -fi - -# Checks for programs. -AC_PROG_INSTALL -AC_PROG_GREP -AC_PROG_SED - -# Check for php -AC_ARG_VAR([PHP],[php cli binary]) -AC_CHECK_PHP_INCLUDE([Zend/Application.php],[Zend Framework]) -AC_CHECK_PHP_VERSION([5],[3],[0]) -AC_CHECK_BIN([PHP], [php]) - -# Checks for libraries. -AC_CHECK_PHP_MODULE([sockets json]) - -# -# Configuration files -# -AC_ARG_WITH([icingaweb_config_path], - AS_HELP_STRING([--with-icingaweb-config-path=PATH], [Configuration path for icinga web (default $prefix/config)]), - icingaweb_config_path=$withval, - icingaweb_config_path=$prefix/config -) - -# -# Log files -# -AC_ARG_WITH([icingaweb_log_path], - AS_HELP_STRING([--with-icingaweb-log-path=PATH], [Log path for icinga web (default $prefix/var/log)]), - icingaweb_log_path=$withval, - icingaweb_log_path=$prefix/var/log -) - -# -# Users for webfiles -# - -AC_ARG_WITH([web_user], - AS_HELP_STRING([--with-web-user=USER], [username for web writable files (default www-data)]), - web_user=$withval, - AC_USER_GUESS([www wwwrun www-data apache httpd nobody],[web_user],[www-data]) -) - -AC_ARG_WITH([web_group], - AS_HELP_STRING([--with-web-group=GROUP], [group for web writable files (default www-data)]), - web_group=$withval, - AC_GROUP_GUESS([www www-data apache httpd nogroup nobody],[web_group], [www-data]) -) - -AC_ARG_WITH([web_path], - AS_HELP_STRING([--with-web-path=PATH], [web sub path (default /icingaweb)]), - web_path=$withval, - web_path=/icingaweb -) - -AC_ARG_WITH([httpd_config_path], - AS_HELP_STRING([--with-httpd-config-path=PATH], [Include folder apache2 (default /etc/apache2/conf.d)]), - httpd_config_path=$withval, - httpd_config_path=AC_PATH_GUESS([/etc/httpd/conf.d /etc/apache2/conf-available /etc/apache2/conf.d /etc/apache/conf.d], [httpd_config_path], [/etc/apache2/conf.d]) -) - -# -# Users and groups for installation -# - -AC_ARG_WITH([bin_user], - AS_HELP_STRING([--with-bin-user=USER], [user for all other files (default root)]), - bin_user=$withval, - bin_user=root -) - -AC_ARG_WITH([bin_group], - AS_HELP_STRING([--with-bin-group=GROUP], [group for all other files (default bin)]), - bin_group=$withval, - bin_group=bin -) - -# -# Internal database setup -# - -AC_ARG_WITH([internal_db_type], - AS_HELP_STRING([--with-internal-db-type=TYPE], [database type to use for internal database (default mysql, supported: pgsql, mysql)]), - internal_db_type=$withval, - internal_db_type=mysql -) - -ICINGA_CHECK_DBTYPE($internal_db_type, [--with-internal-db-type]) - -AC_ARG_WITH([internal_db_name], - AS_HELP_STRING([--with-internal-db-name=NAME], [database name to use for internal database (default icingaweb)]), - internal_db_name=$withval, - internal_db_name=icingaweb -) - -AC_ARG_WITH([internal_db_host], - AS_HELP_STRING([--with-internal-db-host=HOST], [database host to use for internal database (default localhost)]), - internal_db_host=$withval, - internal_db_host=localhost -) - -AC_ARG_WITH([internal_db_port], - AS_HELP_STRING([--with-internal-db-port=PORT], [database port to use for internal database (default: 3306 for mysql, 5432 for pgsql)]), - internal_db_port=$withval, - internal_db_port=db_default_port -) - -AC_ARG_WITH([internal_db_password], - AS_HELP_STRING([--with-internal-db-password=PASS], [database pass to use for internal database (default icingaweb)]), - internal_db_password=$withval, - internal_db_password=icingaweb -) - -AC_ARG_WITH([internal_db_user], - AS_HELP_STRING([--with-internal-db-user=USER], [database user to use for internal database (default icingaweb)]), - internal_db_user=$withval, - internal_db_user=icingaweb -) - -# -# Authorization method -# - -AC_ARG_WITH([internal_authentication], - AC_HELP_STRING([--with-internal-authentication], [use the internal database for authentication (default: yes)]), - internal_authentication=$withval, - internal_authentication=yes -) - -AC_ARG_WITH([ldap_authentication], - AC_HELP_STRING([--with-ldap-authentication], [use a ldap server for authentication (default: no)]), - ldap_authentication=$withval, - ldap_authentication=no -) - -# -# LDAP Authorization -# - -AC_ARG_WITH([ldap_host], - AS_HELP_STRING([--with-ldap-host=HOST], [host to use for authentication via ldap (default localhost)]), - ldap_host=$withval, - ldap_host=localhost -) - -AC_ARG_WITH([ldap_port], - AS_HELP_STRING([--with-ldap-port=PORT], [port to use for authentication via ldap (default 389)]), - ldap_port=$withval, - ldap_port=389 -) - -AC_ARG_WITH([ldap_binddn], - AS_HELP_STRING([--with-ldap-binddn=DN], [dn to use for retrieving user information via ldap (default cn=admin, cn=config)]), - ldap_binddn=$withval, - ldap_binddn=["cn=admin,cn=config"] -) - -AC_ARG_WITH([ldap_bindpass], - AS_HELP_STRING([--with-ldap-bindpass=PASS], [password to use for retrieving user information via ldap (default admin)]), - ldap_bindpass=$withval, - ldap_bindpass=["admin"] -) - -AC_ARG_WITH([ldap_rootdn], - AS_HELP_STRING([--with-ldap-rootdn=LDAP_ATTRIBUTE], [root dn to use for user lookup (default ou=people, dc=icinga, dc=org)]), - ldap_rootdn=$withval, - ldap_rootdn=["ou=people, dc=icinga, dc=org"] -) - -AC_ARG_WITH([ldap_user_objectclass], - AS_HELP_STRING([--with-ldap-user-objectclass=LDAP_OBJECT_CLASS], [ldap object class to use for user authentication (default: inetOrgPerson)]), - ldap_user_objectclass=$withval, - ldap_user_objectclass="inetOrgPerson" -) - -AC_ARG_WITH([ldap_attribute_username], - AS_HELP_STRING([--with-ldap-attribute-username=LDAP_ATTRIBUTE], [user attribute to use for the username (default: uid)]), - ldap_attribute_username=$withval, - ldap_attribute_username="uid" -) - -# -# Icinga backend selection -# - -AC_ARG_WITH([icinga_backend], - AS_HELP_STRING([--with-icinga-backend=(ido, statusdat, livestatus)], [backend to use for rb (default: statusdat)]), - icinga_backend=$withval, - icinga_backend="statusdat" -) - -ICINGA_CHECK_BACKENDTYPE($icinga_backend, [--with-icinga-backend]) - -# -# Ido settings -# - -AC_ARG_WITH([ido_db_type], - AS_HELP_STRING([--with-ido-db-type=(mysql, pgsql)], [database engine to use for retrieving data from the ido db (default: mysql)]), - ido_db_type=$withval, - ido_db_type="mysql" -) - -ICINGA_CHECK_DBTYPE($ido_db_type, [--with-ido-db-type]) - -AC_ARG_WITH([ido_host], - AS_HELP_STRING([--with-ido-host=HOST], [host to use for retrieving data from the ido db (default: localhost)]), - ido_host=$withval, - ido_host="localhost" -) - -AC_ARG_WITH([ido_port], - AS_HELP_STRING([--with-ido-port=PORT], [backend to use for retrieving data from the ido db (default: 3306 for mysql. 5432 for pgsql)]), - ido_port=$withval, - ido_port=db_default_port -) - -AC_ARG_WITH([ido_db_name], - AS_HELP_STRING([--with-ido-db-name=DATABASE], [database name to use for retrieving data from the ido db (default: icinga)]), - ido_db_name=$withval, - ido_db_name="icinga" -) - -AC_ARG_WITH([ido_user], - AS_HELP_STRING([--with-ido-user=USER], [user to use for retrieving data from the ido db (default: icinga)]), - ido_user=$withval, - ido_user="icinga" -) - -AC_ARG_WITH([ido_password], - AS_HELP_STRING([--with-ido-password=PASSWORD], [password to use for retrieving data from the ido db (default: icinga)]), - ido_password=$withval, - ido_password="icinga" -) - -# -# Statusdat file location -# - -AC_ARG_WITH([statusdat_file], - AS_HELP_STRING([--with-statusdat-file=FILE], [location of the status.dat file when retrieving data from status.dat (default: /usr/local/icinga/var/status.dat)]), - statusdat_file=$withval, - statusdat_file="/usr/local/icinga/var/status.dat" -) - -AC_ARG_WITH([objects_cache_file], - AS_HELP_STRING([--with-objects-cache-file=FILE], [location of the objects.cache file when retrieving data from status.dat (default: /usr/local/icinga/var/objects.cache)]), - objects_cache_file=$withval, - objects_cache_file="/usr/local/icinga/var/objects.cache" -) - -# -# Livestatus connection -# - -AC_ARG_WITH([livestatus_socket], - AS_HELP_STRING([--with-livestatus-socket=FILE], [location of the livestatus socket (default: /usr/local/icinga/var/rw/live)]), - livestatus_socket=$withval, - livestatus_socket="/usr/local/icinga/var/rw/live" -) - -# -# Icinga commandpipe -# - -AC_ARG_WITH([icinga_commandpipe], - AS_HELP_STRING([--with-icinga-commandpipe=FILE], [location of the command pipe used for sending commands (default: /usr/local/icinga/var/rw/icinga.cmd)]), - icinga_commandpipe=$withval, - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" -) - -AC_ARG_WITH([objects_cache_file], - AS_HELP_STRING([--with-objects-file=FILE], [location of the objects.cache file when retrieving data from status.dat (default: /usr/local/icinga/var/objects.cache)]), - objects_cache_file=$withval, - objects_cache_file="/usr/local/icinga/var/objects.cache" -) - -# -# Livestatus connection -# - -AC_ARG_WITH([livestatus_socket], - AS_HELP_STRING([--with-livestatus-socket=FILE], [location of the livestatus socket (default: /usr/local/icinga/var/rw/live)]), - livestatus_socket=$withval, - livestatus_socket="/usr/local/icinga/var/rw/live" -) - -# -# Icinga commandpipe -# - -AC_ARG_WITH([icinga_commandpipe], - AS_HELP_STRING([--with-icinga-commandpipe=FILE], [location of the command pipe used for sending commands (default: /usr/local/icinga/var/rw/icinga.cmd)]), - icinga_commandpipe=$withval, - icinga_commandpipe="/usr/local/icinga/var/rw/icinga.cmd" -) - -# Installation options -INSTALL_OPTS="-o $bin_user -g $bin_group" -INSTALL_OPTS_WEB="-o $web_user -g $web_group" - -AS_IF([test "x$internal_db_type" = xmysql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Mysql.php],[Zend Framework - MySQL PDO Adapter]) - AC_CHECK_PHP_MODULE([mysql]) - AS_IF([test "x$internal_db_port" == xdb_default_port], [internal_db_port=3306]) -]) - -AS_IF([test "x$ido_db_type" = xmysql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Mysql.php],[Zend Framework - MySQL PDO Adapter]) - AC_CHECK_PHP_MODULE([mysql]) - AS_IF([test "x$ido_port" = xdb_default_port], [ido_port=3306]) -]) - -AS_IF([test "x$internal_db_type" = xpgsql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Pgsql.php],[Zend Framework - PostgreSQL PDO Adapter]) - AC_CHECK_PHP_MODULE([pgsql]) - AS_IF([test "x$internal_db_port" = xdb_default_port], [internal_db_port=5432]) -]) - -AS_IF([test "x$ido_db_type" = xpgsql], [ - AC_CHECK_PHP_INCLUDE([Zend/Db/Adapter/Pdo/Pgsql.php],[Zend Framework - PostgreSQL PDO Adapter]) - AC_CHECK_PHP_MODULE([pgsql]) - AS_IF([test "x$ido_port" = xdb_default_port], [ido_port=5432]) -]) - -# -# Disable authentication backends -# - -ido_enabled="disabled = \"1\"" -statusdat_enabled="disabled = \"1\"" -livestatus_enabled="disabled = \"1\"" - -AS_CASE([$icinga_backend], - ["ido"], [ido_enabled=""], - ["statusdat"], [statusdat_enabled=""], - ["livestatus"], [livestatus_enabled=""], - [statusdat_enabled=""]) - -ldap_auth_disabled="disabled = \"1\"" -AS_IF([test "x$ldap_authentication" != xno], - AC_CHECK_PHP_MODULE([ldap]) - ldap_auth_disabled="" -) - -internal_auth_disabled="disabled = \"1\"" -AS_IF([test "x$internal_authentication" != xno], - AC_CHECK_PHP_MODULE([ldap]) - internal_auth_disabled="" -) - -# -# Substitution variables -# - -# Installation directives -AC_SUBST(app_name) -AC_SUBST(web_user) -AC_SUBST(web_group) -AC_SUBST(web_path) -AC_SUBST(httpd_config_path) -AC_SUBST(bin_user) -AC_SUBST(bin_group) -AC_SUBST(icingaweb_config_path) -AC_SUBST(icingaweb_log_path) - -# Internal db setup -AC_SUBST(internal_db_type) -AC_SUBST(internal_db_name) -AC_SUBST(internal_db_host) -AC_SUBST(internal_db_port) -AC_SUBST(internal_db_user) -AC_SUBST(internal_db_password) - -# ldap setup -AC_SUBST(ldap_host) -AC_SUBST(ldap_port) -AC_SUBST(ldap_rootdn) -AC_SUBST(ldap_binddn) -AC_SUBST(ldap_bindpass) -AC_SUBST(ldap_user_objectclass) -AC_SUBST(ldap_attribute_basedn) -AC_SUBST(ldap_attribute_username) - -# backend setup -AC_SUBST(icinga_backend) - -# ido backend variables -AC_SUBST(ido_enabled) -AC_SUBST(ido_db_type) -AC_SUBST(ido_host) -AC_SUBST(ido_port) -AC_SUBST(ido_db_name) -AC_SUBST(ido_user) -AC_SUBST(ido_password) - -# status.dat backend -AC_SUBST(statusdat_enabled) -AC_SUBST(statusdat_file) -AC_SUBST(objects_cache_file) - -# livestatus backend -AC_SUBST(livestatus_socket) -AC_SUBST(livestatus_enabled) - -# command pipe -AC_SUBST(icinga_commandpipe) - -# Comment placeholders for toggling backends - -AC_SUBST(ldap_auth_disabled) -AC_SUBST(internal_auth_disabled) - -# Application and installation -AC_SUBST(PHP) -AC_SUBST(INSTALL_OPTS) -AC_SUBST(INSTALL_OPTS_WEB) - -# -# Create config files -# -AC_CONFIG_FILES([ - Makefile - config/authentication.ini - config/config.ini - config/resources.ini - config/modules/monitoring/backends.ini - config/modules/monitoring/instances.ini - etc/apache/icingaweb.conf -]) - -# -# Commit and write -# -AC_OUTPUT diff --git a/doc/Icinga-Design/bootstrap.min.css b/doc/Icinga-Design/bootstrap.min.css deleted file mode 100644 index a553c4f5e..000000000 --- a/doc/Icinga-Design/bootstrap.min.css +++ /dev/null @@ -1,9 +0,0 @@ -/*! - * Bootstrap v3.0.0 - * - * Copyright 2013 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world by @mdo and @fat. - *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.099999999999998px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}h1 small,.h1 small{font-size:24px}h2 small,.h2 small{font-size:18px}h3 small,.h3 small,h4 small,.h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td{background-color:#d0e9c6;border-color:#c9e2b3}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td{background-color:#ebcccc;border-color:#e6c1c7}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#428bca}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:hover,a.thumbnail:focus{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-xs{display:none!important}tr.visible-xs{display:none!important}th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm{display:none!important}tr.visible-sm{display:none!important}th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md{display:none!important}tr.visible-md{display:none!important}th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg{display:none!important}tr.visible-lg{display:none!important}th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs{display:none!important}tr.hidden-xs{display:none!important}th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm{display:none!important}tr.hidden-xs.hidden-sm{display:none!important}th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md{display:none!important}tr.hidden-xs.hidden-md{display:none!important}th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg{display:none!important}tr.hidden-xs.hidden-lg{display:none!important}th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs{display:none!important}tr.hidden-sm.hidden-xs{display:none!important}th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}tr.hidden-sm{display:none!important}th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md{display:none!important}tr.hidden-sm.hidden-md{display:none!important}th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg{display:none!important}tr.hidden-sm.hidden-lg{display:none!important}th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs{display:none!important}tr.hidden-md.hidden-xs{display:none!important}th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm{display:none!important}tr.hidden-md.hidden-sm{display:none!important}th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}tr.hidden-md{display:none!important}th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg{display:none!important}tr.hidden-md.hidden-lg{display:none!important}th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs{display:none!important}tr.hidden-lg.hidden-xs{display:none!important}th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm{display:none!important}tr.hidden-lg.hidden-sm{display:none!important}th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md{display:none!important}tr.hidden-lg.hidden-md{display:none!important}th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}tr.hidden-lg{display:none!important}th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print{display:none!important}tr.visible-print{display:none!important}th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print{display:none!important}tr.hidden-print{display:none!important}th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/doc/Icinga-Design/documentation.css b/doc/Icinga-Design/documentation.css deleted file mode 100644 index 30bd9c27f..000000000 --- a/doc/Icinga-Design/documentation.css +++ /dev/null @@ -1,125 +0,0 @@ -/* ========================================================================== - Styles ONLY used for documentation - ========================================================================== */ - -html { - font-family: sans-serif; -} - - -/* Projektname - color customer CI */ - -.docu-project-name { - font-size: 2em; - color: #049BAF; - padding-bottom: 10px; -} - - -.docu-main { - width: 100%; - padding: 20px; - margin: 0 auto; - margin-top: 50px; - display: block; -} - - -.docu-main-headline { - font-size: 2em; - color: #333; - /* customer CI */ - padding-bottom: 10px; - padding-top: 40px; -} - - -.docu-sub-headline { - font-size: 1.5em; - color: #333; - padding-bottom: 3px; - padding-top: 10px; -} - - -.docu-section { - border: 1px solid #dddddd; - overflow: hidden; - display: block; -} - - -.docu-description { - padding-bottom: 10px; -} - - -.docu-example { - background-color: #FFFFFF; - padding: 10px; -} - - -.docu-example:before { - color: #BBBBBB; - content: "Example"; - font-weight: bold; - letter-spacing: 1px; - margin-bottom: 10px; -} - - -.docu-module { - /* width: 320px; */ - /* show your modules in device width */ - padding-top: 10px; -} - - -.docu-codeblock { - background-color: #F7F7F9; - border-top: 1px solid #e1e1e8; - padding: 10px; - overflow: hidden; - height: 100%; -} - - -.docu-codeblock:before { - color: #BBBBBB; - content: "Code"; - font-weight: bold; - letter-spacing: 1px; - margin-bottom: 10px; -} - - -.docu-code { - font-family: "Courier New", Courier, monospace; - font-weight: bold; - color: #777; - padding-top: 10px; - border: none; - background-color: transparent; - display: block; - width: 100%; - height: 150px; -} - - -.docu-footer { - margin-top: 40px; - padding-top: 10px; - border-top: 1px solid #dddddd; - font-size: 0.75em; - color: #ccc; -} - - -.docu-classes { - background-color: #FEFBED; - padding: 3px; - color: #c6b256; - font-family: "Courier New", Courier, monospace, sans-serif; - font-weight: bold; -} diff --git a/doc/Icinga-Design/documentation.html b/doc/Icinga-Design/documentation.html deleted file mode 100644 index e0ae9b066..000000000 --- a/doc/Icinga-Design/documentation.html +++ /dev/null @@ -1,974 +0,0 @@ - - - - - Icinga Documentation - - - - - - - - - - - - - - - - - - - - - - -
- -

Icinga Documentation

- - - -

Basic Elements

- -

Headlines

- - -
-
-
-

Main headline h1

-

Sub headline h2

-
-
- -
- -
-
- - -

Textblocks

-
- Used on simple pages with continuous text e.g. Imprint or Privacy. -
- -
-
-
- -

- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -

- -
-
- -
- -
-
- - - - -

Table

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatusOutput
- - - - - - - - 12 - - -
- - Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok
- - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - -
-
-
-
- - - 6 - - -
- Unreachable
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - - - - - - 6 - - -
- Down
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok -
- - - - - - - 6 - - -
- Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok -
- - - - - - - 6 - - -
- Up
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - -
-
-
-
- - - 6 - - -
- Down
- Since  - 30.09. -
-
- - host_000 - 127.0.0.1 -
- host_000 (checked by localhost.localdomain) OK: random hostcheck ok - - Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. - -
- - - -
-
- -
- -
-
- - - - -

Pagination

- -
- The pagination is placed on top and bottom of every list. -
- -
-
-
- - - -
-
- -
- -
-
- - - - -

Details

- -

Basic Example

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - -
-
- Host Status host_000 ölaierjoe paeurüuaeraeüure - Unreachable since 15:59
-
-
- -
- -
-

host_000 (checked by localhost.localdomain) OK: random hostcheck ok sometimes with multiline and html tags\n

-
- -
- Recheck -
- - -
-
- Last Check -
-
- 1381308168 -
-
- -
-
- Next Check -
-
- 1381309978 -
-
- -
-
- - -
-
- Host Address -
-
- 127.0.0.1 -
-
- -
-
- Alias -
-
- random_000 -
-
- - - -
- - - - - -
-
- Box mit Tabelle
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LoremIpsum xyzblablubb
08.10. 15:51Lorem ipusm_002
08.10. 15:51Ich bin ein toller Text
Hallo halloServer 123 blablaNoch ein Text
Lorem ipsumJuhuhallo_host01128747404
-
- - - - - -
-
- Heading
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Passive Checks
Active Checks
Obsessing
Notifications
Event Handler
Flap Detection
-
- - - -
-
- -
- -
-
- - - - -

Form Elements

- -

Select

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - -
-
- - -
-
-
-
-
-
- - -
-
- -
- -
-
- - -

Main Navigation

- -

Without Subnavigation

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - -
-
- - -
- - - - -

With Subnavigation

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
- - - - -
-
- - -
- - - - - - - - - - - -

Dashboard

- - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Dies ist eine tolle Headline -
09.10. 17:40 - - - - - Service on Hosta
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
unknown - - Ping on Host_123456
unknown - - Ping on Host_123456
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Dies ist eine tolle Headline -
09.10. - - - - Ping on Host_0815
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
unknown - - Ping on Host_123456
unknown - - Ping on Host_123456
11.10. - - - - random_06 on Host_insertEFFECT
11.10. - - - - random_06 on Host_insertEFFECT
-
- -
-
- - -
- - - - - - - - - -

Main Header

- -

Sub Header

-
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. -
- -
-
-
-

bla

-

blubb

-
-
- -
- -
-
- - - - - - - - -
- - - - diff --git a/doc/Icinga-Design/icinga-design.css b/doc/Icinga-Design/icinga-design.css deleted file mode 100644 index d8f2bd724..000000000 --- a/doc/Icinga-Design/icinga-design.css +++ /dev/null @@ -1,955 +0,0 @@ -/* ========================================================================== - Icinga Design - ========================================================================== */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ - overflow-y: scroll; -} - -body { - margin: 0; - color: #262625; - font-family: "Lucida Grande","Lucida Sans Unicode",Verdana,Helvetica,Arial,sans-serif; - font-size: 16px; -} - -p { - line-height: 18px; -} - -.gap { - margin-bottom: 15px; -} - - -/* ========================================================================== - Links - ========================================================================== */ - -a { - color: #049baf; - text-decoration: none; -} - -/** - * Address `outline` inconsistency between Chrome and other browsers. - */ - -a:focus { - outline: thin dotted; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; - color: #049baf; - text-decoration: underline; -} - -/* ========================================================================== - Typography - ========================================================================== */ - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari 5, and Chrome. - */ - -h1 { - color: #262625; - font-size: 20px; -} - -h2 { - color: #262625; - font-size: 16px; -} - - -p { - margin-top: 0; -} - - -/* ========================================================================== - Tables - ========================================================================== */ - - -table, th, td { -text-align: left; -vertical-align: top; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -th { - font-weight: bold; - font-size: 18px; - padding: 8px 8px 10px 8px; - border-bottom: 2px solid #ddd; -} - -.table-detail th { - font-size: 16px; - border-top: 0; -} - - -.table-detail thead > tr > th, .table tbody > tr > th, -.table-detail tbody > tr > td, .table tfoot > tr > td { - border-top: 0 !important; -} - - - - -.table-detail > thead { - border-top: 0 !important; -} - - - -td { - padding: 8px 10px 8px 8px !important; - border-bottom: 1px dotted #ddd !important; - border-top: none; - -} - -.pull-right { - float: right !important; - clear: right !important; - - display: block; - clear: right; - overflow: hidden; -} - -.badge-container { - display: block; - overflow: hidden; -} - - -.badge { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 12px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 3px; - padding-left: 10px; - padding-right: 10px; - padding-top: 3px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; - -} - -.badge a, -.badge a:active, -.badge a:hover, -.badge:hover { - color: #ff3300 !important; - display: inline-block !important; - -} - -.host-name { - display: block; - margin-top: 5px; - font-weight: bold; -} - - -.active { - background-color: #f5f5f5; - -} - -.output-text { - font-size: 12px; - line-height: 14px; - display: inline-block; -} - - - -.panel-disabled { - border-left: 8px solid #FF3300; -} - -.panel-enabled { - border-left: 8px solid #00CC33; -} - - -/* ========================================================================== - Forms - ========================================================================== */ - - -.form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; -} -.form-group { - margin-bottom: 15px; -} - -label { - display: inline-block; - font-weight: bold; - margin-bottom: 5px; -} - -.input-sm { - border-radius: 3px; - font-size: 16px; - - - padding: 5px; - margin-right: 15px; - -} -.form-control { - background-color: #FFFFFF; - border: 1px solid #CCCCCC; - border-radius: 4px; - padding: 5px; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset; - color: #555555; - display: block; - - - - - vertical-align: middle; - width: 100%; -} - -select.input-sm { - -} - - - -/* ========================================================================== - Pagination - ========================================================================== */ - -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - - background-color: #049baf !important; - border-color: fuchsia !important; - -} - - -.pagination-sm > li > a, .pagination-sm > li > span { - font-size: 16px !important; -} - - - -/* ========================================================================== - Status colors - ========================================================================== */ - -.status-up { - background-color: #00cc33; /* green */ -} - -.status-warning { - background-color: #00cc33; /* xx */ -} - -.status-critical { - background-color: #ff3300; /* red */ -} - -.status-unknown { - background-color: #00cc33; /* xx */ -} - -.status-pending { - background-color: #00cc33; /* xx */ -} - - - -/** Service status **/ - -.tacheader-status-critical { - background-color: #FF3300; -} - -.tacheader-status-ok { - background-color: #00CC33; -} - -.tacheader-status-warning { - background-color: #FFA500; -} - -.tacheader-status-unknown { - background-color: #E066FF; -} - -/** Host status **/ - -.tacheader-status-unreachable { - background-color: #E066FF; -} - -.tacheader-status-down { - background-color: #FF3300; -} - -.tacheader-status-up { - background-color: #00CC33; -} - - -/* Borders for Detail Headers */ - -.border-status-critical { - border-left: 10px solid #FF3300; -} - -.border-status-ok { - border-left: 10px solid #00CC33; -} - -.border-status-warning { - border-left: 10px solid #FFA500; -} - -.border-status-unknown { - border-left: 10px solid #E066FF; -} - -/** Host status **/ - -.border-status-unreachable { - border-left: 10px solid #E066FF; -} - -.border-status-down { - border-left: 10px solid #FF3300; -} - -.border-status-up { - background-color: #00CC33; -} - - - - - - - -/* ========================================================================== - Icons - ========================================================================== */ - -.icon-table { - width: 16px; - height: 20px; - display: block; - background-position: 50% 0; -} - -.icon-header { - background-position: 0 50%; - padding-left: 25px; - height: 20px; -} - -.icon-btn-small { - background-position: 0 0; - width: 16px; - height: 16px; - display: block; -} - -.icon-table-hint { - width: 16px; - height: 20px; - display: block; - background-position: 50% 50%; -} -.icon-table-hint:after { - content: "edited"; - padding-left: 22px; -} - - -.icon-flapping { - background-image: url('images/flapping.png'); - background-repeat: no-repeat; -} -.icon-comment { - background-image: url('images/comment.png'); - background-repeat: no-repeat; -} -.icon-unhandled { - background-image: url('images/unhandled.png'); - background-repeat: no-repeat; -} -.icon-host { - background-image: url('images/host.png'); - background-repeat: no-repeat; -} -.icon-acknowledgement { - background-image: url('images/acknowledgement.png'); - background-repeat: no-repeat; -} -.icon-remove { - background-image: url('images/remove.png'); - background-repeat: no-repeat; -} -.icon-submit { - background-image: url('images/submit.png'); - background-repeat: no-repeat; -} -.icon-create { - background-image: url('images/create.png'); - background-repeat: no-repeat; -} -.icon-dashboard { - background-image: url('images/dashboard.png'); - background-repeat: no-repeat; -} -.icon-disable { - background-image: url('images/disable.png'); - background-repeat: no-repeat; -} -.icon-edit { - background-image: url('images/edit.png'); - background-repeat: no-repeat; -} -.icon-error { - background-image: url('images/error.png'); - background-repeat: no-repeat; -} -.icon-downtime { - background-image: url('images/in_downtime.png'); - background-repeat: no-repeat; -} -.icon-save { - background-image: url('images/save.png'); - background-repeat: no-repeat; -} -.icon-service { - background-image: url('images/service.png'); - background-repeat: no-repeat; -} -.icon-user { - background-image: url('images/user.png'); - background-repeat: no-repeat; -} -.icon-reschedule { - background-image: url('images/reschedule.png'); - background-repeat: no-repeat; -} -.icon-refresh { - background-image: url('images/refresh.png'); - background-repeat: no-repeat; -} - - -/* ========================================================================== - Details Panel - ========================================================================== */ - - -.panel-heading { - border-bottom: 0; - margin-bottom: 0px !important; - padding-left: 5px; - padding-bottom: 3px; - padding-top: 5px; - overflow: hidden; - border-radius: 0; -} - -.panel-hostname { - font-weight: bold; -} - -.separator { - border-top: 2px solid #ddd; - border-bottom: 0; - margin: 0; - height: 2px; -} - -.panel-header-status { - font-weight: normal; -} - -.panel-row { - display: block; - margin-bottom: 10px; - overflow: hidden; - border-bottom: 1px dotted #ddd; - padding-bottom: 10px; -} - - -.panel-label { - float: left; - padding-right: 10px; - width: 30%; - clear: left; - -} -.panel-content { - float: left; - padding-right: 10px; - display: inline-block; - max-width: 40%; -} - -.panel-button { - float: right; - display: inline-block; - overflow: hidden; -} - -.panel-body { - margin-bottom: 45px; -} - - - -/* ========================================================================== - Buttons - ========================================================================== */ - -.button { - text-align: center; - padding: 3px; - border-width: 1px; - border-style: solid; - border-radius: 3px; -} - -.btn-common { - border-color: #ddd; - color: #262625; - background: rgb(255,255,255); /* Old browsers */ - background: -moz-linear-gradient(top, rgb(255,255,255) 1%, rgb(245,245,245) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,rgb(255,255,255)), color-stop(100%,rgb(245,245,245))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* W3C */ -} - -.panel-row > a:hover, -.btn-common:hover { - border-color: #262625 !important; - color: #262625 !important; - text-decoration: none; -} - - -.btn-cta { - border-color: #049BAF; - color: #049BAF; - background: rgb(255,255,255); /* Old browsers */ - background: -moz-linear-gradient(top, rgb(255,255,255) 1%, rgb(245,245,245) 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,rgb(255,255,255)), color-stop(100%,rgb(245,245,245))); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* Opera 11.10+ */ - background: -ms-linear-gradient(top, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* IE10+ */ - background: linear-gradient(to bottom, rgb(255,255,255) 1%,rgb(245,245,245) 100%); /* W3C */ -} - - - -.btn-small { - width: 25px; - height: 25px; - display: inline-block; -} - -.btn-wide { - width: 100%; - display: block; -} - -.btn-half-left { - float: left; - width: 48%; -} -.btn-half-right { - float: right; - width: 48%; -} - - -/* ========================================================================== - Main Navigation - ========================================================================== */ - - -.nav-stacked > li + li { - margin-left: 0; - margin-top: 0; -} - - -.nav-stacked { - background-color: #f8f8f8; -} - -.icinga-subnavigation { - list-style: none; -} - - - -.nav-stacked > li { - padding-top: 7px; - padding-bottom: 7px; - border-bottom: 1px dotted #049baf; - border-right: 1px dotted #049baf; -} -.nav-stacked > li:first-child { - border-top: 1px dotted #049baf; -} - - -.icinga-subnavigation > li { - padding-top: 8px; - padding-bottom: 8px; - border-bottom: 1px dotted #049baf; - border-right: 1px dotted #049baf; -} - -ul.icinga-subnavigation { - - border-bottom: 1px dotted #049baf; - margin-left: 0; - padding-left: 15px; -} - -.icinga-subnavigation > li:last-child { - padding-top: 8px; - padding-bottom: 8px; - border-bottom: 0; - -} - -.nav-stacked > li > a, -.icinga-subnavigation > li > a { - padding-left: 40px; - padding-right: 3px; - border-left: 6px solid #049baf; - display: inline-block; -} - -.nav-stacked > li > a.nav-notification, -.icinga-subnavigation > li > a.nav-notification { - border-left: 6px solid red !important; -} - -.nav-stacked > li > a:hover, -.icinga-subnavigation > li > a:focus { -/* font-weight: bold;*/ - background-color: transparent !important; - display: inline-block; -} - -.nav-stacked > li:hover, -.nav-stacked > li:focus, -.icinga-subnavigation > li:hover, -.icinga-subnavigation > li:focus { -background-color: #fff; - -} - -.nav-stacked > li.active, -.icinga-subnavigation > li.active { - background-color: #fff; - border-right: 0; -} - - - - -.nav-icon-hosts { - background-image: url('images/host_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - -.nav-icon-services { - background-image: url('images/service_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-downtimes { - background-image: url('images/in_downtime_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-notifications { - background-image: url('images/notification_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 20px; -} -.nav-icon-comments { - background-image: url('images/comment_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-dashboard { - background-image: url('images/dashboard_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} -.nav-icon-configuration { - background-image: url('images/configuration_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - - -.subnav-icon-configuration { - background-image: url('images/configuration_petrol.png'); - background-repeat: no-repeat; - background-position: 19px 50%; -} - - - - - -.badge-container-nav { - display: inline-block; - overflow: hidden; - padding-top: 0; - margin-bottom: 5px; - -} -.badge-nav { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 12px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 3px; - padding-left: 7px; - padding-right: 7px; - padding-top: 3px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; -} - -.badge-container-subnav { - position: absolute; - overflow: hidden; - padding-top: 0; - margin-left: 2px; - margin-top: -8px; -} -.badge-subnav { - background-color: #fff; - border-radius: 2px; - color: #ff3300; - display: inline-block; - font-size: 10px; - font-weight: bold; - line-height: 1; - min-width: 10px; - padding-bottom: 2px; - padding-left: 5px; - padding-right: 5px; - padding-top: 2px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - border: 1px solid #ff3300; -} - - - -/* ========================================================================== - Dashboard - ========================================================================== */ - -.dashboard-container { - - margin-right: 40px; - margin-bottom: 20px; - - display: inline-block; - vertical-align: top; - -} - -.dashboard-icons { - display: inline-block; - height: 16px; - width: 16px; -} - - - - -/* ========================================================================== - Top Navbar - ========================================================================== */ - - -.icinga-logo { - background-attachment: scroll; - background-clip: border-box; - background-color: rgba(0, 0, 0, 0); - background-image: url("images/logo_icinga.png"); - background-origin: padding-box; - background-position: center center; - background-repeat: no-repeat; - background-size: auto auto; - display: block; - height: 33px; - margin-bottom: 0; - margin-left: 8px; - margin-right: 30px; - margin-top: 8px; - text-indent: -999px; - width: 94px; -} - -.icinga-icon-user { - background-attachment: scroll; - background-clip: border-box; - background-color: rgba(0, 0, 0, 0); - background-image: url("images/user.png"); - background-origin: padding-box; - background-position: center center; - background-repeat: no-repeat; - background-size: auto auto; - display: inline-block; - height: 16px; - width: 16px; -} - -.icinga-navbar { - margin-right: 15px; -} -.icinga-navbar-reload { - margin-top: 13px; - margin-right: 40px; -} - -.icinga-navbar-search { - background-image: url('images/search.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 25px !important; -} - -.icinga-navbar-search-container { - border-left: 1px solid #ddd; - padding-left: 15px; - margin-top: 12px; -} - - - -.icinga-navbar-hosts-container { - background-image: url('images/host.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 30px !important; - margin-top: 15px; -} -.icinga-navbar-services-container { - background-image: url('images/service.png'); - background-repeat: no-repeat; - background-position: 5px 50%; - padding-left: 25px !important; - margin-top: 15px; -} - -.icinga-navbar-pills { - border-style: solid; - border-width: 1px; - padding: 3px 5px 3px 5px; - border-radius: 3px; - font-size: 13px; -} - - - -/** Service status **/ - -.icinga-navbar-pills-critical { - border-color: #FF3300; - color: #FF3300; -} - -.icinga-navbar-pills-ok { - border-color: #00CC33; - color: #00CC33; -} - -.icinga-navbar-pills-warning { - border-color: #FFA500; - color: #FFA500; -} - -.icinga-navbar-pills-unknown { - border-color: #E066FF; - color: #E066FF; -} - -/** Host status **/ - -.icinga-navbar-pills-unreachable { - border-color: #E066FF; - color: #E066FF; -} - -.icinga-navbar-pills-down { - border-color: #FF3300; - color: #FF3300; -} - -.icinga-navbar-pills-up { - border-color: #00CC33; - color: #00CC33; -} - diff --git a/doc/Icinga-Design/images/acknowledgement.png b/doc/Icinga-Design/images/acknowledgement.png deleted file mode 100644 index eb03d2db9..000000000 Binary files a/doc/Icinga-Design/images/acknowledgement.png and /dev/null differ diff --git a/doc/Icinga-Design/images/comment.png b/doc/Icinga-Design/images/comment.png deleted file mode 100644 index b7d88a0ac..000000000 Binary files a/doc/Icinga-Design/images/comment.png and /dev/null differ diff --git a/doc/Icinga-Design/images/comment_petrol.png b/doc/Icinga-Design/images/comment_petrol.png deleted file mode 100644 index 53c1223e9..000000000 Binary files a/doc/Icinga-Design/images/comment_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/configuration_petrol.png b/doc/Icinga-Design/images/configuration_petrol.png deleted file mode 100644 index 8168133ec..000000000 Binary files a/doc/Icinga-Design/images/configuration_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/create.png b/doc/Icinga-Design/images/create.png deleted file mode 100644 index b9bedf82a..000000000 Binary files a/doc/Icinga-Design/images/create.png and /dev/null differ diff --git a/doc/Icinga-Design/images/dashboard.png b/doc/Icinga-Design/images/dashboard.png deleted file mode 100644 index e5f9c09f3..000000000 Binary files a/doc/Icinga-Design/images/dashboard.png and /dev/null differ diff --git a/doc/Icinga-Design/images/dashboard_petrol.png b/doc/Icinga-Design/images/dashboard_petrol.png deleted file mode 100644 index 04936ba85..000000000 Binary files a/doc/Icinga-Design/images/dashboard_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/disabled.png b/doc/Icinga-Design/images/disabled.png deleted file mode 100644 index 54d036410..000000000 Binary files a/doc/Icinga-Design/images/disabled.png and /dev/null differ diff --git a/doc/Icinga-Design/images/edit.png b/doc/Icinga-Design/images/edit.png deleted file mode 100644 index 00d8e291f..000000000 Binary files a/doc/Icinga-Design/images/edit.png and /dev/null differ diff --git a/doc/Icinga-Design/images/error.png b/doc/Icinga-Design/images/error.png deleted file mode 100644 index 62458999f..000000000 Binary files a/doc/Icinga-Design/images/error.png and /dev/null differ diff --git a/doc/Icinga-Design/images/flapping.png b/doc/Icinga-Design/images/flapping.png deleted file mode 100644 index 4b253e09c..000000000 Binary files a/doc/Icinga-Design/images/flapping.png and /dev/null differ diff --git a/doc/Icinga-Design/images/host.png b/doc/Icinga-Design/images/host.png deleted file mode 100644 index 12eb9a6b9..000000000 Binary files a/doc/Icinga-Design/images/host.png and /dev/null differ diff --git a/doc/Icinga-Design/images/host_petrol.png b/doc/Icinga-Design/images/host_petrol.png deleted file mode 100644 index 6568fe6f7..000000000 Binary files a/doc/Icinga-Design/images/host_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/in_downtime.png b/doc/Icinga-Design/images/in_downtime.png deleted file mode 100644 index d609df62e..000000000 Binary files a/doc/Icinga-Design/images/in_downtime.png and /dev/null differ diff --git a/doc/Icinga-Design/images/in_downtime_petrol.png b/doc/Icinga-Design/images/in_downtime_petrol.png deleted file mode 100644 index f6ee49a6b..000000000 Binary files a/doc/Icinga-Design/images/in_downtime_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/logo_icinga.png b/doc/Icinga-Design/images/logo_icinga.png deleted file mode 100644 index 162bfdd69..000000000 Binary files a/doc/Icinga-Design/images/logo_icinga.png and /dev/null differ diff --git a/doc/Icinga-Design/images/notification_petrol.png b/doc/Icinga-Design/images/notification_petrol.png deleted file mode 100644 index cf4e9505a..000000000 Binary files a/doc/Icinga-Design/images/notification_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/refresh.png b/doc/Icinga-Design/images/refresh.png deleted file mode 100644 index b0222a525..000000000 Binary files a/doc/Icinga-Design/images/refresh.png and /dev/null differ diff --git a/doc/Icinga-Design/images/remove.png b/doc/Icinga-Design/images/remove.png deleted file mode 100644 index 98ada7447..000000000 Binary files a/doc/Icinga-Design/images/remove.png and /dev/null differ diff --git a/doc/Icinga-Design/images/reschedule.png b/doc/Icinga-Design/images/reschedule.png deleted file mode 100644 index 5efc20dbc..000000000 Binary files a/doc/Icinga-Design/images/reschedule.png and /dev/null differ diff --git a/doc/Icinga-Design/images/save.png b/doc/Icinga-Design/images/save.png deleted file mode 100644 index 2db271920..000000000 Binary files a/doc/Icinga-Design/images/save.png and /dev/null differ diff --git a/doc/Icinga-Design/images/search.png b/doc/Icinga-Design/images/search.png deleted file mode 100644 index a66c3ca95..000000000 Binary files a/doc/Icinga-Design/images/search.png and /dev/null differ diff --git a/doc/Icinga-Design/images/service.png b/doc/Icinga-Design/images/service.png deleted file mode 100644 index 9df3b4840..000000000 Binary files a/doc/Icinga-Design/images/service.png and /dev/null differ diff --git a/doc/Icinga-Design/images/service_petrol.png b/doc/Icinga-Design/images/service_petrol.png deleted file mode 100644 index ea165a293..000000000 Binary files a/doc/Icinga-Design/images/service_petrol.png and /dev/null differ diff --git a/doc/Icinga-Design/images/submit.png b/doc/Icinga-Design/images/submit.png deleted file mode 100644 index 40e482600..000000000 Binary files a/doc/Icinga-Design/images/submit.png and /dev/null differ diff --git a/doc/Icinga-Design/images/unhandled.png b/doc/Icinga-Design/images/unhandled.png deleted file mode 100644 index 59dab8445..000000000 Binary files a/doc/Icinga-Design/images/unhandled.png and /dev/null differ diff --git a/doc/Icinga-Design/images/user.png b/doc/Icinga-Design/images/user.png deleted file mode 100644 index 694ddfcd6..000000000 Binary files a/doc/Icinga-Design/images/user.png and /dev/null differ diff --git a/doc/api/.gitkeep b/doc/api/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/apidoc_creation.md b/doc/apidoc_creation.md deleted file mode 100644 index 89eb99feb..000000000 --- a/doc/apidoc_creation.md +++ /dev/null @@ -1,27 +0,0 @@ -# Create API documentation - -## Prerequisites - -You need phpDocumentor 2 installed on your system to create the api -documentation. Please visit [phpdoc's website](http://phpdoc.org/) for more -information. Additionally, the graphviz package is required to be installed. - -## Configuration - -phpDocumentator is configured with xml configuration reside in doc/phpdoc.xml. -In there you'll find the target path where the documentation is created as -html. Default location is doc/api/. Just point to index.html in this directory -with a browser. - -If you generated the documentation already, you can follow [this link](apidoc/idnex.html). - -## Generation - -Change to Icinga Web 2 root directory (source tree) and run: - - bin/createapidoc.sh - -## Options for createapidoc.sh - - --build Optional, silent build mode - --help Displays help message diff --git a/doc/container_component.md b/doc/container_component.md deleted file mode 100644 index ed505f81b..000000000 --- a/doc/container_component.md +++ /dev/null @@ -1,198 +0,0 @@ -# The Container Component (app/container) - -The container component is the most basic building block for icingaweb. Even when displaying an empty controller, -you always have at least two containers in your viewport which are implicitly created: The main and the detail container. - -Container handle the following tasks: - -* Updating the url part responsible for the container -* Handling Url changes like they occur when the browser history is used by synchronizing their content with the - associated Url part -* Informing subcomponents about changes in the container - - -## The Container Api - -You can find the sourcecode for containers along with jsdoc comments at *./public/js/icinga/components/container.js*. -Here we will discuss the most important calls and their synopsis: - -### Accessing Containers: - -The container component returns a 'Container' object which allows you to access responsible containers for dom nodes via -the following methods: - -* using `new Container($myDomNodes)` which returns a stateless container object wrapping the container responsible for - the first node in $myDomNodes -* using `Container.getMainContainer()` or `Container.getDetailContainer()` which remove the main or detail container - (this one is stateful with a few notes, read on) - -**Note:** `new Container($('#icingamain')) != Container.getMainContainer()`, but -`(new Container($('#icingamain'))).containerDom == Container.getMainContainer().containerDom` - -** Example #1 getting the container responsible for a dom node ** - -**HTML** - -
-
- Some kind of node -
-
-
- Some other kind of node -

- Insert your lorem ipsum here -

-
-
-
- -**JS**: - - require(['jquery', 'app/container'], function($, Container) { - var firstContainer = new Container($('.myNode')); // firstContainer wraps '#icingamain' - var mainContainer = Container.getMainContainer(); // also wraps '#icingamain' - var secondContainer = new Container($('.myNode p')); // #somecontainer is wrapped by secondContainer - - firstContainer.someProperty = 'What a nice property!'; - mainContainer.someState = 'I have some state'; - console.log(firstContainer.someProperty); // return 'What a nice property' - console.log(main.someProperty); // return 'undefined' - console.log(Container.getMainContainer().someState) // return 'I have some state' when page hasn't been refreshed - }); - -## Containers And The Browser Url - -As noted before (and indicated by the `getMainContainer()` and `getDetailContainer()` function), the main and detail -container have a special role. Considering the following Url: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - -This URL displays the 4th page of your host list in the main container (monitoring/list/host?page=4) and the host information -for localhost in the detail container (monitoring/show/host?host=localhost). When you split this Url up in logical pieces -it looks like this: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - \___________ _______________________/\_________ ______________/ \_ ____/\________________ _______________________/ - \/ \/ \/ \/ - 1. Base URL 2.Main container URL and Query 3.Detail param 4. Encoded detail URL and params - -1. **Base URL** : I don't think this needs much explanation. -2. **Main container URL and query** : This is the *normal* part of your Url and denotes the controller route that is - being displayed in your main container -3. **Detail parameter**: This parameter will be ignored by the main container and used for rendering the detail container, - if omitted there's simple no detail view to be displayed -4 **Encoded detail URL**: The value of the "detail" parameter is the Url (without the base Url) that returns the content - of the detail area - - -### Updating A Container's Url - -If you want your container to display content from a different Url, you can use the *replaceDomFromUrl()* on your -Container object: - -**Example #2 Updating A Containers URL** - -**HTML:** - -
-
-
-
-
-
- -**JS:** - - // this loads the page with the new main container - require(['jquery', 'app/container'], function($, Container) { - new Container('#mainSub').replaceDomFormUrl('/another/url'); - } - - // this loads the page with the new detail container - require(['jquery', 'app/container'], function($, Container) { - new Container('#detailSub').replaceDomFormUrl('/another/url'); - } - - // this does NOT work: - require(['jquery', 'app/container'], function($, Container) { - Container.getMainContainer().replaceDomFormUrl('/another/url'); - // will never be reached due to a reload - Container.getMainContainer().replaceDomFormUrl('/another/url2'); - } - - // this loads the page with both main and detail changed (this is rarely needed and should be avoided) - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - // it's better to use this: - var mainContainer = Container.getMainContainer(); - var detailContainer = Container.getDetailContainer(); - - mainContainer.updateContainerHref('/another/url'); // first update the main container href - detailContainer.updateContainerHref('/another/url2'); // update the detail href - - var url = mainContainer.getContainerHref(detailContainer.getContainerHref()); // fetch the new url - Icinga.replaceBodyFromUrl(url); // and update manual - } - -This results in the URL changing to './another/url?detail=%2Fanother%2Fdetail%2Furl. -The advantage of using a Container instance with the subelements (i.e. '\#mainSub') over calling getMain/DetailContainer -directly is that you don't need to know in what container your view is displayed - when you move 'mainSub' into the -detail container, the detail container would be updated afterwards. - -**NOTE**: You should read the '...' section in order to understand why you shouldn't do it like in this example - -### How container refresh states are handled - -If you refresh containers content (load url or replace dom), the container displaya a loading -mask as default behaviour. To disable this mask and handle it yourself, you can register own events: - -**Example #3 Load indicator events** - - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - var mainContainer = Container.getMainContainer(); - - // Detach the default behaviour from container - mainContainer.removeDefaultLoadIndicator(); - - var showFunction = function() { - console.log('container is loading'); - }; - - var hideFunction = function() { - console.log('container content refreshed'); - }; - - // Install new handlers - mainContainer.registerOnShowLoadIndicator(showFunction); - mainContainer.registerOnHideLoadIndicator(hideFunction); - }; - -**Example #4 Use this for your components** - -Please have a look into [components documentation](components.md) for detailed information about components. - - define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate'], - function(Container, $, logger, URI) { - "use strict"; - - /** - * Master/Detail grid component handling history, link behaviour, selection (@TODO 3788) and updates of - * grids - * - * @param {HTMLElement} The outer element to apply the behaviour on - */ - return function(gridDomNode) { - /** - * Constructor method for this component - */ - this.construct = function(target) { - // Container object for the component - this.container = new Container(target); - - // Detach default handlers - this.container.removeDefaultLoadIndicator(); - }; - - this.construct(gridDomNode); - }; - }; \ No newline at end of file diff --git a/doc/installation.md b/doc/installation.md index 9de3f7d5c..11f644ef7 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -1,119 +1,62 @@ +# Installation -# Installation +The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating +system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source. -## Requirements +## Installing Requirements -* Apache2 with PHP >= 5.3.0 enabled -* PHP Zend Framework -* PHP with MySQL or PostgreSQL libraries -* MySQL or PostgreSQL server and client software -* Icinga 1.x or Icinga 2 as backend providers +* A web server, e.g. Apache or nginx +* PHP >= 5.3.0 +* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database +* LDAP PHP library when using Active Directory or LDAP for authentication +* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled -RHEL/CentOS requires the EPEL repository enabled (which provides the `php-ZendFramework` -package). OpenSUSE requires the [server monitoring](https://build.opensuse.org/project/show/server:monitoring) repository (which provides the `php5-ZendFramework` package) enabled. +## Installing Icinga Web 2 from Package -## configure && make +A guide on how to install Icinga Web 2 from package will follow shortly. -### Basic installation +## Installing Icinga Web 2 from Source -If you like to configurea and install icinga2-web from the command line or -if you want to create packages, configure and make is the best choice for installation. +**Step 1: Getting the Source** - ./configure && make install && make install-apache2-config +First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this +repository either via git or http protocol using the following URLs: -will install the application to the default target (/usr/local/icinga2-web). Also -an apache configuration entry is added to your apache server, so you should restart -your web server according to your systems configuration. + * git://git.icinga.org/icingaweb2.git + * http://git.icinga.org/icingaweb2.git -### Installation directory +There is also a browsable version available at +[gi.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository"). +This version also offers snapshots for easy download which you can use if you do not have git present on your system. -If you want to install the application to a different directory, use the --prefix flag in your -configure call: +```` +git clone git://git.icinga.org/icingaweb2.git +```` - ./configure --prefix=/my/target/directory +**Step 2: Install the Source** +Choose a target directory and move Icinga Web 2 there. -### Authentication +```` +mv icingaweb2 /usr/share/icingaweb2 +```` -By default, icinga2-web will be installed to authenticate againts its internal database, -but you can configure it to use ldap-authentication by adding the `--with-ldap-authentication` -flag. You must provide the authentication details for your ldap server by using the --with-ldap-* flags. -To see a full list of the flags, call `./configure --help` +**Step 3: Configuring the Web Server** -### Icinga backend +Use `icingacli` to generate web server configuration for either Apache or nginx. -The default option for icinga2web is to configure all icinga backends with the default settings (for example -/usr/local/icinga/ as the icinga directory) but only enable statusdat. To use a different backend, -call `--with-icinga-backend=` and provide ido, livestatus or statusdat as an option. To further configure -your backend, take a look at the various options described in `./configure --help` +*Apache* -### Databases +```` +./bin/icingacli setup config webserver apache +```` -It is required to set up all used Databases correctly, which basically means to create all needed user accounts and to -create all database tables. You will find the installation guides for the different databases in the sections below: +*nginx* -*IMPORTANT*: Select a secure password instead of "icingaweb" and alter the config/authentication.ini accordingly. +```` +./bin/icingacli setup config webserver nginx +```` +**Step 4: Web Setup** -#### MySQL - -1. Create the user and the database - - - mysql -u root -p - mysql> CREATE USER `icingaweb`@`localhost` IDENTIFIED BY 'icingaweb'; - mysql> CREATE DATABASE `icingaweb`; - mysql> GRANT ALL PRIVILEGES ON `icingaweb`.* TO `icingaweb`@`localhost`; - mysql> FLUSH PRIVILEGES; - mysql> quit - - -2. Create all tables (You need to be in the icinga2-web folder) - -> **Note** -> -> RPM packages install the schema into /usr/share/doc/icingaweb-<version>/schema - - bash$ mysql -u root -p icingaweb < etc/schema/accounts.mysql.sql - bash$ mysql -u root -p icingaweb < etc/schema/preferences.mysql.sql - - -#### PostgreSQL - -1. Create the user and the database - - - sudo su postgres - psql - postgres=# CREATE USER icingaweb WITH PASSWORD 'icingaweb'; - postgres=# CREATE DATABASE icingaweb; - postgres=# \q - - -2. Enable trust authentication on localhost - -Add the following lines to your pg_hba.conf (etc/postgresql/X.x/main/pg_hba.conf under debian, /var/lib/pgsql/data/pg_hba.conf for Redhat/Fedora) -to enable trust authentication for the icingaweb user when connecting from the localhost. - - local icingaweb icingaweb trust - host icingaweb icingaweb 127.0.0.1/32 trust - host icingaweb icingaweb ::1/128 trust - -And restart your database ('service postgresql restart' or '/etc/init.d/postgresql-X.x reload' while being root) - - -3. Create all tables (You need to be in the icinga2-web folder) - -> **Note** -> -> RPM packages install the schema into /usr/share/doc/icingaweb-<version>/schema - - bash$ psql -U icingaweb -a -f etc/schema/accounts.pgsql.sql - bash$ psql -U icingaweb -a -f etc/schema/preferences.pgsql.sql - - - -Quick and Dirty ----------------- - -tdb. +Visit Icinga Web 2 in your browser and complete installation using the web setup. diff --git a/doc/resources.md b/doc/resources.md index cddfb04d1..fcded81c7 100644 --- a/doc/resources.md +++ b/doc/resources.md @@ -1,96 +1,84 @@ -# Resources +# Resources -The configuration file *config/resources.ini* contains data sources that can be referenced -in other configurations. This allows you to manage all connections to databases at one central -place, avoiding the need to edit several different files, when the connection information of a resource change. +The INI configuration file **config/resources.ini** contains information about data sources that can be referenced in other +configuration files. This allows you to manage all data sources at one central place, avoiding the need to edit several +different files, when the information about a data source changes. -## Configuration +## Configuration -Each section represents a resource, with the section name being the identifier used to -reference this certain section. Depending on the resource type, each section contains different properties. -The property *type* defines the resource type and thus how the properties are going to be interpreted. -The available resource types are 'db', 'statusdat', 'livestatus' and 'ldap' and are -described in detail in the following sections: +Each section in **config/resources.ini** represents a data source with the section name being the identifier used to +reference this specific data source. Depending on the data source type, the sections define different directives. +The available data source types are *db*, *ldap* and *livestatus* which will described in detail in the following +paragraphs. -### db +### Database -This resource type describes a SQL database on an SQL server. Databases can contain users and groups -to handle authentication and permissions, or monitoring data using IDO. +A Database resource defines a connection to a SQL databases which can contain users and groups +to handle authentication and authorization, monitoring data or user preferences. -- *db*: defines the used database vendor, which could be a value like *mysql* or *pgsql*. -- *host*: The hostname that is used to connect to the database. -- *port*: The port that is used to connect to the database. -- *username*: The user name that is used to authenticate. -- *password*: The password of the user given in *username*. -- *dbname*: The name of the database that contains the resources data. +Directive | Description +----------------|------------ +**type** | `db` +**db** | Database management system. Either `mysql` or `pgsql`. +**host** | Connect to the database server on the given host. +**port** | Port number to use for the connection. +**username** | The username to use when connecting to the server. +**password** | The password to use when connecting to the server. +**dbname** | The database to use. -### ldap +**Example:** -The resource is a tree in a ldap domain. This resource type is usually used to fetch users and groups -to handle authentication and permissions. - -- *hostname*: The hostname that is used to connect to the ldap server. -- *port*: The port that is used to connect to the ldap server. -- *root_dn*: The root object of the tree. This is usually an organizational unit like - "ou=people, dc=icinga, dc=org". -- *bind_dn*: The user on the LDAP server that will be used to access it. Usually something - like "cn=admin, cn=config". -- *bind_pw*: The password of the user given in *bind_dn*. +``` +[icingaweb] +type = db +db = mysql +host = localhost +port = 3306 +username = icingaweb +password = icingaweb +dbname = icingaweb +``` -### livestatus +### LDAP -A resource that points to a livestatus socket. This resource type contains monitoring data. +A LDAP resource represents a tree in a LDAP directory. LDAP is usually used for authentication and authorization. -- *socket*: The livestatus socket. Can be either be a path to a domain socket (like - "/usr/local/icinga-mysql/var/rw/live") or to a TCP socket like - (tcp://:) +Directive | Description +----------------|------------ +**type** | `ldap` +**hostname** | Connect to the LDAP server on the given host. +**port** | Port number to use for the connection. +**root_dn** | Root object of the tree, e.g. "ou=people,dc=icinga,dc=org" +**bind_dn** | The user to use when connecting to the server. +**bind_pw** | The password to use when connecting to the server. -### statusdat +**Example:** -A resource that points to statusdat files. This resource type contains monitoring data. - -- *status_file*: The path to the *status.dat* file, like "/usr/local/icinga-mysql/var/status.dat" -- *object_file*: The path to *objects.cache*, like "/usr/local/icinga-mysql/var/objects.cache" +```` +[ad] +type = ldap +hostname = localhost +port = 389 +root_dn = "ou=people,dc=icinga,dc=org" +bind_dn = "cn=admin,ou=people,dc=icinga,dc=org" +bind_pw = admin` +```` -## Factory Implementations +### Livestatus -This section contains documentation documentation for the Icinga2-Web developers that want to -use resources defined in the *resources.ini*. Each supported resource type should have an own -factory class, that can be used to comfortably create instances of classes that provide access -to the data of the resources. +A Livestatus resource represents the location of a Livestatus socket which is used for fetching monitoring data. +Directive | Description +----------------|------------ +**type** | `livestatus` +**socket** | Location of the Livestatus socket. Either a path to a local Livestatus socket or a path to a remote Livestatus socket in the format `tcp://:`. -### ResourceFactory +**Example:** -The ResourceFactory can be used to retrieve objects to access resources. Lets assume -for the following examples, that we have an *resources.ini* that looks like this: - - [statusdat] - type = statusdat - status_file = /usr/local/icinga-mysql/var/status.dat - object_file = /usr/local/icinga-mysql/var/objects.cache - - [ldap_authentication] - type = "ldap" - hostname = "localhost" - port = "389" - root_dn = "ou=people, dc=icinga, dc=org" - bind_dn = "cn=admin, cn=config" - bind_pw = "admin" - - -Here is an example of how to retrieve the resource 'statusdat' from the factory. - - $resource = ResourceFactory::createResource( - ResourceFactory::getResourceConfig('statusdat') - ); - -If you specify a resource that does not exist or has the wrong type, -the factory will throw an ConfigurationException. - - -You can also retrieve a list of all available resources by calling *getResourceConfigs*. - - $resourceConfigs = ResourceFactory::getResourceConfigs(); +```` +[livestatus] +type = livestatus +socket = /var/run/icinga2/cmd/livestatus +```` diff --git a/etc/apache/.gitignore b/etc/apache/.gitignore deleted file mode 100644 index 839e1f407..000000000 --- a/etc/apache/.gitignore +++ /dev/null @@ -1 +0,0 @@ -icingaweb.conf diff --git a/etc/apache/icingaweb.conf.in b/etc/apache/icingaweb.conf.in deleted file mode 100644 index 3884aea5a..000000000 --- a/etc/apache/icingaweb.conf.in +++ /dev/null @@ -1,32 +0,0 @@ -Alias @web_path@ "@prefix@/public" - - - Options SymLinksIfOwnerMatch - AllowOverride None - - - # Apache 2.4 - - Require all granted - - - - - # Apache 2.2 - Order allow,deny - Allow from all - - - SetEnv ICINGAWEB_CONFIGDIR @icingaweb_config_path@ - - EnableSendfile Off - - RewriteEngine on - RewriteBase @web_path@/ - RewriteCond %{REQUEST_FILENAME} -s [OR] - RewriteCond %{REQUEST_FILENAME} -l [OR] - RewriteCond %{REQUEST_FILENAME} -d - RewriteRule ^.*$ - [NC,L] - RewriteRule ^.*$ index.php [NC,L] - - diff --git a/etc/schema/accounts.mysql.sql b/etc/schema/accounts.mysql.sql deleted file mode 100644 index 72eeee4fc..000000000 --- a/etc/schema/accounts.mysql.sql +++ /dev/null @@ -1,24 +0,0 @@ -create table account ( - `username` varchar(255) COLLATE latin1_general_ci NOT NULL, - `salt` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `active` tinyint(1) DEFAULT NULL, - PRIMARY KEY (`username`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -/* - * user: icingaadmin - * password: icinga - */ -INSERT INTO account ( - `username`, - `salt`, - `password`, - `active` - ) - VALUES ( - 'icingaadmin', - '57cfd5746224be4f60c25d4e8514bec35ad2d01810723a138756b285898e71b2', - '43f8e0588eb39f1a41383b48def0b1fdc45e79b8f67194cccee4453eb3f4ea13', - 1 - ); diff --git a/etc/schema/accounts.pgsql.sql b/etc/schema/accounts.pgsql.sql deleted file mode 100644 index 84ecb54e8..000000000 --- a/etc/schema/accounts.pgsql.sql +++ /dev/null @@ -1,28 +0,0 @@ -create table "account" ( - "username" character varying(255) NOT NULL, - "salt" character varying(255), - "password" character varying(255) NOT NULL, - "active" boolean -); - -ALTER TABLE ONLY "account" - ADD CONSTRAINT account_pkey PRIMARY KEY ("username"); - -CREATE UNIQUE INDEX username_lower_unique_idx ON "account" USING btree (lower((username)::text)); - -/* - * user: icingaadmin - * password: icinga - */ -INSERT INTO "account" ( - "username", - "salt", - "password", - "active" - ) - VALUES ( - 'icingaadmin', - '57cfd5746224be4f60c25d4e8514bec35ad2d01810723a138756b285898e71b2', - '43f8e0588eb39f1a41383b48def0b1fdc45e79b8f67194cccee4453eb3f4ea13', - true - ); diff --git a/etc/schema/mysql.schema.sql b/etc/schema/mysql.schema.sql index 7867796b4..74d2665d4 100644 --- a/etc/schema/mysql.schema.sql +++ b/etc/schema/mysql.schema.sql @@ -27,9 +27,10 @@ CREATE TABLE `icingaweb_user`( CREATE TABLE `icingaweb_user_preference`( `username` varchar(64) COLLATE utf8_unicode_ci NOT NULL, + `section` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `value` varchar(255) NOT NULL, `ctime` timestamp NULL DEFAULT NULL, `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`username`,`name`) + PRIMARY KEY (`username`,`section`,`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/etc/schema/pgsql.schema.sql b/etc/schema/pgsql.schema.sql new file mode 100644 index 000000000..77971222b --- /dev/null +++ b/etc/schema/pgsql.schema.sql @@ -0,0 +1,99 @@ +/** + * Table "icingaweb_group" + */ +CREATE TABLE "icingaweb_group" ( + "name" character varying(64) NOT NULL, + "parent" character varying(64) NULL DEFAULT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_group" + ADD CONSTRAINT pk_icingaweb_group + PRIMARY KEY ( + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_group + ON "icingaweb_group" + USING btree ( + lower((name)::text) +); + + +/** + * Table "icingaweb_group_membership" + */ +CREATE TABLE "icingaweb_group_membership" ( + "group_name" character varying(64) NOT NULL, + "username" character varying(64) NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_group_membership" + ADD CONSTRAINT pk_icingaweb_group_membership + PRIMARY KEY ( + "group_name", + "username" +); + +CREATE UNIQUE INDEX idx_icingaweb_group_membership + ON "icingaweb_group_membership" + USING btree ( + lower((group_name)::text), + lower((username)::text) +); + + +/** + * Table "icingaweb_user" + */ +CREATE TABLE "icingaweb_user" ( + "name" character varying(64) NOT NULL, + "active" smallint NOT NULL, + "password_hash" bytea NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_user" + ADD CONSTRAINT pk_icingaweb_user + PRIMARY KEY ( + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_user + ON "icingaweb_user" + USING btree ( + lower((name)::text) +); + + +/** + * Table "icingaweb_user_preference" + */ +CREATE TABLE "icingaweb_user_preference" ( + "username" character varying(64) NOT NULL, + "name" character varying(64) NOT NULL, + "section" character varying(64) NOT NULL, + "value" character varying(255) NOT NULL, + "ctime" timestamp NULL DEFAULT NULL, + "mtime" timestamp NULL DEFAULT NULL +); + +ALTER TABLE ONLY "icingaweb_user_preference" + ADD CONSTRAINT pk_icingaweb_user_preference + PRIMARY KEY ( + "username", + "section", + "name" +); + +CREATE UNIQUE INDEX idx_icingaweb_user_preference + ON "icingaweb_user_preference" + USING btree ( + lower((username)::text), + lower((section)::text), + lower((name)::text) +); \ No newline at end of file diff --git a/etc/schema/preferences.mysql.sql b/etc/schema/preferences.mysql.sql deleted file mode 100644 index 5549daa3f..000000000 --- a/etc/schema/preferences.mysql.sql +++ /dev/null @@ -1,6 +0,0 @@ -create table `preference`( - `username` VARCHAR(255) COLLATE latin1_general_ci NOT NULL, - `key` VARCHAR(100) COLLATE latin1_general_ci NOT NULL, - `value` VARCHAR(255) NOT NULL, - PRIMARY KEY (`username`, `key`) -) ENGINE=InnoDB; \ No newline at end of file diff --git a/etc/schema/preferences.pgsql.sql b/etc/schema/preferences.pgsql.sql deleted file mode 100644 index 8b694f0a0..000000000 --- a/etc/schema/preferences.pgsql.sql +++ /dev/null @@ -1,10 +0,0 @@ -create table "preference"( - "username" VARCHAR(255) NOT NULL, - "key" VARCHAR(100) NOT NULL, - "value" VARCHAR(255) NOT NULL -); - -ALTER TABLE ONLY "preference" - ADD CONSTRAINT preference_pkey PRIMARY KEY ("username", "key"); - -CREATE UNIQUE INDEX username_and_key_lower_unique_idx ON "preference" USING btree (lower((username)::text), lower((key)::text)); \ No newline at end of file diff --git a/icingaweb2.spec b/icingaweb2.spec index db0929f7b..9d9e11345 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -31,7 +31,7 @@ %define prefixdir %{_datadir}/%{name} %define usermodparam -a -G %define logdir %{_localstatedir}/log/%{name} -%define docdir %{sharedir}/log +%define docdir %{sharedir}/doc %if "%{_vendor}" == "suse" %define phpname php5 @@ -179,7 +179,8 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules -%{__cp} -r application doc library modules public %{buildroot}/%{sharedir}/ +# make sure to install local icingacli for setup wizard token generation & webserver config +%{__cp} -r application doc library modules public bin %{buildroot}/%{sharedir}/ ## config # authentication is db only @@ -194,8 +195,8 @@ install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/instances.ini %{bu ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/%{name}/enabledModules/monitoring ## config -# install icingacli -install -D -m0755 packages/rpm/usr/bin/icingacli %{buildroot}/usr/bin/icingacli +# symlink icingacli +ln -sf %{buildroot}/%{sharedir}/bin/icingacli %{buildroot}/usr/bin/icingacli %pre # Add apacheuser in the icingacmd group diff --git a/install-sh b/install-sh deleted file mode 100755 index 6781b987b..000000000 --- a/install-sh +++ /dev/null @@ -1,520 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2009-04-28.21; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -nl=' -' -IFS=" "" $nl" - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -no_target_directory= - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) dst_arg=$2 - shift;; - - -T) no_target_directory=true;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call `install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names starting with `-'. - case $src in - -*) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - - dst=$dst_arg - # Protect names starting with `-'. - case $dst in - -*) dst=./$dst;; - esac - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - -*) prefix='./';; - *) prefix='';; - esac - - eval "$initialize_posix_glob" - - oIFS=$IFS - IFS=/ - $posix_glob set -f - set fnord $dstdir - shift - $posix_glob set +f - IFS=$oIFS - - prefixes= - - for d - do - test -z "$d" && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 368c93a8f..7f1667e5b 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -6,8 +6,9 @@ namespace Icinga\Application; use ErrorException; use Exception; -use Zend_Config; +use LogicException; use Icinga\Application\Modules\Manager as ModuleManager; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; @@ -40,6 +41,43 @@ use Icinga\Exception\IcingaException; */ abstract class ApplicationBootstrap { + /** + * Base directory + * + * Parent folder for at least application, bin, modules, library/vendor and public + * + * @var string + */ + protected $baseDir; + + /** + * Application directory + * + * @var string + */ + protected $appDir; + + /** + * Vendor library directory + * + * @var string + */ + protected $vendorDir; + + /** + * Library directory + * + * @var string + */ + protected $libDir; + + /** + * Configuration directory + * + * @var string + */ + protected $configDir; + /** * Icinga auto loader * @@ -47,34 +85,13 @@ abstract class ApplicationBootstrap */ private $loader; - /** - * Library directory - * - * @var string - */ - private $libDir; - /** * Config object * - * @var Zend_Config + * @var Config */ protected $config; - /** - * Configuration directory - * - * @var string - */ - private $configDir; - - /** - * Application directory - * - * @var string - */ - private $appDir; - /** * Module manager * @@ -98,27 +115,20 @@ abstract class ApplicationBootstrap /** * Constructor + * + * @param string $baseDir Icinga Web 2 base directory + * @param string $configDir Path to Icinga Web 2's configuration files */ - protected function __construct($configDir = null) + protected function __construct($baseDir = null, $configDir = null) { + if ($baseDir === null) { + $baseDir = dirname($this->getBootstrapDirectory()); + } + $this->baseDir = $baseDir; + $this->appDir = $baseDir . '/application'; + $this->vendorDir = $baseDir . '/library/vendor'; $this->libDir = realpath(__DIR__ . '/../..'); - if (!defined('ICINGA_LIBDIR')) { - define('ICINGA_LIBDIR', $this->libDir); - } - - if (defined('ICINGAWEB_APPDIR')) { - $this->appDir = ICINGAWEB_APPDIR; - } elseif (array_key_exists('ICINGAWEB_APPDIR', $_SERVER)) { - $this->appDir = $_SERVER['ICINGAWEB_APPDIR']; - } else { - $this->appDir = realpath($this->libDir. '/../application'); - } - - if (!defined('ICINGAWEB_APPDIR')) { - define('ICINGAWEB_APPDIR', $this->appDir); - } - if ($configDir === null) { if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) { $configDir = $_SERVER['ICINGAWEB_CONFIGDIR']; @@ -130,7 +140,13 @@ abstract class ApplicationBootstrap $this->configDir = $canonical ? $canonical : $configDir; $this->setupAutoloader(); - $this->setupZendAutoloader(); + + set_include_path( + implode( + PATH_SEPARATOR, + array($this->vendorDir, get_include_path()) + ) + ); Benchmark::measure('Bootstrap, autoloader registered'); @@ -196,44 +212,6 @@ abstract class ApplicationBootstrap return $this->isWeb; } - /** - * Getter for application dir - * - * Optional append sub directory - * - * @param string $subdir optional subdir - * - * @return string - */ - public function getApplicationDir($subdir = null) - { - return $this->getDirWithSubDir($this->appDir, $subdir); - } - - /** - * Getter for config dir - * - * @param string $subdir - * - * @return string - */ - public function getConfigDir($subdir = null) - { - return $this->getDirWithSubDir($this->configDir, $subdir); - } - - /** - * Get the path to the bootstrapping directory. - * - * This is usually /public for Web and EmbeddedWeb - * - * @return string - */ - public function getBootstrapDirecory() - { - return dirname($_SERVER['SCRIPT_FILENAME']); - } - /** * Helper to glue directories together * @@ -252,15 +230,102 @@ abstract class ApplicationBootstrap } /** - * Starting concrete bootstrap classes + * Get the base directory * - * @param string $configDir + * @param string $subDir Optional sub directory to get * - * @return ApplicationBootstrap + * @return string */ - public static function start($configDir = null) + public function getBaseDir($subDir = null) { - $application = new static($configDir); + return $this->getDirWithSubDir($this->baseDir, $subDir); + } + + /** + * Get the application directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getApplicationDir($subDir = null) + { + return $this->getDirWithSubDir($this->appDir, $subDir); + } + + /** + * Get the vendor library directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getVendorDir($subDir = null) + { + return $this->getDirWithSubDir($this->vendorDir, $subDir); + } + + /** + * Get the configuration directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getConfigDir($subDir = null) + { + return $this->getDirWithSubDir($this->configDir, $subDir); + } + + /** + * Get the Icinga library directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getLibraryDir($subDir = null) + { + return $this->getDirWithSubDir($this->libDir, $subDir); + } + + /** + * Get the path to the bootstrapping directory + * + * This is usually /public for Web and EmbeddedWeb and /bin for the CLI + * + * @return string + * + * @throws LogicException If the base directory can not be detected + */ + public function getBootstrapDirectory() + { + $script = $_SERVER['SCRIPT_FILENAME']; + $canonical = realpath($script); + if ($canonical !== false) { + $dir = dirname($canonical); + } elseif (substr($script, -14) === '/webrouter.php') { + // If Icinga Web 2 is served using PHP's built-in webserver with our webrouter.php script, the $_SERVER + // variable SCRIPT_FILENAME is set to DOCUMENT_ROOT/webrouter.php which is not a valid path to + // realpath but DOCUMENT_ROOT here still is the bootstrapping directory + $dir = dirname($script); + } else { + throw new LogicException('Can\'t detected base directory'); + } + return $dir; + } + + /** + * Start the bootstrap + * + * @param string $baseDir Icinga Web 2 base directory + * @param string $configDir Path to Icinga Web 2's configuration files + * + * @return static + */ + public static function start($baseDir = null, $configDir = null) + { + $application = new static($baseDir, $configDir); $application->bootstrap(); return $application; } @@ -284,7 +349,7 @@ abstract class ApplicationBootstrap /** * Register the Zend Autoloader * - * @return self + * @return $this */ protected function setupZendAutoloader() { @@ -292,17 +357,12 @@ abstract class ApplicationBootstrap \Zend_Loader_Autoloader::getInstance(); - // Unfortunately this is needed to get the Zend Plugin loader working: - set_include_path( - implode( - PATH_SEPARATOR, - array($this->libDir, get_include_path()) - ) + \Zend_Paginator::addScrollingStylePrefixPath( + 'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle' ); return $this; } - /** * Setup module manager * @@ -313,16 +373,26 @@ abstract class ApplicationBootstrap $this->moduleManager = new ModuleManager( $this, $this->configDir . '/enabledModules', - explode( - ':', - $this->config->global !== null - ? $this->config->global->get('modulePath', ICINGAWEB_APPDIR . '/../modules') - : ICINGAWEB_APPDIR . '/../modules' - ) + explode(':', $this->config->get('global', 'module_path', $this->baseDir . '/modules')) ); return $this; } + /** + * Load all core modules + * + * @return self + */ + protected function loadCoreModules() + { + try { + $this->moduleManager->loadCoreModules(); + } catch (NotReadableError $e) { + Logger::error(new IcingaException('Cannot load core modules. An exception was thrown:', $e)); + } + return $this; + } + /** * Load all enabled modules * @@ -346,7 +416,7 @@ abstract class ApplicationBootstrap protected function setupLogging() { Logger::create( - new Zend_Config( + new ConfigObject( array( 'log' => 'syslog' ) @@ -363,12 +433,14 @@ abstract class ApplicationBootstrap protected function loadConfig() { Config::$configDir = $this->configDir; + try { $this->config = Config::app(); } catch (NotReadableError $e) { Logger::error(new IcingaException('Cannot load application configuration. An exception was thrown:', $e)); - $this->config = new Zend_Config(array()); + $this->config = new Config(); } + return $this; } @@ -388,6 +460,8 @@ abstract class ApplicationBootstrap return false; // Continue with the normal error handler } switch($errno) { + case E_NOTICE: + case E_WARNING: case E_STRICT: throw new ErrorException($errstr, 0, $errno, $errfile, $errline); } @@ -403,9 +477,9 @@ abstract class ApplicationBootstrap */ protected function setupLogger() { - if ($this->config->logging !== null) { + if ($this->config->hasSection('logging')) { try { - Logger::create($this->config->logging); + Logger::create($this->config->getSection('logging')); } catch (ConfigurationError $e) { Logger::error($e); } @@ -433,42 +507,62 @@ abstract class ApplicationBootstrap } /** - * Setup default timezone + * Detect the timezone * - * @return self - * @throws ConfigurationError if the timezone in config.ini isn't valid + * @return null|string */ - protected function setupTimezone() + protected function detectTimezone() { - $default = @date_default_timezone_get(); - if (! $default) { - $default = 'UTC'; + return null; + } + + /** + * Set up the timezone + * + * @return $this + */ + protected final function setupTimezone() + { + $timezone = $this->detectTimeZone(); + if ($timezone === null || @date_default_timezone_set($timezone) === false) { + $timezone = @date_default_timezone_get(); + if ($timezone === false) { + $timezone = 'UTC'; + date_default_timezone_set($timezone); + } } - $timeZoneString = $this->config->global !== null ? $this->config->global->get('timezone', $default) : $default; - date_default_timezone_set($timeZoneString); - DateTimeFactory::setConfig(array('timezone' => $timeZoneString)); + DateTimeFactory::setConfig(array('timezone' => $timezone)); return $this; } /** - * Setup internationalization using gettext + * Detect the locale * - * Uses the preferred language sent by the browser or the default one - * - * @return self + * @return null|string */ - protected function setupInternationalization() + protected function detectLocale() + { + return null; + } + + /** + * Set up internationalization using gettext + * + * @return $this + */ + protected final function setupInternationalization() { if ($this->hasLocales()) { Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir()); } + $locale = $this->detectLocale(); + if ($locale === null) { + $locale = Translator::DEFAULT_LOCALE; + } + try { - Translator::setupLocale( - isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) - ? Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']) - : Translator::DEFAULT_LOCALE - ); + Translator::setupLocale($locale); } catch (Exception $error) { Logger::error($error); } diff --git a/library/Icinga/Application/Cli.php b/library/Icinga/Application/Cli.php index e82eaabbb..abf46262f 100644 --- a/library/Icinga/Application/Cli.php +++ b/library/Icinga/Application/Cli.php @@ -11,8 +11,8 @@ use Icinga\Cli\Loader; use Icinga\Cli\Screen; use Icinga\Application\Logger; use Icinga\Application\Benchmark; +use Icinga\Data\ConfigObject; use Icinga\Exception\ProgrammingError; -use Zend_Config; require_once __DIR__ . '/ApplicationBootstrap.php'; @@ -43,17 +43,17 @@ class Cli extends ApplicationBootstrap ->parseBasicParams() ->setupLogger() ->setupResourceFactory() - ->setupModuleManager(); + ->setupModuleManager() + ->loadCoreModules(); } protected function setupLogging() { Logger::create( - new Zend_Config( + new ConfigObject( array( 'level' => Logger::INFO, - 'log' => 'file', - 'file' => 'php://stderr' + 'log' => 'stdout', ) ) ); diff --git a/library/Icinga/Application/Config.php b/library/Icinga/Application/Config.php index ca377c10a..dcb837fde 100644 --- a/library/Icinga/Application/Config.php +++ b/library/Icinga/Application/Config.php @@ -4,14 +4,16 @@ namespace Icinga\Application; -use Zend_Config; -use Zend_Config_Ini; +use Iterator; +use Countable; +use UnexpectedValueException; +use Icinga\Data\ConfigObject; use Icinga\Exception\NotReadableError; /** - * Global registry of application and module configuration. + * Container for INI like configuration and global registry of application and module related configuration. */ -class Config extends Zend_Config +class Config implements Countable, Iterator { /** * Configuration directory where ALL (application and module) configuration is located @@ -20,13 +22,6 @@ class Config extends Zend_Config */ public static $configDir; - /** - * The INI file this configuration has been loaded from or should be written to - * - * @var string - */ - protected $configFile; - /** * Application config instances per file * @@ -42,96 +37,27 @@ class Config extends Zend_Config protected static $modules = array(); /** - * Load configuration from the given INI file + * The internal ConfigObject * - * @param string $file The file to parse - * - * @throws NotReadableError When the file does not exist or cannot be read + * @var ConfigObject */ - public static function fromIni($file) - { - $config = new static(array(), true); - $filepath = realpath($file); - - if ($filepath === false) { - $config->setConfigFile($file); - } elseif (is_readable($filepath)) { - $config->setConfigFile($filepath); - $config->merge(new Zend_Config_Ini($filepath)); - } else { - throw new NotReadableError('Cannot read config file "%s". Permission denied', $filepath); - } - - return $config; - } + protected $config; /** - * Retrieve a application config instance + * The INI file this config has been loaded from or should be written to * - * @param string $configname The configuration name (without ini suffix) to read and return - * @param bool $fromDisk When set true, the configuration will be read from the disk, even - * if it already has been read - * - * @return Config The configuration object that has been requested + * @var string */ - public static function app($configname = 'config', $fromDisk = false) - { - if (!isset(self::$app[$configname]) || $fromDisk) { - self::$app[$configname] = Config::fromIni(self::resolvePath($configname . '.ini')); - } - return self::$app[$configname]; - } + protected $configFile; /** - * Set module config + * Create a new config * - * @param string $moduleName - * @param string $configName - * @param Zend_Config $config + * @param ConfigObject $config The config object to handle */ - public static function setModuleConfig($moduleName, $configName, Zend_Config $config) + public function __construct(ConfigObject $config = null) { - self::$modules[$moduleName][$configName] = $config; - } - - /** - * Retrieve a module config instance - * - * @param string $modulename The name of the module to look for configurations - * @param string $configname The configuration name (without ini suffix) to read and return - * @param string $fromDisk Whether to read the configuration from disk - * - * @return Config The configuration object that has been requested - */ - public static function module($modulename, $configname = 'config', $fromDisk = false) - { - if (!isset(self::$modules[$modulename])) { - self::$modules[$modulename] = array(); - } - $moduleConfigs = self::$modules[$modulename]; - if (!isset($moduleConfigs[$configname]) || $fromDisk) { - $moduleConfigs[$configname] = Config::fromIni( - self::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') - ); - } - return $moduleConfigs[$configname]; - } - - /** - * Retrieve names of accessible sections or properties - * - * @param $name - * @return array - */ - public function keys($name = null) - { - if ($name === null) { - return array_keys($this->toArray()); - } elseif ($this->$name === null) { - return array(); - } else { - return array_keys($this->$name->toArray()); - } + $this->config = $config !== null ? $config : new ConfigObject(); } /** @@ -147,7 +73,7 @@ class Config extends Zend_Config /** * Set this config's file path * - * @param string $filepath The path to the config file + * @param string $filepath The path to the ini file * * @return self */ @@ -158,10 +84,227 @@ class Config extends Zend_Config } /** - * Prepend configuration base dir if input is relative + * Return the count of available sections * - * @param string $path Input path - * @return string Absolute path + * @return int + */ + public function count() + { + return $this->config->count(); + } + + /** + * Reset the current position of the internal config object + * + * @return ConfigObject + */ + public function rewind() + { + return $this->config->rewind(); + } + + /** + * Return the section of the current iteration + * + * @return ConfigObject + */ + public function current() + { + return $this->config->current(); + } + + /** + * Return whether the position of the current iteration is valid + * + * @return bool + */ + public function valid() + { + return $this->config->valid(); + } + + /** + * Return the section's name of the current iteration + * + * @return string + */ + public function key() + { + return $this->config->key(); + } + + /** + * Advance the position of the current iteration and return the new section + * + * @return ConfigObject + */ + public function next() + { + return $this->config->next(); + } + + /** + * Return whether this config has any sections + * + * @return bool + */ + public function isEmpty() + { + return $this->config->isEmpty(); + } + + /** + * Return this config's section names + * + * @return array + */ + public function keys() + { + return $this->config->keys(); + } + + /** + * Return this config's data as associative array + * + * @return array + */ + public function toArray() + { + return $this->config->toArray(); + } + + /** + * Return the value from a section's property + * + * @param string $section The section where the given property can be found + * @param string $key The section's property to fetch the value from + * @param mixed $default The value to return in case the section or the property is missing + * + * @return mixed + * + * @throws UnexpectedValueException In case the given section does not hold any configuration + */ + public function get($section, $key, $default = null) + { + $value = $this->config->$section; + if ($value instanceof ConfigObject) { + $value = $value->$key; + } elseif ($value !== null) { + throw new UnexpectedValueException( + sprintf('Value "%s" is not of type "%s" or a sub-type of it', $value, get_class($this->config)) + ); + } + + if ($value === null && $default !== null) { + $value = $default; + } + + return $value; + } + + /** + * Return the given section + * + * @param string $name The section's name + * + * @return ConfigObject + */ + public function getSection($name) + { + $section = $this->config->get($name); + return $section !== null ? $section : new ConfigObject(); + } + + /** + * Set or replace a section + * + * @param string $name + * @param array|ConfigObject $config + * + * @return self + */ + public function setSection($name, $config = null) + { + if ($config === null) { + $config = new ConfigObject(); + } elseif (! $config instanceof ConfigObject) { + $config = new ConfigObject($config); + } + + $this->config->$name = $config; + return $this; + } + + /** + * Remove a section + * + * @param string $name + * + * @return self + */ + public function removeSection($name) + { + unset($this->config->$name); + return $this; + } + + /** + * Return whether the given section exists + * + * @param string $name + * + * @return bool + */ + public function hasSection($name) + { + return isset($this->config->$name); + } + + /** + * Initialize a new config using the given array + * + * The returned config has no file associated to it. + * + * @param array $array The array to initialize the config with + * + * @return Config + */ + public static function fromArray(array $array) + { + return new static(new ConfigObject($array)); + } + + /** + * Load configuration from the given INI file + * + * @param string $file The file to parse + * + * @throws NotReadableError When the file does not exist or cannot be read + */ + public static function fromIni($file) + { + $emptyConfig = new static(); + + $filepath = realpath($file); + if ($filepath === false) { + $emptyConfig->setConfigFile($file); + } elseif (is_readable($filepath)) { + $config = new static(new ConfigObject(parse_ini_file($filepath, true))); + $config->setConfigFile($filepath); + return $config; + } else { + throw new NotReadableError(t('Cannot read config file "%s". Permission denied'), $filepath); + } + + return $emptyConfig; + } + + /** + * Prepend configuration base dir to the given relative path + * + * @param string $path A relative path + * + * @return string */ public static function resolvePath($path) { @@ -169,12 +312,46 @@ class Config extends Zend_Config } /** - * Is the configuration empty? + * Retrieve a application config * - * @return bool + * @param string $configname The configuration name (without ini suffix) to read and return + * @param bool $fromDisk When set true, the configuration will be read from disk, even + * if it already has been read + * + * @return Config The requested configuration */ - public function isEmpty() + public static function app($configname = 'config', $fromDisk = false) { - return empty($this->_data); + if (!isset(self::$app[$configname]) || $fromDisk) { + self::$app[$configname] = static::fromIni(static::resolvePath($configname . '.ini')); + } + + return self::$app[$configname]; + } + + /** + * Retrieve a module config + * + * @param string $modulename The name of the module where to look for the requested configuration + * @param string $configname The configuration name (without ini suffix) to read and return + * @param string $fromDisk When set true, the configuration will be read from disk, even + * if it already has been read + * + * @return Config The requested configuration + */ + public static function module($modulename, $configname = 'config', $fromDisk = false) + { + if (!isset(self::$modules[$modulename])) { + self::$modules[$modulename] = array(); + } + + $moduleConfigs = self::$modules[$modulename]; + if (!isset($moduleConfigs[$configname]) || $fromDisk) { + $moduleConfigs[$configname] = static::fromIni( + static::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') + ); + } + + return $moduleConfigs[$configname]; } } diff --git a/library/Icinga/Application/EmbeddedWeb.php b/library/Icinga/Application/EmbeddedWeb.php index 6a160017c..23cb365f0 100644 --- a/library/Icinga/Application/EmbeddedWeb.php +++ b/library/Icinga/Application/EmbeddedWeb.php @@ -27,7 +27,9 @@ class EmbeddedWeb extends ApplicationBootstrap */ protected function bootstrap() { - return $this->loadConfig() + return $this + ->setupZendAutoloader() + ->loadConfig() ->setupErrorHandling() ->setupTimezone() ->setupModuleManager() diff --git a/library/Icinga/Application/Logger.php b/library/Icinga/Application/Logger.php index cb06ef8c3..70eaa774b 100644 --- a/library/Icinga/Application/Logger.php +++ b/library/Icinga/Application/Logger.php @@ -5,7 +5,7 @@ namespace Icinga\Application; use Exception; -use Zend_Config; +use Icinga\Data\ConfigObject; use Icinga\Application\Logger\Writer\FileWriter; use Icinga\Application\Logger\Writer\SyslogWriter; use Icinga\Exception\ConfigurationError; @@ -71,12 +71,12 @@ class Logger /** * Create a new logger object * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws ConfigurationError If the logging configuration directive 'log' is missing or if the logging level is * not defined */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { if ($config->log === null) { throw new ConfigurationError('Required logging configuration directive \'log\' missing'); @@ -118,11 +118,11 @@ class Logger /** * Create a new logger object * - * @param Zend_Config $config + * @param ConfigObject $config * * @return static */ - public static function create(Zend_Config $config) + public static function create(ConfigObject $config) { static::$instance = new static($config); return static::$instance; @@ -131,12 +131,12 @@ class Logger /** * Create a log writer * - * @param Zend_Config $config The configuration to initialize the writer with + * @param ConfigObject $config The configuration to initialize the writer with * * @return \Icinga\Application\Logger\LogWriter The requested log writer * @throws ConfigurationError If the requested writer cannot be found */ - protected function createWriter(Zend_Config $config) + protected function createWriter(ConfigObject $config) { $class = 'Icinga\\Application\\Logger\\Writer\\' . ucfirst(strtolower($config->log)) . 'Writer'; if (! class_exists($class)) { diff --git a/library/Icinga/Application/Logger/LogWriter.php b/library/Icinga/Application/Logger/LogWriter.php index 370af35c1..b89fec62f 100644 --- a/library/Icinga/Application/Logger/LogWriter.php +++ b/library/Icinga/Application/Logger/LogWriter.php @@ -4,17 +4,25 @@ namespace Icinga\Application\Logger; -use Zend_Config; +use Icinga\Data\ConfigObject; /** * Abstract class for writers that write messages to a log */ abstract class LogWriter { + /** + * @var ConfigObject + */ + protected $config; + /** * Create a new log writer initialized with the given configuration */ - abstract public function __construct(Zend_Config $config); + public function __construct(ConfigObject $config) + { + $this->config = $config; + } /** * Log a message with the given severity diff --git a/library/Icinga/Application/Logger/Writer/FileWriter.php b/library/Icinga/Application/Logger/Writer/FileWriter.php index 220b9be79..2f5a292ec 100644 --- a/library/Icinga/Application/Logger/Writer/FileWriter.php +++ b/library/Icinga/Application/Logger/Writer/FileWriter.php @@ -5,7 +5,7 @@ namespace Icinga\Application\Logger\Writer; use Exception; -use Zend_Config; +use Icinga\Data\ConfigObject; use Icinga\Application\Logger; use Icinga\Application\Logger\LogWriter; use Icinga\Exception\ConfigurationError; @@ -26,12 +26,12 @@ class FileWriter extends LogWriter /** * Create a new file log writer * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws ConfigurationError If the configuration directive 'file' is missing or if the path to 'file' does * not exist or if writing to 'file' is not possible */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { if ($config->file === null) { throw new ConfigurationError('Required logging configuration directive \'file\' missing'); diff --git a/library/Icinga/Application/Logger/Writer/StdoutWriter.php b/library/Icinga/Application/Logger/Writer/StdoutWriter.php new file mode 100644 index 000000000..1fe929d92 --- /dev/null +++ b/library/Icinga/Application/Logger/Writer/StdoutWriter.php @@ -0,0 +1,50 @@ +screen === null) { + $this->screen = Screen::instance(); + } + return $this->screen; + } + + /** + * Log a message with the given severity + * + * @param int $severity The severity to use + * @param string $message The message to log + */ + public function log($severity, $message) + { + $color = 'black'; + switch ($severity) { + case Logger::$ERROR: + $color = 'red'; + break; + case Logger::$WARNING: + $color = 'orange'; + break; + case Logger::$INFO: + $color = 'green'; + break; + case Logger::$DEBUG: + $color = 'blue'; + break; + } + file_put_contents('php://stderr', $this->screen()->colorize($message, $color) . "\n"); + } +} diff --git a/library/Icinga/Application/Logger/Writer/SyslogWriter.php b/library/Icinga/Application/Logger/Writer/SyslogWriter.php index 9a5ac28e5..7a69e4cba 100644 --- a/library/Icinga/Application/Logger/Writer/SyslogWriter.php +++ b/library/Icinga/Application/Logger/Writer/SyslogWriter.php @@ -4,7 +4,7 @@ namespace Icinga\Application\Logger\Writer; -use Zend_Config; +use Icinga\Data\ConfigObject; use Icinga\Application\Logger; use Icinga\Application\Logger\LogWriter; @@ -51,9 +51,9 @@ class SyslogWriter extends LogWriter /** * Create a new syslog log writer * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->ident = $config->get('application', 'icingaweb'); $this->facility = static::$facilities['user']; diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 36ab7dbe4..6469d3929 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -13,6 +13,7 @@ use Icinga\Exception\ConfigurationError; use Icinga\Exception\SystemPermissionException; use Icinga\Exception\ProgrammingError; use Icinga\Exception\NotReadableError; +use Icinga\Exception\NotFoundError; /** * Module manager that handles detecting, enabling and disabling of modules @@ -67,6 +68,18 @@ class Manager */ private $modulePaths = array(); + /** + * The core modules + * + * Core modules do not need to be enabled to load and cannot be disabled + * by the user. This must not be writable programmatically! + * + * @var array + */ + private $coreModules = array( + 'setup' + ); + /** * Create a new instance of the module manager * @@ -157,7 +170,21 @@ class Manager } /** - * Try to set all enabled modules in loaded sate + * Try to set all core modules in loaded state + * + * @return self + * @see Manager::loadModule() + */ + public function loadCoreModules() + { + foreach ($this->coreModules as $name) { + $this->loadModule($name); + } + return $this; + } + + /** + * Try to set all enabled modules in loaded state * * @return self * @see Manager::loadModule() @@ -202,6 +229,7 @@ class Manager * * @return self * @throws ConfigurationError When trying to enable a module that is not installed + * @throws NotFoundError In case the "enabledModules" directory does not exist * @throws SystemPermissionException When insufficient permissions for the application exist */ public function enableModule($name) @@ -211,15 +239,19 @@ class Manager 'Cannot enable module "%s". Module is not installed.', $name ); + } elseif (in_array($name, $this->coreModules)) { + return $this; } clearstatcache(true); $target = $this->installedBaseDirs[$name]; $link = $this->enableDir . '/' . $name; - if (!is_writable($this->enableDir)) { + if (! is_dir($this->enableDir)) { + throw new NotFoundError('Cannot enable module "%s". Path "%s" not found.', $name, $this->enableDir); + } elseif (!is_writable($this->enableDir)) { throw new SystemPermissionException( - 'Can not enable module "%s". Insufficient system permissions for enabling modules.', + 'Cannot enable module "%s". Insufficient system permissions for enabling modules.', $name ); } @@ -426,7 +458,7 @@ class Manager } $installed = $this->listInstalledModules(); - foreach ($installed as $name) { + foreach (array_diff($installed, $this->coreModules) as $name) { $info[$name] = (object) array( 'name' => $name, 'path' => $this->installedBaseDirs[$name], @@ -486,11 +518,14 @@ class Manager /** * Detect installed modules from every path provided in modulePaths * + * @param array $availableDirs Installed modules location + * * @return self */ - public function detectInstalledModules() + public function detectInstalledModules(array $availableDirs = null) { - foreach ($this->modulePaths as $basedir) { + $modulePaths = $availableDirs !== null ? $availableDirs : $this->modulePaths; + foreach ($modulePaths as $basedir) { $canonical = realpath($basedir); if ($canonical === false) { Logger::warning('Module path "%s" does not exist', $basedir); @@ -527,4 +562,14 @@ class Manager ksort($this->installedBaseDirs); return $this; } + + /** + * Get the directories where to look for installed modules + * + * @return array + */ + public function getModuleDirs() + { + return $this->modulePaths; + } } diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index b97483f95..8c01eb05e 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -5,7 +5,6 @@ namespace Icinga\Application\Modules; use Exception; -use Zend_Config; use Zend_Controller_Router_Route_Abstract; use Zend_Controller_Router_Route as Route; use Zend_Controller_Router_Route_Regex as RegexRoute; @@ -13,11 +12,13 @@ use Icinga\Application\ApplicationBootstrap; use Icinga\Application\Config; use Icinga\Application\Icinga; use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Util\Translator; use Icinga\Web\Hook; use Icinga\Web\Menu; use Icinga\Web\Widget; use Icinga\Web\Widget\Dashboard\Pane; +use Icinga\Module\Setup\SetupWizard; use Icinga\Util\File; use Icinga\Exception\ProgrammingError; use Icinga\Exception\IcingaException; @@ -134,6 +135,13 @@ class Module */ private $configTabs = array(); + /** + * Provided setup wizard + * + * @var string + */ + private $setupWizard; + /** * Icinga application * @@ -235,7 +243,7 @@ class Module if (array_key_exists($name, $this->menuItems)) { $this->menuItems[$name]->setProperties($properties); } else { - $this->menuItems[$name] = new Menu($name, new Zend_Config($properties)); + $this->menuItems[$name] = new Menu($name, new ConfigObject($properties)); } return $this->menuItems[$name]; @@ -642,6 +650,31 @@ class Module return $tabs; } + /** + * Whether this module provides a setup wizard + * + * @return bool + */ + public function providesSetupWizard() + { + $this->launchConfigScript(); + if (class_exists($this->setupWizard)) { + $wizard = new $this->setupWizard; + return $wizard instanceof SetupWizard; + } + + return false; + } + + /** + * Return this module's setup wizard + * + * @return SetupWizard + */ + public function getSetupWizard() + { + return new $this->setupWizard; + } /** * Provide a named permission @@ -705,6 +738,19 @@ class Module return $this; } + /** + * Provide a setup wizard + * + * @param string $className The name of the class + * + * @return self + */ + protected function provideSetupWizard($className) + { + $this->setupWizard = $className; + return $this; + } + /** * Register new namespaces on the autoloader * @@ -718,7 +764,7 @@ class Module $this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir); if (is_dir($this->getFormDir())) { $this->app->getLoader()->registerNamespace( - 'Icinga\\Module\\' . $moduleName. '\\Form', + 'Icinga\\Module\\' . $moduleName. '\\Forms', $this->getFormDir() ); } diff --git a/library/Icinga/Application/Platform.php b/library/Icinga/Application/Platform.php index 1ca738741..259219435 100644 --- a/library/Icinga/Application/Platform.php +++ b/library/Icinga/Application/Platform.php @@ -30,6 +30,16 @@ class Platform */ protected static $fqdn; + /** + * Return the operating system's name + * + * @return string + */ + public static function getOperatingSystemName() + { + return php_uname('s'); + } + /** * Test of windows * @@ -37,7 +47,7 @@ class Platform */ public static function isWindows() { - return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + return strtoupper(substr(self::getOperatingSystemName(), 0, 3)) === 'WIN'; } /** @@ -47,7 +57,7 @@ class Platform */ public static function isLinux() { - return strtoupper(substr(PHP_OS, 0, 5)) === 'LINUX'; + return strtoupper(substr(self::getOperatingSystemName(), 0, 5)) === 'LINUX'; } /** @@ -116,7 +126,35 @@ class Platform if (substr(self::$fqdn, 0, strlen(self::$hostname)) === self::$hostname) { self::$domain = substr(self::$fqdn, strlen(self::$hostname) + 1); } else { - self::$domain = array_shift(preg_split('~\.~', self::$hostname, 2)); + $parts = preg_split('~\.~', self::$hostname, 2); + self::$domain = array_shift($parts); + } + } + + /** + * Return the version of PHP + * + * @return string + */ + public static function getPhpVersion() + { + return phpversion(); + } + + /** + * Return the username PHP is running as + * + * @return string + */ + public static function getPhpUser() + { + if (static::isWindows()) { + return get_current_user(); // http://php.net/manual/en/function.get-current-user.php#75059 + } + + if (function_exists('posix_geteuid')) { + $userInfo = posix_getpwuid(posix_geteuid()); + return $userInfo['name']; } } @@ -131,4 +169,32 @@ class Platform { return extension_loaded($extensionName); } + + /** + * Return the value for the given PHP configuration option + * + * @param string $option The option name for which to return the value + * + * @return string|false + */ + public static function getPhpConfig($option) + { + return ini_get($option); + } + + /** + * Return whether the given Zend framework class exists + * + * @param string $name The name of the class to check + * + * @return bool + */ + public static function zendClassExists($name) + { + if (class_exists($name)) { + return true; + } + + return (@include str_replace('_', '/', $name) . '.php') !== false; + } } diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index d43b1d34d..37ec5138a 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -7,6 +7,7 @@ namespace Icinga\Application; require_once __DIR__ . '/ApplicationBootstrap.php'; use Icinga\Authentication\Manager as AuthenticationManager; +use Icinga\Authentication\Manager; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; use Icinga\Application\Logger; @@ -14,6 +15,8 @@ use Icinga\Util\TimezoneDetect; use Icinga\Web\Request; use Icinga\Web\Response; use Icinga\Web\View; +use Icinga\Web\Session\Session as BaseSession; +use Icinga\Web\Session; use Icinga\User; use Icinga\Util\Translator; use Icinga\Util\DateTimeFactory; @@ -58,6 +61,13 @@ class Web extends ApplicationBootstrap */ private $request; + /** + * Session object + * + * @var BaseSession + */ + private $session; + /** * User object * @@ -80,10 +90,12 @@ class Web extends ApplicationBootstrap protected function bootstrap() { return $this + ->setupZendAutoloader() ->setupLogging() ->setupErrorHandling() ->loadConfig() ->setupResourceFactory() + ->setupSession() ->setupUser() ->setupTimezone() ->setupLogger() @@ -92,6 +104,7 @@ class Web extends ApplicationBootstrap ->setupZendMvc() ->setupFormNamespace() ->setupModuleManager() + ->loadCoreModules() ->loadEnabledModules() ->setupRoute() ->setupPagination(); @@ -163,6 +176,7 @@ class Web extends ApplicationBootstrap $this->setupFrontController(); $this->setupViewRenderer(); + return $this; } @@ -182,6 +196,17 @@ class Web extends ApplicationBootstrap return $this; } + /** + * Initialize a session provider + * + * @return self + */ + private function setupSession() + { + $this->session = Session::create(); + return $this; + } + /** * Inject dependencies into request * @@ -234,9 +259,7 @@ class Web extends ApplicationBootstrap $view->view->addHelperPath($this->getApplicationDir('/views/helpers')); $view->view->setEncoding('UTF-8'); - $view->view->headTitle()->prepend( - $this->config->global !== null ? $this->config->global->get('project', 'Icinga') : 'Icinga' - ); + $view->view->headTitle()->prepend($this->config->get('global', 'project', 'Icinga')); $view->view->headTitle()->setSeparator(' :: '); @@ -267,29 +290,19 @@ class Web extends ApplicationBootstrap } /** - * Setup user timezone if set and valid, otherwise global default timezone - * - * @return self - * @see ApplicationBootstrap::setupTimezone + * (non-PHPDoc) + * @see ApplicationBootstrap::detectTimezone() For the method documentation. */ - protected function setupTimezone() + protected function detectTimezone() { - $userTimezone = null; - - if ($this->user !== null && $this->user->getPreferences() !== null) { + $auth = Manager::getInstance(); + if (! $auth->isAuthenticated() + || ($timezone = $auth->getUser()->getPreferences()->getValue('icingaweb', 'timezone')) === null + ) { $detect = new TimezoneDetect(); - $userTimezone = $this->user->getPreferences() - ->getValue('icingaweb', 'timezone', $detect->getTimezoneName()); + $timezone = $detect->getTimezoneName(); } - - try { - DateTimeFactory::setConfig(array('timezone' => $userTimezone)); - date_default_timezone_set($userTimezone); - } catch (ConfigurationError $e) { - return parent::setupTimezone(); - } - - return $this; + return $timezone; } /** @@ -299,35 +312,30 @@ class Web extends ApplicationBootstrap * * @return self */ - protected function setupInternationalization() + protected function detectLocale() { - parent::setupInternationalization(); - if ($this->user !== null && $this->user->getPreferences() !== null - && (($locale = $this->user->getPreferences()->getValue('icingaweb', 'language')) !== null) + $auth = Manager::getInstance(); + if (! $auth->isAuthenticated() + || ($locale = $auth->getUser()->getPreferences()->getValue('icingaweb', 'language')) === null + && isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ) { - try { - Translator::setupLocale($locale); - } catch (Exception $error) { - Logger::warning( - 'Cannot set locale "' . $locale . '" configured in ' . - 'preferences of user "' . $this->user->getUsername() . '"' - ); - } + $locale = Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']); } - return $this; + return $locale; } /** - * Setup an autoloader namespace for Icinga\Form + * Setup an autoloader namespace for Icinga\Forms * * @return self */ private function setupFormNamespace() { $this->getLoader()->registerNamespace( - 'Icinga\\Form', + 'Icinga\\Forms', $this->getApplicationDir('forms') ); return $this; } } +// @codeCoverageIgnoreEnd diff --git a/library/Icinga/Authentication/AdmissionLoader.php b/library/Icinga/Authentication/AdmissionLoader.php index 50624003c..65d99f427 100644 --- a/library/Icinga/Authentication/AdmissionLoader.php +++ b/library/Icinga/Authentication/AdmissionLoader.php @@ -6,6 +6,7 @@ namespace Icinga\Authentication; use Icinga\Application\Config; use Icinga\Exception\NotReadableError; +use Icinga\Data\ConfigObject; use Icinga\User; use Icinga\Util\String; @@ -15,13 +16,13 @@ use Icinga\Util\String; class AdmissionLoader { /** - * @param string $username - * @param array $userGroups - * @param mixed $section + * @param string $username + * @param array $userGroups + * @param ConfigObject $section * * @return bool */ - protected function match($username, $userGroups, $section) + protected function match($username, $userGroups, ConfigObject $section) { $username = strtolower($username); if (! empty($section->users)) { diff --git a/library/Icinga/Authentication/AuthChain.php b/library/Icinga/Authentication/AuthChain.php index 12c7143bf..24c12c9de 100644 --- a/library/Icinga/Authentication/AuthChain.php +++ b/library/Icinga/Authentication/AuthChain.php @@ -5,7 +5,8 @@ namespace Icinga\Authentication; use Iterator; -use Zend_Config; +use Icinga\Data\ConfigObject; +use Icinga\Application\Config; use Icinga\Application\Logger; use Icinga\Exception\ConfigurationError; @@ -17,7 +18,7 @@ class AuthChain implements Iterator /** * User backends configuration * - * @var Zend_Config + * @var Config */ private $config; @@ -31,20 +32,22 @@ class AuthChain implements Iterator /** * Create a new authentication chain from config * - * @param Zend_Config $config User backends configuration + * @param Config $config User backends configuration */ - public function __construct(Zend_Config $config) + public function __construct(Config $config) { $this->config = $config; } /** * Rewind the chain + * + * @return ConfigObject */ public function rewind() { - $this->config->rewind(); $this->currentBackend = null; + return $this->config->rewind(); } /** @@ -60,7 +63,7 @@ class AuthChain implements Iterator /** * Return the key of the current user backend config * - * @return string + * @return string */ public function key() { @@ -69,16 +72,18 @@ class AuthChain implements Iterator /** * Move forward to the next user backend config + * + * @return ConfigObject */ public function next() { - $this->config->next(); + return $this->config->next(); } /** - * Check if the current user backend is valid, i.e. it's enabled and the config's valid + * Check if the current user backend is valid, i.e. it's enabled and the config is valid * - * @return bool + * @return bool */ public function valid() { @@ -86,13 +91,15 @@ class AuthChain implements Iterator // Stop when there are no more backends to check return false; } + $backendConfig = $this->config->current(); if ((bool) $backendConfig->get('disabled', false) === true) { $this->next(); return $this->valid(); } + + $name = $this->key(); try { - $name = $this->key(); $backend = UserBackend::create($name, $backendConfig); } catch (ConfigurationError $e) { Logger::error( @@ -105,6 +112,7 @@ class AuthChain implements Iterator $this->next(); return $this->valid(); } + $this->currentBackend = $backend; return true; } diff --git a/library/Icinga/Authentication/Backend/AutoLoginBackend.php b/library/Icinga/Authentication/Backend/AutoLoginBackend.php index 16373bb6c..b4a70bd4f 100644 --- a/library/Icinga/Authentication/Backend/AutoLoginBackend.php +++ b/library/Icinga/Authentication/Backend/AutoLoginBackend.php @@ -4,8 +4,8 @@ namespace Icinga\Authentication\Backend; -use Zend_Config; use Icinga\Authentication\UserBackend; +use Icinga\Data\ConfigObject; use Icinga\User; /** @@ -23,9 +23,9 @@ class AutoLoginBackend extends UserBackend /** * Create new autologin backend * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->stripUsernameRegexp = $config->get('strip_username_regexp'); } @@ -54,7 +54,7 @@ class AutoLoginBackend extends UserBackend if (isset($_SERVER['REMOTE_USER'])) { $username = $_SERVER['REMOTE_USER']; $user->setRemoteUserInformation($username, 'REMOTE_USER'); - if ($this->stripUsernameRegexp !== null) { + if ($this->stripUsernameRegexp) { $stripped = preg_replace($this->stripUsernameRegexp, '', $username); if ($stripped !== false) { // TODO(el): PHP issues a warning when PHP cannot compile the regular expression. Should we log an diff --git a/library/Icinga/Authentication/Backend/DbUserBackend.php b/library/Icinga/Authentication/Backend/DbUserBackend.php index a89a07c81..d2d0147e5 100644 --- a/library/Icinga/Authentication/Backend/DbUserBackend.php +++ b/library/Icinga/Authentication/Backend/DbUserBackend.php @@ -4,6 +4,7 @@ namespace Icinga\Authentication\Backend; +use PDO; use Icinga\Authentication\UserBackend; use Icinga\Data\Db\DbConnection; use Icinga\User; @@ -11,16 +12,29 @@ use Icinga\Exception\AuthenticationException; use Exception; use Zend_Db_Expr; use Zend_Db_Select; -use Icinga\Exception\IcingaException; class DbUserBackend extends UserBackend { + /** + * The algorithm to use when hashing passwords + * + * @var string + */ + const HASH_ALGORITHM = '$1$'; // MD5 + + /** + * The length of the salt to use when hashing a password + * + * @var int + */ + const SALT_LENGTH = 12; // 12 is required by MD5 + /** * Connection to the database * * @var DbConnection */ - private $conn; + protected $conn; public function __construct(DbConnection $conn) { @@ -36,45 +50,69 @@ class DbUserBackend extends UserBackend */ public function hasUser(User $user) { - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array(new Zend_Db_Expr(1))) - ->where('username = ?', $user->getUsername()) + $select = new Zend_Db_Select($this->conn->getDbAdapter()); + $row = $select->from('icingaweb_user', array(new Zend_Db_Expr(1))) + ->where('name = ?', $user->getUsername()) ->query()->fetchObject(); return ($row !== false) ? true : false; } /** - * Authenticate the given user and return true on success, false on failure and null on error + * Add a new user + * + * @param string $username The name of the new user + * @param string $password The new user's password + * @param bool $active Whether the user is active + */ + public function addUser($username, $password, $active = true) + { + $passwordHash = $this->hashPassword($password); + + $stmt = $this->conn->getDbAdapter()->prepare( + 'INSERT INTO icingaweb_user VALUES (:name, :active, :password_hash, now(), DEFAULT);' + ); + $stmt->bindParam(':name', $username, PDO::PARAM_STR); + $stmt->bindParam(':active', $active, PDO::PARAM_INT); + $stmt->bindParam(':password_hash', $passwordHash, PDO::PARAM_LOB); + $stmt->execute(); + } + + /** + * Fetch the hashed password for the given user + * + * @param string $username The name of the user + * + * @return string + */ + protected function getPasswordHash($username) + { + $stmt = $this->conn->getDbAdapter()->prepare( + 'SELECT password_hash FROM icingaweb_user WHERE name = :name AND active = 1' + ); + $stmt->execute(array(':name' => $username)); + $stmt->bindColumn(1, $lob, PDO::PARAM_LOB); + $stmt->fetch(PDO::FETCH_BOUND); + return is_resource($lob) ? stream_get_contents($lob) : $lob; + } + + /** + * Authenticate the given user and return true on success, false on failure and throw an exception on error * * @param User $user * @param string $password * - * @return bool|null + * @return bool + * * @throws AuthenticationException */ public function authenticate(User $user, $password) { try { - $salt = $this->getSalt($user->getUsername()); - if ($salt === null) { - return false; - } - if ($salt === '') { - throw new IcingaException( - 'Cannot find salt for user %s', - $user->getUsername() - ); - } - - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array(new Zend_Db_Expr(1))) - ->where('username = ?', $user->getUsername()) - ->where('active = ?', true) - ->where('password = ?', $this->hashPassword($password, $salt)) - ->query()->fetchObject(); - - return ($row !== false) ? true : false; + $passwordHash = $this->getPasswordHash($user->getUsername()); + $passwordSalt = $this->getSalt($passwordHash); + $hashToCompare = $this->hashPassword($password, $passwordSalt); + return $hashToCompare === $passwordHash; } catch (Exception $e) { throw new AuthenticationException( 'Failed to authenticate user "%s" against backend "%s". An exception was thrown:', @@ -86,29 +124,40 @@ class DbUserBackend extends UserBackend } /** - * Get salt by username + * Extract salt from the given password hash * - * @param string $username + * @param string $hash The hashed password * - * @return string|null + * @return string */ - private function getSalt($username) + protected function getSalt($hash) { - $select = new Zend_Db_Select($this->conn->getConnection()); - $row = $select->from('account', array('salt'))->where('username = ?', $username)->query()->fetchObject(); - return ($row !== false) ? $row->salt : null; + return substr($hash, strlen(self::HASH_ALGORITHM), self::SALT_LENGTH); + } + + /** + * Return a random salt + * + * The returned salt is safe to be used for hashing a user's password + * + * @return string + */ + protected function generateSalt() + { + return openssl_random_pseudo_bytes(self::SALT_LENGTH); } /** * Hash a password * - * @param string $password - * @param string $salt + * @param string $password + * @param string $salt * * @return string */ - private function hashPassword($password, $salt) { - return hash_hmac('sha256', $password, $salt); + protected function hashPassword($password, $salt = null) + { + return crypt($password, self::HASH_ALGORITHM . ($salt !== null ? $salt : $this->generateSalt())); } /** @@ -118,12 +167,29 @@ class DbUserBackend extends UserBackend */ public function count() { - $select = new Zend_Db_Select($this->conn->getConnection()); + $select = new Zend_Db_Select($this->conn->getDbAdapter()); $row = $select->from( - 'account', + 'icingaweb_user', array('count' => 'COUNT(*)') )->query()->fetchObject(); return ($row !== false) ? $row->count : 0; } + + /** + * Return the names of all available users + * + * @return array + */ + public function listUsers() + { + $query = $this->conn->select()->from('icingaweb_user', array('name')); + + $users = array(); + foreach ($query->fetchAll() as $row) { + $users[] = $row->name; + } + + return $users; + } } diff --git a/library/Icinga/Authentication/Backend/LdapUserBackend.php b/library/Icinga/Authentication/Backend/LdapUserBackend.php index b859dfb3d..519dd3c48 100644 --- a/library/Icinga/Authentication/Backend/LdapUserBackend.php +++ b/library/Icinga/Authentication/Backend/LdapUserBackend.php @@ -4,7 +4,6 @@ namespace Icinga\Authentication\Backend; -use Icinga\Application\Logger; use Icinga\User; use Icinga\Authentication\UserBackend; use Icinga\Protocol\Ldap\Connection; @@ -20,20 +19,36 @@ class LdapUserBackend extends UserBackend **/ protected $conn; + protected $baseDn; + protected $userClass; protected $userNameAttribute; protected $groupOptions; - public function __construct(Connection $conn, $userClass, $userNameAttribute, $groupOptions = null) + public function __construct(Connection $conn, $userClass, $userNameAttribute, $baseDn, $groupOptions = null) { $this->conn = $conn; + $this->baseDn = trim($baseDn) !== '' ? $baseDn : $conn->getDN(); $this->userClass = $userClass; $this->userNameAttribute = $userNameAttribute; $this->groupOptions = $groupOptions; } + /** + * @return \Icinga\Protocol\Ldap\Query + */ + protected function selectUsers() + { + return $this->conn->select()->setBase($this->baseDn)->from( + $this->userClass, + array( + $this->userNameAttribute + ) + ); + } + /** * Create query * @@ -41,14 +56,9 @@ class LdapUserBackend extends UserBackend * * @return \Icinga\Protocol\Ldap\Query **/ - protected function createQuery($username) + protected function selectUser($username) { - return $this->conn->select() - ->from( - $this->userClass, - array($this->userNameAttribute) - ) - ->where( + return $this->selectUsers()->where( $this->userNameAttribute, str_replace('*', '', $username) ); @@ -68,13 +78,18 @@ class LdapUserBackend extends UserBackend */ public function assertAuthenticationPossible() { - $q = $this->conn->select()->from($this->userClass); - $result = $q->fetchRow(); + try { + $q = $this->conn->select()->setBase($this->baseDn)->from($this->userClass); + $result = $q->fetchRow(); + } catch (LdapException $e) { + throw new AuthenticationException('Connection not possible.', $e); + } + if (! isset($result)) { throw new AuthenticationException( 'No objects with objectClass="%s" in DN="%s" found.', $this->userClass, - $this->conn->getDN() + $this->baseDn ); } @@ -94,12 +109,12 @@ class LdapUserBackend extends UserBackend * * @param string $dn * - * @return array|null + * @return array */ public function getGroups($dn) { if (empty($this->groupOptions) || ! isset($this->groupOptions['group_base_dn'])) { - return null; + return array(); } $q = $this->conn->select() @@ -135,7 +150,7 @@ class LdapUserBackend extends UserBackend public function hasUser(User $user) { $username = $user->getUsername(); - return $this->conn->fetchOne($this->createQuery($username)) === $username; + return $this->conn->fetchOne($this->selectUser($username)) === $username; } /** @@ -158,7 +173,7 @@ class LdapUserBackend extends UserBackend } catch (AuthenticationException $e) { // Authentication not possible throw new AuthenticationException( - 'Authentication against backend "%s" not possible: ', + 'Authentication against backend "%s" not possible.', $this->getName(), $e ); @@ -168,7 +183,7 @@ class LdapUserBackend extends UserBackend return false; } try { - $userDn = $this->conn->fetchDN($this->createQuery($user->getUsername())); + $userDn = $this->conn->fetchDN($this->selectUser($user->getUsername())); $authenticated = $this->conn->testCredentials( $userDn, $password @@ -198,14 +213,20 @@ class LdapUserBackend extends UserBackend */ public function count() { + return $this->conn->count($this->selectUsers()); + } - return $this->conn->count( - $this->conn->select()->from( - $this->userClass, - array( - $this->userNameAttribute - ) - ) - ); + /** + * Return the names of all available users + * + * @return array + */ + public function listUsers() + { + $users = array(); + foreach ($this->selectUsers()->fetchAll() as $row) { + $users[] = $row->{$this->userNameAttribute}; + } + return $users; } } diff --git a/library/Icinga/Authentication/Manager.php b/library/Icinga/Authentication/Manager.php index c7d03b16a..88258351e 100644 --- a/library/Icinga/Authentication/Manager.php +++ b/library/Icinga/Authentication/Manager.php @@ -5,7 +5,6 @@ namespace Icinga\Authentication; use Exception; -use Zend_Config; use Icinga\Application\Config; use Icinga\Exception\IcingaException; use Icinga\Exception\NotReadableError; @@ -62,9 +61,10 @@ class Manager $e ) ); - $config = new Zend_Config(array()); + $config = new Config(); } - if (($preferencesConfig = $config->preferences) !== null) { + if ($config->hasSection('preferences')) { + $preferencesConfig = $config->getSection('preferences'); try { $preferencesStore = PreferencesStore::create( $preferencesConfig, @@ -120,10 +120,7 @@ class Manager */ public function persistCurrentUser() { - $session = Session::getSession(); - $session->set('user', $this->user); - $session->write(); - $session->refreshId(); + Session::getSession()->set('user', $this->user)->refreshId(); } /** diff --git a/library/Icinga/Authentication/UserBackend.php b/library/Icinga/Authentication/UserBackend.php index 7829210fd..eaf39e49d 100644 --- a/library/Icinga/Authentication/UserBackend.php +++ b/library/Icinga/Authentication/UserBackend.php @@ -6,9 +6,9 @@ namespace Icinga\Authentication; use Countable; use Icinga\Authentication\Backend\AutoLoginBackend; -use Zend_Config; use Icinga\Authentication\Backend\DbUserBackend; use Icinga\Authentication\Backend\LdapUserBackend; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\User; @@ -45,7 +45,7 @@ abstract class UserBackend implements Countable return $this->name; } - public static function create($name, Zend_Config $backendConfig) + public static function create($name, ConfigObject $backendConfig) { if ($backendConfig->name !== null) { $name = $backendConfig->name; @@ -103,6 +103,7 @@ abstract class UserBackend implements Countable $resource, $backendConfig->get('user_class', 'user'), $backendConfig->get('user_name_attribute', 'sAMAccountName'), + $backendConfig->get('base_dn', $resource->getDN()), $groupOptions ); break; @@ -129,6 +130,7 @@ abstract class UserBackend implements Countable $resource, $backendConfig->user_class, $backendConfig->user_name_attribute, + $backendConfig->get('base_dn', $resource->getDN()), $groupOptions ); break; diff --git a/library/Icinga/Authentication/UserGroupBackend.php b/library/Icinga/Authentication/UserGroupBackend.php index e411aee03..f1a41adcb 100644 --- a/library/Icinga/Authentication/UserGroupBackend.php +++ b/library/Icinga/Authentication/UserGroupBackend.php @@ -4,9 +4,9 @@ namespace Icinga\Authentication; -use Zend_Config; use Icinga\Authentication\Backend\DbUserGroupBackend; use Icinga\Authentication\Backend\IniUserGroupBackend; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Exception\IcingaException; @@ -50,13 +50,13 @@ abstract class UserGroupBackend /** * Create a user group backend * - * @param string $name - * @param Zend_Config $backendConfig + * @param string $name + * @param ConfigObject $backendConfig * * @return DbUserGroupBackend|IniUserGroupBackend * @throws ConfigurationError If the backend configuration is invalid */ - public static function create($name, Zend_Config $backendConfig) + public static function create($name, ConfigObject $backendConfig) { if ($backendConfig->name !== null) { $name = $backendConfig->name; diff --git a/library/Icinga/Cli/Loader.php b/library/Icinga/Cli/Loader.php index 11ca2b70b..655ef7c18 100644 --- a/library/Icinga/Cli/Loader.php +++ b/library/Icinga/Cli/Loader.php @@ -66,7 +66,7 @@ class Loader public function __construct(App $app) { $this->app = $app; - $this->coreAppDir = ICINGAWEB_APPDIR . '/clicommands'; + $this->coreAppDir = $app->getApplicationDir('clicommands'); } /** diff --git a/library/Icinga/Data/ConfigObject.php b/library/Icinga/Data/ConfigObject.php new file mode 100644 index 000000000..23b2e1651 --- /dev/null +++ b/library/Icinga/Data/ConfigObject.php @@ -0,0 +1,304 @@ +data = array(); + + foreach ($data as $key => $value) { + if (is_array($value)) { + $this->data[$key] = new static($value); + } else { + $this->data[$key] = $value; + } + } + } + + /** + * Deep clone this config + */ + public function __clone() + { + $array = array(); + foreach ($this->data as $key => $value) { + if ($value instanceof self) { + $array[$key] = clone $value; + } else { + $array[$key] = $value; + } + } + + $this->data = $array; + } + + /** + * Return the count of available sections and properties + * + * @return int + */ + public function count() + { + return count($this->data); + } + + /** + * Reset the current position of $this->data + * + * @return mixed + */ + public function rewind() + { + return reset($this->data); + } + + /** + * Return the section's or property's value of the current iteration + * + * @return mixed + */ + public function current() + { + return current($this->data); + } + + /** + * Return whether the position of the current iteration is valid + * + * @return bool + */ + public function valid() + { + return key($this->data) !== null; + } + + /** + * Return the section's or property's name of the current iteration + * + * @return mixed + */ + public function key() + { + return key($this->data); + } + + /** + * Advance the position of the current iteration and return the new section's or property's value + * + * @return mixed + */ + public function next() + { + return next($this->data); + } + + /** + * Return whether the given section or property is set + * + * @param string $key The name of the section or property + * + * @return bool + */ + public function __isset($key) + { + return isset($this->data[$key]); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * + * @return mixed|NULL The value or NULL in case $key does not exist + */ + public function __get($key) + { + return $this->get($key); + } + + /** + * Add a new property or section + * + * @param string $key The name of the new property or section + * @param mixed $value The value to set for the new property or section + */ + public function __set($key, $value) + { + if (is_array($value)) { + $this->data[$key] = new static($value); + } else { + $this->data[$key] = $value; + } + } + + /** + * Remove the given property or section + * + * @param string $key The property or section to remove + */ + public function __unset($key) + { + unset($this->data[$key]); + } + + /** + * Return whether the given section or property is set + * + * @param string $key The name of the section or property + * + * @return bool + */ + public function offsetExists($key) + { + return isset($this->$key); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * + * @return mixed|NULL The value or NULL in case $key does not exist + */ + public function offsetGet($key) + { + return $this->get($key); + } + + /** + * Add a new property or section + * + * @param string $key The name of the new property or section + * @param mixed $value The value to set for the new property or section + */ + public function offsetSet($key, $value) + { + if ($key === null) { + throw new LogicException('Appending values without an explicit key is not supported'); + } + + $this->$key = $value; + } + + /** + * Remove the given property or section + * + * @param string $key The property or section to remove + */ + public function offsetUnset($key) + { + unset($this->$key); + } + + /** + * Return whether this config has any data + * + * @return bool + */ + public function isEmpty() + { + return empty($this->data); + } + + /** + * Return the value for the given property or the config for the given section + * + * @param string $key The name of the property or section + * @param mixed $default The value to return in case the property or section is missing + * + * @return mixed + */ + public function get($key, $default = null) + { + if (array_key_exists($key, $this->data)) { + return $this->data[$key]; + } + + return $default !== null ? $default : null; + } + + /** + * Return all section and property names + * + * @return array + */ + public function keys() + { + return array_keys($this->data); + } + + /** + * Return this config's data as associative array + * + * @return array + */ + public function toArray() + { + $array = array(); + foreach ($this->data as $key => $value) { + if ($value instanceof self) { + $array[$key] = $value->toArray(); + } else { + $array[$key] = $value; + } + } + + return $array; + } + + /** + * Merge the given data with this config + * + * @param array|Config $data An array or a config + * + * @return self + */ + public function merge($data) + { + if ($data instanceof self) { + $data = $data->toArray(); + } + + foreach ($data as $key => $value) { + if (array_key_exists($key, $this->data)) { + if (is_array($value)) { + if ($this->data[$key] instanceof self) { + $this->data[$key]->merge($value); + } else { + $this->data[$key] = new static($value); + } + } else { + $this->data[$key] = $value; + } + } else { + $this->data[$key] = is_array($value) ? new static($value) : $value; + } + } + + return $this; + } +} diff --git a/library/Icinga/Data/Db/DbConnection.php b/library/Icinga/Data/Db/DbConnection.php index 0157bcd72..38153a1cf 100644 --- a/library/Icinga/Data/Db/DbConnection.php +++ b/library/Icinga/Data/Db/DbConnection.php @@ -4,14 +4,14 @@ namespace Icinga\Data\Db; +use PDO; +use Zend_Db; use Icinga\Application\Benchmark; +use Icinga\Data\ConfigObject; use Icinga\Data\Db\DbQuery; use Icinga\Data\ResourceFactory; use Icinga\Data\Selectable; use Icinga\Exception\ConfigurationError; -use PDO; -use Zend_Config; -use Zend_Db; /** * Encapsulate database connections and query creation @@ -21,7 +21,7 @@ class DbConnection implements Selectable /** * Connection config * - * @var Zend_Config + * @var ConfigObject */ private $config; @@ -59,9 +59,9 @@ class DbConnection implements Selectable /** * Create a new connection object * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config = null) + public function __construct(ConfigObject $config = null) { $this->config = $config; if (isset($config->prefix)) { @@ -216,7 +216,10 @@ class DbConnection implements Selectable */ public function fetchRow(DbQuery $query) { - return $this->dbAdapter->fetchRow($query->getSelectQuery()); + Benchmark::measure('DB is fetching row'); + $result = $this->dbAdapter->fetchRow($query->getSelectQuery()); + Benchmark::measure('DB row done'); + return $result; } /** diff --git a/library/Icinga/Data/Db/DbQuery.php b/library/Icinga/Data/Db/DbQuery.php index 94765d98f..e89236df5 100644 --- a/library/Icinga/Data/Db/DbQuery.php +++ b/library/Icinga/Data/Db/DbQuery.php @@ -72,6 +72,12 @@ class DbQuery extends SimpleQuery parent::init(); } + public function setUseSubqueryCount($useSubqueryCount = true) + { + $this->useSubqueryCount = $useSubqueryCount; + return $this; + } + public function where($condition, $value = null) { // $this->count = $this->select = null; @@ -128,11 +134,11 @@ class DbQuery extends SimpleQuery return $select; } - public function applyFilterSql($query) + protected function applyFilterSql($select) { $where = $this->renderFilter($this->filter); if ($where !== '') { - $query->where($where); + $select->where($where); } } @@ -245,10 +251,12 @@ class DbQuery extends SimpleQuery if (is_array($expression) && $sign === '=') { // TODO: Should we support this? Doesn't work for blub* return $col . ' IN (' . $this->escapeForSql($expression) . ')'; - } elseif (strpos($expression, '*') === false) { - return $col . ' ' . $sign . ' ' . $this->escapeForSql($expression); - } else { + } elseif ($sign === '=' && strpos($expression, '*') !== false) { return $col . ' LIKE ' . $this->escapeForSql($this->escapeWildcards($expression)); + } elseif ($sign === '!=' && strpos($expression, '*') !== false) { + return $col . ' NOT LIKE ' . $this->escapeForSql($this->escapeWildcards($expression)); + } else { + return $col . ' ' . $sign . ' ' . $this->escapeForSql($expression); } } @@ -259,11 +267,13 @@ class DbQuery extends SimpleQuery */ public function getCountQuery() { - // TODO: there may be situations where we should clone the "select" + // TODO: there may be situations where we should clone the "select" $count = $this->dbSelect(); - + if ($this->group) { + $count->group($this->group); + } $this->applyFilterSql($count); - if ($this->useSubqueryCount) { + if ($this->useSubqueryCount || $this->group) { $count->columns($this->columns); $columns = array('cnt' => 'COUNT(*)'); return $this->db->select()->from($count, $columns); @@ -305,6 +315,13 @@ class DbQuery extends SimpleQuery . "\n\n"; } + public function __clone() + { + if ($this->select) { + $this->select = clone $this->select; + } + } + /** * @return string */ diff --git a/library/Icinga/Data/Filter/Filter.php b/library/Icinga/Data/Filter/Filter.php index 64607a4a0..5793a4749 100644 --- a/library/Icinga/Data/Filter/Filter.php +++ b/library/Icinga/Data/Filter/Filter.php @@ -22,7 +22,17 @@ abstract class Filter return $this; } - abstract function toQueryString(); + abstract public function isExpression(); + + abstract public function isChain(); + + abstract public function isEmpty(); + + abstract public function toQueryString(); + + abstract public function andFilter(Filter $filter); + + abstract public function orFilter(Filter $filter); public function getUrlParams() { @@ -52,6 +62,8 @@ abstract class Filter return false === strpos($this->id, '-'); } + abstract public function listFilteredColumns(); + public function applyChanges($changes) { $filter = $this; @@ -79,7 +91,7 @@ abstract class Filter } } - krsort($operators, SORT_NATURAL); + krsort($operators, version_compare(PHP_VERSION, '5.4.0') >= 0 ? SORT_NATURAL : SORT_REGULAR); foreach ($operators as $id => $operator) { $f = $filter->getById($id); if ($f->getOperatorName() !== $operator) { @@ -96,7 +108,7 @@ abstract class Filter public function getParentId() { - if ($self->isRootNode()) { + if ($this->isRootNode()) { throw new ProgrammingError('Filter root nodes have no parent'); } return substr($this->id, 0, strrpos($this->id, '-')); diff --git a/library/Icinga/Data/Filter/FilterAnd.php b/library/Icinga/Data/Filter/FilterAnd.php index 899f488ce..8fd2f2411 100644 --- a/library/Icinga/Data/Filter/FilterAnd.php +++ b/library/Icinga/Data/Filter/FilterAnd.php @@ -30,4 +30,14 @@ class FilterAnd extends FilterChain } return true; } + + public function andFilter(Filter $filter) + { + return $this->addFilter($filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($this, $filter); + } } diff --git a/library/Icinga/Data/Filter/FilterChain.php b/library/Icinga/Data/Filter/FilterChain.php index 9d32252fe..cdb3a1123 100644 --- a/library/Icinga/Data/Filter/FilterChain.php +++ b/library/Icinga/Data/Filter/FilterChain.php @@ -117,6 +117,20 @@ abstract class FilterChain extends Filter return $this->operatorSymbol; } + public function listFilteredColumns() + { + $columns = array(); + foreach ($this->filters as $filter) { + if ($filter instanceof FilterExpression) { + $columns[] = $filter->getColumn(); + } else { + $columns += $filter->listFilteredColumns(); + } + } + // array_unique? + return $columns; + } + public function toQueryString() { $parts = array(); @@ -166,6 +180,16 @@ abstract class FilterChain extends Filter } } + public function isExpression() + { + return false; + } + + public function isChain() + { + return true; + } + public function isEmpty() { return empty($this->filters); @@ -174,7 +198,8 @@ abstract class FilterChain extends Filter public function addFilter(Filter $filter) { $this->filters[] = $filter; - $filter->setId($this->getId() . '-' . (count($this->filters))); + $filter->setId($this->getId() . '-' . $this->count()); + return $this; } public function &filters() @@ -182,6 +207,11 @@ abstract class FilterChain extends Filter return $this->filters; } + public function count() + { + return count($this->filters); + } + public function __clone() { foreach ($this->filters as & $filter) { diff --git a/library/Icinga/Data/Filter/FilterExpression.php b/library/Icinga/Data/Filter/FilterExpression.php index 8378b5ae3..0782bcd89 100644 --- a/library/Icinga/Data/Filter/FilterExpression.php +++ b/library/Icinga/Data/Filter/FilterExpression.php @@ -19,6 +19,16 @@ class FilterExpression extends Filter $this->expression = $expression; } + public function isExpression() + { + return true; + } + + public function isChain() + { + return false; + } + public function isEmpty() { return false; @@ -59,6 +69,11 @@ class FilterExpression extends Filter return $this; } + public function listFilteredColumns() + { + return array($this->getColumn()); + } + public function __toString() { $expression = is_array($this->expression) ? @@ -97,4 +112,14 @@ class FilterExpression extends Filter return (bool) preg_match($pattern, $row->{$this->column}); } } + + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($this, $filter); + } } diff --git a/library/Icinga/Data/Filter/FilterGreaterThan.php b/library/Icinga/Data/Filter/FilterGreaterThan.php index bda8665b1..62ba16fca 100644 --- a/library/Icinga/Data/Filter/FilterGreaterThan.php +++ b/library/Icinga/Data/Filter/FilterGreaterThan.php @@ -6,9 +6,12 @@ namespace Icinga\Data\Filter; class FilterGreaterThan extends FilterExpression { - public function matches($row) { + if (! isset($row->{$this->column})) { + // TODO: REALLY? Exception? + return false; + } return (string) $row->{$this->column} > (string) $this->expression; } } diff --git a/library/Icinga/Data/Filter/FilterMatch.php b/library/Icinga/Data/Filter/FilterMatch.php index ef3cad801..159feb04e 100644 --- a/library/Icinga/Data/Filter/FilterMatch.php +++ b/library/Icinga/Data/Filter/FilterMatch.php @@ -8,6 +8,10 @@ class FilterMatch extends FilterExpression { public function matches($row) { + if (! isset($row->{$this->column})) { + // TODO: REALLY? Exception? + return false; + } $expression = (string) $this->expression; if (strpos($expression, '*') === false) { return (string) $row->{$this->column} === $expression; diff --git a/library/Icinga/Data/Filter/FilterNot.php b/library/Icinga/Data/Filter/FilterNot.php index a49a7ab3d..5e63691f1 100644 --- a/library/Icinga/Data/Filter/FilterNot.php +++ b/library/Icinga/Data/Filter/FilterNot.php @@ -22,6 +22,16 @@ class FilterNot extends FilterChain return true; } + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return Filter::matchAny($filter); + } + public function toQueryString() { $parts = array(); diff --git a/library/Icinga/Data/Filter/FilterOr.php b/library/Icinga/Data/Filter/FilterOr.php index 427c17fd2..8291d32dc 100644 --- a/library/Icinga/Data/Filter/FilterOr.php +++ b/library/Icinga/Data/Filter/FilterOr.php @@ -19,4 +19,22 @@ class FilterOr extends FilterChain } return false; } + + public function setOperatorName($name) + { + if ($this->count() > 1 && $name === 'NOT') { + return Filter::not(clone $this); + } + return parent::setOperatorName($name); + } + + public function andFilter(Filter $filter) + { + return Filter::matchAll($this, $filter); + } + + public function orFilter(Filter $filter) + { + return $this->addFilter($filter); + } } diff --git a/library/Icinga/Data/PivotTable.php b/library/Icinga/Data/PivotTable.php index ab6fab13d..0a1f009fe 100644 --- a/library/Icinga/Data/PivotTable.php +++ b/library/Icinga/Data/PivotTable.php @@ -69,11 +69,13 @@ class PivotTable protected function prepareQueries() { $this->xAxisQuery = clone $this->baseQuery; - $this->xAxisQuery->distinct(); + $this->xAxisQuery->group($this->xAxisColumn); $this->xAxisQuery->columns(array($this->xAxisColumn)); + $this->xAxisQuery->setUseSubqueryCount(); $this->yAxisQuery = clone $this->baseQuery; - $this->yAxisQuery->distinct(); + $this->yAxisQuery->group($this->yAxisColumn); $this->yAxisQuery->columns(array($this->yAxisColumn)); + $this->yAxisQuery->setUseSubqueryCount(); return $this; } @@ -85,24 +87,14 @@ class PivotTable */ protected function adjustSorting() { - $currentOrderColumns = $this->baseQuery->getOrder(); - $xAxisOrderColumns = array(array($this->baseQuery->getMappedField($this->xAxisColumn), SimpleQuery::SORT_ASC)); - $yAxisOrderColumns = array(array($this->baseQuery->getMappedField($this->yAxisColumn), SimpleQuery::SORT_ASC)); - - foreach ($currentOrderColumns as $orderInfo) { - if ($orderInfo[0] === $xAxisOrderColumns[0][0]) { - $xAxisOrderColumns[0] = $orderInfo; - } elseif ($orderInfo[0] === $yAxisOrderColumns[0][0]) { - $yAxisOrderColumns[0] = $orderInfo; - } else { - $xAxisOrderColumns[] = $orderInfo; - $yAxisOrderColumns[] = $orderInfo; - } + if (false === $this->xAxisQuery->hasOrder($this->xAxisColumn)) { + $this->xAxisQuery->order($this->xAxisColumn, 'ASC'); } -//TODO: simplify this whole function. No need to care about mapping -// foreach ($xAxisOrderColumns as -// $this->xAxisQuery->setOrder($xAxisOrderColumns); -// $this->yAxisQuery->setOrder($yAxisOrderColumns); + + if (false === $this->yAxisQuery->hasOrder($this->yAxisColumn)) { + $this->yAxisQuery->order($this->yAxisColumn, 'ASC'); + } + return $this; } diff --git a/library/Icinga/Data/ResourceFactory.php b/library/Icinga/Data/ResourceFactory.php index 1c443f9d0..754360740 100644 --- a/library/Icinga/Data/ResourceFactory.php +++ b/library/Icinga/Data/ResourceFactory.php @@ -4,7 +4,6 @@ namespace Icinga\Data; -use Zend_Config; use Icinga\Application\Config; use Icinga\Exception\ProgrammingError; use Icinga\Util\ConfigAwareFactory; @@ -22,14 +21,14 @@ class ResourceFactory implements ConfigAwareFactory /** * Resource configuration * - * @var Zend_Config + * @var Config */ private static $resources; /** * Set resource configurations * - * @param Zend_Config $config + * @param Config $config */ public static function setConfig($config) { @@ -41,14 +40,15 @@ class ResourceFactory implements ConfigAwareFactory * * @param $resourceName String The resource's name * - * @return Zend_Config The configuration of the resource + * @return ConfigObject The configuration of the resource * * @throws ConfigurationError */ public static function getResourceConfig($resourceName) { self::assertResourcesExist(); - if (($resourceConfig = self::$resources->get($resourceName)) === null) { + $resourceConfig = self::$resources->getSection($resourceName); + if ($resourceConfig->isEmpty()) { throw new ConfigurationError( 'Cannot load resource config "%s". Resource does not exist', $resourceName @@ -60,24 +60,12 @@ class ResourceFactory implements ConfigAwareFactory /** * Return the configuration of all existing resources, or get all resources of a given type. * - * @param String|null $type Fetch only resources that have the given type. - * - * @return Zend_Config The configuration containing all resources + * @return Config The configuration containing all resources */ - public static function getResourceConfigs($type = null) + public static function getResourceConfigs() { self::assertResourcesExist(); - if (!isset($type)) { - return self::$resources; - } else { - $resources = array(); - foreach (self::$resources as $name => $resource) { - if (strtolower($resource->type) === $type) { - $resources[$name] = $resource; - } - } - return new Zend_Config($resources); - } + return self::$resources; } /** @@ -100,13 +88,13 @@ class ResourceFactory implements ConfigAwareFactory * NOTE: The factory does not test if the given configuration is valid and the resource is accessible, this * depends entirely on the implementation of the returned resource. * - * @param Zend_Config $config The configuration for the created resource. + * @param ConfigObject $config The configuration for the created resource. * * @return DbConnection|LdapConnection|LivestatusConnection An object that can be used to access * the given resource. The returned class depends on the configuration property 'type'. * @throws ConfigurationError When an unsupported type is given */ - public static function createResource(Zend_Config $config) + public static function createResource(ConfigObject $config) { switch (strtolower($config->type)) { case 'db': diff --git a/library/Icinga/Data/SimpleQuery.php b/library/Icinga/Data/SimpleQuery.php index 6a0b71c35..41d050ea2 100644 --- a/library/Icinga/Data/SimpleQuery.php +++ b/library/Icinga/Data/SimpleQuery.php @@ -210,7 +210,7 @@ class SimpleQuery implements QueryInterface, Queryable $dir = $this->order[$col_num][1]; // TODO: throw Exception if column is missing //$res = strnatcmp(strtolower($a->$col), strtolower($b->$col)); - $res = strcmp(strtolower($a->$col), strtolower($b->$col)); + $res = @strcmp(strtolower($a->$col), strtolower($b->$col)); if ($res === 0) { // return $this->compare($a, $b, $col_num++); diff --git a/library/Icinga/Exception/NotFoundError.php b/library/Icinga/Exception/NotFoundError.php new file mode 100644 index 000000000..c90b0322b --- /dev/null +++ b/library/Icinga/Exception/NotFoundError.php @@ -0,0 +1,9 @@ + $separator) { + $key[$i] = $this->sanitize($separator); + } return implode($this->nestSeparator, $key); } @@ -599,7 +602,7 @@ class IniEditor } /** - * Prepare a value for INe + * Prepare a value for INI * * @param $value The value of the string * @@ -613,10 +616,12 @@ class IniEditor return $value; } elseif (is_bool($value)) { return ($value ? 'true' : 'false'); - } elseif (strpos($value, '"') === false) { - return '"' . $value . '"'; - } else { - return '"' . str_replace('"', '\"', $value) . '"'; } + return '"' . str_replace('"', '\"', $this->sanitize($value)) . '"'; + } + + private function sanitize($value) + { + return str_replace('\n', '', $value); } } diff --git a/library/Icinga/File/Ini/IniWriter.php b/library/Icinga/File/Ini/IniWriter.php index dfe588bbe..c44ffbc79 100644 --- a/library/Icinga/File/Ini/IniWriter.php +++ b/library/Icinga/File/Ini/IniWriter.php @@ -6,7 +6,9 @@ namespace Icinga\File\Ini; use Zend_Config; use Zend_Config_Ini; +use Zend_Config_Exception; use Zend_Config_Writer_FileAbstract; +use Icinga\Application\Config; /** * A INI file adapter that respects the file structure and the comments of already existing ini files @@ -20,11 +22,18 @@ class IniWriter extends Zend_Config_Writer_FileAbstract */ protected $options; + /** + * The mode to set on new files + * + * @var int + */ + public static $fileMode = 0664; + /** * Create a new INI writer * - * @param array $options Supports all options of Zend_Config_Writer and additional - * options for the internal IniEditor: + * @param array $options Supports all options of Zend_Config_Writer and additional options: + * * filemode: The mode to set on new files * * valueIndentation: The indentation level of the values * * commentIndentation: The indentation level of the comments * * sectionSeparators: The amount of newlines between sections @@ -33,49 +42,16 @@ class IniWriter extends Zend_Config_Writer_FileAbstract */ public function __construct(array $options = null) { + if (isset($options['config']) && $options['config'] instanceof Config) { + // As this class inherits from Zend_Config_Writer_FileAbstract we must + // not pass the config directly as it needs to be of type Zend_Config + $options['config'] = new Zend_Config($options['config']->toArray(), true); + } + $this->options = $options; parent::__construct($options); } - /** - * Find all keys containing dots and convert it to a nested configuration - * - * Ensure that configurations with the same ini representation the have - * similarly nested Zend_Config objects. The configuration may be altered - * during that process. - * - * @param Zend_Config $config The configuration to normalize - * @return Zend_Config The normalized config - */ - private function normalizeKeys(Zend_Config $config) - { - foreach ($config as $key => $value) { - if (preg_match('/\./', $key) > 0) { - // remove old key - unset ($config->$key); - - // insert new key - $nests = explode('.', $key); - $current = $config; - $i = 0; - for (; $i < count($nests) - 1; $i++) { - if (! isset($current->{$nests[$i]})) { - // configuration key doesn't exist, create a new nesting level - $current->{$nests[$i]} = new Zend_Config (array(), true); - } - // move to next nesting level - $current = $current->{$nests[$i]}; - } - // reached last nesting level, insert value - $current->{$nests[$i]} = $value; - } - if ($value instanceof Zend_Config) { - $config->$key = $this->normalizeKeys ($value); - } - } - return $config; - } - /** * Render the Zend_Config into a config file string * @@ -91,16 +67,6 @@ class IniWriter extends Zend_Config_Writer_FileAbstract $content = ''; } - // create an internal copy of the given configuration, since the user of this class - // won't expect that a configuration will ever be altered during - // the rendering process. - $extends = $this->_config->getExtends(); - $this->_config = new Zend_Config ($this->_config->toArray(), true); - foreach ($extends as $extending => $extended) { - $this->_config->setExtend($extending, $extended); - } - $this->_config = $this->normalizeKeys($this->_config); - $newconfig = $this->_config; $editor = new IniEditor($content, $this->options); $this->diffConfigs($oldconfig, $newconfig, $editor); @@ -108,6 +74,30 @@ class IniWriter extends Zend_Config_Writer_FileAbstract return $editor->getText(); } + /** + * Write configuration to file and set file mode in case it does not exist yet + * + * @param string $filename + * @param Zend_Config $config + * @param bool $exclusiveLock + */ + public function write($filename = null, Zend_Config $config = null, $exclusiveLock = null) + { + $filePath = $filename !== null ? $filename : $this->_filename; + $setMode = false === file_exists($filePath); + + parent::write($filename, $config, $exclusiveLock); + + if ($setMode) { + $mode = isset($this->options['filemode']) ? $this->options['filemode'] : static::$fileMode; + $old = umask(0); // Make sure that the mode we're going to set doesn't get mangled + if (is_int($mode) && false === @chmod($filePath, $mode)) { + throw new Zend_Config_Exception(sprintf('Failed to set file mode "%o" on file "%s"', $mode, $filePath)); + } + umask($old); + } + } + /** * Create a property diff and apply the changes to the editor * diff --git a/library/Icinga/File/Pdf.php b/library/Icinga/File/Pdf.php index 2e8a97887..44d1a107a 100644 --- a/library/Icinga/File/Pdf.php +++ b/library/Icinga/File/Pdf.php @@ -13,9 +13,8 @@ use Icinga\Web\StyleSheet; use Icinga\Web\Url; use Icinga\Exception\ProgrammingError; -require_once 'IcingaVendor/dompdf/dompdf_config.inc.php'; - -spl_autoload_register('DOMPDF_autoload'); +require_once 'dompdf/dompdf_config.inc.php'; +require_once 'dompdf/include/autoload.inc.php'; class Pdf extends DOMPDF { @@ -49,7 +48,7 @@ class Pdf extends DOMPDF $layout->content = $controller->getResponse(); $html = $layout->render(); $imgDir = Url::fromPath('img'); - $html = preg_replace('~src="' . $imgDir . '/~', 'src="' . Icinga::app()->getBootstrapDirecory() . '/img/', $html); + $html = preg_replace('~src="' . $imgDir . '/~', 'src="' . Icinga::app()->getBootstrapDirectory() . '/img/', $html); $html = preg_replace('~src="/svg/chart.php(.*)"~', 'class="icon" src="http://master1.com/png/chart.php$1"', $html); $this->load_html($html); $this->render(); diff --git a/library/Icinga/Protocol/Dns.php b/library/Icinga/Protocol/Dns.php index 92e8b2a4d..950c22f44 100644 --- a/library/Icinga/Protocol/Dns.php +++ b/library/Icinga/Protocol/Dns.php @@ -9,7 +9,6 @@ namespace Icinga\Protocol; */ class Dns { - /** * Discover all service records on a given domain * @@ -17,21 +16,12 @@ class Dns * @param string $service The type of the service, like for example 'ldaps' or 'ldap' * @param string $protocol The transport protocol used by the service, defaults to 'tcp' * - * @return array|null An array of all service domains + * @return array An array of all found service records */ public static function getSrvRecords($domain, $service, $protocol = 'tcp') { $records = dns_get_record('_' . $service . '._' . $protocol . '.' . $domain, DNS_SRV); - if ($records === false) { - return null; - } - $targets = array(); - foreach ($records as $record) { - if (array_key_exists('target', $record)) { - $targets[] = $record['target']; - } - } - return $targets; + return $records === false ? array() : $records; } /** diff --git a/library/Icinga/Protocol/File/FileReader.php b/library/Icinga/Protocol/File/FileReader.php index 49da989ef..363f8e173 100644 --- a/library/Icinga/Protocol/File/FileReader.php +++ b/library/Icinga/Protocol/File/FileReader.php @@ -4,9 +4,9 @@ namespace Icinga\Protocol\File; -use Icinga\Data\Selectable; use Countable; -use Zend_Config; +use Icinga\Data\Selectable; +use Icinga\Data\ConfigObject; /** * Read file line by line @@ -30,11 +30,11 @@ class FileReader implements Selectable, Countable /** * Create a new reader * - * @param Zend_Config $config + * @param ConfigObject $config * * @throws FileReaderException If a required $config directive (filename or fields) is missing */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { foreach (array('filename', 'fields') as $key) { if (isset($config->{$key})) { diff --git a/library/Icinga/Protocol/Ldap/Connection.php b/library/Icinga/Protocol/Ldap/Connection.php index 8f5c14c4f..2f8737c8b 100644 --- a/library/Icinga/Protocol/Ldap/Connection.php +++ b/library/Icinga/Protocol/Ldap/Connection.php @@ -8,7 +8,7 @@ use Icinga\Protocol\Ldap\Exception as LdapException; use Icinga\Application\Platform; use Icinga\Application\Config; use Icinga\Application\Logger; -use Zend_Config; +use Icinga\Data\ConfigObject; /** * Backend class managing all the LDAP stuff for you. @@ -95,15 +95,16 @@ class Connection protected $capabilities; protected $namingContexts; + protected $discoverySuccess = false; /** * Constructor * * TODO: Allow to pass port and SSL options * - * @param Zend_Config $config + * @param ConfigObject $config */ - public function __construct(Zend_Config $config) + public function __construct(ConfigObject $config) { $this->hostname = $config->hostname; $this->bind_dn = $config->bind_dn; @@ -112,6 +113,16 @@ class Connection $this->port = $config->get('port', $this->port); } + public function getHostname() + { + return $this->hostname; + } + + public function getPort() + { + return $this->port; + } + public function getDN() { return $this->root_dn; @@ -336,9 +347,9 @@ class Connection public function testCredentials($username, $password) { - $ds = $this->prepareNewConnection(); + $this->connect(); - $r = @ldap_bind($ds, $username, $password); + $r = @ldap_bind($this->ds, $username, $password); if ($r) { Logger::debug( 'Successfully tested LDAP credentials (%s / %s)', @@ -351,7 +362,7 @@ class Connection 'Testing LDAP credentials (%s / %s) failed: %s', $username, '***', - ldap_error($ds) + ldap_error($this->ds) ); return false; } @@ -364,7 +375,7 @@ class Connection */ protected function getConfigDir($sub = null) { - $dir = Config::getInstance()->getConfigDir() . '/ldap'; + $dir = Config::$configDir . '/ldap'; if ($sub !== null) { $dir .= '/' . $sub; } @@ -388,7 +399,20 @@ class Connection } $ds = ldap_connect($this->hostname, $this->port); - list($cap, $namingContexts) = $this->discoverCapabilities($ds); + try { + $capabilities = $this->discoverCapabilities($ds); + list($cap, $namingContexts) = $capabilities; + $this->discoverySuccess = true; + } catch (LdapException $e) { + + // discovery failed, guess defaults + $cap = (object) array( + 'supports_ldapv3' => true, + 'supports_starttls' => false, + 'msCapabilities' => array() + ); + $namingContexts = null; + } $this->capabilities = $cap; $this->namingContexts = $namingContexts; @@ -590,6 +614,17 @@ class Connection return $this->namingContexts; } + /** + * Whether service discovery was successful + * + * @return boolean True when ldap settings were discovered, false when + * settings were guessed + */ + public function discoverySuccessful() + { + return $this->discoverySuccess; + } + /** * Discover the capabilities of the given ldap-server * @@ -626,7 +661,8 @@ class Connection if (! $result) { throw new LdapException( sprintf( - 'Capability query failed (%s:%d): %s', + 'Capability query failed (%s:%d): %s. Check if hostname and port of the ldap resource are correct ' + . ' and if anonymous access is permitted.', $this->hostname, $this->port, ldap_error($ds) @@ -634,6 +670,16 @@ class Connection ); } $entry = ldap_first_entry($ds, $result); + if ($entry === false) { + throw new LdapException( + sprintf( + 'Capabilities not available (%s:%d): %s. Discovery of root DSE probably not permitted.', + $this->hostname, + $this->port, + ldap_error($ds) + ) + ); + } $cap = (object) array( 'supports_ldapv3' => false, @@ -641,10 +687,6 @@ class Connection 'msCapabilities' => array() ); - if ($entry === false) { - // TODO: Is it OK to have no capabilities? - return false; - } $ldapAttributes = ldap_get_attributes($ds, $entry); $result = $this->cleanupAttributes($ldapAttributes); $cap->supports_ldapv3 = $this->hasCapabilityLdapV3($result); diff --git a/library/Icinga/Protocol/Ldap/Discovery.php b/library/Icinga/Protocol/Ldap/Discovery.php new file mode 100644 index 000000000..b876a5d6f --- /dev/null +++ b/library/Icinga/Protocol/Ldap/Discovery.php @@ -0,0 +1,158 @@ +connection = $conn; + } + + /** + * Execute the discovery on the underlying connection + */ + private function execDiscovery() + { + if (! $this->discovered) { + $this->connection->connect(); + $this->discovered = true; + } + } + + /** + * Suggests a resource configuration of hostname, port and root_dn + * based on the discovery + * + * @return array The suggested configuration as an array + */ + public function suggestResourceSettings() + { + if (! $this->discovered) { + $this->execDiscovery(); + } + + return array( + 'hostname' => $this->connection->getHostname(), + 'port' => $this->connection->getPort(), + 'root_dn' => $this->connection->getDefaultNamingContext() + ); + } + + /** + * Suggests a backend configuration of base_dn, user_class and user_name_attribute + * based on the discovery + * + * @return array The suggested configuration as an array + */ + public function suggestBackendSettings() + { + $this->execDiscovery(); + if ($this->isAd()) { + return array( + 'base_dn' => $this->connection->getDefaultNamingContext(), + 'user_class' => 'user', + 'user_name_attribute' => 'sAMAccountName' + ); + } else { + return array( + 'base_dn' => $this->connection->getDefaultNamingContext(), + 'user_class' => 'getDefaultNamingContext', + 'user_name_attribute' => 'uid' + ); + } + } + + /** + * Whether the suggested ldap server is an ActiveDirectory + * + * @return boolean + */ + public function isAd() + { + $this->execDiscovery(); + $caps = $this->connection->getCapabilities(); + return isset($caps->msCapabilities->ActiveDirectoryOid) && $caps->msCapabilities->ActiveDirectoryOid; + } + + /** + * Whether the discovery was successful + * + * @return bool False when the suggestions are guessed + */ + public function isSuccess() + { + $this->execDiscovery(); + return $this->connection->discoverySuccessful(); + } + + /** + * Discover LDAP servers on the given domain + * + * @param string $domain The object containing the form elements + * + * @return Discovery True when the discovery was successful, false when the configuration was guessed + */ + public static function discoverDomain($domain) + { + if (! isset($domain)) { + return false; + } + + // Attempt 1: Connect to the domain directly + $disc = Discovery::discover($domain, 389); + if ($disc->isSuccess()) { + return $disc; + } + + // Attempt 2: Discover all available ldap dns records and connect to the first one + $records = array_merge(Dns::getSrvRecords($domain, 'ldap'), Dns::getSrvRecords($domain, 'ldaps')); + if (isset($records[0])) { + $record = $records[0]; + return Discovery::discover( + isset($record['target']) ? $record['target'] : $domain, + isset($record['port']) ? $record['port'] : $domain + ); + } + + // Return the first failed discovery, which will suggest properties based on guesses + return $disc; + } + + /** + * Convenience method to instantiate a new Discovery + * + * @param $host The host on which to execute the discovery + * @param $port The port on which to execute the discovery + * + * @return Discover The resulting Discovery + */ + public static function discover($host, $port) + { + $conn = new Connection(new ConfigObject(array( + 'hostname' => $host, + 'port' => $port + ))); + return new Discovery($conn); + } +} \ No newline at end of file diff --git a/library/Icinga/Protocol/Livestatus/Connection.php b/library/Icinga/Protocol/Livestatus/Connection.php index c014ba70f..b2340eeec 100644 --- a/library/Icinga/Protocol/Livestatus/Connection.php +++ b/library/Icinga/Protocol/Livestatus/Connection.php @@ -5,8 +5,11 @@ namespace Icinga\Protocol\Livestatus; use Icinga\Application\Benchmark; -use Exception; +use Icinga\Exception\ConfigurationError; +use Icinga\Exception\SystemPermissionException; use Icinga\Exception\IcingaException; +use Exception; +use SplFixedArray; /** * Backend class managing handling MKI Livestatus connections @@ -31,6 +34,15 @@ class Connection const TYPE_UNIX = 1; const TYPE_TCP = 2; + const FIELD_SEPARATOR = '`'; + + protected $bytesRead = 0; + protected $responseSize; + protected $status; + protected $headers; + + // List of available Livestatus tables. Kept here as we otherwise get no + // useful error message protected $available_tables = array( 'hosts', // hosts 'services', // services, joined with all data from hosts @@ -64,6 +76,13 @@ class Connection protected $socket_type; protected $connection; + /** + * Whether the given table name is valid + * + * @param string $name table name + * + * @return bool + */ public function hasTable($name) { return in_array($name, $this->available_tables); @@ -74,7 +93,7 @@ class Connection $this->assertPhpExtensionLoaded('sockets'); if ($socket[0] === '/') { if (! is_writable($socket)) { - throw new IcingaException( + throw new SystemPermissionException( 'Cannot write to livestatus socket "%s"', $socket ); @@ -83,52 +102,106 @@ class Connection $this->socket_path = $socket; } else { if (! preg_match('~^tcp://([^:]+):(\d+)~', $socket, $m)) { - throw new IcingaException( + throw new ConfigurationError( 'Invalid TCP socket syntax: "%s"', $socket ); } - // TODO: Better syntax checks + // TODO: Better config syntax checks $this->socket_host = $m[1]; $this->socket_port = (int) $m[2]; $this->socket_type = self::TYPE_TCP; } } - public function select() - { - $select = new Query($this); - return $select; - } - + /** + * Count unlimited rows matching the query filter + * + * TODO: Currently hardcoded value, as the old variant was stupid + * Create a working variant doing this->execute(query->renderCount())... + * + * @param Query $query the query object + * + * @return int + */ public function count(Query $query) { + return 100; $count = clone($query); - $count->count(); + // WTF? $count->count(); Benchmark::measure('Sending Livestatus Count Query'); - $data = $this->doFetch((string) $count); + $this->execute($query); + $data = $this->fetchRowFromSocket(); Benchmark::measure('Got Livestatus count result'); return $data[0][0]; } + /** + * Fetch a single row + * + * TODO: Currently based on fetchAll, that's bullshit + * + * @param Query $query the query object + * + * @return object the first result row + */ + public function fetchRow(Query $query) + { + $all = $this->fetchAll($query); + return array_shift($all); + } + + /** + * Fetch key/value pairs + * + * TODO: Currently slow, needs improvement + * + * @param Query $query the query object + * + * @return array + */ + public function fetchPairs(Query $query) + { + $res = array(); + $all = $this->fetchAll($query); + foreach ($all as $row) { + // slow + $keys = array_keys((array) $row); + $res[$row->{$keys[0]}] = $row->{$keys[1]}; + } + return $res; + } + + /** + * Fetch all result rows + * + * @param Query $query the query object + * + * @return array + */ public function fetchAll(Query $query) { Benchmark::measure('Sending Livestatus Query'); - $data = $this->doFetch((string) $query); + $this->execute($query); Benchmark::measure('Got Livestatus Data'); + if ($query->hasColumns()) { $headers = $query->getColumnAliases(); } else { + // TODO: left this here, find out how to handle it better + die('F*** no data'); $headers = array_shift($data); } $result = array(); - foreach ($data as $row) { - $result_row = & $result[]; - $result_row = (object) array(); - foreach ($row as $key => $val) { - $result_row->{$headers[$key]} = $val; - } + $filter = $query->filterIsSupported() ? null : $query->getFilter(); + + while ($row = $this->fetchRowFromSocket()) { + $r = new ResponseRow($row, $query); + $res = $query->resultRow($row); + if ($filter !== null && ! $filter->matches($res)) continue; + $result[] = $res; } + if ($query->hasOrder()) { usort($result, array($query, 'compare')); } @@ -144,70 +217,137 @@ class Connection return $result; } - protected function doFetch($raw_query) + protected function hasBeenExecuted() { - $conn = $this->getConnection(); - $this->writeToSocket($raw_query); - $header = $this->readFromSocket(16); - $status = (int) substr($header, 0, 3); - $length = (int) trim(substr($header, 4)); - $body = $this->readFromSocket($length); - if ($status !== 200) { - throw new IcingaException( - 'Problem while reading %d bytes from livestatus: %s', - $length, - $body - ); - } - $result = json_decode($body); - if ($result === null) { - throw new IcingaException('Got invalid response body from livestatus'); - } - - return $result; + return $this->status !== null; } - protected function readFromSocket($length) + protected function execute($query) { - $offset = 0; - $buffer = ''; + // Reset state + $this->status = null; + $this->responseSize = null; + $this->bytesRead = 0; - while ($offset < $length) { - $data = socket_read($this->connection, $length - $offset); - if ($data === false) { - throw new IcingaException( - 'Failed to read from livestatus socket: %s', - socket_strerror(socket_last_error($this->connection)) - ); - } - $size = strlen($data); - $offset += $size; - $buffer .= $data; + $raw = $query->toString(); - if ($size === 0) { - break; - } - } - if ($offset !== $length) { - throw new IcingaException( - 'Got only %d instead of %d bytes from livestatus socket', - $offset, - $length + Benchmark::measure($raw); + + // "debug" + // echo $raw . "\n
"; + $this->writeToSocket($raw); + $header = $this->readLineFromSocket(); + + if (! preg_match('~^(\d{3})\s\s*(\d+)$~', $header, $m)) { + $this->disconnect(); + throw new Exception( + sprintf('Got invalid header. First 16 Bytes: %s', $header) ); } - - return $buffer; + $this->status = (int) $m[1]; + $this->bytesRead = 0; + $this->responseSize = (int) $m[2]; + if ($this->status !== 200) { + // "debug" + //die(var_export($raw, 1)); + throw new Exception( + sprintf( + 'Error %d while querying livestatus: %s %s', + $this->status, + $raw, + $this->readLineFromSocket() + ) + ); + } + $this->discoverColumnHeaders($query); } + protected function discoverColumnHeaders($query) + { + if ($query->hasColumns()) { + $this->headers = $query->getColumnAliases(); + } else { + $this->headers = $this->splitLine($this->readLineFromSocket()); + } + } + + protected function splitLine(& $line) + { + if ($this->headers === null) { + $res = array(); + } else { + $res = new SplFixedArray(count($this->headers)); + $size = count($res); + } + $start = 0; + $col = 0; + while (false !== ($pos = strpos($line, self::FIELD_SEPARATOR, $start))) { +// TODO: safety measure for not killing the SPL. To be removed once code is clean +if ($col > $size -1 ) return $res; // ??? + $res[$col] = substr($line, $start, $pos - $start); + $start = $pos + 1; + $col++; + } +// TODO: safety measure for not killing the SPL. To be removed once code is clean +if ($col > $size - 1) return $res; + $res[$col] = rtrim(substr($line, $start), "\r\n"); + return $res; + } + + public function fetchRowFromSocket() + { + $line = $this->readLineFromSocket(); + if (! $line) { + return false; + } + return $this->splitLine($line); + } + + protected function readLineFromSocket() + { + if ($this->bytesRead === $this->responseSize) { + return false; + } + $maxRowLength = 100 * 1024; + $row = socket_read($this->getConnection(), $maxRowLength, PHP_NORMAL_READ); + $this->bytesRead += strlen($row); + + if ($row === false) { + $this->socketError('Failed to read next row from livestatus socket'); + } + return $row; + } + + /** + * Write given string to livestatus socket + * + * @param string $data Data string to write to the socket + * + * @return boolean + */ protected function writeToSocket($data) { - $res = socket_write($this->connection, $data); + $res = @socket_write($this->getConnection(), $data); if ($res === false) { - throw new IcingaException('Writing to livestatus socket failed'); + $this->socketError('Writing to livestatus socket failed'); } return true; } + /** + * Raise an exception showing given message string and last socket error + * + * TODO: Find a better exception type for such errors + * + * @throws IcingaException + */ + protected function socketError($msg) + { + throw new IcingaException( + $msg . ': ' . socket_strerror(socket_last_error($this->connection)) + ); + } + protected function assertPhpExtensionLoaded($name) { if (! extension_loaded($name)) { @@ -221,22 +361,24 @@ class Connection protected function getConnection() { if ($this->connection === null) { + Benchmark::measure('Establishing livestatus connection...'); + if ($this->socket_type === self::TYPE_TCP) { $this->establishTcpConnection(); + Benchmark::measure('...got TCP socket'); } else { $this->establishSocketConnection(); + Benchmark::measure('...got local socket'); } } return $this->connection; } + /** + * Establish a TCP socket connection + */ protected function establishTcpConnection() { - // TODO: find a bedder place for this - if (! defined('TCP_NODELAY')) { - define('TCP_NODELAY', 1); - } - $this->connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (! @socket_connect($this->connection, $this->socket_host, $this->socket_port)) { throw new IcingaException( @@ -249,6 +391,9 @@ class Connection socket_set_option($this->connection, SOL_TCP, TCP_NODELAY, 1); } + /** + * Establish a UNIX socket connection + */ protected function establishSocketConnection() { $this->connection = socket_create(AF_UNIX, SOCK_STREAM, 0); @@ -269,13 +414,26 @@ class Connection return $this; } + /** + * Disconnect in case we are connected to a Livestatus socket + * + * @return self + */ public function disconnect() { - if ($this->connection) { + if (is_resource($this->connection) + && get_resource_type($this->connection) === 'Socket') + { + Benchmark::measure('Disconnecting livestatus...'); socket_close($this->connection); + Benchmark::measure('...socket closed'); } + return $this; } + /** + * Try to cleanly close the socket on shutdown + */ public function __destruct() { $this->disconnect(); diff --git a/library/Icinga/Protocol/Livestatus/Query.php b/library/Icinga/Protocol/Livestatus/Query.php index 7c1e73c8a..a421c7e71 100644 --- a/library/Icinga/Protocol/Livestatus/Query.php +++ b/library/Icinga/Protocol/Livestatus/Query.php @@ -4,135 +4,49 @@ namespace Icinga\Protocol\Livestatus; -use Icinga\Protocol\AbstractQuery; +use Icinga\Data\SimpleQuery; use Icinga\Exception\IcingaException; +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; +use Icinga\Data\Filter\FilterOr; +use Icinga\Data\Filter\FilterAnd; +use Icinga\Data\Filter\FilterNot; +use Exception; -class Query extends AbstractQuery +class Query extends SimpleQuery { + protected $customvars = array(); + + /** + * Columns in this array are always "combined" ones creating their value + * based on a filter expression. The result is always either "1" or "0" + */ + protected $filter_flags = array(); + + /** + * Columns that return arrays. Will be decoded. + */ + protected $arrayColumns = array( + 'members' => true, + ); + + /** + * Columns to be fetched for sorting / filtering, will not be returned + */ + protected $extraFiltercolumns = array(); + + /** + * All available columns. To be overridden by specific query implementations + */ + protected $available_columns = array(); - protected $connection; - protected $table; - protected $filters = array(); - protected $limit_count; - protected $limit_offset; - protected $columns; - protected $order_columns = array(); protected $count = false; - public function __construct(Connection $connection) - { - $this->connection = $connection; - } - - public function getAdapter() - { - return $this->connection; - } - - public function compare(& $a, & $b, $col_num = 0) - { - if (! array_key_exists($col_num, $this->order_columns)) { - return 0; - } - $col = $this->order_columns[$col_num][0]; - $dir = $this->order_columns[$col_num][1]; - - //$res = strnatcmp(strtolower($a->$col), strtolower($b->$col)); - $res = strcmp(strtolower($a->$col), strtolower($b->$col)); - if ($res === 0) { - if (array_key_exists(++$col_num, $this->order_columns)) { - return $this->compare($a, $b, $col_num); - } else { - return 0; - } - } - if ($dir === self::SORT_ASC) { - return $res; - } else { - return $res * -1; - } - } - - public function hasOrder() - { - return ! empty($this->order_columns); - } - - public function where($key, $val = null) - { - $this->filters[$key] = $val; - return $this; - } - - public function order($col) - { - if (($pos = strpos($col, ' ')) === false) { - $col = $col; - $dir = self::SORT_ASC; - } else { - $dir = strtoupper(substr($col, $pos + 1)); - if ($dir === 'DESC') { - $dir = self::SORT_DESC; - } else { - $dir = self::SORT_ASC; - } - $col = substr($col, 0, $pos); - } - $this->order_columns[] = array($col, $dir); - return $this; - } - - // Nur wenn keine stats, sonst im RAM!! - // Offset gibt es nicht, muss simuliert werden - public function limit($count = null, $offset = null) - { - if (! preg_match('~^\d+~', $count . $offset)) { - throw new IcingaException( - 'Got invalid limit: %s, %s', - $count, - $offset - ); - } - $this->limit_count = (int) $count; - $this->limit_offset = (int) $offset; - return $this; - } - - public function hasLimit() - { - return $this->limit_count !== null; - } - - public function hasOffset() - { - return $this->limit_offset > 0; - } - - public function getLimit() - { - return $this->limit_count; - } - - public function getOffset() - { - return $this->limit_offset; - } - - public function from($table, $columns = null) - { - if (! $this->connection->hasTable($table)) { - throw new IcingaException( - 'This livestatus connection does not provide "%s"', - $table - ); - } - $this->table = $table; - if (is_array($columns)) { - // TODO: check for valid names? - $this->columns = $columns; - } - return $this; - } + /** + * Headers for columns sent to Livestatus socket + */ + protected $preparedHeaders = array(); public function hasColumns() { @@ -144,10 +58,133 @@ class Query extends AbstractQuery return $this->columns; } + public function withHeaders(& $row) + { + return array_combine($this->preparedHeaders, $row->toArray()); + } + + /** + * Whether the named columns value is generated by a filter expression + */ + public function isFilterFlag($column) + { + return array_key_exists($column, $this->filter_flags); + } + + // completes a given row + public function resultRow(& $row) + { + // $row -> raw SplArray + // $res -> object + // $cv -> + // $result -> object to be returned + $result = (object) array(); + $res = $this->withHeaders($row); + $cv = array(); + if (array_key_exists('custom_variables', $res)) { + foreach ($this->parseArray($res['custom_variables']) as $cvp) { + $cv[$cvp[0]] = $cvp[1]; + } + } + + $combined = array(); + + foreach ($this->columns as $alias => $col) { + if (is_int($alias)) { + $alias = $col; + } + if ($col[0] === '_') { + $result->$alias = array_key_exists($alias, $cv) ? $cv[$alias] : null; + } else { + $func = 'mungeResult_' . $col; + if (method_exists($this, $func)) { + $this->$func($res[$this->available_columns[$col]], $result); + } elseif (is_array($this->available_columns[$col])) { + $combined[$alias] = $col; + $result->$alias = null; + } else { + if (strpos($this->available_columns[$col], ' ') === false) { + $result->$alias = $res[$this->available_columns[$col]]; + } else { + $result->$alias = $res[$alias]; + } + } + } + } + // TODO: Quite some redundancy here :( + if (! $this->filterIsSupported()) { + foreach ($this->filter->listFilteredColumns() as $col) { + if ($this->isFilterFlag($col)) { + $result->$col = (string) (int) $this->filterStringToFilter( + $this->filter_flags[$col] + )->matches((object) $res); + } else { + $func = 'combineResult_' . $col; + if (method_exists($this, $func)) { + $result->$col = $this->$func($result, $res); + } + } + } + } + + foreach ($combined as $alias => $col) { + if ($this->isFilterFlag($col)) { + $result->$alias = (string) (int) $this->filterStringToFilter( + $this->filter_flags[$col] + )->matches((object) $res); + continue; + } + $func = 'combineResult_' . $col; + if (method_exists($this, $func)) { + $result->$alias = $this->$func($result, $res); + } else { + $result->$alias = implode(' - ', $this->available_columns[$col]); + } + } + + + return $result; + } + + /** + * Parse the given encoded array + * + * @param string $str the encoded array string + * + * @return array + */ + public function parseArray($str) + { + if (empty($str)) { + return array(); + } + + $result = array(); + $entries = preg_split('/,/', $str); + foreach ($entries as $e) { + $result[] = preg_split('/;/', $e); + } + + return $result; + } + public function getColumnAliases() { + $this->columnsToString(); + return $this->preparedHeaders; + + // TODO: Remove once no longer needed: $aliases = array(); + $hasCustom = false; foreach ($this->getColumns() as $key => $val) { + if ($val[0] === '_') { + $this->customvars[$val] = null; + if (! $hasCustom) { + $aliases[] = 'custom_variables'; + $hasCustom = true; + } + continue; + } if (is_int($key)) { $aliases[] = $val; } else { @@ -156,57 +193,277 @@ class Query extends AbstractQuery } return $aliases; } - +/* public function count() { $this->count = true; return $this; } +*/ + /** + * Automagic string casting + * + * @return string + */ public function __toString() + { + try { + return $this->toString(); + } catch (Exception $e) { + trigger_error( + sprintf( + '%s in %s on line %d', + $e->getMessage(), + $e->getFile(), + $e->getLine() + ), + E_USER_ERROR + ); + } + } + + /** + * Render query string + * + * @return string + */ + public function toString() { if ($this->table === null) { throw new IcingaException('Table is required'); } + + // Headers we always send $default_headers = array( - 'OutputFormat: json', + // Our preferred output format is CSV as it allows us to fetch and + // process the result row by row + 'OutputFormat: csv', 'ResponseHeader: fixed16', + // Tried to find a save list of separators, this might be subject to + // change and eventually be transforment into constants + 'Separators: ' . implode(' ', array(ord("\n"), ord('`'), ord(','), ord(';'))), + // We always use the keepalive feature, connection teardown happens + // in the connection destructor 'KeepAlive: on' ); $parts = array( sprintf('GET %s', $this->table) ); - if ($this->count === false && $this->columns !== null) { - $parts[] = 'Columns: ' . implode(' ', $this->columns); - } - foreach ($this->filters as $key => $val) { - if ($key === 'search') { - $parts[] = 'Filter: host_name ~~ ' . $val; - $parts[] = 'Filter: description ~~ ' . $val; - $parts[] = 'Or: 2'; - continue; - } - if ($val === null) { - $parts[] = 'Filter: ' . $key; - } elseif (strpos($key, '?') === false) { - $parts[] = sprintf('Filter: %s = %s', $key, $val); - } else { - $parts[] = sprintf('Filter: %s', str_replace('?', $val, $key)); - } + + // Fetch all required columns + $parts[] = $this->columnsToString(); + + // In case we need to apply a userspace filter as of Livestatus lacking + // support for some of them we also need to fetch all filtered columns + if ($this->filterIsSupported() && $filter = $this->filterToString()) { + $parts[] = $filter; } + + // TODO: Old way of rendering a count query, this should definitively be + // improved if ($this->count === true) { $parts[] = 'Stats: state >= 0'; } + + // TODO: Well... ordering is still missing if (! $this->count && $this->hasLimit() && ! $this->hasOrder()) { - $parts[] = 'Limit: ' . ($this->limit_count + $this->limit_offset); + $parts[] = 'Limit: ' . ($this->getLimit() + $this->getOffset()); } $lql = implode("\n", $parts) . "\n" . implode("\n", $default_headers) . "\n\n"; + return $lql; } + /** + * Get all available columns + * + * @return array + */ + public function getAvailableColumns() + { + return $this->available_columns; + } + + protected function columnsToString() + { + $columns = array(); + $this->preparedHeaders = array(); + + + $usedColumns = $this->columns; + if (! $this->filterIsSupported()) { + foreach ($this->filter->listFilteredColumns() as $col) { + if (! in_array($col, $usedColumns)) { + $usedColumns[] = $col; + } + } + } + foreach ($usedColumns as $col) { +// TODO: No alias if filter??? + if (array_key_exists($col, $this->available_columns)) { + // Alias if such + $col = $this->available_columns[$col]; + } + if ($col[0] === '_') { + $columns['custom_variables'] = true; + } elseif (is_array($col)) { + foreach ($col as $k) { + $columns[$k] = true; + } + } else { + $columns[$col] = true; + } + } + + $this->preparedHeaders = array_keys($columns); + + if ($this->count === false && $this->columns !== null) { + return 'Columns: ' . implode(' ', array_keys($columns)); + } else { + return ''; // TODO: 'Stats: state >= 0'; when count + } + } + + /** + * Whether Livestatus is able to apply the current filter + * + * TODO: find a better method name + * TODO: more granular checks, also render filter-flag columns with lql + * + * @return bool + */ + public function filterIsSupported() + { + foreach ($this->filter->listFilteredColumns() as $column) { + if (is_array($this->available_columns[$column])) { + // Combined column, hardly filterable. Is it? May work! + return false; + } + } + return true; + } + + /** + * Create a Filter object for a given URL-like filter string. We allow + * for spaces as we do not search for custom string values here. This is + * internal voodoo. + * + * @param string $string Filter string + * + * @return Filter + */ + protected function filterStringToFilter($string) + { + return Filter::fromQueryString(str_replace(' ', '', $string)); + } + + /** + * Render the current filter to LQL + * + * @return string + */ + protected function filterToString() + { + return $this->renderFilter($this->filter); + } + + /** + * Filter rendering + * + * Happens recursively, useful for filters and for Stats expressions + * + * @param Filter $filter The filter that should be rendered + * @param string $type Filter type. Usually "Filter" or "Stats" + * @param int $level Nesting level during recursion. Don't touch + * @param bool $keylookup Whether to resolve alias names + * + * @return string + */ + protected function renderFilter(Filter $filter, $type = 'Filter', $level = 0, $keylookup = true) + { + $str = ''; + if ($filter instanceof FilterChain) { + if ($filter instanceof FilterAnd) { + $op = 'And'; + } elseif ($filter instanceof FilterOr) { + $op = 'Or'; + } elseif ($filter instanceof FilterNot) { + $op = 'Negate'; + } else { + throw new IcingaException( + 'Cannot render filter: %s', + $filter + ); + } + $parts = array(); + if (! $filter->isEmpty()) { + foreach ($filter->filters() as $f) { + $parts[] = $this->renderFilter($f, $type, $level + 1, $keylookup); + } + $str .= implode("\n", $parts); + if ($type === 'Filter') { + if (count($parts) > 1) { + $str .= "\n" . $op . ': ' . count($parts); + } + } else { + $str .= "\n" . $type . $op . ': ' . count($parts); + } + } + } else { + $str .= $type . ': ' . $this->renderFilterExpression($filter, $keylookup); + } + + return $str; + } + + /** + * Produce a safe regex string as required by LQL + * + * @param string $expression search expression + * + * @return string + */ + protected function safeRegex($expression) + { + return '^' . preg_replace('/\*/', '.*', $expression) . '$'; + } + + /** + * Render a single filter expression + * + * @param FilterExpression $filter the filter expression + * @param bool $keylookup whether to resolve alias names + * + * @return string + */ + public function renderFilterExpression(FilterExpression $filter, $keylookup = true) + { + if ($keylookup) { + $col = $this->available_columns[$filter->getColumn()]; + } else { + $col = $filter->getColumn(); + } + + $isArray = array_key_exists($col, $this->arrayColumns); + + $sign = $filter->getSign(); + if ($isArray && $sign === '=') { + $sign = '>='; + } + $expression = $filter->getExpression(); + if ($sign === '=' && strpos($expression, '*') !== false) { + return $col . ' ~~ ' . $this->safeRegex($expression); + } elseif ($sign === '!=' && strpos($expression, '*') !== false) { + return $col . ' !~~ ' . $this->safeRegex($expression); + } else { + return $col . ' ' . $sign . ' ' . $expression; + } + } + public function __destruct() { unset($this->connection); diff --git a/library/Icinga/Protocol/Livestatus/ResponseRow.php b/library/Icinga/Protocol/Livestatus/ResponseRow.php new file mode 100644 index 000000000..d4b0fd7cb --- /dev/null +++ b/library/Icinga/Protocol/Livestatus/ResponseRow.php @@ -0,0 +1,18 @@ +raw = $raw; + $this->query = $query; + } +} diff --git a/library/Icinga/Test/BaseTestCase.php b/library/Icinga/Test/BaseTestCase.php index a735550cb..c70bc5cd9 100644 --- a/library/Icinga/Test/BaseTestCase.php +++ b/library/Icinga/Test/BaseTestCase.php @@ -24,10 +24,10 @@ namespace Icinga\Test { use Exception; use RuntimeException; use Mockery; - use Zend_Config; use PHPUnit_Framework_TestCase; use Icinga\Application\Icinga; use Icinga\Util\DateTimeFactory; + use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Data\Db\DbConnection; @@ -158,11 +158,17 @@ namespace Icinga\Test { ->andReturnUsing(function ($name, $default) { return $default; })->byDefault(); $responseMock = Mockery::mock('Icinga\Web\Response')->shouldDeferMissing(); - // Can't express this as demeter chains. See: https://github.com/padraic/mockery/issues/59 $bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing(); + $libDir = dirname(self::$libDir); $bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock) ->shouldReceive('getApplicationDir')->andReturn(self::$appDir) + ->shouldReceive('getLibraryDir')->andReturnUsing(function ($subdir = null) use ($libDir) { + if ($subdir !== null) { + $libDir .= '/' . ltrim($subdir, '/'); + } + return $libDir; + }) ->shouldReceive('getRequest')->andReturn($requestMock) ->shouldReceive('getResponse')->andReturn($responseMock); @@ -191,17 +197,17 @@ namespace Icinga\Test { } /** - * Create Zend_Config for database configuration + * Create Config for database configuration * * @param string $name * - * @return Zend_Config + * @return ConfigObject * @throws RuntimeException */ protected function createDbConfigFor($name) { if (array_key_exists($name, self::$dbConfiguration)) { - return new Zend_Config(self::$dbConfiguration[$name]); + return new ConfigObject(self::$dbConfiguration[$name]); } throw new RuntimeException('Configuration for database type not available: ' . $name); diff --git a/library/Icinga/User/Preferences/PreferencesStore.php b/library/Icinga/User/Preferences/PreferencesStore.php index b8121eb25..c2cba0c41 100644 --- a/library/Icinga/User/Preferences/PreferencesStore.php +++ b/library/Icinga/User/Preferences/PreferencesStore.php @@ -4,13 +4,13 @@ namespace Icinga\User\Preferences; -use Zend_Config; +use Icinga\Application\Config; use Icinga\User; use Icinga\User\Preferences; +use Icinga\Data\ConfigObject; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; use Icinga\Data\Db\DbConnection; -use Icinga\Application\Config as IcingaConfig; /** * Preferences store factory @@ -19,14 +19,14 @@ use Icinga\Application\Config as IcingaConfig; * * 'ini', + * new ConfigObject( + * 'type' => 'ini', * 'config_path' => '/path/to/preferences' * ), * $user // Instance of \Icinga\User @@ -42,7 +42,7 @@ abstract class PreferencesStore /** * Store config * - * @var Zend_Config + * @var ConfigObject */ protected $config; @@ -56,10 +56,10 @@ abstract class PreferencesStore /** * Create a new store * - * @param Zend_Config $config The config for this adapter + * @param ConfigObject $config The config for this adapter * @param User $user The user to which these preferences belong */ - public function __construct(Zend_Config $config, User $user) + public function __construct(ConfigObject $config, User $user) { $this->config = $config; $this->user = $user; @@ -69,7 +69,7 @@ abstract class PreferencesStore /** * Getter for the store config * - * @return Zend_Config + * @return ConfigObject */ public function getStoreConfig() { @@ -108,14 +108,14 @@ abstract class PreferencesStore /** * Create preferences storage adapter from config * - * @param Zend_Config $config The config for the adapter + * @param ConfigObject $config The config for the adapter * @param User $user The user to which these preferences belong * * @return self * * @throws ConfigurationError When the configuration defines an invalid storage type */ - public static function create(Zend_Config $config, User $user) + public static function create(ConfigObject $config, User $user) { if (($type = $config->type) === null) { throw new ConfigurationError( @@ -133,7 +133,7 @@ abstract class PreferencesStore } if ($type === 'Ini') { - $config->location = IcingaConfig::resolvePath('preferences'); + $config->location = Config::resolvePath('preferences'); } elseif ($type === 'Db') { $config->connection = new DbConnection(ResourceFactory::getResourceConfig($config->resource)); } diff --git a/library/Icinga/User/Preferences/Store/DbStore.php b/library/Icinga/User/Preferences/Store/DbStore.php index 5ef4a5b6e..4d7b10584 100644 --- a/library/Icinga/User/Preferences/Store/DbStore.php +++ b/library/Icinga/User/Preferences/Store/DbStore.php @@ -9,6 +9,7 @@ use Icinga\Exception\NotReadableError; use Icinga\Exception\NotWritableError; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; +use Zend_Db_Expr; /** * Load and save user preferences by using a database @@ -20,22 +21,37 @@ class DbStore extends PreferencesStore */ const COLUMN_USERNAME = 'username'; + /** + * Column name for section + */ + const COLUMN_SECTION = 'section'; + /** * Column name for preference */ - const COLUMN_PREFERENCE = 'key'; + const COLUMN_PREFERENCE = 'name'; /** * Column name for value */ const COLUMN_VALUE = 'value'; + /** + * Column name for created time + */ + const COLUMN_CREATED_TIME = 'ctime'; + + /** + * Column name for modified time + */ + const COLUMN_MODIFIED_TIME = 'mtime'; + /** * Table name * * @var string */ - protected $table = 'preference'; + protected $table = 'icingaweb_user_preference'; /** * Stored preferences @@ -74,7 +90,7 @@ class DbStore extends PreferencesStore try { $select = $this->getStoreConfig()->connection->getDbAdapter()->select(); $result = $select - ->from($this->table, array(self::COLUMN_PREFERENCE, self::COLUMN_VALUE)) + ->from($this->table, array(self::COLUMN_SECTION, self::COLUMN_PREFERENCE, self::COLUMN_VALUE)) ->where(self::COLUMN_USERNAME . ' = ?', $this->getUser()->getUsername()) ->query() ->fetchAll(); @@ -89,7 +105,7 @@ class DbStore extends PreferencesStore if ($result !== false) { $values = array(); foreach ($result as $row) { - $values[$row->{self::COLUMN_PREFERENCE}] = $row->{self::COLUMN_VALUE}; + $values[$row->{self::COLUMN_SECTION}][$row->{self::COLUMN_PREFERENCE}] = $row->{self::COLUMN_VALUE}; } $this->preferences = $values; } @@ -106,22 +122,32 @@ class DbStore extends PreferencesStore { $preferences = $preferences->toArray(); - $toBeInserted = array_diff_key($preferences, $this->preferences); - if (!empty($toBeInserted)) { - $this->insert($toBeInserted); - } + $sections = array_keys($preferences); - $toBeUpdated = array_intersect_key( - array_diff_assoc($preferences, $this->preferences), - array_diff_assoc($this->preferences, $preferences) - ); - if (!empty($toBeUpdated)) { - $this->update($toBeUpdated); - } + foreach ($sections as $section) { + if (! array_key_exists($section, $this->preferences)) { + $this->preferences[$section] = array(); + } + if (! array_key_exists($section, $preferences)) { + $preferences[$section] = array(); + } + $toBeInserted = array_diff_key($preferences[$section], $this->preferences[$section]); + if (!empty($toBeInserted)) { + $this->insert($toBeInserted, $section); + } - $toBeDeleted = array_keys(array_diff_key($this->preferences, $preferences)); - if (!empty($toBeDeleted)) { - $this->delete($toBeDeleted); + $toBeUpdated = array_intersect_key( + array_diff_assoc($preferences[$section], $this->preferences[$section]), + array_diff_assoc($this->preferences[$section], $preferences[$section]) + ); + if (!empty($toBeUpdated)) { + $this->update($toBeUpdated, $section); + } + + $toBeDeleted = array_keys(array_diff_key($this->preferences[$section], $preferences[$section])); + if (!empty($toBeDeleted)) { + $this->delete($toBeDeleted, $section); + } } } @@ -129,11 +155,13 @@ class DbStore extends PreferencesStore * Insert the given preferences into the database * * @param array $preferences The preferences to insert + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function insert(array $preferences) + protected function insert(array $preferences, $section) { + /** @var \Zend_Db_Adapter_Abstract $db */ $db = $this->getStoreConfig()->connection->getDbAdapter(); try { @@ -142,8 +170,11 @@ class DbStore extends PreferencesStore $this->table, array( self::COLUMN_USERNAME => $this->getUser()->getUsername(), + $db->quoteIdentifier(self::COLUMN_SECTION) => $section, $db->quoteIdentifier(self::COLUMN_PREFERENCE) => $key, - self::COLUMN_VALUE => $value + self::COLUMN_VALUE => $value, + self::COLUMN_CREATED_TIME => new Zend_Db_Expr('NOW()'), + self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()') ) ); } @@ -160,11 +191,13 @@ class DbStore extends PreferencesStore * Update the given preferences in the database * * @param array $preferences The preferences to update + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function update(array $preferences) + protected function update(array $preferences, $section) { + /** @var \Zend_Db_Adapter_Abstract $db */ $db = $this->getStoreConfig()->connection->getDbAdapter(); try { @@ -174,7 +207,9 @@ class DbStore extends PreferencesStore array(self::COLUMN_VALUE => $value), array( self::COLUMN_USERNAME . '=?' => $this->getUser()->getUsername(), - $db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key + $db->quoteIdentifier(self::COLUMN_SECTION) . '=?' => $section, + $db->quoteIdentifier(self::COLUMN_PREFERENCE) . '=?' => $key, + self::COLUMN_MODIFIED_TIME => new Zend_Db_Expr('NOW()') ) ); } @@ -191,11 +226,13 @@ class DbStore extends PreferencesStore * Delete the given preference names from the database * * @param array $preferenceKeys The preference names to delete + * @param string $section The preferences in section to update * * @throws NotWritableError In case the database operation failed */ - protected function delete(array $preferenceKeys) + protected function delete(array $preferenceKeys, $section) { + /** @var \Zend_Db_Adapter_Abstract $db */ $db = $this->getStoreConfig()->connection->getDbAdapter(); try { @@ -203,6 +240,7 @@ class DbStore extends PreferencesStore $this->table, array( self::COLUMN_USERNAME . '=?' => $this->getUser()->getUsername(), + $db->quoteIdentifier(self::COLUMN_SECTION) . '=?' => $section, $db->quoteIdentifier(self::COLUMN_PREFERENCE) . ' IN (?)' => $preferenceKeys ) ); diff --git a/library/Icinga/User/Preferences/Store/IniStore.php b/library/Icinga/User/Preferences/Store/IniStore.php index acffff223..1a7efe760 100644 --- a/library/Icinga/User/Preferences/Store/IniStore.php +++ b/library/Icinga/User/Preferences/Store/IniStore.php @@ -4,7 +4,7 @@ namespace Icinga\User\Preferences\Store; -use Zend_Config; +use Icinga\Application\Config; use Icinga\Exception\NotReadableError; use Icinga\Exception\NotWritableError; use Icinga\File\Ini\IniWriter; @@ -67,7 +67,7 @@ class IniStore extends PreferencesStore $this->getUser()->getUsername() ); } else { - $this->preferences = parse_ini_file($this->preferencesFile); + $this->preferences = parse_ini_file($this->preferencesFile, true); } } @@ -81,9 +81,13 @@ class IniStore extends PreferencesStore */ public function save(Preferences $preferences) { - $preferences = $preferences->toArray(); - $this->update(array_diff_assoc($preferences, $this->preferences)); - $this->delete(array_keys(array_diff_key($this->preferences, $preferences))); + $this->preferences = $preferences->toArray(); + + // TODO: Elaborate whether we need to patch the contents + // $preferences = $preferences->toArray(); + // $this->update(array_diff_assoc($preferences, $this->preferences)); + // $this->delete(array_keys(array_diff_key($this->preferences, $preferences))); + $this->write(); } @@ -116,7 +120,7 @@ class IniStore extends PreferencesStore $this->writer = new IniWriter( array( - 'config' => new Zend_Config($this->preferences), + 'config' => Config::fromArray($this->preferences), 'filename' => $this->preferencesFile ) ); diff --git a/library/Icinga/Util/Translator.php b/library/Icinga/Util/Translator.php index 755203474..52a84bd62 100644 --- a/library/Icinga/Util/Translator.php +++ b/library/Icinga/Util/Translator.php @@ -224,6 +224,7 @@ class Translator } } } + sort($codes); return $codes; } diff --git a/library/Icinga/Web/Controller.php b/library/Icinga/Web/Controller.php new file mode 100644 index 000000000..111ee244c --- /dev/null +++ b/library/Icinga/Web/Controller.php @@ -0,0 +1,14 @@ +getResponse()->setHeader('X-Icinga-Reload-Css', 'now'); } + $this->shutdownSession(); + $this->getResponse() ->setHeader('X-Icinga-Redirect', rawurlencode($url->getAbsoluteUrl())) ->sendHeaders(); - // TODO: Session shutdown? exit; } + protected function redirectHttp($url) + { + if (! $url instanceof Url) { + $url = Url::fromPath($url); + } + $this->shutdownSession(); + $this->_helper->Redirector->gotoUrlAndExit($url->getRelativeUrl()); + } + /** * Redirect to a specific url, updating the browsers URL field * @@ -343,10 +351,7 @@ class ActionController extends Zend_Controller_Action if ($this->isXhr()) { $this->redirectXhr($url); } else { - if (! $url instanceof Url) { - $url = Url::fromPath($url); - } - $this->_helper->Redirector->gotoUrlAndExit($url->getRelativeUrl()); + $this->redirectHttp($url); } } @@ -374,6 +379,7 @@ class ActionController extends Zend_Controller_Action if ($req->getParam('format') === 'pdf') { $layout->setLayout('pdf'); + $this->shutdownSession(); $this->sendAsPdf(); exit; } @@ -381,6 +387,8 @@ class ActionController extends Zend_Controller_Action if ($this->isXhr()) { $this->postDispatchXhr(); } + + $this->shutdownSession(); } protected function postDispatchXhr() @@ -430,6 +438,14 @@ class ActionController extends Zend_Controller_Action $pdf->renderControllerAction($this); } + protected function shutdownSession() + { + $session = Session::getSession(); + if ($session->hasChanged()) { + $session->write(); + } + } + /** * Render the benchmark * diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 8eab0f6a5..163dba455 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -36,6 +36,13 @@ class Form extends Zend_Form */ protected $created = false; + /** + * The request associated with this form + * + * @var Request + */ + protected $request; + /** * The callback to call instead of Form::onSuccess() * @@ -94,19 +101,50 @@ class Form extends Zend_Form */ protected $uidElementName = 'formUID'; + /** + * Whether the form should validate the sent data when being automatically submitted + * + * @var bool + */ + protected $validatePartial = false; + /** * Default element decorators * * @var array */ public static $defaultElementDecorators = array( - 'ViewHelper', - 'Errors', - array('Description', array('tag' => 'span', 'class' => 'description')), - 'Label', - array('HtmlTag', array('tag' => 'div')) + array('ViewHelper', array('separator' => '')), + array('Errors', array('separator' => '')), + array('Help'), + array('Label', array('separator' => '')), + array('HtmlTag', array('tag' => 'div', 'class' => 'element')) ); + /** + * (non-PHPDoc) + * @see \Zend_Form::construct() For the method documentation. + */ + public function __construct($options = null) + { + // Zend's plugin loader reverses the order of added prefix paths thus trying our paths first before trying + // Zend paths + $this->addPrefixPaths(array( + array( + 'prefix' => 'Icinga\\Web\\Form\\Element\\', + 'path' => Icinga::app()->getLibraryDir('Icinga/Web/Form/Element'), + 'type' => static::ELEMENT + ), + array( + 'prefix' => 'Icinga\\Web\\Form\\Decorator\\', + 'path' => Icinga::app()->getLibraryDir('Icinga/Web/Form/Decorator'), + 'type' => static::DECORATOR + ) + )); + + parent::__construct($options); + } + /** * Set a callback that is called instead of this form's onSuccess method * @@ -304,6 +342,29 @@ class Form extends Zend_Form return $this->uidElementName; } + /** + * Set whether this form should validate the sent data when being automatically submitted + * + * @param bool $state + * + * @return self + */ + public function setValidatePartial($state) + { + $this->validatePartial = $state; + return $this; + } + + /** + * Return whether this form should validate the sent data when being automatically submitted + * + * @return bool + */ + public function getValidatePartial() + { + return $this->validatePartial; + } + /** * Create this form * @@ -348,11 +409,9 @@ class Form extends Zend_Form * * Intended to be implemented by concrete form classes. The base implementation returns always FALSE. * - * @param Request $request The valid request used to process this form - * * @return null|bool Return FALSE in case no redirect should take place */ - public function onSuccess(Request $request) + public function onSuccess() { return false; } @@ -361,10 +420,8 @@ class Form extends Zend_Form * Perform actions when no form dependent data was sent * * Intended to be implemented by concrete form classes. - * - * @param Request $request The current request */ - public function onRequest(Request $request) + public function onRequest() { } @@ -430,8 +487,8 @@ class Form extends Zend_Form * `disableLoadDefaultDecorators' option to any other value than `true'. For loading custom element decorators use * the 'decorators' option. * - * @param string $type String element type - * @param string $name The name of the element to add + * @param string $type The type of the element + * @param string $name The name of the element * @param mixed $options The options for the element * * @return Zend_Form_Element @@ -456,7 +513,15 @@ class Form extends Zend_Form $el = parent::createElement($type, $name, $options); if ($el && $el->getAttrib('autosubmit')) { - $el->addDecorator(new NoScriptApply()); // Non-JS environments + $noScript = new NoScriptApply(); // Non-JS environments + $decorators = $el->getDecorators(); + $pos = array_search('Zend_Form_Decorator_ViewHelper', array_keys($decorators)) + 1; + $el->setDecorators( + array_slice($decorators, 0, $pos, true) + + array(get_class($noScript) => $noScript) + + array_slice($decorators, $pos, count($decorators) - $pos, true) + ); + $class = $el->getAttrib('class'); if (is_array($class)) { $class[] = 'autosubmit'; @@ -466,6 +531,7 @@ class Form extends Zend_Form $class .= ' autosubmit'; } $el->setAttrib('class', $class); // JS environments + unset($el->autosubmit); } @@ -533,23 +599,25 @@ class Form extends Zend_Form { if ($request === null) { $request = $this->getRequest(); + } else { + $this->request = $request; } - $formData = $this->getRequestData($request); + $formData = $this->getRequestData(); if ($this->getUidDisabled() || $this->wasSent($formData)) { $this->populate($formData); // Necessary to get isSubmitted() to work if (! $this->getSubmitLabel() || $this->isSubmitted()) { if ($this->isValid($formData) - && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $request, $this)) - || ($this->onSuccess === null && false !== $this->onSuccess($request)))) { + && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this)) + || ($this->onSuccess === null && false !== $this->onSuccess()))) { $this->getResponse()->redirectAndExit($this->getRedirectUrl()); } - } else { - // The form can't be processed but we want to show validation errors though + } elseif ($this->getValidatePartial()) { + // The form can't be processed but we may want to show validation errors though $this->isValidPartial($formData); } } else { - $this->onRequest($request); + $this->onRequest(); } return $request; @@ -599,6 +667,14 @@ class Form extends Zend_Form public function isValidPartial(array $formData) { $this->create($formData); + + // Ensure that disabled elements are not overwritten (http://www.zendframework.com/issues/browse/ZF-6909) + foreach ($this->getElements() as $name => $element) { + if ($element->getAttrib('disabled')) { + $formData[$name] = $element->getValue(); + } + } + return parent::isValidPartial($formData); } @@ -612,6 +688,14 @@ class Form extends Zend_Form public function isValid($formData) { $this->create($formData); + + // Ensure that disabled elements are not overwritten (http://www.zendframework.com/issues/browse/ZF-6909) + foreach ($this->getElements() as $name => $element) { + if ($element->getAttrib('disabled')) { + $formData[$name] = $element->getValue(); + } + } + return parent::isValid($formData); } @@ -675,29 +759,19 @@ class Form extends Zend_Form } /** - * Return the request data based on this form's request method + * Return the request associated with this form * - * @param Request $request The request to fetch the data from - * - * @return array - */ - public function getRequestData(Request $request) - { - if (strtolower($request->getMethod()) === $this->getMethod()) { - return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}(); - } - - return array(); - } - - /** - * Return the current request + * Returns the global request if none has been set for this form yet. * * @return Request */ public function getRequest() { - return Icinga::app()->getFrontController()->getRequest(); + if ($this->request === null) { + $this->request = Icinga::app()->getFrontController()->getRequest(); + } + + return $this->request; } /** @@ -710,6 +784,20 @@ class Form extends Zend_Form return Icinga::app()->getFrontController()->getResponse(); } + /** + * Return the request data based on this form's request method + * + * @return array + */ + protected function getRequestData() + { + if (strtolower($this->request->getMethod()) === $this->getMethod()) { + return $this->request->{'get' . ($this->request->isPost() ? 'Post' : 'Query')}(); + } + + return array(); + } + /** * Render this form * diff --git a/library/Icinga/Web/Form/Decorator/ElementDoubler.php b/library/Icinga/Web/Form/Decorator/ElementDoubler.php new file mode 100644 index 000000000..8bedf9492 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/ElementDoubler.php @@ -0,0 +1,64 @@ +getElement(); + if ($group->getElement($this->getOption('condition')) !== null) { + if ($this->getPlacement() === static::APPEND) { + return $content . $this->applyAttributes($group->getElement($this->getOption('double')))->render(); + } else { // $this->getPlacement() === static::PREPEND + return $this->applyAttributes($group->getElement($this->getOption('double')))->render() . $content; + } + } + + return $content; + } + + /** + * Apply all element attributes + * + * @param Zend_Form_Element $element The element to apply the attributes to + * + * @return Zend_Form_Element + */ + protected function applyAttributes(Zend_Form_Element $element) + { + $attributes = $this->getOption('attributes'); + if ($attributes !== null) { + foreach ($attributes as $name => $value) { + $element->setAttrib($name, $value); + } + } + + return $element; + } +} diff --git a/library/Icinga/Web/Form/Decorator/Help.php b/library/Icinga/Web/Form/Decorator/Help.php new file mode 100644 index 000000000..1f8df2ce0 --- /dev/null +++ b/library/Icinga/Web/Form/Decorator/Help.php @@ -0,0 +1,33 @@ +getElement(); + $description = $element->getView()->escape($element->getDescription()); + + if (! empty($description)) { + $helpIcon = Icinga::app()->getViewRenderer()->view->icon('help', $description); + return $helpIcon . $content; + } + + return $content; + } +} diff --git a/library/Icinga/Web/Form/Element/Button.php b/library/Icinga/Web/Form/Element/Button.php new file mode 100644 index 000000000..1c5499373 --- /dev/null +++ b/library/Icinga/Web/Form/Element/Button.php @@ -0,0 +1,81 @@ + $options); + } + + if (!isset($options['ignore'])) { + $options['ignore'] = true; + } + + parent::__construct($spec, $options); + + if ($label = $this->getLabel()) { + // Necessary to get the label shown on the generated HTML + $this->content = $label; + } + } + + /** + * Validate element value (pseudo) + * + * There is no need to reset the value + * + * @param mixed $value Is always ignored + * @param mixed $context Is always ignored + * + * @return bool Returns always TRUE + */ + public function isValid($value, $context = null) + { + return true; + } + + /** + * Has this button been selected? + * + * @return bool + */ + public function isChecked() + { + return $this->getRequest()->getParam($this->getName()) === $this->getValue(); + } + + /** + * Return the current request + * + * @return Request + */ + protected function getRequest() + { + return Icinga::app()->getFrontController()->getRequest(); + } +} diff --git a/library/Icinga/Web/Form/Element/Note.php b/library/Icinga/Web/Form/Element/Note.php index 78881ab44..37bc127e9 100644 --- a/library/Icinga/Web/Form/Element/Note.php +++ b/library/Icinga/Web/Form/Element/Note.php @@ -4,13 +4,12 @@ namespace Icinga\Web\Form\Element; -use Zend_Form_Element; -use Icinga\Web\Form; +use Icinga\Web\Form\FormElement; /** * A note */ -class Note extends Zend_Form_Element +class Note extends FormElement { /** * Form view helper to use for rendering @@ -32,7 +31,15 @@ class Note extends Zend_Form_Element */ public function init() { - $this->setDecorators(Form::$defaultElementDecorators); + if (count($this->getDecorators()) === 0) { + $this->setDecorators(array( + 'ViewHelper', + array( + 'HtmlTag', + array('tag' => 'p') + ) + )); + } } /** diff --git a/library/Icinga/Web/Form/Element/Number.php b/library/Icinga/Web/Form/Element/Number.php index 836142514..02f0aaad3 100644 --- a/library/Icinga/Web/Form/Element/Number.php +++ b/library/Icinga/Web/Form/Element/Number.php @@ -47,7 +47,6 @@ class Number extends FormElement */ public function init() { - $this->addValidator('Float', true); // true for breaking the validator chain on failure if ($this->min !== null) { $this->addValidator('GreaterThan', true, array('min' => $this->min)); } @@ -127,4 +126,19 @@ class Number extends FormElement { return $this->step; } + + /** + * (non-PHPDoc) + * @see \Zend_Form_Element::isValid() For the method documentation. + */ + public function isValid($value, $context = null) + { + $this->setValue($value); + $value = $this->getValue(); + if (! is_numeric($value)) { + $this->addError(sprintf($this->translate('\'%s\' is not a valid number'), $value)); + return false; + } + return parent::isValid($value, $context); + } } diff --git a/library/Icinga/Web/Form/Validator/WritablePathValidator.php b/library/Icinga/Web/Form/Validator/WritablePathValidator.php index 8387c5cf5..239ab77c8 100644 --- a/library/Icinga/Web/Form/Validator/WritablePathValidator.php +++ b/library/Icinga/Web/Form/Validator/WritablePathValidator.php @@ -5,7 +5,6 @@ namespace Icinga\Web\Form\Validator; use Zend_Validate_Abstract; -use Icinga\Application\Config as IcingaConfig; /** * Validator that interprets the value as a path and checks if it's writable diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php index 6224b5b82..9fa687042 100644 --- a/library/Icinga/Web/JavaScript.php +++ b/library/Icinga/Web/JavaScript.php @@ -67,7 +67,7 @@ class JavaScript public static function send($minified = false) { header('Content-Type: application/javascript'); - $basedir = Icinga::app()->getBootstrapDirecory(); + $basedir = Icinga::app()->getBootstrapDirectory(); $js = $out = ''; $min = $minified ? '.min' : ''; @@ -118,7 +118,7 @@ class JavaScript } if ($minified) { - require_once 'IcingaVendor/JShrink/Minifier.php'; + require_once 'JShrink/Minifier.php'; $out .= Minifier::minify($js, array('flaggedComments' => false)); } else { $out .= $js; diff --git a/library/Icinga/Web/LessCompiler.php b/library/Icinga/Web/LessCompiler.php index 16514cf6d..791fdbab0 100644 --- a/library/Icinga/Web/LessCompiler.php +++ b/library/Icinga/Web/LessCompiler.php @@ -41,7 +41,7 @@ class LessCompiler */ public function __construct() { - require_once 'IcingaVendor/lessphp/lessc.inc.php'; + require_once 'lessphp/lessc.inc.php'; $this->lessc = new lessc(); $this->lessc->setVariables( diff --git a/library/Icinga/Web/Menu.php b/library/Icinga/Web/Menu.php index a556484e9..a2711f1b2 100644 --- a/library/Icinga/Web/Menu.php +++ b/library/Icinga/Web/Menu.php @@ -4,12 +4,13 @@ namespace Icinga\Web; +use Icinga\Authentication\Manager; use Icinga\Web\Menu\MenuItemRenderer; use RecursiveIterator; -use Zend_Config; use Icinga\Application\Config; use Icinga\Application\Icinga; use Icinga\Application\Logger; +use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; use Icinga\Exception\ProgrammingError; use Icinga\Web\Url; @@ -68,7 +69,7 @@ class Menu implements RecursiveIterator * @var MenuItemRenderer */ protected $itemRenderer = null; - + /* * Parent menu * @@ -80,9 +81,9 @@ class Menu implements RecursiveIterator * Create a new menu * * @param int $id The id of this menu - * @param Zend_Config $config The configuration for this menu + * @param ConfigObject $config The configuration for this menu */ - public function __construct($id, Zend_Config $config = null, Menu $parent = null) + public function __construct($id, ConfigObject $config = null, Menu $parent = null) { $this->id = $id; if ($parent !== null) { @@ -94,7 +95,7 @@ class Menu implements RecursiveIterator /** * Set all given properties * - * @param array|Zend_Config $props Property list + * @param array|ConfigObject $props Property list */ public function setProperties($props = null) { @@ -170,7 +171,7 @@ class Menu implements RecursiveIterator foreach ($modules as $moduleName) { $moduleMenuConfig = Config::module($moduleName, 'menu'); - if (false === empty($moduleMenuConfig)) { + if (! $moduleMenuConfig->isEmpty()) { $menuConfigs[] = $moduleMenuConfig; } } @@ -201,45 +202,50 @@ class Menu implements RecursiveIterator */ protected function addMainMenuItems() { - $this->add(t('Dashboard'), array( - 'url' => 'dashboard', - 'icon' => 'img/icons/dashboard.png', - 'priority' => 10 - )); + $auth = Manager::getInstance(); - $section = $this->add(t('System'), array( - 'icon' => 'img/icons/configuration.png', - 'priority' => 200 - )); - $section->add(t('Preferences'), array( - 'url' => 'preference', - 'priority' => 200 - )); - $section->add(t('Configuration'), array( - 'url' => 'config', - 'priority' => 300 - )); - $section->add(t('Modules'), array( - 'url' => 'config/modules', - 'priority' => 400 - )); - $section->add(t('Security'), array( - 'url' => 'security', - 'priority' => 500 - )); + if ($auth->isAuthenticated()) { - if (Logger::writesToFile()) { - $section->add(t('Application Log'), array( - 'url' => 'list/applicationlog', - 'priority' => 500 + $this->add(t('Dashboard'), array( + 'url' => 'dashboard', + 'icon' => 'dashboard', + 'priority' => 10 + )); + + $section = $this->add(t('System'), array( + 'icon' => 'conf-alt', + 'priority' => 200 + )); + $section->add(t('Configuration'), array( + 'url' => 'config', + 'priority' => 300 + )); + $section->add(t('Modules'), array( + 'url' => 'config/modules', + 'priority' => 400 + )); + + if (Logger::writesToFile()) { + $section->add(t('Application Log'), array( + 'url' => 'list/applicationlog', + 'priority' => 500 + )); + } + + $section = $this->add($auth->getUser()->getUsername(), array( + 'icon' => 'user', + 'priority' => 600 + )); + $section->add(t('Preferences'), array( + 'url' => 'preference', + 'priority' => 601 + )); + + $section->add(t('Logout'), array( + 'url' => 'authentication/logout', + 'priority' => 700 )); } - - $this->add(t('Logout'), array( - 'url' => 'authentication/logout', - 'icon' => 'img/icons/logout.png', - 'priority' => 300 - )); } /** @@ -419,11 +425,11 @@ class Menu implements RecursiveIterator * Add a sub menu to this menu * * @param string $id The id of the menu to add - * @param Zend_Config $itemConfig The config with which to initialize the menu + * @param ConfigObject $itemConfig The config with which to initialize the menu * * @return self */ - public function addSubMenu($id, Zend_Config $menuConfig = null) + public function addSubMenu($id, ConfigObject $menuConfig = null) { if (false === ($pos = strpos($id, '.'))) { $subMenu = new self($id, $menuConfig, $this); @@ -513,7 +519,7 @@ class Menu implements RecursiveIterator */ public function add($name, $config = array()) { - return $this->addSubMenu($name, new Zend_Config($config)); + return $this->addSubMenu($name, new ConfigObject($config)); } /** @@ -695,7 +701,7 @@ class Menu implements RecursiveIterator } /** - * PHP 5.3 GC should not leak, but just to be on the safe side... + * PHP 5.3 GC should not leak, but just to be on the safe side... */ public function __destruct() { diff --git a/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php new file mode 100644 index 000000000..6493497af --- /dev/null +++ b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php @@ -0,0 +1,100 @@ +select()->from( + 'statusSummary', + array( + 'hosts_down_unhandled', + 'services_critical_unhandled' + ) + )->getQuery()->fetchRow(); + } + + if ($column === null) { + return self::$summary; + } elseif (isset(self::$summary->$column)) { + return self::$summary->$column; + } else { + return null; + } + } + + protected function getBadgeTitle() + { + $translations = array( + 'hosts_down_unhandled' => mt('monitoring', '%d unhandled hosts down'), + 'services_critical_unhandled' => mt('monitoring', '%d unhandled services critical') + ); + + $titles = array(); + $sum = $this->summary(); + + foreach ($this->columns as $col) { + if (isset($sum->$col) && $sum->$col > 0) { + $titles[] = sprintf($translations[$col], $sum->$col); + } + } + + return implode(', ', $titles); + } + + protected function countItems() + { + $sum = self::summary(); + $count = 0; + + foreach ($this->columns as $col) { + if (isset($sum->$col)) { + $count += $sum->$col; + } + } + + return $count; + } + + public function render(Menu $menu) + { + $count = $this->countItems(); + $badge = ''; + if ($count) { + $badge = sprintf( + '
%s
', + $this->getBadgeTitle(), + $count + ); + } + if ($menu->getIcon() && strpos($menu->getIcon(), '.') === false) { + return sprintf( + '%s%s', + $menu->getUrl() ?: '#', + $menu->getIcon(), + htmlspecialchars($menu->getTitle()), + $badge + ); + } + + return sprintf( + '%s%s%s', + $menu->getUrl() ?: '#', + $menu->getIcon() ? ' ' : '', + htmlspecialchars($menu->getTitle()), + $badge + ); + } +} diff --git a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php index 1254033ae..58689547f 100644 --- a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php @@ -1,39 +1,11 @@ select()->from( - 'statusSummary', - array( - 'hosts_down_unhandled', - 'services_critical_unhandled' - ) - )->getQuery()->fetchRow(); - $unhandled = $statusSummary->hosts_down_unhandled + $statusSummary->services_critical_unhandled; - $badge = ''; - if ($unhandled) { - $badge = sprintf( - '
%s
', - $unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class ProblemMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'hosts_down_unhandled', + 'services_critical_unhandled' + ); } diff --git a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php index c7e6036fb..10a75c00f 100644 --- a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php @@ -1,38 +1,12 @@ select()->from( - 'statusSummary', - array( - 'hosts_down_unhandled' - ) - )->getQuery()->fetchRow(); - $badge = ''; - if ($statusSummary->hosts_down_unhandled) { - $badge = sprintf( - '
%s
', - t(sprintf('%d unhandled host problems', $statusSummary->hosts_down_unhandled)), - $statusSummary->hosts_down_unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class UnhandledHostMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'hosts_down_unhandled', + ); } diff --git a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php index b677a4935..8a59e9baa 100644 --- a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php +++ b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php @@ -1,38 +1,12 @@ select()->from( - 'statusSummary', - array( - 'services_critical_unhandled' - ) - )->getQuery()->fetchRow(); - $badge = ''; - if ($statusSummary->services_critical_unhandled) { - $badge = sprintf( - '
%s
', - t(sprintf('%d unhandled service problems', $statusSummary->services_critical_unhandled)), - $statusSummary->services_critical_unhandled - ); - } - return sprintf( - '%s%s %s', - $menu->getUrl() ?: '#', - $menu->getIcon() ? ' ' : '', - htmlspecialchars($menu->getTitle()), - $badge - ); - } +class UnhandledServiceMenuItemRenderer extends MonitoringMenuItemRenderer +{ + protected $columns = array( + 'services_critical_unhandled' + ); } diff --git a/library/Icinga/Web/MenuRenderer.php b/library/Icinga/Web/MenuRenderer.php index bbd5c208d..8502e5215 100644 --- a/library/Icinga/Web/MenuRenderer.php +++ b/library/Icinga/Web/MenuRenderer.php @@ -114,6 +114,14 @@ class MenuRenderer extends RecursiveIteratorIterator Logger::error('Could not invoke custom renderer. Exception: '. $e->getMessage()); } } + if ($child->getIcon() && strpos($child->getIcon(), '.') === false) { + return sprintf( + '%s', + $child->getUrl() ?: '#', + $child->getIcon(), + htmlspecialchars($child->getTitle()) + ); + } return sprintf( '%s%s', $child->getUrl() ?: '#', diff --git a/library/Icinga/Web/Notification.php b/library/Icinga/Web/Notification.php index c85dbcc13..b046476b3 100644 --- a/library/Icinga/Web/Notification.php +++ b/library/Icinga/Web/Notification.php @@ -75,35 +75,28 @@ class Notification return; } - $mo = (object) array( + $messages = & Session::getSession()->getByRef('messages'); + $messages[] = (object) array( 'type' => $type, 'message' => $message, ); - - // Get, change, set - just to be on the safe side: - $session = Session::getSession(); - $msgs = $session->messages; - $msgs[] = $mo; - $session->messages = $msgs; - $session->write(); } public function hasMessages() { $session = Session::getSession(); - return !empty($session->messages); + return false === empty($session->messages); } public function getMessages() { $session = Session::getSession(); - $msgs = $session->messages; - if (false === empty($msgs)) { + $messages = $session->messages; + if (false === empty($messages)) { $session->messages = array(); - $session->write(); } - return $msgs; + return $messages; } final private function __construct() diff --git a/library/Icinga/Web/Request.php b/library/Icinga/Web/Request.php index 8b09f68fb..ae957f6a9 100644 --- a/library/Icinga/Web/Request.php +++ b/library/Icinga/Web/Request.php @@ -19,6 +19,16 @@ class Request extends Zend_Controller_Request_Http */ private $user; + private $url; + + public function getUrl() + { + if ($this->url === null) { + $this->url = Url::fromRequest($this); + } + return $this->url; + } + /** * Setter for user * diff --git a/library/Icinga/Web/Response.php b/library/Icinga/Web/Response.php index 6ad4f6f87..d0d8912e6 100644 --- a/library/Icinga/Web/Response.php +++ b/library/Icinga/Web/Response.php @@ -21,6 +21,12 @@ class Response extends Zend_Controller_Response_Http } else { $this->setRedirect($url->getAbsoluteUrl()); } + + $session = Session::getSession(); + if ($session->hasChanged()) { + $session->write(); + } + $this->sendHeaders(); exit; } diff --git a/library/Icinga/Web/Session/PhpSession.php b/library/Icinga/Web/Session/PhpSession.php index cb311cc4a..bef978c0b 100644 --- a/library/Icinga/Web/Session/PhpSession.php +++ b/library/Icinga/Web/Session/PhpSession.php @@ -121,7 +121,7 @@ class PhpSession extends Session foreach ($_SESSION as $key => $value) { if (strpos($key, self::NAMESPACE_PREFIX) === 0) { - $namespace = new SessionNamespace($this); + $namespace = new SessionNamespace(); $namespace->setAll($value); $this->namespaces[substr($key, strlen(self::NAMESPACE_PREFIX))] = $namespace; } else { diff --git a/library/Icinga/Web/Session/Session.php b/library/Icinga/Web/Session/Session.php index 0c60d7f98..ab73dcac7 100644 --- a/library/Icinga/Web/Session/Session.php +++ b/library/Icinga/Web/Session/Session.php @@ -75,7 +75,7 @@ abstract class Session extends SessionNamespace unset($this->removedNamespaces[array_search($identifier, $this->removedNamespaces)]); } - $this->namespaces[$identifier] = new SessionNamespace($this); + $this->namespaces[$identifier] = new SessionNamespace(); } return $this->namespaces[$identifier]; @@ -104,13 +104,22 @@ abstract class Session extends SessionNamespace $this->removedNamespaces[] = $identifier; } + /** + * Return whether the session has changed + * + * @return bool + */ + public function hasChanged() + { + return parent::hasChanged() || false === empty($this->namespaces) || false === empty($this->removedNamespaces); + } + /** * Clear all values and namespaces from the session cache */ public function clear() { - $this->values = array(); - $this->removed = array(); + parent::clear(); $this->namespaces = array(); $this->removedNamespaces = array(); } diff --git a/library/Icinga/Web/Session/SessionNamespace.php b/library/Icinga/Web/Session/SessionNamespace.php index b7495683b..c72d69c36 100644 --- a/library/Icinga/Web/Session/SessionNamespace.php +++ b/library/Icinga/Web/Session/SessionNamespace.php @@ -14,13 +14,6 @@ use IteratorAggregate; */ class SessionNamespace implements IteratorAggregate { - /** - * The session this namespace is associated to - * - * @var Session - */ - protected $session; - /** * The actual values stored in this container * @@ -35,16 +28,6 @@ class SessionNamespace implements IteratorAggregate */ protected $removed = array(); - /** - * Create a new session namespace - * - * @param Session $session The session this namespace is associated to - */ - public function __construct(Session $session = null) - { - $this->session = $session; - } - /** * Return an iterator for all values in this namespace * @@ -120,7 +103,18 @@ class SessionNamespace implements IteratorAggregate $this->values[$key] = $value; if (in_array($key, $this->removed)) { - unset($this->removed[array_search($key, $this->values)]); + unset($this->removed[array_search($key, $this->removed)]); + } + + return $this; + } + + public function setByRef($key, &$value) + { + $this->values[$key] = & $value; + + if (in_array($key, $this->removed)) { + unset($this->removed[array_search($key, $this->removed)]); } return $this; @@ -139,6 +133,16 @@ class SessionNamespace implements IteratorAggregate return isset($this->values[$key]) ? $this->values[$key] : $default; } + public function & getByRef($key, $default = null) + { + $value = $default; + if (isset($this->values[$key])) { + $value = & $this->values[$key]; + } + + return $value; + } + /** * Delete the given value from the session * @@ -177,14 +181,21 @@ class SessionNamespace implements IteratorAggregate } /** - * Save the session this namespace is associated to + * Return whether the session namespace has been changed + * + * @return bool */ - public function write() + public function hasChanged() { - if (!$this->session) { - throw new IcingaException('Cannot save, session not set'); - } + return false === empty($this->values) || false === empty($this->removed); + } - $this->session->write(); + /** + * Clear all values from the session namespace + */ + public function clear() + { + $this->values = array(); + $this->removed = array(); } } diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index 3c4baf943..ec926d992 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -19,18 +19,21 @@ class StyleSheet 'css/icinga/main-content.less', 'css/icinga/tabs.less', 'css/icinga/forms.less', + 'css/icinga/setup.less', 'css/icinga/widgets.less', 'css/icinga/pagination.less', 'css/icinga/monitoring-colors.less', 'css/icinga/selection-toolbar.less', 'css/icinga/login.less', + '../application/fonts/fontanello-ifont/css/ifont-embedded.css', 'css/vendor/tipsy.css' ); public static function compileForPdf() { + self::checkPhp(); $less = new LessCompiler(); - $basedir = Icinga::app()->getBootstrapDirecory(); + $basedir = Icinga::app()->getBootstrapDirectory(); foreach (self::$lessFiles as $file) { $less->addFile($basedir . '/' . $file); } @@ -53,10 +56,19 @@ class StyleSheet ); } + protected static function checkPhp() + { + // PHP had a rather conservative PCRE backtrack limit unless 5.3.7 + if (version_compare(PHP_VERSION, '5.3.7') <= 0) { + ini_set('pcre.backtrack_limit', 1000000); + } + } + public static function send($minified = false) { + self::checkPhp(); $app = Icinga::app(); - $basedir = $app->getBootstrapDirecory(); + $basedir = $app->getBootstrapDirectory(); foreach (self::$lessFiles as $file) { $lessFiles[] = $basedir . '/' . $file; } diff --git a/library/Icinga/Web/View/helpers/url.php b/library/Icinga/Web/View/helpers/url.php index 935a55a97..901e68803 100644 --- a/library/Icinga/Web/View/helpers/url.php +++ b/library/Icinga/Web/View/helpers/url.php @@ -51,19 +51,32 @@ $this->addHelperFunction('img', function ($url, array $properties = array()) use }); $this->addHelperFunction('icon', function ($img, $title = null, array $properties = array()) use ($view) { - // TODO: join with classes passed in $properties? - $attributes = array( - 'class' => 'icon', - ); - if ($title !== null) { - $attributes['alt'] = $title; - $attributes['title'] = $title; - } + $isClass = strpos($img, '.') === false; + $class = null; - return $view->img( - 'img/icons/' . $img, - array_merge($attributes, $properties) - ); + if ($isClass) { + $class = 'icon-' . $img; + } else { + $class = 'icon'; + } + if ($title !== null) { + $properties['alt'] = $title; + $properties['title'] = $title; + } + + if ($class !== null) { + if (isset($props['class'])) { + $properties['class'] .= ' ' . $class; + } else { + $properties['class'] = $class; + } + } + if ($isClass) { + return sprintf('', $view->propertiesToString($properties)); + + } else { + return $view->img('img/icons/' . $img, $properties); + } }); $this->addHelperFunction('propertiesToString', function ($properties) use ($view) { diff --git a/library/Icinga/Web/Widget/AbstractWidget.php b/library/Icinga/Web/Widget/AbstractWidget.php index fe4d2434d..5b9d8876b 100644 --- a/library/Icinga/Web/Widget/AbstractWidget.php +++ b/library/Icinga/Web/Widget/AbstractWidget.php @@ -34,7 +34,7 @@ abstract class AbstractWidget protected static $view; // TODO: Should we kick this? - protected $properties; + protected $properties = array(); /** * Getter for widget properties diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php index d22923131..3ff97b2df 100644 --- a/library/Icinga/Web/Widget/Chart/InlinePie.php +++ b/library/Icinga/Web/Widget/Chart/InlinePie.php @@ -73,28 +73,28 @@ EOD; * * @var int The value in px */ - private $width = 28; + private $width = 16; /** * The height of the rendered chart * * @var int The value in px */ - private $height = 28; + private $height = 16; /** * PieChart border width * * @var float */ - private $borderWidth = 0; + private $borderWidth = 1; /** * The color of the border * * @var string */ - private $borderColor = '#888'; + private $borderColor = '#fff'; /** * The title of the chart diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index a86204d87..f7daa5d02 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -5,7 +5,7 @@ namespace Icinga\Web\Widget; use Icinga\Application\Icinga; -use Icinga\Application\Config as IcingaConfig; +use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\ProgrammingError; use Icinga\Web\Widget\Dashboard\Pane; @@ -26,7 +26,7 @@ class Dashboard extends AbstractWidget /** * The configuration containing information about this dashboard * - * @var IcingaConfig; + * @var Config; */ private $config; @@ -140,11 +140,11 @@ class Dashboard extends AbstractWidget /** * Populate this dashboard via the given configuration file * - * @param IcingaConfig $config The configuration file to populate this dashboard with + * @param Config $config The configuration file to populate this dashboard with * * @return self */ - public function readConfig(IcingaConfig $config) + public function readConfig(Config $config) { $this->config = $config; $this->panes = array(); @@ -366,9 +366,7 @@ class Dashboard extends AbstractWidget */ private function loadConfigPanes() { - $items = $this->config; - foreach ($items->keys() as $key) { - $item = $this->config->get($key, false); + foreach ($this->config as $key => $item) { if (false === strstr($key, '.')) { $this->addPane(Pane::fromIni($key, $item)); } else { diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 7410c6210..e0ac4b3d7 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -4,16 +4,12 @@ namespace Icinga\Web\Widget\Dashboard; -use Icinga\Exception\IcingaException; -use Icinga\Util\Dimension; +use Zend_Form_Element_Button; use Icinga\Web\Form; use Icinga\Web\Url; use Icinga\Web\Widget\AbstractWidget; -use Icinga\Web\View; -use Zend_Config; -use Zend_Form_Element_Submit; -use Zend_Form_Element_Button; -use Exception; +use Icinga\Data\ConfigObject; +use Icinga\Exception\IcingaException; /** * A dashboard pane component @@ -218,13 +214,13 @@ EOD; /** * Create a @see Component instance from the given Zend config, using the provided title * - * @param $title The title for this component - * @param Zend_Config $config The configuration defining url, parameters, height, width, etc. - * @param Pane $pane The pane this component belongs to + * @param $title The title for this component + * @param ConfigObject $config The configuration defining url, parameters, height, width, etc. + * @param Pane $pane The pane this component belongs to * - * @return Component A newly created Component for use in the Dashboard + * @return Component A newly created Component for use in the Dashboard */ - public static function fromIni($title, Zend_Config $config, Pane $pane) + public static function fromIni($title, ConfigObject $config, Pane $pane) { $height = null; $width = null; diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 8c1e66bad..92523578f 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -4,7 +4,7 @@ namespace Icinga\Web\Widget\Dashboard; -use Zend_Config; +use Icinga\Data\ConfigObject; use Icinga\Web\Widget\AbstractWidget; use Icinga\Exception\ProgrammingError; use Icinga\Exception\ConfigurationError; @@ -253,11 +253,11 @@ class Pane extends AbstractWidget * Create a new pane with the title $title from the given configuration * * @param $title The title for this pane - * @param Zend_Config $config The configuration to use for setup + * @param ConfigObject $config The configuration to use for setup * * @return Pane */ - public static function fromIni($title, Zend_Config $config) + public static function fromIni($title, ConfigObject $config) { $pane = new Pane($title); if ($config->get('title', false)) { diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index af46a40f2..3721e488c 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -8,7 +8,9 @@ use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterExpression; use Icinga\Data\Filter\FilterChain; use Icinga\Web\Url; +use Icinga\Application\Icinga; use Icinga\Exception\ProgrammingError; +use Exception; /** * Filter @@ -24,6 +26,16 @@ class FilterEditor extends AbstractWidget protected $query; + protected $url; + + protected $addTo; + + protected $cachedColumnSelect; + + protected $preserveParams = array(); + + protected $ignoreParams = array(); + /** * @var string */ @@ -36,10 +48,200 @@ class FilterEditor extends AbstractWidget */ public function __construct($props) { - $this->filter = $props['filter']; - if (array_key_exists('query', $props)) { - $this->query = $props['query']; + if (array_key_exists('filter', $props)) { + $this->setFilter($props['filter']); } + if (array_key_exists('query', $props)) { + $this->setQuery($props['query']); + } + } + + public function setFilter(Filter $filter) + { + $this->filter = $filter; + return $this; + } + + public function getFilter() + { + if ($this->filter === null) { + $this->filter = Filter::fromQueryString((string) $this->url()->getParams()); + } + return $this->filter; + } + + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + protected function url() + { + if ($this->url === null) { + $this->url = Url::fromRequest(); + } + return $this->url; + } + + public function setQuery($query) + { + $this->query = $query; + return $this; + } + + public function ignoreParams() + { + $this->ignoreParams = func_get_args(); + return $this; + } + + public function preserveParams() + { + $this->preserveParams = func_get_args(); + return $this; + } + + protected function redirectNow($url) + { + $response = Icinga::app()->getFrontController()->getResponse(); + $response->redirectAndExit($url); + } + + protected function mergeRootExpression($filter, $column, $sign, $expression) + { + $found = false; + if ($filter->isChain() && $filter->getOperatorName() === 'AND') { + foreach ($filter->filters() as $f) { + if ($f->isExpression() + && $f->getColumn() === $column + && $f->getSign() === $sign + ) { + $f->setExpression($expression); + $found = true; + break; + } + } + } elseif ($filter->isExpression()) { + if ($filter->getColumn() === $column && $filter->getSign() === $sign) { + $filter->setExpression($expression); + $found = true; + } + } + if (! $found) { + $filter = $filter->andFilter( + Filter::expression($column, $sign, $expression) + ); + } + return $filter; + } + + public function handleRequest($request) + { + $this->setUrl($request->getUrl()->without($this->ignoreParams)); + $params = $this->url()->getParams(); + + $preserve = array(); + foreach ($this->preserveParams as $key) { + if (null !== ($value = $params->shift($key))) { + $preserve[$key] = $value; + } + } + + $add = $params->shift('addFilter'); + $remove = $params->shift('removeFilter'); + $strip = $params->shift('stripFilter'); + $modify = $params->shift('modifyFilter'); + + + + $search = null; + if ($request->isPost()) { + $search = $request->getPost('q'); + } + + if ($search === null) { + $search = $params->shift('q'); + } + + $filter = $this->getFilter(); + + if ($search !== null) { + if (strpos($search, '=') === false) { + // TODO: Ask the view for (multiple) search columns + switch($request->getActionName()) { + case 'services': + $searchCol = 'service_description'; + break; + case 'hosts': + $searchCol = 'host_name'; + break; + case 'hostgroups': + $searchCol = 'hostgroup'; + break; + case 'servicegroups': + $searchCol = 'servicegroup'; + break; + default: + $searchCol = null; + } + + if ($searchCol === null) { + throw new Exception('Cannot search here'); + } + $filter = $this->mergeRootExpression($filter, $searchCol, '=', "*$search*"); + + } else { + list($k, $v) = preg_split('/=/', $search); + $filter = $this->mergeRootExpression($filter, $k, '=', $v); + } + + $url = $this->url()->setQueryString( + $filter->toQueryString() + )->addParams($preserve); + if ($modify) { + $url->getParams()->add('modifyFilter'); + } + $this->redirectNow($url); + } + + if ($remove) { + $redirect = $this->url(); + if ($filter->getById($remove)->isRootNode()) { + $redirect->setQueryString(''); + } else { + $filter->removeId($remove); + $redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter'); + } + $this->redirectNow($redirect->addParams($preserve)); + } + + if ($strip) { + $redirect = $this->url(); + $filter->replaceById($strip, $filter->getById($strip . '-1')); + $redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter'); + $this->redirectNow($redirect->addParams($preserve)); + } + + + if ($modify) { + if ($request->isPost()) { + if ($request->get('cancel') === 'Cancel') { + $this->redirectNow($this->url()->without('modifyFilter')); + } + + $filter = $this->applyChanges($request->getPost()); + $url = $this->url()->setQueryString($filter->toQueryString())->addParams($preserve); + $url->getParams()->add('modifyFilter'); + $this->redirectNow($url); + } + $this->url()->getParams()->add('modifyFilter'); + } + + if ($add) { + $this->addFilterToId($add); + } + return $this; } protected function select($name, $list, $selected, $attributes = null) @@ -50,9 +252,12 @@ class FilterEditor extends AbstractWidget } else { $attributes = $view->propertiesToString($attributes); } - $html = '' . "\n", + $view->escape($name), + $attributes + ); - asort($list); foreach ($list as $k => $v) { $active = ''; if ($k === $selected) { @@ -69,100 +274,169 @@ class FilterEditor extends AbstractWidget return $html; } - public function markIndex($idx) + protected function addFilterToId($id) + { + $this->addTo = $id; + return $this; + } + + protected function removeIndex($idx) { $this->selectedIdx = $idx; return $this; } - public function removeIndex($idx) + protected function removeLink(Filter $filter) { - $this->selectedIdx = $idx; - return $this; + return $this->view()->qlink( + '', + $this->url()->with('removeFilter', $filter->getId()), + null, + array( + 'title' => t('Click to remove this part of your filter'), + 'class' => 'icon-cancel' + ) + ); + } + + protected function addLink(Filter $filter) + { + return $this->view()->qlink( + '', + $this->url()->with('addFilter', $filter->getId()), + null, + array( + 'title' => t('Click to add another filter'), + 'class' => 'icon-plus' + ) + ); + } + + protected function stripLink(Filter $filter) + { + return $this->view()->qlink( + '', + $this->url()->with('stripFilter', $filter->getId()), + null, + array( + 'title' => t('Strip this filter'), + 'class' => 'icon-minus' + ) + ); + } + + protected function cancelLink() + { + return $this->view()->qlink( + '', + $this->url()->without('addFilter'), + null, + array( + 'title' => t('Cancel this operation'), + 'class' => 'icon-cancel' + ) + ); } protected function renderFilter($filter, $level = 0) { - $html = ''; - $url = Url::fromRequest(); - - $view = $this->view(); - $idx = $filter->getId(); - $markUrl = clone($url); - $markUrl->setParam('fIdx', $idx); - - $removeUrl = clone $url; - $removeUrl->setParam('removeFilter', $idx); - $removeLink = ' ' . $view->icon('remove.png') . ''; - - /* - // Temporarilly removed, not implemented yet - $addUrl = clone($url); - $addUrl->setParam('addToId', $idx); - $addLink = ' ' . t('Operator') . ' (&, !, |)'; - $addLink .= ' ' . t('Expression') . ' (=, <, >, <=, >=)'; - */ - $selectedIndex = ($idx === $this->selectedIdx ? ' -<--' : ''); - $selectIndex = ' o'; + if ($level === 0 && $filter->isChain() && $filter->isEmpty()) { + return '
  • ' . $this->renderNewFilter() . '
'; + } if ($filter instanceof FilterChain) { - $parts = array(); - $i = 0; + return $this->renderFilterChain($filter, $level); + } elseif ($filter instanceof FilterExpression) { + return $this->renderFilterExpression($filter); + } else { + throw new ProgrammingError('Got a Filter being neither expression nor chain'); + } + } - foreach ($filter->filters() as $f) { - $i++; - $parts[] = $this->renderFilter($f, $level + 1); - } + protected function renderFilterChain(FilterChain $filter, $level) + { + $html = ' ' + . $this->selectOperator($filter) + . $this->removeLink($filter) + . ($filter->count() === 1 ? $this->stripLink($filter) : '') + . $this->addLink($filter); - $op = $this->select( - 'operator_' . $filter->getId(), - array( - 'OR' => 'OR', - 'AND' => 'AND', - 'NOT' => 'NOT' - ), - $filter->getOperatorName(), - array('style' => 'width: 5em') - ) . $removeLink; // Disabled: . ' ' . t('Add') . ': ' . $addLink; - $html .= ' '; - - if ($level === 0) { - $html .= $op; - if (! empty($parts)) { - $html .= '
  • ' - . implode('
  • ', $parts) - . '
'; - } - } else { - $html .= $op . "
    \n
  • \n" . implode("
  • \n
  • ", $parts) . "
  • \n
\n"; - } + if ($filter->isEmpty() && ! $this->addTo) { return $html; } - if ($filter instanceof FilterExpression) { - $u = $url->without($filter->getColumn()); - } else { - throw new ProgrammingError('Got a Filter being neither expression nor chain'); + $parts = array(); + foreach ($filter->filters() as $f) { + $parts[] = '
  • ' . $this->renderFilter($f, $level + 1) . '
  • '; } - $value = $filter->getExpression(); + + if ($this->addTo && $this->addTo == $filter->getId()) { + $parts[] = '
  • ' . $this->renderNewFilter() .$this->cancelLink(). '
  • '; + } + + $class = $level === 0 ? ' class="datafilter"' : ''; + $html .= sprintf( + "\n%s\n", + $class, + implode("", $parts) + ); + return $html; + } + + protected function renderFilterExpression(FilterExpression $filter) + { + if ($this->addTo && $this->addTo === $filter->getId()) { + return + preg_replace( + '/ class="autosubmit"/', + ' class="autofocus"', + $this->selectOperator() + ) + . '
    • ' + . $this->selectColumn($filter) + . $this->selectSign($filter) + . $this->text($filter) + . $this->removeLink($filter) + . $this->addLink($filter) + . '
    • ' + . $this->renderNewFilter() .$this->cancelLink() + . '
    ' + ; + } else { + return $this->selectColumn($filter) + . $this->selectSign($filter) + . $this->text($filter) + . $this->removeLink($filter) + . $this->addLink($filter) + ; + + } + } + + protected function text(Filter $filter = null) + { + $value = $filter === null ? '' : $filter->getExpression(); if (is_array($value)) { $value = '(' . implode('|', $value) . ')'; } - $html .= $this->selectColumn($filter) . ' ' - . $this->selectSign($filter) - . ' ' . $removeLink; + return sprintf( + '', + $this->elementId('value', $filter), + $value + ); + } - return $html; + protected function renderNewFilter() + { + $html = $this->selectColumn() + . $this->selectSign() + . $this->text(); + + return preg_replace( + '/ class="autosubmit"/', + '', + $html + ); } protected function arrayForSelect($array) @@ -179,9 +453,33 @@ class FilterEditor extends AbstractWidget return $res; } - protected function selectSign($filter) + protected function elementId($prefix, Filter $filter = null) + { + if ($filter === null) { + return $prefix . '_new_' . ($this->addTo ?: '0'); + } else { + return $prefix . '_' . $filter->getId(); + } + } + + protected function selectOperator(Filter $filter = null) + { + $ops = array( + 'AND' => 'AND', + 'OR' => 'OR', + 'NOT' => 'NOT' + ); + + return $this->select( + $this->elementId('operator', $filter), + $ops, + $filter === null ? null : $filter->getOperatorName(), + array('style' => 'width: 5em') + ); + } + + protected function selectSign(Filter $filter = null) { - $name = 'sign_' . $filter->getId(); $signs = array( '=' => '=', '!=' => '!=', @@ -192,17 +490,30 @@ class FilterEditor extends AbstractWidget ); return $this->select( - $name, + $this->elementId('sign', $filter), $signs, - $filter->getSign(), + $filter === null ? null : $filter->getSign(), array('style' => 'width: 4em') ); } - protected function selectColumn($filter) + + protected function selectColumn(Filter $filter = null) { - $name = 'column_' . $filter->getId(); - $cols = $this->arrayForSelect($this->query->getColumns()); - $active = $filter->getColumn(); + $active = $filter === null ? null : $filter->getColumn(); + + if ($this->query === null) { + return sprintf( + '', + $this->elementId('column', $filter), + $this->view()->escape($active) // Escape attribute? + ); + } + + if ($this->cachedColumnSelect === null) { + $this->cachedColumnSelect = $this->arrayForSelect($this->query->getColumns()); + asort($this->cachedColumnSelect); + } + $cols = $this->cachedColumnSelect; $seen = false; foreach ($cols as $k => & $v) { $v = str_replace('_', ' ', ucfirst($v)); @@ -215,32 +526,169 @@ class FilterEditor extends AbstractWidget $cols[$active] = str_replace('_', ' ', ucfirst(ltrim($active, '_'))); } - if ($this->query === null) { - return sprintf( - '', - $name, - $filter->getColumn() - ); - } else { - return $this->select( - $name, - $cols, - $active - ); + return $this->select($this->elementId('column', $filter), $cols, $active); + } + + protected function applyChanges($changes) + { + $filter = $this->filter; + $pairs = array(); + $addTo = null; + $add = array(); + foreach ($changes as $k => $v) { + if (preg_match('/^(column|value|sign|operator)((?:_new)?)_([\d-]+)$/', $k, $m)) { + if ($m[2] === '_new') { + if ($addTo !== null && $addTo !== $m[3]) { + throw new \Exception('F...U'); + } + $addTo = $m[3]; + $add[$m[1]] = $v; + } else { + $pairs[$m[3]][$m[1]] = $v; + } + } } + + $operators = array(); + foreach ($pairs as $id => $fs) { + if (array_key_exists('operator', $fs)) { + $operators[$id] = $fs['operator']; + } else { + $f = $filter->getById($id); + $f->setColumn($fs['column']); + if ($f->getSign() !== $fs['sign']) { + if ($f->isRootNode()) { + $filter = $f->setSign($fs['sign']); + } else { + $filter->replaceById($id, $f->setSign($fs['sign'])); + } + } + $f->setExpression($fs['value']); + } + } + + krsort($operators, version_compare(PHP_VERSION, '5.4.0') >= 0 ? SORT_NATURAL : SORT_REGULAR); + foreach ($operators as $id => $operator) { + $f = $filter->getById($id); + if ($f->getOperatorName() !== $operator) { + if ($f->isRootNode()) { + $filter = $f->setOperatorName($operator); + } else { + $filter->replaceById($id, $f->setOperatorName($operator)); + } + } + } + + if ($addTo !== null) { + if ($addTo === '0') { + $filter = Filter::expression($add['column'], $add['sign'], $add['value']); + } else { + $parent = $filter->getById($addTo); + $f = Filter::expression($add['column'], $add['sign'], $add['value']); + if ($add['operator']) { + switch($add['operator']) { + case 'AND': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::matchAll(clone $parent, $f); + } else { + $filter = $filter->replaceById($addTo, Filter::matchAll(clone $parent, $f)); + } + } else { + $parent->addFilter(Filter::matchAll($f)); + } + break; + case 'OR': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::matchAny(clone $parent, $f); + } else { + $filter = $filter->replaceById($addTo, Filter::matchAny(clone $parent, $f)); + } + } else { + $parent->addFilter(Filter::matchAny($f)); + } + break; + case 'NOT': + if ($parent->isExpression()) { + if ($parent->isRootNode()) { + $filter = Filter::not(Filter::matchAll($parent, $f)); + } else { + $filter = $filter->replaceById($addTo, Filter::not(Filter::matchAll($parent, $f))); + } + } else { + $parent->addFilter(Filter::not($f)); + } + break; + } + } else { + $parent->addFilter($f); + } + } + } + + return $filter; + } + + public function renderSearch() + { + $html = '
    '; + + if ($this->filter->isEmpty()) { + $title = t('Filter this list'); + } else { + $title = t('Modify this filter'); + if (! $this->filter->isEmpty()) { + $title .= ': ' . $this->filter; + } + } + return $html + . '' + . '' + . ''; } public function render() { - return '

    ' - . t('Modify this filter') - . '

    ' + if (! $this->url()->getParam('modifyFilter')) { + return $this->renderSearch() . $this->shorten($this->filter, 50); + } + return $this->renderSearch() . '
    ' . '
    • ' . $this->renderFilter($this->filter) - . '

    ' + . '' + . '
    ' + . '' + . '' + . '
    ' . '
    '; } + + protected function shorten($string, $length) + { + if (strlen($string) > $length) { + return substr($string, 0, $length) . '...'; + } + return $string; + } + + public function __toString() + { + try { + return $this->render(); + } catch (Exception $e) { + return 'ERROR in FilterEditor: ' . $e->getMessage(); + } + } } diff --git a/library/Icinga/Web/Widget/FilterWidget.php b/library/Icinga/Web/Widget/FilterWidget.php index 013f9b252..cf47ef581 100644 --- a/library/Icinga/Web/Widget/FilterWidget.php +++ b/library/Icinga/Web/Widget/FilterWidget.php @@ -88,7 +88,7 @@ class FilterWidget extends AbstractWidget $editorUrl->setParam('modifyFilter', true); if ($this->filter->isEmpty()) { $title = t('Filter this list'); - $txt = $view->icon('create.png'); + $txt = $view->icon('plus'); $remove = ''; } else { $txt = t('Filtered'); @@ -98,7 +98,7 @@ class FilterWidget extends AbstractWidget . '" title="' . t('Remove this filter') . '">' - . $view->icon('remove.png') + . $view->icon('cancel') . ''; } $filter = $this->filter->isEmpty() ? '' : ': ' . $this->filter; diff --git a/library/Icinga/Web/Widget/Tab.php b/library/Icinga/Web/Widget/Tab.php index 92a1a9954..a06389b98 100644 --- a/library/Icinga/Web/Widget/Tab.php +++ b/library/Icinga/Web/Widget/Tab.php @@ -85,7 +85,7 @@ class Tab extends AbstractWidget */ public function setIcon($icon) { - if (is_string($icon)) { + if (is_string($icon) && strpos($icon, '.') !== false) { $icon = Url::fromPath($icon); } $this->icon = $icon; @@ -197,27 +197,41 @@ class Tab extends AbstractWidget public function render() { $view = $this->view(); - $class = $this->active ? ' class="active" ' : ''; + $classes = array(); + if ($this->active) { + $classes[] = 'active'; + } $caption = $view->escape($this->title); + $tagParams = $this->tagParams; if ($this->icon !== null) { - $caption = $view->img($this->icon, array('class' => 'icon')) . ' ' . $caption; + if (strpos($this->icon, '.') === false) { + if ($tagParams && array_key_exists('class', $tagParams)) { + $tagParams['class'] .= ' icon-' . $this->icon; + } else { + $tagParams['class'] = 'icon-' . $this->icon; + } + } else { + $caption = $view->img($this->icon, array('class' => 'icon')) . $caption; + } } if ($this->url !== null) { $this->url->overwriteParams($this->urlParams); - $tagParams = ''; - if ($this->tagParams !== null) { - $tagParams = $view->propertiesToString($this->tagParams); + if ($tagParams !== null) { + $params = $view->propertiesToString($tagParams); + } else { + $params = ''; } $tab = sprintf( '%s', $this->url, - $tagParams, + $params, $caption ); } else { $tab = $caption; } + $class = empty($classes) ? '' : sprintf(' class="%s"', implode(' ', $classes)); return '
  • ' . $tab . "
  • \n"; } } diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php index 241b83556..a8cce1cc0 100644 --- a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php +++ b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php @@ -24,7 +24,7 @@ class DashboardAction implements Tabextension $tabs->addAsDropdown( 'dashboard', array( - 'icon' => 'img/icons/dashboard.png', + 'icon' => 'dashboard', 'title' => 'Add To Dashboard', 'url' => Url::fromPath('dashboard/addurl'), 'urlParams' => array( diff --git a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php index 46c55fad2..b5426ea47 100644 --- a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php +++ b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php @@ -40,13 +40,13 @@ class OutputFormat implements Tabextension self::TYPE_PDF => array( 'name' => 'pdf', 'title' => 'PDF', - 'icon' => 'img/icons/pdf.png', + 'icon' => 'file-pdf', 'urlParams' => array('format' => 'pdf'), ), self::TYPE_CSV => array( 'name' => 'csv', 'title' => 'CSV', - 'icon' => 'img/icons/csv.png', + 'icon' => 'file-excel', 'urlParams' => array('format' => 'csv') ), self::TYPE_JSON => array( diff --git a/library/Icinga/Web/Widget/Tabs.php b/library/Icinga/Web/Widget/Tabs.php index b2a34e0ec..72522282e 100644 --- a/library/Icinga/Web/Widget/Tabs.php +++ b/library/Icinga/Web/Widget/Tabs.php @@ -34,7 +34,7 @@ EOT; */ private $dropdownTpl = <<< 'EOT'