latham
2013-03-02 30fc1b7c564e4062266bd4b53fd95fa229f62f31
Silly Microsoft line endings removed to not error on Linux Subversion servers...


68 files modified
11206 ■■■■ changed files
install/tpl/server.ini.master 26 ●●●● patch | view | raw | blame | history
interface/lib/classes/aps_base.inc.php 204 ●●●● patch | view | raw | blame | history
interface/lib/classes/aps_crawler.inc.php 1182 ●●●● patch | view | raw | blame | history
interface/lib/classes/aps_guicontroller.inc.php 1680 ●●●● patch | view | raw | blame | history
interface/lib/classes/tform.inc.php 74 ●●●● patch | view | raw | blame | history
interface/web/admin/form/server_config.tform.php 60 ●●●● patch | view | raw | blame | history
interface/web/admin/lib/lang/en_server_config.lng 12 ●●●● patch | view | raw | blame | history
interface/web/admin/lib/menu.d/tpl_default.menu.php 30 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/iptables_edit.htm 132 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/iptables_list.htm 146 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_server_edit.htm 28 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_web_edit.htm 32 ●●●● patch | view | raw | blame | history
interface/web/admin/templates/system_config_branding_edit.html 42 ●●●● patch | view | raw | blame | history
interface/web/client/client_template_edit.php 194 ●●●● patch | view | raw | blame | history
interface/web/mail/templates/user_quota_stats_list.htm 102 ●●●● patch | view | raw | blame | history
interface/web/monitor/templates/show_sys_state.htm 48 ●●●● patch | view | raw | blame | history
interface/web/sites/aps_cron_apscrawler_if.php 124 ●●●● patch | view | raw | blame | history
interface/web/sites/aps_do_operation.php 224 ●●●● patch | view | raw | blame | history
interface/web/sites/aps_install_package.php 420 ●●●● patch | view | raw | blame | history
interface/web/sites/aps_installedpackages_list.php 282 ●●●● patch | view | raw | blame | history
interface/web/sites/aps_packagedetails_show.php 198 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/ar_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/bg_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/br_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/cz_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/el_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_aps.lng 114 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_aps_instances_list.lng 24 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_aps_packages_list.lng 14 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/en_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/es_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/fi_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/fr_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/hr_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/hu_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/id_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/it_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/nl_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/pl_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/pt_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/ro_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/ru_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/se_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/sk_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/lib/lang/tr_aps_update_packagelist.lng 12 ●●●● patch | view | raw | blame | history
interface/web/sites/list/aps_availablepackages.list.php 170 ●●●● patch | view | raw | blame | history
interface/web/sites/list/aps_installedpackages.list.php 164 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/aps_install_package.htm 110 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/aps_instances_list.htm 122 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/aps_packagedetails_show.htm 280 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/aps_packages_list.htm 108 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/web_aliasdomain_advanced.htm 72 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/web_subdomain_advanced.htm 74 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/css/screen/redmond/jquery-ui-1.8.16.custom.css 886 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/css/screen/tipsy.css 50 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/templates/monitor/show_sys_state.htm 48 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/templates/sites/aps_install_package.htm 110 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/templates/sites/aps_instances_list.htm 122 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/templates/sites/aps_packagedetails_show.htm 276 ●●●● patch | view | raw | blame | history
interface/web/themes/default-304/templates/sites/aps_packages_list.htm 98 ●●●● patch | view | raw | blame | history
interface/web/themes/default/CHANGELOG 62 ●●●● patch | view | raw | blame | history
interface/web/themes/default/TODO 14 ●●●● patch | view | raw | blame | history
interface/web/themes/default/css/jquery-ui-1.8.16.custom.css 890 ●●●● patch | view | raw | blame | history
interface/web/tools/lib/interface.d/tpl_default.menu.php 16 ●●●● patch | view | raw | blame | history
server/lib/classes/aps_base.inc.php 204 ●●●● patch | view | raw | blame | history
server/lib/classes/aps_installer.inc.php 1418 ●●●● patch | view | raw | blame | history
server/plugins-available/apache2_plugin.inc.php 34 ●●●● patch | view | raw | blame | history
server/plugins-available/aps_plugin.inc.php 234 ●●●● patch | view | raw | blame | history
install/tpl/server.ini.master
@@ -5,13 +5,13 @@
[server]
auto_network_configuration=n
ip_address=0.0.0.0
netmask=255.255.255.0
v6_prefix=
gateway=0.0.0.0
hostname=server1.domain.tld
nameservers=8.8.8.8,8.8.4.4
auto_network_configuration=n
ip_address=0.0.0.0
netmask=255.255.255.0
v6_prefix=
gateway=0.0.0.0
hostname=server1.domain.tld
nameservers=8.8.8.8,8.8.4.4
firewall=bastille
loglevel=2
backup_dir=/var/backup
@@ -42,12 +42,12 @@
[web]
server_type=apache
website_basedir=/var/www
website_path=/var/www/clients/client[client_id]/web[website_id]
website_symlinks=/var/www/[website_domain]/:/var/www/clients/client[client_id]/[website_domain]/
website_symlinks_rel=n
vhost_conf_dir=/etc/apache2/sites-available
vhost_conf_enabled_dir=/etc/apache2/sites-enabled
nginx_vhost_conf_dir=/etc/nginx/sites-available
website_path=/var/www/clients/client[client_id]/web[website_id]
website_symlinks=/var/www/[website_domain]/:/var/www/clients/client[client_id]/[website_domain]/
website_symlinks_rel=n
vhost_conf_dir=/etc/apache2/sites-available
vhost_conf_enabled_dir=/etc/apache2/sites-enabled
nginx_vhost_conf_dir=/etc/nginx/sites-available
nginx_vhost_conf_enabled_dir=/etc/nginx/sites-enabled
security_level=20
user=www-data
interface/lib/classes/aps_base.inc.php
@@ -1,103 +1,103 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Constants describing instances
define('INSTANCE_PENDING', 0);
define('INSTANCE_INSTALL', 1);
define('INSTANCE_ERROR', 2);
define('INSTANCE_SUCCESS', 3);
define('INSTANCE_REMOVE', 4);
// Constants describing packages
define('PACKAGE_LOCKED', 1);
define('PACKAGE_ENABLED', 2);
define('PACKAGE_OUTDATED', 3);
define('PACKAGE_ERROR_NOMETA', 4);
class ApsBase
{
    protected $log_prefix = '';
    protected $fetch_url = '';
    protected $aps_version = '';
    protected $packages_dir = '';
    protected $temp_pkg_dir = '';
    protected $interface_pkg_dir = '';
    protected $interface_mode = false; // server mode by default
    /**
     * Constructor
     *
     * @param $app the application instance (db handle + log method)
     * @param $interface_mode act in interface (true) or server mode (false)
     * @param $log_prefix a prefix to set before all log entries
     */
    public function __construct($app, $log_prefix = 'APS: ', $interface_mode = false)
    {
        $this->log_prefix = $log_prefix;
        $this->interface_mode = $interface_mode;
        $this->fetch_url = 'apscatalog.com';
        $this->aps_version = '1';
        $this->packages_dir = ISPC_ROOT_PATH.'/aps_packages';
        $this->interface_pkg_dir = ISPC_ROOT_PATH.'/web/sites/aps_meta_packages';
    }
    /**
     * Converts a given value to it's native representation in 1024 units
     *
     * @param $value the size to convert
     * @return integer and string
     */
    public function convertSize($value)
    {
        $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
        return @round($value/pow(1024, ($i = floor(log($value, 1024)))), 2).' '.$unit[$i];
    }
    /**
     * Determine a specific xpath from a given SimpleXMLElement handle. If the
     * element is found, it's string representation is returned. If not,
     * the return value will stay empty
     *
     * @param $xml_handle the SimpleXMLElement handle
     * @param $query the XPath query
     * @param $array define whether to return an array or a string
     * @return $ret the return string
     */
    protected function getXPathValue($xml_handle, $query, $array = false)
    {
        $ret = '';
        $xp_result = @($xml_handle->xpath($query)) ? $xml_handle->xpath($query) : false;
        if($xp_result !== false) $ret = (($array === false) ? (string)$xp_result[0] : $xp_result);
        return $ret;
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Constants describing instances
define('INSTANCE_PENDING', 0);
define('INSTANCE_INSTALL', 1);
define('INSTANCE_ERROR', 2);
define('INSTANCE_SUCCESS', 3);
define('INSTANCE_REMOVE', 4);
// Constants describing packages
define('PACKAGE_LOCKED', 1);
define('PACKAGE_ENABLED', 2);
define('PACKAGE_OUTDATED', 3);
define('PACKAGE_ERROR_NOMETA', 4);
class ApsBase
{
    protected $log_prefix = '';
    protected $fetch_url = '';
    protected $aps_version = '';
    protected $packages_dir = '';
    protected $temp_pkg_dir = '';
    protected $interface_pkg_dir = '';
    protected $interface_mode = false; // server mode by default
    /**
     * Constructor
     *
     * @param $app the application instance (db handle + log method)
     * @param $interface_mode act in interface (true) or server mode (false)
     * @param $log_prefix a prefix to set before all log entries
     */
    public function __construct($app, $log_prefix = 'APS: ', $interface_mode = false)
    {
        $this->log_prefix = $log_prefix;
        $this->interface_mode = $interface_mode;
        $this->fetch_url = 'apscatalog.com';
        $this->aps_version = '1';
        $this->packages_dir = ISPC_ROOT_PATH.'/aps_packages';
        $this->interface_pkg_dir = ISPC_ROOT_PATH.'/web/sites/aps_meta_packages';
    }
    /**
     * Converts a given value to it's native representation in 1024 units
     *
     * @param $value the size to convert
     * @return integer and string
     */
    public function convertSize($value)
    {
        $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
        return @round($value/pow(1024, ($i = floor(log($value, 1024)))), 2).' '.$unit[$i];
    }
    /**
     * Determine a specific xpath from a given SimpleXMLElement handle. If the
     * element is found, it's string representation is returned. If not,
     * the return value will stay empty
     *
     * @param $xml_handle the SimpleXMLElement handle
     * @param $query the XPath query
     * @param $array define whether to return an array or a string
     * @return $ret the return string
     */
    protected function getXPathValue($xml_handle, $query, $array = false)
    {
        $ret = '';
        $xp_result = @($xml_handle->xpath($query)) ? $xml_handle->xpath($query) : false;
        if($xp_result !== false) $ret = (($array === false) ? (string)$xp_result[0] : $xp_result);
        return $ret;
    }
}
?>
interface/lib/classes/aps_crawler.inc.php
@@ -1,592 +1,592 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
@set_time_limit(0);
@ignore_user_abort(1);
class ApsCrawler extends ApsBase
{
   //public $app_download_url_list = array();
   /**
    * Constructor
    *
    * @param $app the application instance (db handle + log method)
    * @param $interface_mode act in interface (true) or server mode (false)
    */
    public function __construct($app, $interface_mode = false)
    {
        parent::__construct($app, 'APS crawler: ', $interface_mode);
    }
    /**
     * Before the cron is executed, make sure all necessary options are set
     * and all functions (i.e. cURL) are available
     */
    private function checkRequirements()
    {
        global $app;
        try
        {
            // Check if allow_url_fopen is enabled
            if(!@ini_get('allow_url_fopen')) throw new Exception('allow_url_fopen is not enabled');
            // Check if the cURL module is available
            if(!function_exists('curl_version')) throw new Exception('cURL is not available');
            // Check if used folders are writable
            if($this->interface_mode)
            {
                if(!is_writable($this->interface_pkg_dir))
                    throw new Exception('the folder '.basename($this->interface_pkg_dir).' is not writable');
            }
            else
            {
                if(!is_writable($this->packages_dir))
                    throw new Exception('the folder '.basename($this->packages_dir).' is not writable');
            }
            return true;
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.'Aborting execution because '.$e->getMessage(), LOGLEVEL_ERROR);
            return false;
        }
    }
    /**
     * Remove a directory recursively
     * In case of error be silent
     *
     * @param $dir the directory to remove
     */
    private function removeDirectory($dir)
    {
        if(is_dir($dir))
        {
            $files = scandir($dir);
            foreach($files as $file)
            {
                if($file != '.' && $file != '..')
                    if(filetype($dir.'/'.$file) == 'dir') $this->removeDirectory($dir.'/'.$file);
                    else @unlink($dir.'/'.$file);
            }
            reset($files);
            @rmdir($dir);
        }
    }
    /**
     * Fetch HTML data from one or more given URLs
     * If a string is given, a string is returned, if an array of URLs should
     * be fetched, the responses of the parallel queries are returned as array
     *
     * @param $input the string or array to fetch
     * @return $ret a query response string or array
     */
    private function fetchPage($input)
    {
        $ret = array();
        $url = array();
        $conn = array();
        // Make sure we are working with an array, further on
        if(!is_array($input)) $url[] = $input;
        else $url = $input;
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        for($i = 0; $i < count($url); $i++)
        {
            $conn[$i] = curl_init('http://'.$this->fetch_url.$url[$i]);
            curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Get the response(s)
        for($i = 0; $i < count($url); $i++)
        {
            $ret[$i] = curl_multi_getcontent($conn[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
        if(count($url) == 1) $ret = $ret[0];
        return $ret;
    }
    /**
     * Fetch binary data from a given array
     * The data is retrieved in binary mode and
     * then directly written to an output file
     *
     * @param $input a specially structed array
     * @see $this->startUpdate()
     */
    private function fetchFiles($input)
    {
        $fh = array();
        $url = array();
        $conn = array();
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        // Process each app
        for($i = 0; $i < count($input); $i++)
        {
            $conn[$i] = curl_init($input[$i]['url']);
            $fh[$i] = fopen($input[$i]['localtarget'], 'wb');
            curl_setopt($conn[$i], CURLOPT_BINARYTRANSFER, true);
            curl_setopt($conn[$i], CURLOPT_FILE, $fh[$i]);
            curl_setopt($conn[$i], CURLOPT_TIMEOUT, 0);
            curl_setopt($conn[$i], CURLOPT_FAILONERROR, 1);
            curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, 1);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Close the handles
        for($i = 0; $i < count($input); $i++)
        {
            fclose($fh[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
    }
    /**
     * A method to build query URLs out of a list of vendors
     *
    */
    private function formatVendorCallback($array_item)
    {
        $array_item = str_replace(' ', '%20', $array_item);
        $array_item = str_replace('http://', '', $array_item);
        $array_item = '/'.$this->aps_version.'.atom?vendor='.$array_item.'&pageSize=100';
        return($array_item);
    }
    /**
     * The main method which performs the actual crawling
     */
    public function startCrawler()
    {
        global $app;
        try
        {
            // Make sure the requirements are given so that this script can execute
            $req_ret = $this->checkRequirements();
            if(!$req_ret) return false;
            // Execute the open task and first fetch all vendors (APS catalog API 1.1, p. 12)
            $app->log($this->log_prefix.'Fetching data from '.$this->fetch_url);
            $vendor_page = $this->fetchPage('/all-app/'); //$vendor_page = $this->fetchPage('/'.$this->aps_version.'/');
            preg_match_all("/\<a href=\"(.+)\/\" class=\"vendor\"/i", $vendor_page, $matches);
            $vendors = array_map('urldecode', $matches[1]);
            if(!$vendors) throw new Exception('Unable to fetch vendors. Aborting');
            // Format all vendors for further processing (i.e. typo3.org -> /1.atom?vendor=typo3.org&pageSize=100
            //array_walk($vendors, array($this, 'formatVendorCallback'));
            if(is_array($vendors)) {
                foreach($vendors as $key => $array_item) {
                    $vendors[$key] = $this->formatVendorCallback($array_item);
                }
            }
            // Process all vendors in chunks of 50 entries
            $vendor_chunks = array_chunk($vendors, 50);
            //var_dump($vendor_chunks);
            // Get all known apps from the database and the highest known version
            // Note: A dirty hack is used for numerical sorting of the VARCHAR field Version: +0 -> cast
            // A longer but typesafe way would be: ORDER BY CAST(REPLACE(Version, '.', '') AS UNSIGNED) DESC
            $existing_apps = $app->db->queryAllRecords("SELECT * FROM (
                SELECT name AS Name, CONCAT(version, '-', CAST(`release` AS CHAR)) AS CurrentVersion
                FROM aps_packages ORDER BY REPLACE(version, '.', '')+0 DESC, `release` DESC
                ) as Versions GROUP BY name");
            //var_dump($existing_apps);
            // Used for statistics later
            $apps_in_repo = 0;
            $apps_updated = 0;
            $apps_downloaded = 0;
            $apps_to_dl = array();
            for($i = 0; $i < count($vendor_chunks); $i++)
            {
                // Fetch all apps for the current chunk of vendors
                $apps = $this->fetchPage($vendor_chunks[$i]);
                for($j = 0; $j < count($apps); $j++)
                {
                    // Before parsing, make sure it's worth the work by checking if at least one app exists
                    $apps_count = substr_count($apps[$j], '<opensearch:totalResults>0</opensearch:totalResults>');
                    if($apps_count == 0) // obviously this vendor provides one or more apps
                    {
                        // Rename namespaces and register them
                        $xml = str_replace("xmlns=", "ns=", $apps[$j]);
                        $sxe = new SimpleXMLElement($xml);
                        $namespaces = $sxe->getDocNamespaces(true);
                        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
                        // Fetching values of interest
                        $app_name = parent::getXPathValue($sxe, 'entry[position()=1]/a:name');
                        $app_version = parent::getXPathValue($sxe, 'entry[position()=1]/a:version');
                        $app_release = parent::getXPathValue($sxe, 'entry[position()=1]/a:release');
                        // Find out a (possibly) existing package version
                        $ex_ver = '';
                        /*
                        array_walk($existing_apps,
                            create_function('$v, $k, $ex_ver', 'if($v["Name"] == "'.$app_name.'") $ex_ver = $v["CurrentVersion"];'), &$ex_ver);
                        */
                        if(is_array($existing_apps)) {
                            foreach($existing_apps as $k => $v) {
                                if($v["Name"] == $app_name) $ex_ver = $v["CurrentVersion"];
                            }
                        }
                        $new_ver = $app_version.'-'.$app_release;
                        $local_intf_folder = $this->interface_pkg_dir.'/'.$app_name.'-'.$new_ver.'.app.zip/';
                        // Proceed if a newer or at least equal version has been found with server mode or
                        // interface mode is activated and there are no valid APP-META.xml and PKG_URL existing yet
                        if((!$this->interface_mode && version_compare($new_ver, $ex_ver) >= 0) || ($this->interface_mode && (!file_exists($local_intf_folder.'APP-META.xml') || filesize($local_intf_folder.'APP-META.xml') == 0 || !file_exists($local_intf_folder.'PKG_URL') || filesize($local_intf_folder.'PKG_URL') == 0))){
                            // Check if we already have an old version of this app
                            if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1) $apps_updated++;
                            $app_dl = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='aps']/@href");
                            $app_filesize = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='aps']/@length");
                            $app_metafile = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='meta']/@href");
                            //$this->app_download_url_list[$app_name.'-'.$new_ver.'.app.zip'] = $app_dl;
                            // Skip ASP.net packages because they can't be used at all
                            $asp_handler = parent::getXPathValue($sxe, '//aspnet:handler');
                            $asp_permissions = parent::getXPathValue($sxe, '//aspnet:permissions');
                            $asp_version = parent::getXPathValue($sxe, '//aspnet:version');
                            if(!empty($asp_handler) || !empty($asp_permissions) || !empty($asp_version)) continue;
                            // Interface mode (download only parts)
                            if($this->interface_mode)
                            {
                                // Delete an obviously out-dated version from the system and DB
                                if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1)
                                {
                                    $old_folder = $this->interface_pkg_dir.'/'.$app_name.'-'.$ex_ver.'.app.zip';
                                    if(file_exists($old_folder)) $this->removeDirectory($old_folder);
                                    /*
                                    $app->db->query("UPDATE aps_packages SET package_status = '".PACKAGE_OUTDATED."' WHERE name = '".
                                        $app->db->quote($app_name)."' AND CONCAT(version, '-', CAST(`release` AS CHAR)) = '".
                                        $app->db->quote($ex_ver)."';");
                                    */
                                    $tmp = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE name = '".
                                        $app->db->quote($app_name)."' AND CONCAT(version, '-', CAST(`release` AS CHAR)) = '".
                                        $app->db->quote($ex_ver)."';");
                                    $app->db->datalogUpdate('aps_packages', "package_status = ".PACKAGE_OUTDATED, 'id', $tmp['id']);
                                    unset($tmp);
                                }
                                // Create the local folder if not yet existing
                                if(!file_exists($local_intf_folder)) @mkdir($local_intf_folder, 0777, true);
                                // Save the package URL in an extra file because it's not part of the APP-META.xml file
                                @file_put_contents($local_intf_folder.'PKG_URL', $app_dl);
                                // Download the meta file
                                $local_metafile = $local_intf_folder.'APP-META.xml';
                                if(!file_exists($local_metafile) || filesize($local_metafile) == 0)
                                {
                                    $apps_to_dl[] = array('name' => 'APP-META.xml',
                                                          'url' => $app_metafile,
                                                          'filesize' => 0,
                                                          'localtarget' => $local_metafile);
                                    $apps_downloaded++;
                                }
                                // Download package license
                                $license = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='eula']/@href");
                                if($license != '')
                                {
                                    $local_license = $local_intf_folder.'LICENSE';
                                    if(!file_exists($local_license) || filesize($local_license) == 0)
                                    {
                                        $apps_to_dl[] = array('name' => basename($license),
                                                              'url' => $license,
                                                              'filesize' => 0,
                                                              'localtarget' => $local_license);
                                    }
                                }
                                // Download package icon
                                $icon = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='icon']/@href");
                                if($icon != '')
                                {
                                    $local_icon = $local_intf_folder.basename($icon);
                                    if(!file_exists($local_icon) || filesize($local_icon) == 0)
                                    {
                                        $apps_to_dl[] = array('name' => basename($icon),
                                                              'url' => $icon,
                                                              'filesize' => 0,
                                                              'localtarget' => $local_icon);
                                    }
                                }
                                // Download available screenshots
                                $screenshots = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='screenshot']", true);
                                if(!empty($screenshots))
                                {
                                    foreach($screenshots as $screen)
                                    {
                                        $local_screen = $local_intf_folder.basename($screen['href']);
                                        if(!file_exists($local_screen) || filesize($local_screen) == 0)
                                        {
                                            $apps_to_dl[] = array('name' => basename($screen['href']),
                                                                  'url' => $screen['href'],
                                                                  'filesize' => 0,
                                                                  'localtarget' => $local_screen);
                                        }
                                    }
                                }
                            }
                            else // Server mode (download whole ZIP archive)
                            {
                                // Delete an obviously out-dated version from the system
                                if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1)
                                {
                                    $old_file = $this->packages_dir.'/'.$app_name.'-'.$ex_ver.'.app.zip';
                                    if(file_exists($old_file)) $this->removeDirectory($old_file);
                                }
                                // Attention: $new_ver can also be == $ex_ver (according to version_compare >= 0)
                                $local_zip = $this->packages_dir.'/'.$app_name.'-'.$new_ver.'.app.zip';
                                // Before re-downloading a file, make sure it's not yet existing on HDD (due to DB inconsistency)
                                if((file_exists($local_zip) && (filesize($local_zip) == $app_filesize)) === false)
                                {
                                    $apps_to_dl[] = array('name' => $app_name,
                                                          'url' => $app_dl,
                                                          'filesize' => $app_filesize,
                                                          'localtarget' => $local_zip);
                                    $apps_downloaded++;
                                }
                            }
                        }
                        unset($sxe);
                        $apps_in_repo++;
                    }
                }
                //var_dump($apps);
                // For memory reasons, unset the current vendor and his apps
                unset($apps);
            }
            // Shuffle the download array (in order to compensate unexpected php aborts)
            shuffle($apps_to_dl);
            // After collecting all provisioned apps, download them
            $apps_to_dl_chunks = array_chunk($apps_to_dl, 10);
            for($i = 0; $i < count($apps_to_dl_chunks); $i++)
            {
                $this->fetchFiles($apps_to_dl_chunks[$i]);
                // Check the integrity of all downloaded files
                // but exclude cases where no filesize is available (i.e. screenshot or metafile download)
                for($j = 0; $j < count($apps_to_dl_chunks[$i]); $j++)
                {
                    if($apps_to_dl_chunks[$i][$j]['filesize'] != 0 &&
                       $apps_to_dl_chunks[$i][$j]['filesize'] != filesize($apps_to_dl_chunks[$i][$j]['localtarget']))
                    {
                            $app->log($this->log_prefix.' The filesize of the package "'.
                                $apps_to_dl_chunks[$i][$j]['name'].'" is wrong. Download failure?', LOGLEVEL_WARN);
                    }
                }
            }
            $app->log($this->log_prefix.'Processed '.$apps_in_repo.
                ' apps from the repo. Downloaded '.$apps_updated.
                ' updates, '.$apps_downloaded.' new apps');
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            return false;
        }
    }
    /**
     * Read in all possible packages from the interface packages folder and
     * check if they are not ASP.net code (as this can't be processed).
     *
     * Note: There's no need to check if the packages to register are newer
     * than those in the database because this already happended in startCrawler()
     */
    public function parseFolderToDB()
    {
        global $app;
        try
        {
            // This method must be used in interface mode
            if(!$this->interface_mode) return false;
            $pkg_list = array();
            // Read in every package having a correct filename
            $temp_handle = @dir($this->interface_pkg_dir);
            if(!$temp_handle) throw new Exception('The temp directory is not accessible');
            while($folder = $temp_handle->read())
                if(substr($folder, -8) == '.app.zip') $pkg_list[] = $folder;
            $temp_handle->close();
            // If no packages are available -> exception (because at this point there should exist packages)
            if(empty($pkg_list)) throw new Exception('No packages to read in');
            // Get registered packages and mark non-existant packages with an error code to omit the install
            $existing_packages = array();
            $path_query = $app->db->queryAllRecords('SELECT path AS Path FROM aps_packages;');
            foreach($path_query as $path) $existing_packages[] = $path['Path'];
            $diff = array_diff($existing_packages, $pkg_list);
            foreach($diff as $todelete) {
                /*$app->db->query("UPDATE aps_packages SET package_status = '".PACKAGE_ERROR_NOMETA."'
                    WHERE path = '".$app->db->quote($todelete)."';");*/
                $tmp = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE path = '".$app->db->quote($todelete)."';");
                $app->db->datalogUpdate('aps_packages', "package_status = ".PACKAGE_ERROR_NOMETA, 'id', $tmp['id']);
                unset($tmp);
            }
            // Register all new packages
            $new_packages = array_diff($pkg_list, $existing_packages);
            foreach($new_packages as $pkg)
            {
                // Load in meta file if existing and register its namespaces
                $metafile = $this->interface_pkg_dir.'/'.$pkg.'/APP-META.xml';
                if(!file_exists($metafile))
                {
                    $app->log($this->log_prefix.'Cannot read metadata from '.$pkg, LOGLEVEL_ERROR);
                    continue;
                }
                $metadata = file_get_contents($metafile);
                $metadata = str_replace("xmlns=", "ns=", $metadata);
                $sxe = new SimpleXMLElement($metadata);
                $namespaces = $sxe->getDocNamespaces(true);
                foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
                // Insert the new package
                $pkg_name = parent::getXPathValue($sxe, 'name');
                $pkg_category = parent::getXPathValue($sxe, '//category');
                $pkg_version = parent::getXPathValue($sxe, 'version');
                $pkg_release = parent::getXPathValue($sxe, 'release');
                //$pkg_url = $this->app_download_url_list[$pkg];
                $pkg_url = @file_get_contents($this->interface_pkg_dir.'/'.$pkg.'/PKG_URL');
                /*
                $app->db->query("INSERT INTO `aps_packages`
                    (`path`, `name`, `category`, `version`, `release`, `package_status`) VALUES
                    ('".$app->db->quote($pkg)."', '".$app->db->quote($pkg_name)."',
                    '".$app->db->quote($pkg_category)."', '".$app->db->quote($pkg_version)."',
                    ".$app->db->quote($pkg_release).", ".PACKAGE_ENABLED.");");
                */
                // Insert only if data is complete
                if($pkg != '' && $pkg_name != '' && $pkg_category != '' && $pkg_version != '' && $pkg_release != '' && $pkg_url){
                    $insert_data = "(`path`, `name`, `category`, `version`, `release`, `package_url`, `package_status`) VALUES
                    ('".$app->db->quote($pkg)."', '".$app->db->quote($pkg_name)."',
                    '".$app->db->quote($pkg_category)."', '".$app->db->quote($pkg_version)."',
                    ".$app->db->quote($pkg_release).", '".$app->db->quote($pkg_url)."', ".PACKAGE_ENABLED.");";
                    $app->db->datalogInsert('aps_packages', $insert_data, 'id');
                } else {
                    if(file_exists($this->interface_pkg_dir.'/'.$pkg)) $this->removeDirectory($this->interface_pkg_dir.'/'.$pkg);
                }
            }
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            $app->error($e->getMessage());
            return false;
        }
    }
    /**
     * Add missing package URLs to database
     */
    public function fixURLs()
    {
        global $app;
        try
        {
            // This method must be used in interface mode
            if(!$this->interface_mode) return false;
            $incomplete_pkgs = $app->db->queryAllRecords("SELECT * FROM aps_packages WHERE package_url = ''");
            if(is_array($incomplete_pkgs) && !empty($incomplete_pkgs)){
                foreach($incomplete_pkgs as $incomplete_pkg){
                    $pkg_url = @file_get_contents($this->interface_pkg_dir.'/'.$incomplete_pkg['path'].'/PKG_URL');
                    if($pkg_url != ''){
                        $app->db->datalogUpdate('aps_packages', "package_url = '".$pkg_url."'", 'id', $incomplete_pkg['id']);
                    }
                }
            }
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            $app->error($e->getMessage());
            return false;
        }
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
@set_time_limit(0);
@ignore_user_abort(1);
class ApsCrawler extends ApsBase
{
   //public $app_download_url_list = array();
   /**
    * Constructor
    *
    * @param $app the application instance (db handle + log method)
    * @param $interface_mode act in interface (true) or server mode (false)
    */
    public function __construct($app, $interface_mode = false)
    {
        parent::__construct($app, 'APS crawler: ', $interface_mode);
    }
    /**
     * Before the cron is executed, make sure all necessary options are set
     * and all functions (i.e. cURL) are available
     */
    private function checkRequirements()
    {
        global $app;
        try
        {
            // Check if allow_url_fopen is enabled
            if(!@ini_get('allow_url_fopen')) throw new Exception('allow_url_fopen is not enabled');
            // Check if the cURL module is available
            if(!function_exists('curl_version')) throw new Exception('cURL is not available');
            // Check if used folders are writable
            if($this->interface_mode)
            {
                if(!is_writable($this->interface_pkg_dir))
                    throw new Exception('the folder '.basename($this->interface_pkg_dir).' is not writable');
            }
            else
            {
                if(!is_writable($this->packages_dir))
                    throw new Exception('the folder '.basename($this->packages_dir).' is not writable');
            }
            return true;
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.'Aborting execution because '.$e->getMessage(), LOGLEVEL_ERROR);
            return false;
        }
    }
    /**
     * Remove a directory recursively
     * In case of error be silent
     *
     * @param $dir the directory to remove
     */
    private function removeDirectory($dir)
    {
        if(is_dir($dir))
        {
            $files = scandir($dir);
            foreach($files as $file)
            {
                if($file != '.' && $file != '..')
                    if(filetype($dir.'/'.$file) == 'dir') $this->removeDirectory($dir.'/'.$file);
                    else @unlink($dir.'/'.$file);
            }
            reset($files);
            @rmdir($dir);
        }
    }
    /**
     * Fetch HTML data from one or more given URLs
     * If a string is given, a string is returned, if an array of URLs should
     * be fetched, the responses of the parallel queries are returned as array
     *
     * @param $input the string or array to fetch
     * @return $ret a query response string or array
     */
    private function fetchPage($input)
    {
        $ret = array();
        $url = array();
        $conn = array();
        // Make sure we are working with an array, further on
        if(!is_array($input)) $url[] = $input;
        else $url = $input;
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        for($i = 0; $i < count($url); $i++)
        {
            $conn[$i] = curl_init('http://'.$this->fetch_url.$url[$i]);
            curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Get the response(s)
        for($i = 0; $i < count($url); $i++)
        {
            $ret[$i] = curl_multi_getcontent($conn[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
        if(count($url) == 1) $ret = $ret[0];
        return $ret;
    }
    /**
     * Fetch binary data from a given array
     * The data is retrieved in binary mode and
     * then directly written to an output file
     *
     * @param $input a specially structed array
     * @see $this->startUpdate()
     */
    private function fetchFiles($input)
    {
        $fh = array();
        $url = array();
        $conn = array();
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        // Process each app
        for($i = 0; $i < count($input); $i++)
        {
            $conn[$i] = curl_init($input[$i]['url']);
            $fh[$i] = fopen($input[$i]['localtarget'], 'wb');
            curl_setopt($conn[$i], CURLOPT_BINARYTRANSFER, true);
            curl_setopt($conn[$i], CURLOPT_FILE, $fh[$i]);
            curl_setopt($conn[$i], CURLOPT_TIMEOUT, 0);
            curl_setopt($conn[$i], CURLOPT_FAILONERROR, 1);
            curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, 1);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Close the handles
        for($i = 0; $i < count($input); $i++)
        {
            fclose($fh[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
    }
    /**
     * A method to build query URLs out of a list of vendors
     *
    */
    private function formatVendorCallback($array_item)
    {
        $array_item = str_replace(' ', '%20', $array_item);
        $array_item = str_replace('http://', '', $array_item);
        $array_item = '/'.$this->aps_version.'.atom?vendor='.$array_item.'&pageSize=100';
        return($array_item);
    }
    /**
     * The main method which performs the actual crawling
     */
    public function startCrawler()
    {
        global $app;
        try
        {
            // Make sure the requirements are given so that this script can execute
            $req_ret = $this->checkRequirements();
            if(!$req_ret) return false;
            // Execute the open task and first fetch all vendors (APS catalog API 1.1, p. 12)
            $app->log($this->log_prefix.'Fetching data from '.$this->fetch_url);
            $vendor_page = $this->fetchPage('/all-app/'); //$vendor_page = $this->fetchPage('/'.$this->aps_version.'/');
            preg_match_all("/\<a href=\"(.+)\/\" class=\"vendor\"/i", $vendor_page, $matches);
            $vendors = array_map('urldecode', $matches[1]);
            if(!$vendors) throw new Exception('Unable to fetch vendors. Aborting');
            // Format all vendors for further processing (i.e. typo3.org -> /1.atom?vendor=typo3.org&pageSize=100
            //array_walk($vendors, array($this, 'formatVendorCallback'));
            if(is_array($vendors)) {
                foreach($vendors as $key => $array_item) {
                    $vendors[$key] = $this->formatVendorCallback($array_item);
                }
            }
            // Process all vendors in chunks of 50 entries
            $vendor_chunks = array_chunk($vendors, 50);
            //var_dump($vendor_chunks);
            // Get all known apps from the database and the highest known version
            // Note: A dirty hack is used for numerical sorting of the VARCHAR field Version: +0 -> cast
            // A longer but typesafe way would be: ORDER BY CAST(REPLACE(Version, '.', '') AS UNSIGNED) DESC
            $existing_apps = $app->db->queryAllRecords("SELECT * FROM (
                SELECT name AS Name, CONCAT(version, '-', CAST(`release` AS CHAR)) AS CurrentVersion
                FROM aps_packages ORDER BY REPLACE(version, '.', '')+0 DESC, `release` DESC
                ) as Versions GROUP BY name");
            //var_dump($existing_apps);
            // Used for statistics later
            $apps_in_repo = 0;
            $apps_updated = 0;
            $apps_downloaded = 0;
            $apps_to_dl = array();
            for($i = 0; $i < count($vendor_chunks); $i++)
            {
                // Fetch all apps for the current chunk of vendors
                $apps = $this->fetchPage($vendor_chunks[$i]);
                for($j = 0; $j < count($apps); $j++)
                {
                    // Before parsing, make sure it's worth the work by checking if at least one app exists
                    $apps_count = substr_count($apps[$j], '<opensearch:totalResults>0</opensearch:totalResults>');
                    if($apps_count == 0) // obviously this vendor provides one or more apps
                    {
                        // Rename namespaces and register them
                        $xml = str_replace("xmlns=", "ns=", $apps[$j]);
                        $sxe = new SimpleXMLElement($xml);
                        $namespaces = $sxe->getDocNamespaces(true);
                        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
                        // Fetching values of interest
                        $app_name = parent::getXPathValue($sxe, 'entry[position()=1]/a:name');
                        $app_version = parent::getXPathValue($sxe, 'entry[position()=1]/a:version');
                        $app_release = parent::getXPathValue($sxe, 'entry[position()=1]/a:release');
                        // Find out a (possibly) existing package version
                        $ex_ver = '';
                        /*
                        array_walk($existing_apps,
                            create_function('$v, $k, $ex_ver', 'if($v["Name"] == "'.$app_name.'") $ex_ver = $v["CurrentVersion"];'), &$ex_ver);
                        */
                        if(is_array($existing_apps)) {
                            foreach($existing_apps as $k => $v) {
                                if($v["Name"] == $app_name) $ex_ver = $v["CurrentVersion"];
                            }
                        }
                        $new_ver = $app_version.'-'.$app_release;
                        $local_intf_folder = $this->interface_pkg_dir.'/'.$app_name.'-'.$new_ver.'.app.zip/';
                        // Proceed if a newer or at least equal version has been found with server mode or
                        // interface mode is activated and there are no valid APP-META.xml and PKG_URL existing yet
                        if((!$this->interface_mode && version_compare($new_ver, $ex_ver) >= 0) || ($this->interface_mode && (!file_exists($local_intf_folder.'APP-META.xml') || filesize($local_intf_folder.'APP-META.xml') == 0 || !file_exists($local_intf_folder.'PKG_URL') || filesize($local_intf_folder.'PKG_URL') == 0))){
                            // Check if we already have an old version of this app
                            if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1) $apps_updated++;
                            $app_dl = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='aps']/@href");
                            $app_filesize = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='aps']/@length");
                            $app_metafile = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='meta']/@href");
                            //$this->app_download_url_list[$app_name.'-'.$new_ver.'.app.zip'] = $app_dl;
                            // Skip ASP.net packages because they can't be used at all
                            $asp_handler = parent::getXPathValue($sxe, '//aspnet:handler');
                            $asp_permissions = parent::getXPathValue($sxe, '//aspnet:permissions');
                            $asp_version = parent::getXPathValue($sxe, '//aspnet:version');
                            if(!empty($asp_handler) || !empty($asp_permissions) || !empty($asp_version)) continue;
                            // Interface mode (download only parts)
                            if($this->interface_mode)
                            {
                                // Delete an obviously out-dated version from the system and DB
                                if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1)
                                {
                                    $old_folder = $this->interface_pkg_dir.'/'.$app_name.'-'.$ex_ver.'.app.zip';
                                    if(file_exists($old_folder)) $this->removeDirectory($old_folder);
                                    /*
                                    $app->db->query("UPDATE aps_packages SET package_status = '".PACKAGE_OUTDATED."' WHERE name = '".
                                        $app->db->quote($app_name)."' AND CONCAT(version, '-', CAST(`release` AS CHAR)) = '".
                                        $app->db->quote($ex_ver)."';");
                                    */
                                    $tmp = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE name = '".
                                        $app->db->quote($app_name)."' AND CONCAT(version, '-', CAST(`release` AS CHAR)) = '".
                                        $app->db->quote($ex_ver)."';");
                                    $app->db->datalogUpdate('aps_packages', "package_status = ".PACKAGE_OUTDATED, 'id', $tmp['id']);
                                    unset($tmp);
                                }
                                // Create the local folder if not yet existing
                                if(!file_exists($local_intf_folder)) @mkdir($local_intf_folder, 0777, true);
                                // Save the package URL in an extra file because it's not part of the APP-META.xml file
                                @file_put_contents($local_intf_folder.'PKG_URL', $app_dl);
                                // Download the meta file
                                $local_metafile = $local_intf_folder.'APP-META.xml';
                                if(!file_exists($local_metafile) || filesize($local_metafile) == 0)
                                {
                                    $apps_to_dl[] = array('name' => 'APP-META.xml',
                                                          'url' => $app_metafile,
                                                          'filesize' => 0,
                                                          'localtarget' => $local_metafile);
                                    $apps_downloaded++;
                                }
                                // Download package license
                                $license = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='eula']/@href");
                                if($license != '')
                                {
                                    $local_license = $local_intf_folder.'LICENSE';
                                    if(!file_exists($local_license) || filesize($local_license) == 0)
                                    {
                                        $apps_to_dl[] = array('name' => basename($license),
                                                              'url' => $license,
                                                              'filesize' => 0,
                                                              'localtarget' => $local_license);
                                    }
                                }
                                // Download package icon
                                $icon = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='icon']/@href");
                                if($icon != '')
                                {
                                    $local_icon = $local_intf_folder.basename($icon);
                                    if(!file_exists($local_icon) || filesize($local_icon) == 0)
                                    {
                                        $apps_to_dl[] = array('name' => basename($icon),
                                                              'url' => $icon,
                                                              'filesize' => 0,
                                                              'localtarget' => $local_icon);
                                    }
                                }
                                // Download available screenshots
                                $screenshots = parent::getXPathValue($sxe, "entry[position()=1]/link[@a:type='screenshot']", true);
                                if(!empty($screenshots))
                                {
                                    foreach($screenshots as $screen)
                                    {
                                        $local_screen = $local_intf_folder.basename($screen['href']);
                                        if(!file_exists($local_screen) || filesize($local_screen) == 0)
                                        {
                                            $apps_to_dl[] = array('name' => basename($screen['href']),
                                                                  'url' => $screen['href'],
                                                                  'filesize' => 0,
                                                                  'localtarget' => $local_screen);
                                        }
                                    }
                                }
                            }
                            else // Server mode (download whole ZIP archive)
                            {
                                // Delete an obviously out-dated version from the system
                                if(!empty($ex_ver) && version_compare($new_ver, $ex_ver) == 1)
                                {
                                    $old_file = $this->packages_dir.'/'.$app_name.'-'.$ex_ver.'.app.zip';
                                    if(file_exists($old_file)) $this->removeDirectory($old_file);
                                }
                                // Attention: $new_ver can also be == $ex_ver (according to version_compare >= 0)
                                $local_zip = $this->packages_dir.'/'.$app_name.'-'.$new_ver.'.app.zip';
                                // Before re-downloading a file, make sure it's not yet existing on HDD (due to DB inconsistency)
                                if((file_exists($local_zip) && (filesize($local_zip) == $app_filesize)) === false)
                                {
                                    $apps_to_dl[] = array('name' => $app_name,
                                                          'url' => $app_dl,
                                                          'filesize' => $app_filesize,
                                                          'localtarget' => $local_zip);
                                    $apps_downloaded++;
                                }
                            }
                        }
                        unset($sxe);
                        $apps_in_repo++;
                    }
                }
                //var_dump($apps);
                // For memory reasons, unset the current vendor and his apps
                unset($apps);
            }
            // Shuffle the download array (in order to compensate unexpected php aborts)
            shuffle($apps_to_dl);
            // After collecting all provisioned apps, download them
            $apps_to_dl_chunks = array_chunk($apps_to_dl, 10);
            for($i = 0; $i < count($apps_to_dl_chunks); $i++)
            {
                $this->fetchFiles($apps_to_dl_chunks[$i]);
                // Check the integrity of all downloaded files
                // but exclude cases where no filesize is available (i.e. screenshot or metafile download)
                for($j = 0; $j < count($apps_to_dl_chunks[$i]); $j++)
                {
                    if($apps_to_dl_chunks[$i][$j]['filesize'] != 0 &&
                       $apps_to_dl_chunks[$i][$j]['filesize'] != filesize($apps_to_dl_chunks[$i][$j]['localtarget']))
                    {
                            $app->log($this->log_prefix.' The filesize of the package "'.
                                $apps_to_dl_chunks[$i][$j]['name'].'" is wrong. Download failure?', LOGLEVEL_WARN);
                    }
                }
            }
            $app->log($this->log_prefix.'Processed '.$apps_in_repo.
                ' apps from the repo. Downloaded '.$apps_updated.
                ' updates, '.$apps_downloaded.' new apps');
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            return false;
        }
    }
    /**
     * Read in all possible packages from the interface packages folder and
     * check if they are not ASP.net code (as this can't be processed).
     *
     * Note: There's no need to check if the packages to register are newer
     * than those in the database because this already happended in startCrawler()
     */
    public function parseFolderToDB()
    {
        global $app;
        try
        {
            // This method must be used in interface mode
            if(!$this->interface_mode) return false;
            $pkg_list = array();
            // Read in every package having a correct filename
            $temp_handle = @dir($this->interface_pkg_dir);
            if(!$temp_handle) throw new Exception('The temp directory is not accessible');
            while($folder = $temp_handle->read())
                if(substr($folder, -8) == '.app.zip') $pkg_list[] = $folder;
            $temp_handle->close();
            // If no packages are available -> exception (because at this point there should exist packages)
            if(empty($pkg_list)) throw new Exception('No packages to read in');
            // Get registered packages and mark non-existant packages with an error code to omit the install
            $existing_packages = array();
            $path_query = $app->db->queryAllRecords('SELECT path AS Path FROM aps_packages;');
            foreach($path_query as $path) $existing_packages[] = $path['Path'];
            $diff = array_diff($existing_packages, $pkg_list);
            foreach($diff as $todelete) {
                /*$app->db->query("UPDATE aps_packages SET package_status = '".PACKAGE_ERROR_NOMETA."'
                    WHERE path = '".$app->db->quote($todelete)."';");*/
                $tmp = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE path = '".$app->db->quote($todelete)."';");
                $app->db->datalogUpdate('aps_packages', "package_status = ".PACKAGE_ERROR_NOMETA, 'id', $tmp['id']);
                unset($tmp);
            }
            // Register all new packages
            $new_packages = array_diff($pkg_list, $existing_packages);
            foreach($new_packages as $pkg)
            {
                // Load in meta file if existing and register its namespaces
                $metafile = $this->interface_pkg_dir.'/'.$pkg.'/APP-META.xml';
                if(!file_exists($metafile))
                {
                    $app->log($this->log_prefix.'Cannot read metadata from '.$pkg, LOGLEVEL_ERROR);
                    continue;
                }
                $metadata = file_get_contents($metafile);
                $metadata = str_replace("xmlns=", "ns=", $metadata);
                $sxe = new SimpleXMLElement($metadata);
                $namespaces = $sxe->getDocNamespaces(true);
                foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
                // Insert the new package
                $pkg_name = parent::getXPathValue($sxe, 'name');
                $pkg_category = parent::getXPathValue($sxe, '//category');
                $pkg_version = parent::getXPathValue($sxe, 'version');
                $pkg_release = parent::getXPathValue($sxe, 'release');
                //$pkg_url = $this->app_download_url_list[$pkg];
                $pkg_url = @file_get_contents($this->interface_pkg_dir.'/'.$pkg.'/PKG_URL');
                /*
                $app->db->query("INSERT INTO `aps_packages`
                    (`path`, `name`, `category`, `version`, `release`, `package_status`) VALUES
                    ('".$app->db->quote($pkg)."', '".$app->db->quote($pkg_name)."',
                    '".$app->db->quote($pkg_category)."', '".$app->db->quote($pkg_version)."',
                    ".$app->db->quote($pkg_release).", ".PACKAGE_ENABLED.");");
                */
                // Insert only if data is complete
                if($pkg != '' && $pkg_name != '' && $pkg_category != '' && $pkg_version != '' && $pkg_release != '' && $pkg_url){
                    $insert_data = "(`path`, `name`, `category`, `version`, `release`, `package_url`, `package_status`) VALUES
                    ('".$app->db->quote($pkg)."', '".$app->db->quote($pkg_name)."',
                    '".$app->db->quote($pkg_category)."', '".$app->db->quote($pkg_version)."',
                    ".$app->db->quote($pkg_release).", '".$app->db->quote($pkg_url)."', ".PACKAGE_ENABLED.");";
                    $app->db->datalogInsert('aps_packages', $insert_data, 'id');
                } else {
                    if(file_exists($this->interface_pkg_dir.'/'.$pkg)) $this->removeDirectory($this->interface_pkg_dir.'/'.$pkg);
                }
            }
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            $app->error($e->getMessage());
            return false;
        }
    }
    /**
     * Add missing package URLs to database
     */
    public function fixURLs()
    {
        global $app;
        try
        {
            // This method must be used in interface mode
            if(!$this->interface_mode) return false;
            $incomplete_pkgs = $app->db->queryAllRecords("SELECT * FROM aps_packages WHERE package_url = ''");
            if(is_array($incomplete_pkgs) && !empty($incomplete_pkgs)){
                foreach($incomplete_pkgs as $incomplete_pkg){
                    $pkg_url = @file_get_contents($this->interface_pkg_dir.'/'.$incomplete_pkg['path'].'/PKG_URL');
                    if($pkg_url != ''){
                        $app->db->datalogUpdate('aps_packages', "package_url = '".$pkg_url."'", 'id', $incomplete_pkg['id']);
                    }
                }
            }
        }
        catch(Exception $e)
        {
            $app->log($this->log_prefix.$e->getMessage(), LOGLEVEL_ERROR);
            $app->error($e->getMessage());
            return false;
        }
    }
}
?>
interface/lib/classes/aps_guicontroller.inc.php
@@ -1,841 +1,841 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
class ApsGUIController extends ApsBase
{
    /**
    * Constructor
    *
    * @param $app the application instance (db handle)
    */
    public function __construct($app)
    {
        parent::__construct($app);
    }
    /**
     * Reads in a package metadata file and registers it's namespaces
     *
     * @param $filename the file to read
     * @return $sxe a SimpleXMLElement handle
     */
    private function readInMetaFile($filename)
    {
        $metadata = file_get_contents($filename);
        $metadata = str_replace("xmlns=", "ns=", $metadata);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        return $sxe;
    }
    /**
     * Applies a RegEx pattern onto a location path in order to secure it against
     * code injections and invalid input
     *
     * @param $location_unfiltered the file path to secure
     * @return $location
     */
    private function secureLocation($location_unfiltered)
    {
        // Filter invalid slashes from string
        $location = preg_replace(array('#/+#', '#\.+#', '#\0+#', '#\\\\+#'),
                                 array('/', '', '', '/'),
                                 $location_unfiltered);
        // Remove a beginning or trailing slash
        if(substr($location, -1) == '/') $location = substr($location, 0, strlen($location) - 1);
        if(substr($location, 0, 1) == '/') $location = substr($location, 1);
        return $location;
    }
    /**
     * Gets the CustomerID (ClientID) which belongs to a specific domain
     *
     * @param $domain the domain
     * @return $customerid
     */
    private function getCustomerIDFromDomain($domain)
    {
        global $app;
        $customerid = 0;
        $customerdata = $app->db->queryOneRecord("SELECT client_id FROM sys_group, web_domain
            WHERE web_domain.sys_groupid = sys_group.groupid
            AND web_domain.domain = '".$app->db->quote($domain)."';");
        if(!empty($customerdata)) $customerid = $customerdata['client_id'];
        return $customerid;
    }
    /**
     * Returns the server_id for an already installed instance. Is actually
     * just a little helper method to avoid redundant code
     *
     * @param $instanceid the instance to process
     * @return $webserver_id the server_id
     */
    private function getInstanceDataForDatalog($instanceid)
    {
        global $app;
        $webserver_id = '';
        $websrv = $app->db->queryOneRecord("SELECT server_id FROM web_domain
            WHERE domain = (SELECT value FROM aps_instances_settings
                WHERE name = 'main_domain' AND instance_id = ".$app->db->quote($instanceid).");");
        // If $websrv is empty, an error has occured. Domain no longer existing? Settings table damaged?
        // Anyhow, remove this instance record because it's not useful at all
        if(empty($websrv))
        {
            $app->db->query("DELETE FROM aps_instances WHERE id = ".$app->db->quote($instanceid).";");
            $app->db->query("DELETE FROM aps_instances_settings WHERE instance_id = ".$app->db->quote($instanceid).";");
        }
        else $webserver_id = $websrv['server_id'];
        return $webserver_id;
    }
    /**
     * Finds out if there is a newer package version for
     * a given (possibly valid) package ID
     *
     * @param $id the ID to check
     * @return $newer_pkg_id the newer package ID
     */
    public function getNewestPackageID($id)
    {
        global $app;
        if(preg_match('/^[0-9]+$/', $id) != 1) return 0;
        $result = $app->db->queryOneRecord("SELECT id, name,
            CONCAT(version, '-', CAST(`release` AS CHAR)) AS current_version
            FROM aps_packages
            WHERE name = (SELECT name FROM aps_packages WHERE id = ".$app->db->quote($id).")
            ORDER BY REPLACE(version, '.', '')+0 DESC, `release` DESC");
        if(!empty($result) && ($id != $result['id'])) return $result['id'];
        return 0;
    }
    /**
     * Validates a given package ID
     *
     * @param $id the ID to check
     * @param $is_admin a flag to allow locked IDs too (for admin calls)
     * @return boolean
     */
    public function isValidPackageID($id, $is_admin = false)
    {
        global $app;
         if(preg_match('/^[0-9]+$/', $id) != 1) return false;
         $sql_ext = (!$is_admin) ?
            'package_status = '.PACKAGE_ENABLED.' AND' :
            '(package_status = '.PACKAGE_ENABLED.' OR package_status = '.PACKAGE_LOCKED.') AND';
         $result = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE ".$sql_ext." id = ".$app->db->quote($id).";");
         if(!$result) return false;
         return true;
    }
    /**
     * Validates a given instance ID
     *
     * @param $id the ID to check
     * @param $client_id the calling client ID
     * @param $is_admin a flag to ignore the client ID check for admins
     * @return boolean
     */
    public function isValidInstanceID($id, $client_id, $is_admin = false)
    {
        global $app;
         if(preg_match('/^[0-9]+$/', $id) != 1) return false;
         // Only filter if not admin
         $sql_ext = (!$is_admin) ? 'customer_id = '.$app->db->quote($client_id).' AND' : '';
         $result = $app->db->queryOneRecord('SELECT id FROM aps_instances WHERE '.$sql_ext.' id = '.$app->db->quote($id).';');
         if(!$result) return false;
         return true;
    }
    /**
     * Creates a new database record for the package instance and
     * an install task
     *
     * @param $settings the settings to enter into the DB
     * @param $packageid the PackageID
     */
    public function createPackageInstance($settings, $packageid)
    {
        global $app;
        $app->uses('tools_sites');
        $webserver_id = 0;
        $websrv = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain = '".$app->db->quote($settings['main_domain'])."';");
        if(!empty($websrv)) $webserver_id = $websrv['server_id'];
        $customerid = $this->getCustomerIDFromDomain($settings['main_domain']);
        if(empty($settings) || empty($webserver_id)) return false;
        //* Get server config of the web server
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config($app->functions->intval($websrv["server_id"]),'web');
        //* Set PHP mode to php-fcgi and enable suexec in website on apache servers / set PHP mode to PHP-FPM on nginx servers
        if($web_config['server_type'] == 'apache') {
            if(($websrv['php'] != 'fast-cgi' || $websrv['suexec'] != 'y') && $websrv['php'] != 'php-fpm') {
                $app->db->datalogUpdate('web_domain', "php = 'fast-cgi', suexec = 'y'", 'domain_id', $websrv['domain_id']);
            }
        } else {
            // nginx
            if($websrv['php'] != 'php-fpm' && $websrv['php'] != 'fast-cgi') {
                $app->db->datalogUpdate('web_domain', "php = 'php-fpm'", 'domain_id', $websrv['domain_id']);
            }
        }
        //* Create the MySQL database for the application
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($packageid).';');
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        $sxe = $this->readInMetaFile($metafile);
        $db_id = parent::getXPathValue($sxe, '//db:id');
        if (!empty($db_id)) {
            $global_config = $app->getconf->get_global_config('sites');
            $tmp = array();
            $tmp['parent_domain_id'] = $websrv['domain_id'];
            $tmp['sys_groupid'] = $websrv['sys_groupid'];
            $dbname_prefix = $app->tools_sites->replacePrefix($global_config['dbname_prefix'], $tmp);
            $dbuser_prefix = $app->tools_sites->replacePrefix($global_config['dbuser_prefix'], $tmp);
            unset($tmp);
            // get information if the webserver is a db server, too
            $web_server = $app->db->queryOneRecord("SELECT server_id,server_name,db_server FROM server WHERE server_id  = ".$websrv['server_id']);
            if($web_server['db_server'] == 1) {
                // create database on "localhost" (webserver)
                $mysql_db_server_id = $websrv['server_id'];
                $mysql_db_host = 'localhost';
                $mysql_db_remote_access = 'n';
                $mysql_db_remote_ips = '';
            } else {
                //* get the default database server of the client
                $client = $app->db->queryOneRecord("SELECT default_dbserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ".$websrv['sys_groupid']);
                if(is_array($client) && $client['default_dbserver'] > 0 && $client['default_dbserver'] != $websrv['server_id']) {
                    $mysql_db_server_id =  $client['default_dbserver'];
                    $dbserver_config = $web_config = $app->getconf->get_server_config($app->functions->intval($mysql_db_server_id),'server');
                    $mysql_db_host = $dbserver_config['ip_address'];
                    $mysql_db_remote_access = 'y';
                    $webserver_config = $app->getconf->get_server_config($app->functions->intval($websrv['server_id']),'server');
                    $mysql_db_remote_ips = $webserver_config['ip_address'];
                } else {
                    /* I left this in place for a fallback that should NEVER! happen.
                     * if we reach this point it means that there is NO default db server for the client
                     * AND the webserver has NO db service enabled.
                     * We have to abort the aps installation here... so I added a return false
                     * although this does not present any error message to the user.
                     */
                    return false;
                    /*$mysql_db_server_id = $websrv['server_id'];
                    $mysql_db_host = 'localhost';
                    $mysql_db_remote_access = 'n';
                    $mysql_db_remote_ips = '';*/
                }
            }
            //* Find a free db name for the app
            for($n = 1; $n <= 1000; $n++) {
                $mysql_db_name = ($dbname_prefix != '' ? $dbname_prefix.'aps'.$n : uniqid('aps'));
                $tmp = $app->db->queryOneRecord("SELECT count(database_id) as number FROM web_database WHERE database_name = '".$app->db->quote($mysql_db_name)."'");
                if($tmp['number'] == 0) break;
            }
            //* Find a free db username for the app
            for($n = 1; $n <= 1000; $n++) {
                $mysql_db_user = ($dbuser_prefix != '' ? $dbuser_prefix.'aps'.$n : uniqid('aps'));
                $tmp = $app->db->queryOneRecord("SELECT count(database_user_id) as number FROM web_database_user WHERE database_user = '".$app->db->quote($mysql_db_user)."'");
                if($tmp['number'] == 0) break;
            }
            $mysql_db_password = $settings['main_database_password'];
            //* Create the mysql database user
            $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `database_user`, `database_user_prefix`, `database_password`)
                      VALUES( ".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', 0, '$mysql_db_user', '".$app->db->quote($dbuser_prefix) . "', PASSWORD('$mysql_db_password'))";
            $mysql_db_user_id = $app->db->datalogInsert('web_database_user', $insert_data, 'database_user_id');
            //* Create the mysql database
            $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `parent_domain_id`, `type`, `database_name`, `database_name_prefix`, `database_user_id`, `database_ro_user_id`, `database_charset`, `remote_access`, `remote_ips`, `backup_copies`, `active`, `backup_interval`)
                      VALUES( ".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', $mysql_db_server_id, ".$websrv['domain_id'].", 'mysql', '$mysql_db_name', '" . $app->db->quote($dbname_prefix) . "', '$mysql_db_user_id', 0, '', '$mysql_db_remote_access', '$mysql_db_remote_ips', ".$websrv['backup_copies'].", 'y', '".$websrv['backup_interval']."')";
            $app->db->datalogInsert('web_database', $insert_data, 'database_id');
            //* Add db details to package settings
            $settings['main_database_host'] = $mysql_db_host;
            $settings['main_database_name'] = $mysql_db_name;
            $settings['main_database_login'] = $mysql_db_user;
        }
        //* Insert new package instance
        $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `customer_id`, `package_id`, `instance_status`) VALUES (".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', ".$app->db->quote($webserver_id).",".$app->db->quote($customerid).", ".$app->db->quote($packageid).", ".INSTANCE_PENDING.")";
        $InstanceID = $app->db->datalogInsert('aps_instances', $insert_data, 'id');
        //* Insert all package settings
        if(is_array($settings)) {
            foreach($settings as $key => $value) {
                $insert_data = "(server_id, instance_id, name, value) VALUES (".$app->db->quote($webserver_id).",".$app->db->quote($InstanceID).", '".$app->db->quote($key)."', '".$app->db->quote($value)."')";
                $app->db->datalogInsert('aps_instances_settings', $insert_data, 'id');
            }
        }
        //* Set package status to install afetr we inserted the settings
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_INSTALL, 'id', $InstanceID);
    }
    /**
     * Sets the status of an instance to "should be removed" and creates a
     * datalog entry to give the ISPConfig server a real removal advice
     *
     * @param $instanceid the instance to delete
     */
    public function deleteInstance($instanceid)
    {
        global $app;
        /*
        $app->db->query("UPDATE aps_instances SET instance_status = ".INSTANCE_REMOVE." WHERE id = ".$instanceid.";");
        $webserver_id = $this->getInstanceDataForDatalog($instanceid);
        if($webserver_id == '') return;
        // Create a sys_datalog entry for deletion
        $datalog = array('Instance_id' => $instanceid, 'server_id' => $webserver_id);
        $app->db->datalogSave('aps', 'DELETE', 'id', $instanceid, array(), $datalog);
        */
        $sql = "SELECT web_database.database_id as database_id, web_database.database_user_id as `database_user_id` FROM aps_instances_settings, web_database WHERE aps_instances_settings.value = web_database.database_name AND aps_instances_settings.value =  aps_instances_settings.name = 'main_database_name' AND aps_instances_settings.instance_id = ".$instanceid." LIMIT 0,1";
        $tmp = $app->db->queryOneRecord($sql);
        if($tmp['database_id'] > 0) $app->db->datalogDelete('web_database', 'database_id', $tmp['database_id']);
        $database_user = $tmp['database_user_id'];
        $tmp = $app->db->queryOneRecord("SELECT COUNT(*) as `cnt` FROM `web_database` WHERE `database_user_id` = '" . $app->functions->intval($database_user) . "' OR `database_ro_user_id` = '" . $app->functions->intval($database_user) . "'");
        if($tmp['cnt'] < 1) $app->db->datalogDelete('web_database_user', 'database_user_id', $database_user);
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_REMOVE, 'id', $instanceid);
    }
    /**
     * Sets the status of an instance to "installation planned" and creates a
     * datalog entry to re-install the package. The existing package is simply overwritten.
     *
     * @param $instanceid the instance to delete
     */
    public function reinstallInstance($instanceid)
    {
        global $app;
        /*
        $app->db->query("UPDATE aps_instances SET instance_status = ".INSTANCE_INSTALL." WHERE id = ".$instanceid.";");
        $webserver_id = $this->getInstanceDataForDatalog($instanceid);
        if($webserver_id == '') return;
        // Create a sys_datalog entry for re-installation
        $datalog = array('instance_id' => $instanceid, 'server_id' => $webserver_id);
        $app->db->datalogSave('aps', 'INSERT', 'id', $instanceid, array(), $datalog);
        */
        $sql = "SELECT web_database.database_id as database_id FROM aps_instances_settings, web_database WHERE aps_instances_settings.value = web_database.database_name AND aps_instances_settings.value =  aps_instances_settings.name = 'main_database_name' AND aps_instances_settings.instance_id = ".$instanceid." LIMIT 0,1";
        $tmp = $app->db->queryOneRecord($sql);
        if($tmp['database_id'] > 0) $app->db->datalogDelete('web_database', 'database_id', $tmp['database_id']);
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_INSTALL, 'id', $instanceid);
    }
    /**
     * Read the settings to be filled when installing
     *
     * @param $id the internal ID of the package
     * @return array
     */
    public function getPackageSettings($id)
    {
        global $app;
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($id).';');
        // Load in meta file if existing and register its namespaces
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        if(!file_exists($metafile))
            return array('error' => 'The metafile for '.$settings['Name'].' couldn\'t be found');
        $sxe = $this->readInMetaFile($metafile);
        $groupsettings = parent::getXPathValue($sxe, '//settings/group/setting', true);
        if(empty($groupsettings)) return array();
        $settings = array();
        foreach($groupsettings as $setting)
        {
            $setting_id = strval($setting['id']);
            if($setting['type'] == 'string' || $setting['type'] == 'email' || $setting['type'] == 'integer'
            || $setting['type'] == 'float' || $setting['type'] == 'domain-name')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => $setting['type'],
                                    'SettingInputType' => 'string',
                                    'SettingDefaultValue' => strval($setting['default-value']),
                                    'SettingRegex' => $setting['regex'],
                                    'SettingMinLength' => $setting['min-length'],
                                    'SettingMaxLength' => $setting['max-length']);
            }
            else if($setting['type'] == 'password')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => 'password',
                                    'SettingInputType' => 'password',
                                    'SettingDefaultValue' => '',
                                    'SettingRegex' => $setting['regex'],
                                    'SettingMinLength' => $setting['min-length'],
                                    'SettingMaxLength' => $setting['max-length']);
            }
            else if($setting['type'] == 'boolean')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => 'boolean',
                                    'SettingInputType' => 'checkbox',
                                    'SettingDefaultValue' => strval($setting['default-value']));
            }
            else if($setting['type'] == 'enum')
            {
              $choices = array();
              foreach($setting->choice as $choice)
              {
                $choices[] = array('EnumID' => strval($choice['id']),
                                   'EnumName' => $choice->name);
              }
              $settings[] = array('SettingID' => $setting_id,
                                  'SettingName' => $setting->name,
                                  'SettingDescription' => $setting->description,
                                  'SettingType' => 'enum',
                                  'SettingInputType' => 'select',
                                  'SettingDefaultValue' => strval($setting['default-value']),
                                  'SettingChoices' => $choices);
            }
        }
        return $settings;
    }
    /**
     * Validates the user input according to the settings array and
     * delivers errors if occurring
     *
     * @param $input the user $_POST array
     * @param $pkg_details the package details
     * @param $settings the package settings array
     * @return array in this structure:
     *               array(2) {
     *                  ["input"]=> ...
     *                  ["errors"]=> ...
     *               }
     */
    public function validateInstallerInput($postinput, $pkg_details, $domains, $settings = array())
    {
        global $app;
        $ret = array();
        $input = array();
        $error = array();
        // Main domain (obligatory)
        if(isset($postinput['main_domain']))
        {
            if(!in_array($postinput['main_domain'], $domains)) $error[] = $app->lng('error_main_domain');
            else $input['main_domain'] = $postinput['main_domain'];
        }
        else $error[] = $app->lng('error_main_domain');
        // Main location (not obligatory but must be supplied)
        if(isset($postinput['main_location']))
        {
            $temp_errstr = '';
            // It can be empty but if the user did write something, check it
            $userinput = false;
            if(strlen($postinput['main_location']) > 0) $userinput = true;
            // Filter invalid input slashes (twice!)
            $main_location = $this->secureLocation($postinput['main_location']);
            $main_location = $this->secureLocation($main_location);
            // Only allow digits, words, / and -
            $main_location = preg_replace("/[^\d\w\/\-]/i", "", $main_location);
            if($userinput && (strlen($main_location) == 0)) $temp_errstr = $app->lng('error_inv_main_location');
            // Find out document_root and make sure no apps are installed twice to one location
            if(in_array($postinput['main_domain'], $domains))
            {
                $docroot = $app->db->queryOneRecord("SELECT document_root FROM web_domain
                    WHERE domain = '".$app->db->quote($postinput['main_domain'])."';");
                $new_path = $docroot['document_root'];
                if(substr($new_path, -1) != '/') $new_path .= '/';
                $new_path .= $main_location;
                // Get the $customerid which belongs to the selected domain
                $customerid = $this->getCustomerIDFromDomain($postinput['main_domain']);
                // First get all domains used for an install, then their loop them
                // and get the corresponding document roots as well as the defined
                // locations. If an existing doc_root + location matches with the
                // new one -> error
                $instance_domains = $app->db->queryAllRecords("SELECT instance_id, s.value AS domain
                    FROM aps_instances AS i, aps_instances_settings AS s
                    WHERE i.id = s.instance_id AND s.name = 'main_domain'
                        AND i.customer_id = '".$app->db->quote($customerid)."';");
                for($i = 0; $i < count($instance_domains); $i++)
                {
                    $used_path = '';
                    $doc_root = $app->db->queryOneRecord("SELECT document_root FROM web_domain
                        WHERE domain = '".$app->db->quote($instance_domains[$i]['domain'])."';");
                    // Probably the domain settings were changed later, so make sure the doc_root
                    // is not empty for further validation
                    if(!empty($doc_root))
                    {
                        $used_path = $doc_root['document_root'];
                        if(substr($used_path, -1) != '/') $used_path .= '/';
                        $location_for_domain = $app->db->queryOneRecord("SELECT value
                            FROM aps_instances_settings WHERE name = 'main_location'
                            AND instance_id = '".$app->db->quote($instance_domains[$i]['instance_id'])."';");
                        // The location might be empty but the DB return must not be false!
                        if($location_for_domain) $used_path .= $location_for_domain['value'];
                        if($new_path == $used_path)
                        {
                            $temp_errstr = $app->lng('error_used_location');
                            break;
                        }
                    }
                }
            }
            else $temp_errstr = $app->lng('error_main_domain');
            if($temp_errstr == '') $input['main_location'] = htmlspecialchars($main_location);
            else $error[] = $temp_errstr;
        }
        else $error[] = $app->lng('error_no_main_location');
        // License (the checkbox must be set)
        if(isset($pkg_details['License need agree'])
        && $pkg_details['License need agree'] == 'true')
        {
            if(isset($postinput['license']) && $postinput['license'] == 'on') $input['license'] = 'true';
            else $error[] = $app->lng('error_license_agreement');
        }
        // Database
        if(isset($pkg_details['Requirements Database'])
        && $pkg_details['Requirements Database'] != '')
        {
            if(isset($postinput['main_database_password']))
            {
                if($postinput['main_database_password'] == '') $error[] = $app->lng('error_no_database_pw');
                else if(strlen($postinput['main_database_password']) > 8)
                    $input['main_database_password'] = htmlspecialchars($postinput['main_database_password']);
                else $error[] = $app->lng('error_short_database_pw');
            }
            else $error[] = $app->lng('error_no_database_pw');
        }
        // Validate the package settings
        foreach($settings as $setting)
        {
            $temp_errstr = '';
            $setting_id = strval($setting['SettingID']);
            // We assume that every setting must be set
            if((isset($postinput[$setting_id]) && ($postinput[$setting_id] != ''))
            || ($setting['SettingType'] == 'boolean'))
            {
                if($setting['SettingType'] == 'string' || $setting['SettingType'] == 'password')
                {
                    if($app->functions->intval($setting['SettingMinLength'], true) != 0
                    && strlen($postinput[$setting_id]) < $app->functions->intval($setting['SettingMinLength'], true))
                        $temp_errstr = sprintf($app->lng('error_short_value_for'), $setting['setting_name']);
                    if($app->functions->intval($setting['SettingMaxLength'], true) != 0
                    && strlen($postinput[$setting_id]) > $app->functions->intval($setting['SettingMaxLength'], true))
                        $temp_errstr = sprintf($app->lng('error_long_value_for'), $setting['setting_name']);
                    if(isset($setting['SettingRegex'])
                    && !preg_match("/".$setting['SettingRegex']."/", $postinput[$setting_id]))
                        $temp_errstr = sprintf($app->lng('error_inv_value_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'email')
                {
                    if(filter_var(strtolower($postinput[$setting_id]), FILTER_VALIDATE_EMAIL) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_email_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'domain-name')
                {
                    if(!preg_match("^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$",
                        $postinput[$setting_id]))
                    $temp_errstr = sprintf($app->lng('error_inv_domain_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'integer')
                {
                    if(filter_var($postinput[$setting_id], FILTER_VALIDATE_INT) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_integer_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'float')
                {
                    if(filter_var($postinput[$setting_id], FILTER_VALIDATE_FLOAT) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_float_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'boolean')
                {
                    // If we have a boolean value set, it must be either true or false
                    if(!isset($postinput[$setting_id])) $postinput[$setting_id] = 'false';
                    else if(isset($postinput[$setting_id]) && $postinput[$setting_id] != 'true')
                        $postinput[$setting_id] = 'true';
                }
                else if($setting['SettingType'] == 'enum')
                {
                    $found = false;
                    for($i = 0; $i < count($setting['SettingChoices']); $i++)
                    {
                        if($setting['SettingChoices'][$i]['EnumID'] == $postinput[$setting_id])
                            $found = true;
                    }
                    if(!$found) $temp_errstr = sprintf($app->lng('error_inv_value_for'), $setting['SettingName']);
                }
                if($temp_errstr == '') $input[$setting_id] = $postinput[$setting_id];
                else $error[] = $temp_errstr;
            }
            else $error[] = sprintf($app->lng('error_no_value_for'), $setting['SettingName']);
        }
        $ret['input'] = $input;
        $ret['error'] = array_unique($error);
        return $ret;
    }
    /**
     * Read the metadata of a package and returns some content
     *
     * @param $id the internal ID of the package
     * @return array
     */
    public function getPackageDetails($id)
    {
        global $app;
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($id).';');
        // Load in meta file if existing and register its namespaces
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        if(!file_exists($metafile))
            return array('error' => 'The metafile for '.$pkg['name'].' couldn\'t be found');
        $metadata = file_get_contents($metafile);
        $metadata = str_replace("xmlns=", "ns=", $metadata);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        $pkg['Summary'] = htmlspecialchars(parent::getXPathValue($sxe, '//summary'));
        $pkg['Homepage'] = parent::getXPathValue($sxe, '//homepage');
        $pkg['Description'] = nl2br(htmlspecialchars(trim(parent::getXPathValue($sxe, '//description'))));
        $pkg['Config script'] = strtoupper(parent::getXPathValue($sxe, '//configuration-script-language'));
        $installed_size = parent::getXPathValue($sxe, '//installed-size');
        $pkg['Installed Size'] = (!empty($installed_size)) ? parent::convertSize((int)$installed_size) : '';
        // License
        $pkg['License need agree'] = parent::getXPathValue($sxe, '//license/@must-accept');
        $pkg['License name'] = parent::getXPathValue($sxe, '//license/text/name'); // might be empty
        $pkg['License type'] = 'file'; // default type
        $pkg['License content'] = ''; // default license filename on local system
        $license_url = parent::getXPathValue($sxe, '//license/text/url');
        if(!empty($license_url))
        {
            $pkg['License type'] = 'url';
            $pkg['License content'] = htmlspecialchars($license_url);
        }
        else
        {
            $lic = @file_get_contents($this->interface_pkg_dir.'/'.$pkg['path'].'/LICENSE');
            $pkg['License content'] = htmlentities($lic, ENT_QUOTES, 'ISO-8859-1');
        }
        // Languages
        $languages = parent::getXPathValue($sxe, '//languages/language', true);
        $pkg['Languages'] = (is_array($languages)) ? implode(' ', $languages) : '';
        // Icon
        $icon = parent::getXPathValue($sxe, '//icon/@path');
        if(!empty($icon))
        {
            // Using parse_url() to filter malformed URLs
            $path = dirname(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH)).'/'.
                    basename($this->interface_pkg_dir).'/'.$pkg['path'].'/'.basename((string)$icon);
            $pkg['Icon'] = $path;
        }
        else $pkg['Icon'] = '';
        // Screenshots
        $screenshots = parent::getXPathValue($sxe, '//screenshot', true);
        if(!empty($screenshots))
        {
            foreach($screenshots as $screen)
            {
                // Using parse_url() to filter malformed URLs
                $path = dirname(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH)).'/'.
                        basename($this->interface_pkg_dir).'/'.$pkg['path'].'/'.basename((string)$screen['path']);
                $pkg['Screenshots'][] = array('ScreenPath' => $path,
                                              'ScreenDescription' => htmlspecialchars(trim((string)$screen->description)));
            }
        }
        else $pkg['Screenshots'] = ''; // if no screenshots are available, set the variable though
        // Changelog
        $changelog = parent::getXPathValue($sxe, '//changelog/version', true);
        if(!empty($changelog))
        {
            foreach($changelog as $change)
            {
                $entries = array();
                foreach($change->entry as $entry) $entries[] = htmlspecialchars(trim((string)$entry));
                $pkg['Changelog'][] = array('ChangelogVersion' => (string)$change['version'],
                                            'ChangelogDescription' => implode('<br />', $entries));
            }
        }
        else $pkg['Changelog'] = '';
        // PHP extensions
        $php_extensions = parent::getXPathValue($sxe, '//php:extension', true);
        $php_ext = '';
        if(!empty($php_extensions))
        {
            foreach($php_extensions as $extension)
            {
                if(strtolower($extension) == 'php') continue;
                $php_ext .= $extension.' ';
            }
        }
        $pkg['Requirements PHP extensions'] = trim($php_ext);
        // PHP bool options
        $pkg['Requirements PHP settings'] = '';
        $php_bool_options = array('allow-url-fopen', 'file-uploads', 'magic-quotes-gpc',
                                  'register-globals', 'safe-mode', 'short-open-tag');
        foreach($php_bool_options as $option)
        {
            $value = parent::getXPathValue($sxe, '//php:'.$option);
            if(!empty($value))
            {
                $option = str_replace('-', '_', $option);
                $value = str_replace(array('false', 'true'), array('off', 'on'), $value);
                $pkg['Requirements PHP settings'][] = array('PHPSettingName' => $option,
                                                            'PHPSettingValue' => $value);
            }
        }
        // PHP integer value settings
        $memory_limit = parent::getXPathValue($sxe, '//php:memory-limit');
        if(!empty($memory_limit))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'memory_limit',
                                                        'PHPSettingValue' => parent::convertSize((int)$memory_limit));
        $max_exec_time = parent::getXPathValue($sxe, '//php:max-execution-time');
        if(!empty($max_exec_time))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'max-execution-time',
                                                        'PHPSettingValue' => $max_exec_time);
        $post_max_size = parent::getXPathValue($sxe, '//php:post-max-size');
        if(!empty($post_max_size))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'post_max_size',
                                                        'PHPSettingValue' => parent::convertSize((int)$post_max_size));
        // Get supported PHP versions
        $pkg['Requirements Supported PHP versions'] = '';
        $php_min_version = parent::getXPathValue($sxe, '//php:version/@min');
        $php_max_not_including = parent::getXPathValue($sxe, '//php:version/@max-not-including');
        if(!empty($php_min_version) && !empty($php_max_not_including))
            $pkg['Requirements Supported PHP versions'] = $php_min_version.' - '.$php_max_not_including;
        else if(!empty($php_min_version))
            $pkg['Requirements Supported PHP versions'] = '> '.$php_min_version;
        else if(!empty($php_max_not_including))
            $pkg['Requirements Supported PHP versions'] = '< '.$php_min_version;
        // Database
        $db_id = parent::getXPathValue($sxe, '//db:id');
        $db_server_type = parent::getXPathValue($sxe, '//db:server-type');
        $db_min_version = parent::getXPathValue($sxe, '//db:server-min-version');
        if(!empty($db_id))
        {
            $db_server_type = str_replace('postgresql', 'PostgreSQL', $db_server_type);
            $db_server_type = str_replace('microsoft:sqlserver', 'MSSQL', $db_server_type);
            $db_server_type = str_replace('mysql', 'MySQL', $db_server_type);
            $pkg['Requirements Database'] = $db_server_type;
            if(!empty($db_min_version)) $pkg['Requirements Database'] .= ' > '.$db_min_version;
        }
        else $pkg['Requirements Database'] = '';
        return $pkg;
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
class ApsGUIController extends ApsBase
{
    /**
    * Constructor
    *
    * @param $app the application instance (db handle)
    */
    public function __construct($app)
    {
        parent::__construct($app);
    }
    /**
     * Reads in a package metadata file and registers it's namespaces
     *
     * @param $filename the file to read
     * @return $sxe a SimpleXMLElement handle
     */
    private function readInMetaFile($filename)
    {
        $metadata = file_get_contents($filename);
        $metadata = str_replace("xmlns=", "ns=", $metadata);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        return $sxe;
    }
    /**
     * Applies a RegEx pattern onto a location path in order to secure it against
     * code injections and invalid input
     *
     * @param $location_unfiltered the file path to secure
     * @return $location
     */
    private function secureLocation($location_unfiltered)
    {
        // Filter invalid slashes from string
        $location = preg_replace(array('#/+#', '#\.+#', '#\0+#', '#\\\\+#'),
                                 array('/', '', '', '/'),
                                 $location_unfiltered);
        // Remove a beginning or trailing slash
        if(substr($location, -1) == '/') $location = substr($location, 0, strlen($location) - 1);
        if(substr($location, 0, 1) == '/') $location = substr($location, 1);
        return $location;
    }
    /**
     * Gets the CustomerID (ClientID) which belongs to a specific domain
     *
     * @param $domain the domain
     * @return $customerid
     */
    private function getCustomerIDFromDomain($domain)
    {
        global $app;
        $customerid = 0;
        $customerdata = $app->db->queryOneRecord("SELECT client_id FROM sys_group, web_domain
            WHERE web_domain.sys_groupid = sys_group.groupid
            AND web_domain.domain = '".$app->db->quote($domain)."';");
        if(!empty($customerdata)) $customerid = $customerdata['client_id'];
        return $customerid;
    }
    /**
     * Returns the server_id for an already installed instance. Is actually
     * just a little helper method to avoid redundant code
     *
     * @param $instanceid the instance to process
     * @return $webserver_id the server_id
     */
    private function getInstanceDataForDatalog($instanceid)
    {
        global $app;
        $webserver_id = '';
        $websrv = $app->db->queryOneRecord("SELECT server_id FROM web_domain
            WHERE domain = (SELECT value FROM aps_instances_settings
                WHERE name = 'main_domain' AND instance_id = ".$app->db->quote($instanceid).");");
        // If $websrv is empty, an error has occured. Domain no longer existing? Settings table damaged?
        // Anyhow, remove this instance record because it's not useful at all
        if(empty($websrv))
        {
            $app->db->query("DELETE FROM aps_instances WHERE id = ".$app->db->quote($instanceid).";");
            $app->db->query("DELETE FROM aps_instances_settings WHERE instance_id = ".$app->db->quote($instanceid).";");
        }
        else $webserver_id = $websrv['server_id'];
        return $webserver_id;
    }
    /**
     * Finds out if there is a newer package version for
     * a given (possibly valid) package ID
     *
     * @param $id the ID to check
     * @return $newer_pkg_id the newer package ID
     */
    public function getNewestPackageID($id)
    {
        global $app;
        if(preg_match('/^[0-9]+$/', $id) != 1) return 0;
        $result = $app->db->queryOneRecord("SELECT id, name,
            CONCAT(version, '-', CAST(`release` AS CHAR)) AS current_version
            FROM aps_packages
            WHERE name = (SELECT name FROM aps_packages WHERE id = ".$app->db->quote($id).")
            ORDER BY REPLACE(version, '.', '')+0 DESC, `release` DESC");
        if(!empty($result) && ($id != $result['id'])) return $result['id'];
        return 0;
    }
    /**
     * Validates a given package ID
     *
     * @param $id the ID to check
     * @param $is_admin a flag to allow locked IDs too (for admin calls)
     * @return boolean
     */
    public function isValidPackageID($id, $is_admin = false)
    {
        global $app;
         if(preg_match('/^[0-9]+$/', $id) != 1) return false;
         $sql_ext = (!$is_admin) ?
            'package_status = '.PACKAGE_ENABLED.' AND' :
            '(package_status = '.PACKAGE_ENABLED.' OR package_status = '.PACKAGE_LOCKED.') AND';
         $result = $app->db->queryOneRecord("SELECT id FROM aps_packages WHERE ".$sql_ext." id = ".$app->db->quote($id).";");
         if(!$result) return false;
         return true;
    }
    /**
     * Validates a given instance ID
     *
     * @param $id the ID to check
     * @param $client_id the calling client ID
     * @param $is_admin a flag to ignore the client ID check for admins
     * @return boolean
     */
    public function isValidInstanceID($id, $client_id, $is_admin = false)
    {
        global $app;
         if(preg_match('/^[0-9]+$/', $id) != 1) return false;
         // Only filter if not admin
         $sql_ext = (!$is_admin) ? 'customer_id = '.$app->db->quote($client_id).' AND' : '';
         $result = $app->db->queryOneRecord('SELECT id FROM aps_instances WHERE '.$sql_ext.' id = '.$app->db->quote($id).';');
         if(!$result) return false;
         return true;
    }
    /**
     * Creates a new database record for the package instance and
     * an install task
     *
     * @param $settings the settings to enter into the DB
     * @param $packageid the PackageID
     */
    public function createPackageInstance($settings, $packageid)
    {
        global $app;
        $app->uses('tools_sites');
        $webserver_id = 0;
        $websrv = $app->db->queryOneRecord("SELECT * FROM web_domain WHERE domain = '".$app->db->quote($settings['main_domain'])."';");
        if(!empty($websrv)) $webserver_id = $websrv['server_id'];
        $customerid = $this->getCustomerIDFromDomain($settings['main_domain']);
        if(empty($settings) || empty($webserver_id)) return false;
        //* Get server config of the web server
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config($app->functions->intval($websrv["server_id"]),'web');
        //* Set PHP mode to php-fcgi and enable suexec in website on apache servers / set PHP mode to PHP-FPM on nginx servers
        if($web_config['server_type'] == 'apache') {
            if(($websrv['php'] != 'fast-cgi' || $websrv['suexec'] != 'y') && $websrv['php'] != 'php-fpm') {
                $app->db->datalogUpdate('web_domain', "php = 'fast-cgi', suexec = 'y'", 'domain_id', $websrv['domain_id']);
            }
        } else {
            // nginx
            if($websrv['php'] != 'php-fpm' && $websrv['php'] != 'fast-cgi') {
                $app->db->datalogUpdate('web_domain', "php = 'php-fpm'", 'domain_id', $websrv['domain_id']);
            }
        }
        //* Create the MySQL database for the application
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($packageid).';');
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        $sxe = $this->readInMetaFile($metafile);
        $db_id = parent::getXPathValue($sxe, '//db:id');
        if (!empty($db_id)) {
            $global_config = $app->getconf->get_global_config('sites');
            $tmp = array();
            $tmp['parent_domain_id'] = $websrv['domain_id'];
            $tmp['sys_groupid'] = $websrv['sys_groupid'];
            $dbname_prefix = $app->tools_sites->replacePrefix($global_config['dbname_prefix'], $tmp);
            $dbuser_prefix = $app->tools_sites->replacePrefix($global_config['dbuser_prefix'], $tmp);
            unset($tmp);
            // get information if the webserver is a db server, too
            $web_server = $app->db->queryOneRecord("SELECT server_id,server_name,db_server FROM server WHERE server_id  = ".$websrv['server_id']);
            if($web_server['db_server'] == 1) {
                // create database on "localhost" (webserver)
                $mysql_db_server_id = $websrv['server_id'];
                $mysql_db_host = 'localhost';
                $mysql_db_remote_access = 'n';
                $mysql_db_remote_ips = '';
            } else {
                //* get the default database server of the client
                $client = $app->db->queryOneRecord("SELECT default_dbserver FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ".$websrv['sys_groupid']);
                if(is_array($client) && $client['default_dbserver'] > 0 && $client['default_dbserver'] != $websrv['server_id']) {
                    $mysql_db_server_id =  $client['default_dbserver'];
                    $dbserver_config = $web_config = $app->getconf->get_server_config($app->functions->intval($mysql_db_server_id),'server');
                    $mysql_db_host = $dbserver_config['ip_address'];
                    $mysql_db_remote_access = 'y';
                    $webserver_config = $app->getconf->get_server_config($app->functions->intval($websrv['server_id']),'server');
                    $mysql_db_remote_ips = $webserver_config['ip_address'];
                } else {
                    /* I left this in place for a fallback that should NEVER! happen.
                     * if we reach this point it means that there is NO default db server for the client
                     * AND the webserver has NO db service enabled.
                     * We have to abort the aps installation here... so I added a return false
                     * although this does not present any error message to the user.
                     */
                    return false;
                    /*$mysql_db_server_id = $websrv['server_id'];
                    $mysql_db_host = 'localhost';
                    $mysql_db_remote_access = 'n';
                    $mysql_db_remote_ips = '';*/
                }
            }
            //* Find a free db name for the app
            for($n = 1; $n <= 1000; $n++) {
                $mysql_db_name = ($dbname_prefix != '' ? $dbname_prefix.'aps'.$n : uniqid('aps'));
                $tmp = $app->db->queryOneRecord("SELECT count(database_id) as number FROM web_database WHERE database_name = '".$app->db->quote($mysql_db_name)."'");
                if($tmp['number'] == 0) break;
            }
            //* Find a free db username for the app
            for($n = 1; $n <= 1000; $n++) {
                $mysql_db_user = ($dbuser_prefix != '' ? $dbuser_prefix.'aps'.$n : uniqid('aps'));
                $tmp = $app->db->queryOneRecord("SELECT count(database_user_id) as number FROM web_database_user WHERE database_user = '".$app->db->quote($mysql_db_user)."'");
                if($tmp['number'] == 0) break;
            }
            $mysql_db_password = $settings['main_database_password'];
            //* Create the mysql database user
            $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `database_user`, `database_user_prefix`, `database_password`)
                      VALUES( ".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', 0, '$mysql_db_user', '".$app->db->quote($dbuser_prefix) . "', PASSWORD('$mysql_db_password'))";
            $mysql_db_user_id = $app->db->datalogInsert('web_database_user', $insert_data, 'database_user_id');
            //* Create the mysql database
            $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `parent_domain_id`, `type`, `database_name`, `database_name_prefix`, `database_user_id`, `database_ro_user_id`, `database_charset`, `remote_access`, `remote_ips`, `backup_copies`, `active`, `backup_interval`)
                      VALUES( ".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', $mysql_db_server_id, ".$websrv['domain_id'].", 'mysql', '$mysql_db_name', '" . $app->db->quote($dbname_prefix) . "', '$mysql_db_user_id', 0, '', '$mysql_db_remote_access', '$mysql_db_remote_ips', ".$websrv['backup_copies'].", 'y', '".$websrv['backup_interval']."')";
            $app->db->datalogInsert('web_database', $insert_data, 'database_id');
            //* Add db details to package settings
            $settings['main_database_host'] = $mysql_db_host;
            $settings['main_database_name'] = $mysql_db_name;
            $settings['main_database_login'] = $mysql_db_user;
        }
        //* Insert new package instance
        $insert_data = "(`sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_id`, `customer_id`, `package_id`, `instance_status`) VALUES (".$websrv['sys_userid'].", ".$websrv['sys_groupid'].", 'riud', '".$websrv['sys_perm_group']."', '', ".$app->db->quote($webserver_id).",".$app->db->quote($customerid).", ".$app->db->quote($packageid).", ".INSTANCE_PENDING.")";
        $InstanceID = $app->db->datalogInsert('aps_instances', $insert_data, 'id');
        //* Insert all package settings
        if(is_array($settings)) {
            foreach($settings as $key => $value) {
                $insert_data = "(server_id, instance_id, name, value) VALUES (".$app->db->quote($webserver_id).",".$app->db->quote($InstanceID).", '".$app->db->quote($key)."', '".$app->db->quote($value)."')";
                $app->db->datalogInsert('aps_instances_settings', $insert_data, 'id');
            }
        }
        //* Set package status to install afetr we inserted the settings
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_INSTALL, 'id', $InstanceID);
    }
    /**
     * Sets the status of an instance to "should be removed" and creates a
     * datalog entry to give the ISPConfig server a real removal advice
     *
     * @param $instanceid the instance to delete
     */
    public function deleteInstance($instanceid)
    {
        global $app;
        /*
        $app->db->query("UPDATE aps_instances SET instance_status = ".INSTANCE_REMOVE." WHERE id = ".$instanceid.";");
        $webserver_id = $this->getInstanceDataForDatalog($instanceid);
        if($webserver_id == '') return;
        // Create a sys_datalog entry for deletion
        $datalog = array('Instance_id' => $instanceid, 'server_id' => $webserver_id);
        $app->db->datalogSave('aps', 'DELETE', 'id', $instanceid, array(), $datalog);
        */
        $sql = "SELECT web_database.database_id as database_id, web_database.database_user_id as `database_user_id` FROM aps_instances_settings, web_database WHERE aps_instances_settings.value = web_database.database_name AND aps_instances_settings.value =  aps_instances_settings.name = 'main_database_name' AND aps_instances_settings.instance_id = ".$instanceid." LIMIT 0,1";
        $tmp = $app->db->queryOneRecord($sql);
        if($tmp['database_id'] > 0) $app->db->datalogDelete('web_database', 'database_id', $tmp['database_id']);
        $database_user = $tmp['database_user_id'];
        $tmp = $app->db->queryOneRecord("SELECT COUNT(*) as `cnt` FROM `web_database` WHERE `database_user_id` = '" . $app->functions->intval($database_user) . "' OR `database_ro_user_id` = '" . $app->functions->intval($database_user) . "'");
        if($tmp['cnt'] < 1) $app->db->datalogDelete('web_database_user', 'database_user_id', $database_user);
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_REMOVE, 'id', $instanceid);
    }
    /**
     * Sets the status of an instance to "installation planned" and creates a
     * datalog entry to re-install the package. The existing package is simply overwritten.
     *
     * @param $instanceid the instance to delete
     */
    public function reinstallInstance($instanceid)
    {
        global $app;
        /*
        $app->db->query("UPDATE aps_instances SET instance_status = ".INSTANCE_INSTALL." WHERE id = ".$instanceid.";");
        $webserver_id = $this->getInstanceDataForDatalog($instanceid);
        if($webserver_id == '') return;
        // Create a sys_datalog entry for re-installation
        $datalog = array('instance_id' => $instanceid, 'server_id' => $webserver_id);
        $app->db->datalogSave('aps', 'INSERT', 'id', $instanceid, array(), $datalog);
        */
        $sql = "SELECT web_database.database_id as database_id FROM aps_instances_settings, web_database WHERE aps_instances_settings.value = web_database.database_name AND aps_instances_settings.value =  aps_instances_settings.name = 'main_database_name' AND aps_instances_settings.instance_id = ".$instanceid." LIMIT 0,1";
        $tmp = $app->db->queryOneRecord($sql);
        if($tmp['database_id'] > 0) $app->db->datalogDelete('web_database', 'database_id', $tmp['database_id']);
        $app->db->datalogUpdate('aps_instances', "instance_status = ".INSTANCE_INSTALL, 'id', $instanceid);
    }
    /**
     * Read the settings to be filled when installing
     *
     * @param $id the internal ID of the package
     * @return array
     */
    public function getPackageSettings($id)
    {
        global $app;
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($id).';');
        // Load in meta file if existing and register its namespaces
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        if(!file_exists($metafile))
            return array('error' => 'The metafile for '.$settings['Name'].' couldn\'t be found');
        $sxe = $this->readInMetaFile($metafile);
        $groupsettings = parent::getXPathValue($sxe, '//settings/group/setting', true);
        if(empty($groupsettings)) return array();
        $settings = array();
        foreach($groupsettings as $setting)
        {
            $setting_id = strval($setting['id']);
            if($setting['type'] == 'string' || $setting['type'] == 'email' || $setting['type'] == 'integer'
            || $setting['type'] == 'float' || $setting['type'] == 'domain-name')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => $setting['type'],
                                    'SettingInputType' => 'string',
                                    'SettingDefaultValue' => strval($setting['default-value']),
                                    'SettingRegex' => $setting['regex'],
                                    'SettingMinLength' => $setting['min-length'],
                                    'SettingMaxLength' => $setting['max-length']);
            }
            else if($setting['type'] == 'password')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => 'password',
                                    'SettingInputType' => 'password',
                                    'SettingDefaultValue' => '',
                                    'SettingRegex' => $setting['regex'],
                                    'SettingMinLength' => $setting['min-length'],
                                    'SettingMaxLength' => $setting['max-length']);
            }
            else if($setting['type'] == 'boolean')
            {
                $settings[] = array('SettingID' => $setting_id,
                                    'SettingName' => $setting->name,
                                    'SettingDescription' => $setting->description,
                                    'SettingType' => 'boolean',
                                    'SettingInputType' => 'checkbox',
                                    'SettingDefaultValue' => strval($setting['default-value']));
            }
            else if($setting['type'] == 'enum')
            {
              $choices = array();
              foreach($setting->choice as $choice)
              {
                $choices[] = array('EnumID' => strval($choice['id']),
                                   'EnumName' => $choice->name);
              }
              $settings[] = array('SettingID' => $setting_id,
                                  'SettingName' => $setting->name,
                                  'SettingDescription' => $setting->description,
                                  'SettingType' => 'enum',
                                  'SettingInputType' => 'select',
                                  'SettingDefaultValue' => strval($setting['default-value']),
                                  'SettingChoices' => $choices);
            }
        }
        return $settings;
    }
    /**
     * Validates the user input according to the settings array and
     * delivers errors if occurring
     *
     * @param $input the user $_POST array
     * @param $pkg_details the package details
     * @param $settings the package settings array
     * @return array in this structure:
     *               array(2) {
     *                  ["input"]=> ...
     *                  ["errors"]=> ...
     *               }
     */
    public function validateInstallerInput($postinput, $pkg_details, $domains, $settings = array())
    {
        global $app;
        $ret = array();
        $input = array();
        $error = array();
        // Main domain (obligatory)
        if(isset($postinput['main_domain']))
        {
            if(!in_array($postinput['main_domain'], $domains)) $error[] = $app->lng('error_main_domain');
            else $input['main_domain'] = $postinput['main_domain'];
        }
        else $error[] = $app->lng('error_main_domain');
        // Main location (not obligatory but must be supplied)
        if(isset($postinput['main_location']))
        {
            $temp_errstr = '';
            // It can be empty but if the user did write something, check it
            $userinput = false;
            if(strlen($postinput['main_location']) > 0) $userinput = true;
            // Filter invalid input slashes (twice!)
            $main_location = $this->secureLocation($postinput['main_location']);
            $main_location = $this->secureLocation($main_location);
            // Only allow digits, words, / and -
            $main_location = preg_replace("/[^\d\w\/\-]/i", "", $main_location);
            if($userinput && (strlen($main_location) == 0)) $temp_errstr = $app->lng('error_inv_main_location');
            // Find out document_root and make sure no apps are installed twice to one location
            if(in_array($postinput['main_domain'], $domains))
            {
                $docroot = $app->db->queryOneRecord("SELECT document_root FROM web_domain
                    WHERE domain = '".$app->db->quote($postinput['main_domain'])."';");
                $new_path = $docroot['document_root'];
                if(substr($new_path, -1) != '/') $new_path .= '/';
                $new_path .= $main_location;
                // Get the $customerid which belongs to the selected domain
                $customerid = $this->getCustomerIDFromDomain($postinput['main_domain']);
                // First get all domains used for an install, then their loop them
                // and get the corresponding document roots as well as the defined
                // locations. If an existing doc_root + location matches with the
                // new one -> error
                $instance_domains = $app->db->queryAllRecords("SELECT instance_id, s.value AS domain
                    FROM aps_instances AS i, aps_instances_settings AS s
                    WHERE i.id = s.instance_id AND s.name = 'main_domain'
                        AND i.customer_id = '".$app->db->quote($customerid)."';");
                for($i = 0; $i < count($instance_domains); $i++)
                {
                    $used_path = '';
                    $doc_root = $app->db->queryOneRecord("SELECT document_root FROM web_domain
                        WHERE domain = '".$app->db->quote($instance_domains[$i]['domain'])."';");
                    // Probably the domain settings were changed later, so make sure the doc_root
                    // is not empty for further validation
                    if(!empty($doc_root))
                    {
                        $used_path = $doc_root['document_root'];
                        if(substr($used_path, -1) != '/') $used_path .= '/';
                        $location_for_domain = $app->db->queryOneRecord("SELECT value
                            FROM aps_instances_settings WHERE name = 'main_location'
                            AND instance_id = '".$app->db->quote($instance_domains[$i]['instance_id'])."';");
                        // The location might be empty but the DB return must not be false!
                        if($location_for_domain) $used_path .= $location_for_domain['value'];
                        if($new_path == $used_path)
                        {
                            $temp_errstr = $app->lng('error_used_location');
                            break;
                        }
                    }
                }
            }
            else $temp_errstr = $app->lng('error_main_domain');
            if($temp_errstr == '') $input['main_location'] = htmlspecialchars($main_location);
            else $error[] = $temp_errstr;
        }
        else $error[] = $app->lng('error_no_main_location');
        // License (the checkbox must be set)
        if(isset($pkg_details['License need agree'])
        && $pkg_details['License need agree'] == 'true')
        {
            if(isset($postinput['license']) && $postinput['license'] == 'on') $input['license'] = 'true';
            else $error[] = $app->lng('error_license_agreement');
        }
        // Database
        if(isset($pkg_details['Requirements Database'])
        && $pkg_details['Requirements Database'] != '')
        {
            if(isset($postinput['main_database_password']))
            {
                if($postinput['main_database_password'] == '') $error[] = $app->lng('error_no_database_pw');
                else if(strlen($postinput['main_database_password']) > 8)
                    $input['main_database_password'] = htmlspecialchars($postinput['main_database_password']);
                else $error[] = $app->lng('error_short_database_pw');
            }
            else $error[] = $app->lng('error_no_database_pw');
        }
        // Validate the package settings
        foreach($settings as $setting)
        {
            $temp_errstr = '';
            $setting_id = strval($setting['SettingID']);
            // We assume that every setting must be set
            if((isset($postinput[$setting_id]) && ($postinput[$setting_id] != ''))
            || ($setting['SettingType'] == 'boolean'))
            {
                if($setting['SettingType'] == 'string' || $setting['SettingType'] == 'password')
                {
                    if($app->functions->intval($setting['SettingMinLength'], true) != 0
                    && strlen($postinput[$setting_id]) < $app->functions->intval($setting['SettingMinLength'], true))
                        $temp_errstr = sprintf($app->lng('error_short_value_for'), $setting['setting_name']);
                    if($app->functions->intval($setting['SettingMaxLength'], true) != 0
                    && strlen($postinput[$setting_id]) > $app->functions->intval($setting['SettingMaxLength'], true))
                        $temp_errstr = sprintf($app->lng('error_long_value_for'), $setting['setting_name']);
                    if(isset($setting['SettingRegex'])
                    && !preg_match("/".$setting['SettingRegex']."/", $postinput[$setting_id]))
                        $temp_errstr = sprintf($app->lng('error_inv_value_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'email')
                {
                    if(filter_var(strtolower($postinput[$setting_id]), FILTER_VALIDATE_EMAIL) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_email_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'domain-name')
                {
                    if(!preg_match("^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$",
                        $postinput[$setting_id]))
                    $temp_errstr = sprintf($app->lng('error_inv_domain_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'integer')
                {
                    if(filter_var($postinput[$setting_id], FILTER_VALIDATE_INT) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_integer_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'float')
                {
                    if(filter_var($postinput[$setting_id], FILTER_VALIDATE_FLOAT) === false)
                        $temp_errstr = sprintf($app->lng('error_inv_float_for'), $setting['setting_name']);
                }
                else if($setting['SettingType'] == 'boolean')
                {
                    // If we have a boolean value set, it must be either true or false
                    if(!isset($postinput[$setting_id])) $postinput[$setting_id] = 'false';
                    else if(isset($postinput[$setting_id]) && $postinput[$setting_id] != 'true')
                        $postinput[$setting_id] = 'true';
                }
                else if($setting['SettingType'] == 'enum')
                {
                    $found = false;
                    for($i = 0; $i < count($setting['SettingChoices']); $i++)
                    {
                        if($setting['SettingChoices'][$i]['EnumID'] == $postinput[$setting_id])
                            $found = true;
                    }
                    if(!$found) $temp_errstr = sprintf($app->lng('error_inv_value_for'), $setting['SettingName']);
                }
                if($temp_errstr == '') $input[$setting_id] = $postinput[$setting_id];
                else $error[] = $temp_errstr;
            }
            else $error[] = sprintf($app->lng('error_no_value_for'), $setting['SettingName']);
        }
        $ret['input'] = $input;
        $ret['error'] = array_unique($error);
        return $ret;
    }
    /**
     * Read the metadata of a package and returns some content
     *
     * @param $id the internal ID of the package
     * @return array
     */
    public function getPackageDetails($id)
    {
        global $app;
        $pkg = $app->db->queryOneRecord('SELECT * FROM aps_packages WHERE id = '.$app->db->quote($id).';');
        // Load in meta file if existing and register its namespaces
        $metafile = $this->interface_pkg_dir.'/'.$pkg['path'].'/APP-META.xml';
        if(!file_exists($metafile))
            return array('error' => 'The metafile for '.$pkg['name'].' couldn\'t be found');
        $metadata = file_get_contents($metafile);
        $metadata = str_replace("xmlns=", "ns=", $metadata);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        $pkg['Summary'] = htmlspecialchars(parent::getXPathValue($sxe, '//summary'));
        $pkg['Homepage'] = parent::getXPathValue($sxe, '//homepage');
        $pkg['Description'] = nl2br(htmlspecialchars(trim(parent::getXPathValue($sxe, '//description'))));
        $pkg['Config script'] = strtoupper(parent::getXPathValue($sxe, '//configuration-script-language'));
        $installed_size = parent::getXPathValue($sxe, '//installed-size');
        $pkg['Installed Size'] = (!empty($installed_size)) ? parent::convertSize((int)$installed_size) : '';
        // License
        $pkg['License need agree'] = parent::getXPathValue($sxe, '//license/@must-accept');
        $pkg['License name'] = parent::getXPathValue($sxe, '//license/text/name'); // might be empty
        $pkg['License type'] = 'file'; // default type
        $pkg['License content'] = ''; // default license filename on local system
        $license_url = parent::getXPathValue($sxe, '//license/text/url');
        if(!empty($license_url))
        {
            $pkg['License type'] = 'url';
            $pkg['License content'] = htmlspecialchars($license_url);
        }
        else
        {
            $lic = @file_get_contents($this->interface_pkg_dir.'/'.$pkg['path'].'/LICENSE');
            $pkg['License content'] = htmlentities($lic, ENT_QUOTES, 'ISO-8859-1');
        }
        // Languages
        $languages = parent::getXPathValue($sxe, '//languages/language', true);
        $pkg['Languages'] = (is_array($languages)) ? implode(' ', $languages) : '';
        // Icon
        $icon = parent::getXPathValue($sxe, '//icon/@path');
        if(!empty($icon))
        {
            // Using parse_url() to filter malformed URLs
            $path = dirname(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH)).'/'.
                    basename($this->interface_pkg_dir).'/'.$pkg['path'].'/'.basename((string)$icon);
            $pkg['Icon'] = $path;
        }
        else $pkg['Icon'] = '';
        // Screenshots
        $screenshots = parent::getXPathValue($sxe, '//screenshot', true);
        if(!empty($screenshots))
        {
            foreach($screenshots as $screen)
            {
                // Using parse_url() to filter malformed URLs
                $path = dirname(parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH)).'/'.
                        basename($this->interface_pkg_dir).'/'.$pkg['path'].'/'.basename((string)$screen['path']);
                $pkg['Screenshots'][] = array('ScreenPath' => $path,
                                              'ScreenDescription' => htmlspecialchars(trim((string)$screen->description)));
            }
        }
        else $pkg['Screenshots'] = ''; // if no screenshots are available, set the variable though
        // Changelog
        $changelog = parent::getXPathValue($sxe, '//changelog/version', true);
        if(!empty($changelog))
        {
            foreach($changelog as $change)
            {
                $entries = array();
                foreach($change->entry as $entry) $entries[] = htmlspecialchars(trim((string)$entry));
                $pkg['Changelog'][] = array('ChangelogVersion' => (string)$change['version'],
                                            'ChangelogDescription' => implode('<br />', $entries));
            }
        }
        else $pkg['Changelog'] = '';
        // PHP extensions
        $php_extensions = parent::getXPathValue($sxe, '//php:extension', true);
        $php_ext = '';
        if(!empty($php_extensions))
        {
            foreach($php_extensions as $extension)
            {
                if(strtolower($extension) == 'php') continue;
                $php_ext .= $extension.' ';
            }
        }
        $pkg['Requirements PHP extensions'] = trim($php_ext);
        // PHP bool options
        $pkg['Requirements PHP settings'] = '';
        $php_bool_options = array('allow-url-fopen', 'file-uploads', 'magic-quotes-gpc',
                                  'register-globals', 'safe-mode', 'short-open-tag');
        foreach($php_bool_options as $option)
        {
            $value = parent::getXPathValue($sxe, '//php:'.$option);
            if(!empty($value))
            {
                $option = str_replace('-', '_', $option);
                $value = str_replace(array('false', 'true'), array('off', 'on'), $value);
                $pkg['Requirements PHP settings'][] = array('PHPSettingName' => $option,
                                                            'PHPSettingValue' => $value);
            }
        }
        // PHP integer value settings
        $memory_limit = parent::getXPathValue($sxe, '//php:memory-limit');
        if(!empty($memory_limit))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'memory_limit',
                                                        'PHPSettingValue' => parent::convertSize((int)$memory_limit));
        $max_exec_time = parent::getXPathValue($sxe, '//php:max-execution-time');
        if(!empty($max_exec_time))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'max-execution-time',
                                                        'PHPSettingValue' => $max_exec_time);
        $post_max_size = parent::getXPathValue($sxe, '//php:post-max-size');
        if(!empty($post_max_size))
            $pkg['Requirements PHP settings'][] = array('PHPSettingName' => 'post_max_size',
                                                        'PHPSettingValue' => parent::convertSize((int)$post_max_size));
        // Get supported PHP versions
        $pkg['Requirements Supported PHP versions'] = '';
        $php_min_version = parent::getXPathValue($sxe, '//php:version/@min');
        $php_max_not_including = parent::getXPathValue($sxe, '//php:version/@max-not-including');
        if(!empty($php_min_version) && !empty($php_max_not_including))
            $pkg['Requirements Supported PHP versions'] = $php_min_version.' - '.$php_max_not_including;
        else if(!empty($php_min_version))
            $pkg['Requirements Supported PHP versions'] = '> '.$php_min_version;
        else if(!empty($php_max_not_including))
            $pkg['Requirements Supported PHP versions'] = '< '.$php_min_version;
        // Database
        $db_id = parent::getXPathValue($sxe, '//db:id');
        $db_server_type = parent::getXPathValue($sxe, '//db:server-type');
        $db_min_version = parent::getXPathValue($sxe, '//db:server-min-version');
        if(!empty($db_id))
        {
            $db_server_type = str_replace('postgresql', 'PostgreSQL', $db_server_type);
            $db_server_type = str_replace('microsoft:sqlserver', 'MSSQL', $db_server_type);
            $db_server_type = str_replace('mysql', 'MySQL', $db_server_type);
            $pkg['Requirements Database'] = $db_server_type;
            if(!empty($db_min_version)) $pkg['Requirements Database'] .= ' > '.$db_min_version;
        }
        else $pkg['Requirements Database'] = '';
        return $pkg;
    }
}
?>
interface/lib/classes/tform.inc.php
@@ -884,43 +884,43 @@
                                             $this->errorMessage .= $this->wordbook[$errmsg]."<br />\r\n";
                                          } else {
                                             $this->errorMessage .= $errmsg."<br />\r\n";
                                          }
                                        }
                                break;
                case 'ISV6PREFIX':
                    $v6_prefix_ok = 0;
                    $explode_field_value = explode(':',$field_value);
                    if ($explode_field_value[count($explode_field_value)-1]=='' && $explode_field_value[count($explode_field_value)-2]=='' ){
                            if ( count($explode_field_value) <= 9 ) {
                                    if(filter_var(substr($field_value,0,strlen($field_value)-2),FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).'::0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).':0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) ) {
                                            $v6_prefix_ok = 1;
                                    }
                            }
                    } else {
                        $v6_prefix_ok = 2;
                    }
                    // check subnet against defined server-ipv6
                    $sql_v6 = $app->db->queryOneRecord("SELECT ip_address FROM server_ip WHERE ip_type = 'IPv6' AND virtualhost = 'y' LIMIT 0,1");
                    $sql_v6_explode=explode(':',$sql_v6['ip_address']);
                    if ( count($sql_v6_explode) < count($explode_field_value) && isset($sql_v6['ip_address']) )  {
                        $v6_prefix_ok = 3;
                    }
                    if($v6_prefix_ok == 0) {
                        $errmsg = $validator['errmsg'];
                    }
                    if($v6_prefix_ok == 2) {
                        $errmsg = 'IPv6 Prefix must end with ::';
                    }
                    if($v6_prefix_ok == 3) {
                        $errmsg = 'IPv6 Prefix too long (according to Server IP Addresses)';
                    }
                    if($v6_prefix_ok <> 1){
                        $this->errorMessage .= $errmsg."<br />\r\n";
                    }
                break;
                                case 'ISIPV4':
                                $vip=1;
                                if(preg_match("/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/", $field_value)){
                                          }
                                        }
                                break;
                case 'ISV6PREFIX':
                    $v6_prefix_ok = 0;
                    $explode_field_value = explode(':',$field_value);
                    if ($explode_field_value[count($explode_field_value)-1]=='' && $explode_field_value[count($explode_field_value)-2]=='' ){
                            if ( count($explode_field_value) <= 9 ) {
                                    if(filter_var(substr($field_value,0,strlen($field_value)-2),FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).'::0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) or filter_var(substr($field_value,0,strlen($field_value)-2).':0',FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) ) {
                                            $v6_prefix_ok = 1;
                                    }
                            }
                    } else {
                        $v6_prefix_ok = 2;
                    }
                    // check subnet against defined server-ipv6
                    $sql_v6 = $app->db->queryOneRecord("SELECT ip_address FROM server_ip WHERE ip_type = 'IPv6' AND virtualhost = 'y' LIMIT 0,1");
                    $sql_v6_explode=explode(':',$sql_v6['ip_address']);
                    if ( count($sql_v6_explode) < count($explode_field_value) && isset($sql_v6['ip_address']) )  {
                        $v6_prefix_ok = 3;
                    }
                    if($v6_prefix_ok == 0) {
                        $errmsg = $validator['errmsg'];
                    }
                    if($v6_prefix_ok == 2) {
                        $errmsg = 'IPv6 Prefix must end with ::';
                    }
                    if($v6_prefix_ok == 3) {
                        $errmsg = 'IPv6 Prefix too long (according to Server IP Addresses)';
                    }
                    if($v6_prefix_ok <> 1){
                        $this->errorMessage .= $errmsg."<br />\r\n";
                    }
                break;
                                case 'ISIPV4':
                                $vip=1;
                                if(preg_match("/^[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}(\.)[0-9]{1,3}$/", $field_value)){
                                $groups=explode(".",$field_value);
                                foreach($groups as $group){
                                    if($group<0 OR $group>255)
interface/web/admin/form/server_config.tform.php
@@ -83,20 +83,20 @@
                    'errmsg' => 'netmask_error_wrong'),
            ),
            'value' => '',
            'width' => '15',
            'maxlength' => '255'
        ),
        'v6_prefix' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
                        'validators' => array(0 => array('type' => 'ISV6PREFIX',
                                        'errmsg' => 'v6_prefix_wrong'),
                        ),
        'default' => ''
        ),
        'gateway' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'width' => '15',
            'maxlength' => '255'
        ),
        'v6_prefix' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
                        'validators' => array(0 => array('type' => 'ISV6PREFIX',
                                        'errmsg' => 'v6_prefix_wrong'),
                        ),
        'default' => ''
        ),
        'gateway' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'default' => '192.168.0.1',
            'validators' => array(0 => array('type' => 'ISIPV4',
                    'errmsg' => 'gateway_error_wrong'),
@@ -421,22 +421,22 @@
            'formtype' => 'TEXT',
            'default' => '',
            'value' => '',
            'width' => '40',
            'maxlength' => '255'
        ),
/*
'vhost_rewrite_v6' => array (
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
'default' => 'n',
'value' => array(0 => 'n',1 => 'y')
),
*/
        'vhost_conf_dir' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'width' => '40',
            'maxlength' => '255'
        ),
/*
'vhost_rewrite_v6' => array (
'datatype' => 'VARCHAR',
'formtype' => 'CHECKBOX',
'default' => 'n',
'value' => array(0 => 'n',1 => 'y')
),
*/
        'vhost_conf_dir' => array(
            'datatype' => 'VARCHAR',
            'formtype' => 'TEXT',
            'default' => '',
            'validators' => array(0 => array('type' => 'NOTEMPTY',
                    'errmsg' => 'vhost_conf_dir_error_empty'),
interface/web/admin/lib/lang/en_server_config.lng
@@ -167,15 +167,15 @@
$wb["firewall_txt"] = 'Firewall';
$wb["mailbox_quota_stats_txt"] = 'Mailbox quota statistics';
$wb["enable_ip_wildcard_txt"] = 'Enable IP wildcard (*)';
$wb["web_folder_protection_txt"] = 'Make web folders immutable (extended attributes)';
$wb["overtraffic_notify_admin_txt"] = 'Send overtraffic notification to admin';
$wb["overtraffic_notify_client_txt"] = 'Send overtraffic notification to client';
$wb["v6_prefix_txt"] = 'IPv6 Prefix';
$wb["vhost_rewrite_v6_txt"] = 'Rewrite IPv6 on Mirror';
$wb["web_folder_protection_txt"] = 'Make web folders immutable (extended attributes)';
$wb["overtraffic_notify_admin_txt"] = 'Send overtraffic notification to admin';
$wb["overtraffic_notify_client_txt"] = 'Send overtraffic notification to client';
$wb["v6_prefix_txt"] = 'IPv6 Prefix';
$wb["vhost_rewrite_v6_txt"] = 'Rewrite IPv6 on Mirror';
$wb["v6_prefix_wrong"] = 'Invalid v6 Netmask format.';
$wb["php_ini_check_minutes_txt"] = 'Check system php.ini files for changes each';
$wb["php_ini_check_minutes_info_txt"] = 'minutes (0 disables checking)';
$wb['php_ini_check_minutes_error_empty'] = 'Invalid value for php.ini checking.';
$wb["sendmail_path_txt"] = 'Sendmail Path';
$wb["sendmail_path_error_empty"] = 'Sendmail Path is empty.';
?>
?>
interface/web/admin/lib/menu.d/tpl_default.menu.php
@@ -1,15 +1,15 @@
<?php
/* Removed because tpl_default.php does not work
for($m = 0; $m < count($module['nav']); $m++) {
    if($module['nav'][$m]['title'] == 'Interface') {
        $module['nav'][$m]['items'][] = array(  'title'     => 'Default Theme',
                                                'target'     => 'content',
                                                'link'    => 'admin/tpl_default.php',
                                                'html_id'   => 'tpl_default');
        break;
    }
}
*/
?>
<?php
/* Removed because tpl_default.php does not work
for($m = 0; $m < count($module['nav']); $m++) {
    if($module['nav'][$m]['title'] == 'Interface') {
        $module['nav'][$m]['items'][] = array(  'title'     => 'Default Theme',
                                                'target'     => 'content',
                                                'link'    => 'admin/tpl_default.php',
                                                'html_id'   => 'tpl_default');
        break;
    }
}
*/
?>
interface/web/admin/templates/iptables_edit.htm
@@ -1,67 +1,67 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_iptables">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <div class="ctrlHolder">
                <label for="server_id">{tmpl_var name='server_id_txt'}</label>
                <select name="server_id" id="server_id" class="selectInput">
                    {tmpl_var name='server_id'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="table">{tmpl_var name='table_txt'}</label>
                <select name="table" id="table" class="selectInput formLengthLimit">
                    {tmpl_var name='table'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="protocol">{tmpl_var name='protocol_txt'}</label>
                <select name="protocol" id="protocol" class="selectInput formLengthLimit">
                    {tmpl_var name='protocol'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="singleport">{tmpl_var name='singleport_txt'}</label>
                <input name="singleport" id="singleport" value="{tmpl_var name='singleport'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
            <div class="ctrlHolder">
                <label for="multiport">{tmpl_var name='multiport_txt'}</label>
                <input name="multiport" id="multiport" value="{tmpl_var name='multiport'}" size="20" maxlength="40" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder">
                <label for="destination_ip">{tmpl_var name='destination_ip_txt'}</label>
                <input name="destination_ip" id="destination_ip" value="{tmpl_var name='destination_ip'}" size="16" maxlength="20" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="source_ip">{tmpl_var name='source_ip_txt'}</label>
                <input name="source_ip" id="source_ip" value="{tmpl_var name='source_ip'}" size="16" maxlength="20" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="state">{tmpl_var name='state_txt'}</label>
                <input name="state" id="state" value="{tmpl_var name='state'}" size="16" maxlength="20" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder">
                <label for="target">{tmpl_var name='target_txt'}</label>
                <select name="target" id="target" class="selectInput formLengthLimit">
                    {tmpl_var name='target'}
                </select>
            </div>
            <div class="ctrlHolder">
                <p class="label">{tmpl_var name='active_txt'}</p>
                <div class="multiField">
                    {tmpl_var name='active'}
                </div>
            </div>
        </fieldset>
        <input type="hidden" name="id" value="{tmpl_var name='id'}">
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','admin/iptables_edit.php');">
                <span>{tmpl_var name='btn_save_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('admin/iptables_list.php');">
                <span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_iptables">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <div class="ctrlHolder">
                <label for="server_id">{tmpl_var name='server_id_txt'}</label>
                <select name="server_id" id="server_id" class="selectInput">
                    {tmpl_var name='server_id'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="table">{tmpl_var name='table_txt'}</label>
                <select name="table" id="table" class="selectInput formLengthLimit">
                    {tmpl_var name='table'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="protocol">{tmpl_var name='protocol_txt'}</label>
                <select name="protocol" id="protocol" class="selectInput formLengthLimit">
                    {tmpl_var name='protocol'}
                </select>
            </div>
            <div class="ctrlHolder">
                <label for="singleport">{tmpl_var name='singleport_txt'}</label>
                <input name="singleport" id="singleport" value="{tmpl_var name='singleport'}" size="10" maxlength="10" type="text" class="textInput formLengthLimit" />
            </div>
            <div class="ctrlHolder">
                <label for="multiport">{tmpl_var name='multiport_txt'}</label>
                <input name="multiport" id="multiport" value="{tmpl_var name='multiport'}" size="20" maxlength="40" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder">
                <label for="destination_ip">{tmpl_var name='destination_ip_txt'}</label>
                <input name="destination_ip" id="destination_ip" value="{tmpl_var name='destination_ip'}" size="16" maxlength="20" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="source_ip">{tmpl_var name='source_ip_txt'}</label>
                <input name="source_ip" id="source_ip" value="{tmpl_var name='source_ip'}" size="16" maxlength="20" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="state">{tmpl_var name='state_txt'}</label>
                <input name="state" id="state" value="{tmpl_var name='state'}" size="16" maxlength="20" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder">
                <label for="target">{tmpl_var name='target_txt'}</label>
                <select name="target" id="target" class="selectInput formLengthLimit">
                    {tmpl_var name='target'}
                </select>
            </div>
            <div class="ctrlHolder">
                <p class="label">{tmpl_var name='active_txt'}</p>
                <div class="multiField">
                    {tmpl_var name='active'}
                </div>
            </div>
        </fieldset>
        <input type="hidden" name="id" value="{tmpl_var name='id'}">
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','admin/iptables_edit.php');">
                <span>{tmpl_var name='btn_save_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('admin/iptables_list.php');">
                <span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
</div>
interface/web/admin/templates/iptables_list.htm
@@ -1,74 +1,74 @@
<h2><tmpl_var name="list_head_txt"></h2>
<div class="panel panel_list_iptables">
    <div class="pnl_toolsarea">
        <fieldset><legend>Tools</legend>
            <div class="buttons">
                <button class="button iconstxt icoAdd" type="button" onclick="loadContent('admin/iptables_edit.php');">
                    <span>{tmpl_var name="add_new_rule_txt"}</span>
                </button>
            </div>
        </fieldset>
    </div>
    <div class="pnl_listarea">
        <fieldset><legend><tmpl_var name="list_head_txt"></legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_active" scope="col"><tmpl_var name="active_txt"></th>
                        <th class="tbl_col_server_id" scope="col"><tmpl_var name="server_id_txt"></th>
                        <th class="tbl_col_table" scope="col"><tmpl_var name="table_txt"></th>
                        <th class="tbl_col_protocol" scope="col"><tmpl_var name="protocol_txt"></th>
                        <th class="tbl_col_port" scope="col"><tmpl_var name="singleport_txt"></th>
                        <th class="tbl_col_port" scope="col"><tmpl_var name="multiport_txt"></th>
                        <th class="tbl_col_state" scope="col"><tmpl_var name="state_txt"></th>
                        <th class="tbl_col_target" scope="col"><tmpl_var name="target_txt"></th>
                        <th class="tbl_col_buttons" scope="col">&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_active"><select name="search_active">{tmpl_var name='search_active'}</select></td>
                        <td class="tbl_col_server_id"><select name="search_server_id">{tmpl_var name='search_server_id'}</select></td>
                        <td class="tbl_col_table"></td>
                        <td class="tbl_col_protocol"><select name="search_protocol">{tmpl_var name='search_protocol'}</select></td>
                        <td class="tbl_col_singleport"></td>
                        <td class="tbl_col_multiport"></td>
                        <td class="tbl_col_state"></td>
                        <td class="tbl_col_target"><select name="search_target">{tmpl_var name='search_target'}</select></td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" onclick="submitForm('pageForm','admin/iptables_list.php');"><span>{tmpl_var name="filter_txt"}filter_txt</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name="records">
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_active"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="active"}</a></td>
                            <td class="tbl_col_server_id"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="server_id"}</a></td>
                            <td class="tbl_col_table"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="table"}</a></td>
                            <td class="tbl_col_protocol"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="protocol"}</a></td>
                            <td class="tbl_col_singleport"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="singleport"}</a></td>
                            <td class="tbl_col_multiport"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="multiport"}</a></td>
                            <td class="tbl_col_state"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="state"}</a></td>
                            <td class="tbl_col_target"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="target"}</a></td>
                            <td class="tbl_col_buttons">
                                <a class="button icons16 icoDelete" href="javascript: del_record('admin/iptables_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span>{tmpl_var name='delete_txt'}</span></a>
                            </td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="9">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="9"><tmpl_var name="paging"></td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
<h2><tmpl_var name="list_head_txt"></h2>
<div class="panel panel_list_iptables">
    <div class="pnl_toolsarea">
        <fieldset><legend>Tools</legend>
            <div class="buttons">
                <button class="button iconstxt icoAdd" type="button" onclick="loadContent('admin/iptables_edit.php');">
                    <span>{tmpl_var name="add_new_rule_txt"}</span>
                </button>
            </div>
        </fieldset>
    </div>
    <div class="pnl_listarea">
        <fieldset><legend><tmpl_var name="list_head_txt"></legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_active" scope="col"><tmpl_var name="active_txt"></th>
                        <th class="tbl_col_server_id" scope="col"><tmpl_var name="server_id_txt"></th>
                        <th class="tbl_col_table" scope="col"><tmpl_var name="table_txt"></th>
                        <th class="tbl_col_protocol" scope="col"><tmpl_var name="protocol_txt"></th>
                        <th class="tbl_col_port" scope="col"><tmpl_var name="singleport_txt"></th>
                        <th class="tbl_col_port" scope="col"><tmpl_var name="multiport_txt"></th>
                        <th class="tbl_col_state" scope="col"><tmpl_var name="state_txt"></th>
                        <th class="tbl_col_target" scope="col"><tmpl_var name="target_txt"></th>
                        <th class="tbl_col_buttons" scope="col">&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_active"><select name="search_active">{tmpl_var name='search_active'}</select></td>
                        <td class="tbl_col_server_id"><select name="search_server_id">{tmpl_var name='search_server_id'}</select></td>
                        <td class="tbl_col_table"></td>
                        <td class="tbl_col_protocol"><select name="search_protocol">{tmpl_var name='search_protocol'}</select></td>
                        <td class="tbl_col_singleport"></td>
                        <td class="tbl_col_multiport"></td>
                        <td class="tbl_col_state"></td>
                        <td class="tbl_col_target"><select name="search_target">{tmpl_var name='search_target'}</select></td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" onclick="submitForm('pageForm','admin/iptables_list.php');"><span>{tmpl_var name="filter_txt"}filter_txt</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name="records">
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_active"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="active"}</a></td>
                            <td class="tbl_col_server_id"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="server_id"}</a></td>
                            <td class="tbl_col_table"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="table"}</a></td>
                            <td class="tbl_col_protocol"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="protocol"}</a></td>
                            <td class="tbl_col_singleport"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="singleport"}</a></td>
                            <td class="tbl_col_multiport"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="multiport"}</a></td>
                            <td class="tbl_col_state"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="state"}</a></td>
                            <td class="tbl_col_target"><a href="#" onclick="loadContent('admin/iptables_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="target"}</a></td>
                            <td class="tbl_col_buttons">
                                <a class="button icons16 icoDelete" href="javascript: del_record('admin/iptables_del.php?id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}','{tmpl_var name='delete_confirmation'}');"><span>{tmpl_var name='delete_txt'}</span></a>
                            </td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="9">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="9"><tmpl_var name="paging"></td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/admin/templates/server_config_server_edit.htm
@@ -16,16 +16,16 @@
                <input name="ip_address" id="ip_address" value="{tmpl_var name='ip_address'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="netmask">{tmpl_var name='netmask_txt'}</label>
                <input name="netmask" id="netmask" value="{tmpl_var name='netmask'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
       <div class="ctrlHolder">
        <label for="v6_prefix">{tmpl_var name='v6_prefix_txt'}</label>
        <input name="v6_prefix" id="v6_prefix" value="{tmpl_var name='v6_prefix'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
           </div>
            <div class="ctrlHolder">
                <label for="gateway">{tmpl_var name='gateway_txt'}</label>
                <input name="gateway" id="gateway" value="{tmpl_var name='gateway'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
                <label for="netmask">{tmpl_var name='netmask_txt'}</label>
                <input name="netmask" id="netmask" value="{tmpl_var name='netmask'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
       <div class="ctrlHolder">
        <label for="v6_prefix">{tmpl_var name='v6_prefix_txt'}</label>
        <input name="v6_prefix" id="v6_prefix" value="{tmpl_var name='v6_prefix'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
           </div>
            <div class="ctrlHolder">
                <label for="gateway">{tmpl_var name='gateway_txt'}</label>
                <input name="gateway" id="gateway" value="{tmpl_var name='gateway'}" size="15" maxlength="255" type="text" class="textInput formLengthIPv4" />
            </div>
            <div class="ctrlHolder">
                <label for="hostname">{tmpl_var name='hostname_txt'}</label>
@@ -65,7 +65,7 @@
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','admin/server_config_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('admin/server_config_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
</div>
        </div>
    </div>
</div>
interface/web/admin/templates/server_config_web_edit.htm
@@ -32,20 +32,20 @@
                </div>
            </div>
            <div class="ctrlHolder">
                <label for="website_autoalias">{tmpl_var name='website_autoalias_txt'}</label>
                <input name="website_autoalias" id="website_autoalias" value="{tmpl_var name='website_autoalias'}" size="40" maxlength="255" type="text" class="textInput" />&nbsp;{tmpl_var name='website_autoalias_note_txt'} <a href="javascript:void(0);" class="addPlaceholder">[client_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[client_username]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_domain]</a>
                <label for="website_autoalias">{tmpl_var name='website_autoalias_txt'}</label>
                <input name="website_autoalias" id="website_autoalias" value="{tmpl_var name='website_autoalias'}" size="40" maxlength="255" type="text" class="textInput" />&nbsp;{tmpl_var name='website_autoalias_note_txt'} <a href="javascript:void(0);" class="addPlaceholder">[client_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[client_username]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_id]</a>, <a href="javascript:void(0);" class="addPlaceholder">[website_domain]</a>
            </div>
            <!--
        <div class="ctrlHolder apache">
            <label for="vhost_rewrite_v6">{tmpl_var name='vhost_rewrite_v6_txt'}</label>
            <div class="multiField">
                {tmpl_var name='vhost_rewrite_v6'}
            </div>
            <!--
        <div class="ctrlHolder apache">
            <label for="vhost_rewrite_v6">{tmpl_var name='vhost_rewrite_v6_txt'}</label>
            <div class="multiField">
                {tmpl_var name='vhost_rewrite_v6'}
            </div>
        </div>
            -->
            <div class="ctrlHolder apache">
                <label for="vhost_conf_dir">{tmpl_var name='vhost_conf_dir_txt'}</label>
                <input name="vhost_conf_dir" id="vhost_conf_dir" value="{tmpl_var name='vhost_conf_dir'}" size="40" maxlength="255" type="text" class="textInput" />
            -->
            <div class="ctrlHolder apache">
                <label for="vhost_conf_dir">{tmpl_var name='vhost_conf_dir_txt'}</label>
                <input name="vhost_conf_dir" id="vhost_conf_dir" value="{tmpl_var name='vhost_conf_dir'}" size="40" maxlength="255" type="text" class="textInput" />
            </div>
            <div class="ctrlHolder apache">
                <label for="vhost_conf_enabled_dir">{tmpl_var name='vhost_conf_enabled_dir_txt'}</label>
@@ -262,7 +262,7 @@
            jQuery('.apache').hide();
        } else {
            jQuery('.nginx').hide();
            jQuery('.apache').show();
        }
    }
</script>
            jQuery('.apache').show();
        }
    }
</script>
interface/web/admin/templates/system_config_branding_edit.html
@@ -1,22 +1,22 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_system_config">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="branding_txt">Branding</legend>
            <div class="ctrlHolder">
                <p class="label">{tmpl_var name='allow_themechange_txt'}Allow users to change theme</p>
                <div class="multiField">
                    {tmpl_var name='allow_themechange'}
                </div>
            </div>
        </fieldset>
        <input type="hidden" name="id" value="{tmpl_var name='id'}">
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onClick="submitForm('pageForm','admin/system_config_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onClick="loadContent('admin/server_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_system_config">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="branding_txt">Branding</legend>
            <div class="ctrlHolder">
                <p class="label">{tmpl_var name='allow_themechange_txt'}Allow users to change theme</p>
                <div class="multiField">
                    {tmpl_var name='allow_themechange'}
                </div>
            </div>
        </fieldset>
        <input type="hidden" name="id" value="{tmpl_var name='id'}">
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onClick="submitForm('pageForm','admin/system_config_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onClick="loadContent('admin/server_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
</div>
interface/web/client/client_template_edit.php
@@ -1,97 +1,97 @@
<?php
/*
Copyright (c) 2007-2010, Till Brehm, projektfarm Gmbh and Oliver Vogel www.muv.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/******************************************
* Begin Form configuration
******************************************/
$tform_def_file = "form/client_template.tform.php";
/******************************************
* End Form configuration
******************************************/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//* Check permissions for module
$app->auth->check_module_permissions('client');
if(!$_SESSION["s"]["user"]["typ"] == 'admin') die('Client-Templates are only for Admins.');
// Loading classes
$app->uses('tpl,tform,tform_actions');
$app->load('tform_actions');
class page_action extends tform_actions {
    function onBeforeUpdate() {
        global $app;
        if(isset($this->dataRecord['template_type'])) {
            //* Check if the template_type has been changed
            $rec = $app->db->queryOneRecord("SELECT template_type from client_template WHERE template_id = ".$this->id);
            if($rec['template_type'] != $this->dataRecord['template_type']) {
                //* Add a error message and switch back to old server
                $app->tform->errorMessage .= $app->lng('The template type can not be changed.');
                $this->dataRecord['template_type'] = $rec['template_type'];
            }
            unset($rec);
        }
    }
    /*
     This function is called automatically right after
     the data was successful updated in the database.
    */
    function onAfterUpdate() {
        global $app;
        $app->uses('client_templates');
        /*
         * the template has changed. apply the new data to all clients
         */
        if ($this->dataRecord["template_type"] == 'm'){
            $sql = "SELECT client_id FROM client WHERE template_master = " . $this->id;
        } else {
            $sql = "SELECT client_id FROM client WHERE template_additional LIKE '%/" . $this->id . "/%'";
        }
        $clients = $app->db->queryAllRecords($sql);
        if (is_array($clients)){
            foreach ($clients as $client){
                $app->client_templates->apply_client_templates($client['client_id']);
            }
        }
    }
}
$page = new page_action;
$page->onLoad();
?>
<?php
/*
Copyright (c) 2007-2010, Till Brehm, projektfarm Gmbh and Oliver Vogel www.muv.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/******************************************
* Begin Form configuration
******************************************/
$tform_def_file = "form/client_template.tform.php";
/******************************************
* End Form configuration
******************************************/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//* Check permissions for module
$app->auth->check_module_permissions('client');
if(!$_SESSION["s"]["user"]["typ"] == 'admin') die('Client-Templates are only for Admins.');
// Loading classes
$app->uses('tpl,tform,tform_actions');
$app->load('tform_actions');
class page_action extends tform_actions {
    function onBeforeUpdate() {
        global $app;
        if(isset($this->dataRecord['template_type'])) {
            //* Check if the template_type has been changed
            $rec = $app->db->queryOneRecord("SELECT template_type from client_template WHERE template_id = ".$this->id);
            if($rec['template_type'] != $this->dataRecord['template_type']) {
                //* Add a error message and switch back to old server
                $app->tform->errorMessage .= $app->lng('The template type can not be changed.');
                $this->dataRecord['template_type'] = $rec['template_type'];
            }
            unset($rec);
        }
    }
    /*
     This function is called automatically right after
     the data was successful updated in the database.
    */
    function onAfterUpdate() {
        global $app;
        $app->uses('client_templates');
        /*
         * the template has changed. apply the new data to all clients
         */
        if ($this->dataRecord["template_type"] == 'm'){
            $sql = "SELECT client_id FROM client WHERE template_master = " . $this->id;
        } else {
            $sql = "SELECT client_id FROM client WHERE template_additional LIKE '%/" . $this->id . "/%'";
        }
        $clients = $app->db->queryAllRecords($sql);
        if (is_array($clients)){
            foreach ($clients as $client){
                $app->client_templates->apply_client_templates($client['client_id']);
            }
        }
    }
}
$page = new page_action;
$page->onLoad();
?>
interface/web/mail/templates/user_quota_stats_list.htm
@@ -1,51 +1,51 @@
<h2><tmpl_var name="list_head_txt"></h2>
<div class="panel panel_list_user_quota_stats">
    <div class="pnl_listarea">
        <fieldset><legend><tmpl_var name="list_head_txt"></legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_email" scope="col"><tmpl_var name="email_txt"></th>
                        <th class="tbl_col_name" scope="col"><tmpl_var name="name_txt"></th>
                        <th class="tbl_col_used tbl_col_nosort" scope="col"><tmpl_var name="used_txt"></th>
                        <th class="tbl_col_quota" scope="col"><tmpl_var name="quota_txt"></th>
                        <th class="tbl_col_limit" scope="col">{tmpl_var name='search_limit'}</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_email"><input type="text" name="search_email" value="{tmpl_var name='search_email'}" /></td>
                        <td class="tbl_col_name"><input type="text" name="search_system_user" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_used">&nbsp;</td>
                        <td class="tbl_col_quota">&nbsp;</td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" onclick="submitForm('pageForm','mail/user_quota_stats.php');"><span>{tmpl_var name="filter_txt"}</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name="records">
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_email"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="email"}</a></td>
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="name"}</a></td>
                            <td class="tbl_col_used"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="used"}</a></td>
                            <td class="tbl_col_quota"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="quota"}</a></td>
                            <td class="tbl_col_buttons"></td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="5">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5"><tmpl_var name="paging"></td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
<h2><tmpl_var name="list_head_txt"></h2>
<div class="panel panel_list_user_quota_stats">
    <div class="pnl_listarea">
        <fieldset><legend><tmpl_var name="list_head_txt"></legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_email" scope="col"><tmpl_var name="email_txt"></th>
                        <th class="tbl_col_name" scope="col"><tmpl_var name="name_txt"></th>
                        <th class="tbl_col_used tbl_col_nosort" scope="col"><tmpl_var name="used_txt"></th>
                        <th class="tbl_col_quota" scope="col"><tmpl_var name="quota_txt"></th>
                        <th class="tbl_col_limit" scope="col">{tmpl_var name='search_limit'}</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_email"><input type="text" name="search_email" value="{tmpl_var name='search_email'}" /></td>
                        <td class="tbl_col_name"><input type="text" name="search_system_user" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_used">&nbsp;</td>
                        <td class="tbl_col_quota">&nbsp;</td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name="filter_txt"}" onclick="submitForm('pageForm','mail/user_quota_stats.php');"><span>{tmpl_var name="filter_txt"}</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name="records">
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_email"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="email"}</a></td>
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="name"}</a></td>
                            <td class="tbl_col_used"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="used"}</a></td>
                            <td class="tbl_col_quota"><a href="#" onclick="loadContent('mail/mail_user_edit.php?id={tmpl_var name='id'}');">{tmpl_var name="quota"}</a></td>
                            <td class="tbl_col_buttons"></td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="5">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5"><tmpl_var name="paging"></td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/monitor/templates/show_sys_state.htm
@@ -1,25 +1,25 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_sys_state">
    <div class="pnl_toolsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="monTransRefreshsq"></legend>
            <div class="buttons">
                <div class="ctrlHolder">
                    <label for="refreshinterval">&nbsp;</label>
                    <select name="refreshinterval" id="refreshinterval" class="selectInput withicons" onChange="loadContentRefresh('monitor/show_sys_state.php?state={tmpl_var name="state_type"}')">
                        {tmpl_var name='refresh'}
                    </select>
                </div>
            </div>
        </fieldset>
    </div>
    <div class="pnl_formarea">
        <fieldset><legend></legend>
            <div class="stateview"><tmpl_var name="state_data"></div>
        </fieldset>
    </div>
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_sys_state">
    <div class="pnl_toolsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="monTransRefreshsq"></legend>
            <div class="buttons">
                <div class="ctrlHolder">
                    <label for="refreshinterval">&nbsp;</label>
                    <select name="refreshinterval" id="refreshinterval" class="selectInput withicons" onChange="loadContentRefresh('monitor/show_sys_state.php?state={tmpl_var name="state_type"}')">
                        {tmpl_var name='refresh'}
                    </select>
                </div>
            </div>
        </fieldset>
    </div>
    <div class="pnl_formarea">
        <fieldset><legend></legend>
            <div class="stateview"><tmpl_var name="state_data"></div>
        </fieldset>
    </div>
</div>
interface/web/sites/aps_cron_apscrawler_if.php
@@ -1,63 +1,63 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.crawler.php');
$app->load('aps_crawler');
if(!@ini_get('allow_url_fopen')) $app->error('allow_url_fopen is not enabled.');
if(!function_exists('curl_version')) $app->error('The PHP CURL extension is not available.');
$log_prefix = 'APS crawler cron: ';
$aps = new ApsCrawler($app, true); // true = Interface mode, false = Server mode
$app->log($log_prefix.'Used mem at begin: '.$aps->convertSize(memory_get_usage(true)));
$time_start = microtime(true);
$aps->startCrawler();
$aps->parseFolderToDB();
$aps->fixURLs();
$time = microtime(true) - $time_start;
$app->log($log_prefix.'Used mem at end: '.$aps->convertSize(memory_get_usage(true)));
$app->log($log_prefix.'Mem peak during execution: '.$aps->convertSize(memory_get_peak_usage(true)));
$app->log($log_prefix.'Execution time: '.round($time, 3).' seconds');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
$app->load_language_file('web/sites/'.$lngfile);
echo '<div id="OKMsg"><p>'.$app->lng('packagelist_update_finished_txt').'</p></div>';
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.crawler.php');
$app->load('aps_crawler');
if(!@ini_get('allow_url_fopen')) $app->error('allow_url_fopen is not enabled.');
if(!function_exists('curl_version')) $app->error('The PHP CURL extension is not available.');
$log_prefix = 'APS crawler cron: ';
$aps = new ApsCrawler($app, true); // true = Interface mode, false = Server mode
$app->log($log_prefix.'Used mem at begin: '.$aps->convertSize(memory_get_usage(true)));
$time_start = microtime(true);
$aps->startCrawler();
$aps->parseFolderToDB();
$aps->fixURLs();
$time = microtime(true) - $time_start;
$app->log($log_prefix.'Used mem at end: '.$aps->convertSize(memory_get_usage(true)));
$app->log($log_prefix.'Mem peak during execution: '.$aps->convertSize(memory_get_peak_usage(true)));
$app->log($log_prefix.'Execution time: '.round($time, 3).' seconds');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
$app->load_language_file('web/sites/'.$lngfile);
echo '<div id="OKMsg"><p>'.$app->lng('packagelist_update_finished_txt').'</p></div>';
?>
interface/web/sites/aps_do_operation.php
@@ -1,112 +1,112 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
$gui = new ApsGUIController($app);
// An action and ID are required in any case
if(!isset($_GET['action'])) die('No action');
// List of operations which can be performed
if($_GET['action'] == 'change_status')
{
    // Only admins can perform this operation
    if($_SESSION['s']['user']['typ'] != 'admin') die('For admin use only.');
    // Make sure a valid package ID is given
    if(!$gui->isValidPackageID($_GET['id'], true)) die($app->lng('Invalid ID'));
    // Change the existing status to the opposite
    $get_status = $app->db->queryOneRecord("SELECT package_status FROM aps_packages WHERE id = '".$app->functions->intval($_GET['id'])."';");
    if($get_status['package_status'] == strval(PACKAGE_LOCKED))
    {
        $app->db->query("UPDATE aps_packages SET package_status = ".PACKAGE_ENABLED." WHERE id = '".$app->functions->intval($_GET['id'])."';");
        echo '<div class="swap" id="ir-Yes"><span>'.$app->lng('Yes').'</span></div>';
    }
    else
    {
        $app->db->query("UPDATE aps_packages SET Package_status = ".PACKAGE_LOCKED." WHERE id = '".$app->functions->intval($_GET['id'])."';");
        echo '<div class="swap" id="ir-No"><span>'.$app->lng('No').'</span></div>';
    }
}
else if($_GET['action'] == 'delete_instance')
{
    // Make sure a valid package ID is given (also corresponding to the calling user)
    $client_id = 0;
    $is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
    if(!$is_admin)
    {
        $cid = $app->db->queryOneRecord("SELECT client_id FROM client WHERE username = '".$app->db->quote($_SESSION['s']['user']['username'])."';");
        $client_id = $cid['client_id'];
    }
    // Assume that the given instance belongs to the currently calling client_id. Unimportant if status is admin
    if(!$gui->isValidInstanceID($_GET['id'], $client_id, $is_admin)) die($app->lng('Invalid ID'));
    // Only delete the instance if the status is "installed" or "flawed"
    $check = $app->db->queryOneRecord("SELECT id FROM aps_instances
        WHERE id = ".$app->db->quote($_GET['id'])." AND
        (instance_status = ".INSTANCE_SUCCESS." OR instance_status = ".INSTANCE_ERROR.");");
    if($check['id'] > 0) $gui->deleteInstance($_GET['id']);
    //echo $app->lng('Installation_remove');
    @header('Location:aps_installedpackages_list.php');
}
else if($_GET['action'] == 'reinstall_instance')
{
    // Make sure a valid package ID is given (also corresponding to the calling user)
    $client_id = 0;
    $is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
    if(!$is_admin)
    {
        $cid = $app->db->queryOneRecord("SELECT client_id FROM client WHERE username = '".$app->db->quote($_SESSION['s']['user']['username'])."';");
        $client_id = $cid['client_id'];
    }
    // Assume that the given instance belongs to the currently calling client_id. Unimportant if status is admin
    if(!$gui->isValidInstanceID($_GET['id'], $client_id, $is_admin)) die($app->lng('Invalid ID'));
    // We've an InstanceID, so make sure the package is not enabled and InstanceStatus is still "installed"
    $check = $app->db->queryOneRecord("SELECT aps_instances.id FROM aps_instances, aps_packages
        WHERE aps_instances.package_id = aps_packages.id
        AND aps_instances.instance_status = ".INSTANCE_SUCCESS."
        AND aps_packages.package_status = ".PACKAGE_ENABLED."
        AND aps_instances.id = ".$app->db->quote($_GET['id']).";");
    if(!$check) die('Check failed'); // normally this might not happen at all, so just die
    $gui->reinstallInstance($_GET['id']);
    //echo $app->lng('Installation_task');
    @header('Location:aps_installedpackages_list.php');
}
?>
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
$gui = new ApsGUIController($app);
// An action and ID are required in any case
if(!isset($_GET['action'])) die('No action');
// List of operations which can be performed
if($_GET['action'] == 'change_status')
{
    // Only admins can perform this operation
    if($_SESSION['s']['user']['typ'] != 'admin') die('For admin use only.');
    // Make sure a valid package ID is given
    if(!$gui->isValidPackageID($_GET['id'], true)) die($app->lng('Invalid ID'));
    // Change the existing status to the opposite
    $get_status = $app->db->queryOneRecord("SELECT package_status FROM aps_packages WHERE id = '".$app->functions->intval($_GET['id'])."';");
    if($get_status['package_status'] == strval(PACKAGE_LOCKED))
    {
        $app->db->query("UPDATE aps_packages SET package_status = ".PACKAGE_ENABLED." WHERE id = '".$app->functions->intval($_GET['id'])."';");
        echo '<div class="swap" id="ir-Yes"><span>'.$app->lng('Yes').'</span></div>';
    }
    else
    {
        $app->db->query("UPDATE aps_packages SET Package_status = ".PACKAGE_LOCKED." WHERE id = '".$app->functions->intval($_GET['id'])."';");
        echo '<div class="swap" id="ir-No"><span>'.$app->lng('No').'</span></div>';
    }
}
else if($_GET['action'] == 'delete_instance')
{
    // Make sure a valid package ID is given (also corresponding to the calling user)
    $client_id = 0;
    $is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
    if(!$is_admin)
    {
        $cid = $app->db->queryOneRecord("SELECT client_id FROM client WHERE username = '".$app->db->quote($_SESSION['s']['user']['username'])."';");
        $client_id = $cid['client_id'];
    }
    // Assume that the given instance belongs to the currently calling client_id. Unimportant if status is admin
    if(!$gui->isValidInstanceID($_GET['id'], $client_id, $is_admin)) die($app->lng('Invalid ID'));
    // Only delete the instance if the status is "installed" or "flawed"
    $check = $app->db->queryOneRecord("SELECT id FROM aps_instances
        WHERE id = ".$app->db->quote($_GET['id'])." AND
        (instance_status = ".INSTANCE_SUCCESS." OR instance_status = ".INSTANCE_ERROR.");");
    if($check['id'] > 0) $gui->deleteInstance($_GET['id']);
    //echo $app->lng('Installation_remove');
    @header('Location:aps_installedpackages_list.php');
}
else if($_GET['action'] == 'reinstall_instance')
{
    // Make sure a valid package ID is given (also corresponding to the calling user)
    $client_id = 0;
    $is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
    if(!$is_admin)
    {
        $cid = $app->db->queryOneRecord("SELECT client_id FROM client WHERE username = '".$app->db->quote($_SESSION['s']['user']['username'])."';");
        $client_id = $cid['client_id'];
    }
    // Assume that the given instance belongs to the currently calling client_id. Unimportant if status is admin
    if(!$gui->isValidInstanceID($_GET['id'], $client_id, $is_admin)) die($app->lng('Invalid ID'));
    // We've an InstanceID, so make sure the package is not enabled and InstanceStatus is still "installed"
    $check = $app->db->queryOneRecord("SELECT aps_instances.id FROM aps_instances, aps_packages
        WHERE aps_instances.package_id = aps_packages.id
        AND aps_instances.instance_status = ".INSTANCE_SUCCESS."
        AND aps_packages.package_status = ".PACKAGE_ENABLED."
        AND aps_instances.id = ".$app->db->quote($_GET['id']).";");
    if(!$check) die('Check failed'); // normally this might not happen at all, so just die
    $gui->reinstallInstance($_GET['id']);
    //echo $app->lng('Installation_task');
    @header('Location:aps_installedpackages_list.php');
}
?>
interface/web/sites/aps_install_package.php
@@ -1,211 +1,211 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.guicontroller.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl,tform');
$app->tpl->newTemplate("form.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/aps_install_package.htm');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
require_once($lngfile);
$app->tpl->setVar($wb);
$app->load_language_file('web/sites/'.$lngfile);
// we will check only users, not admins
if($_SESSION["s"]["user"]["typ"] == 'user') {
    $app->tform->formDef['db_table_idx'] = 'client_id';
    $app->tform->formDef['db_table'] = 'client';
    if(!$app->tform->checkClientLimit('limit_aps')) {
        $app->error($app->lng("limit_aps_txt"));
    }
    if(!$app->tform->checkResellerLimit('limit_aps')) {
        $app->error('Reseller: '.$wb["limit_aps_txt"]);
    }
}
$adminflag = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
$gui = new ApsGUIController($app);
$pkg_id = (isset($_GET['id'])) ? $app->db->quote($_GET['id']) : '';
// Check if a newer version is available for the current package
// Note: It's intended that here is no strict ID check (see below)
if(isset($pkg_id))
{
    $newest_pkg_id = $gui->getNewestPackageID($pkg_id);
    if($newest_pkg_id != 0) $pkg_id = $newest_pkg_id;
}
// Make sure an integer ID is given
if(!isset($pkg_id) || !$gui->isValidPackageID($pkg_id, $adminflag))
    $app->error($app->lng('Invalid ID'));
// Get package details
$details = $gui->getPackageDetails($pkg_id);
if(isset($details['error'])) $app->error($details['error']);
$settings = $gui->getPackageSettings($pkg_id);
if(isset($settings['error'])) $app->error($settings['error']);
// Get domain list
$domains = array();
$domain_for_user = '';
if(!$adminflag) $domain_for_user = "AND (sys_userid = '".$app->db->quote($_SESSION['s']['user']['userid'])."'
    OR sys_groupid = '".$app->db->quote($_SESSION['s']['user']['userid'])."' )";
$domains_assoc = $app->db->queryAllRecords("SELECT domain FROM web_domain WHERE document_root != '' AND (type = 'vhost' OR type = 'vhostsubdomain') AND active = 'y' ".$domain_for_user." ORDER BY domain;");
if(!empty($domains_assoc)) foreach($domains_assoc as $domain) $domains[] = $domain['domain'];
// If data has been submitted, validate it
$result['input'] = array();
if(count($_POST) > 1)
{
    $result = $gui->validateInstallerInput($_POST, $details, $domains, $settings);
    if(empty($result['error']))
    {
        $gui->createPackageInstance($result['input'], $pkg_id);
        @header('Location:aps_installedpackages_list.php');
    }
    else
    {
        $app->tpl->setVar('error', implode('<br />', $result['error']));
        // Set memorized values (license, db password, install location)
        if(!empty($result['input']))
            foreach($result['input'] as $key => $value) $app->tpl->setVar('inp_'.$key, $value);
    }
}
else $app->tpl->setVar('inp_main_database_password', ucfirst(substr(md5(crypt(rand(0, 10))), 0, 16)));
// Pass the package details to the template
foreach($details as $key => $value)
{
    if(!is_array($value)) $app->tpl->setVar('pkg_'.str_replace(' ', '_', strtolower($key)), $value);
    else if($key == 'Requirements PHP settings') $app->tpl->setLoop('pkg_requirements_php_settings', $details['Requirements PHP settings']);
}
// Parse the template as far as possible, then do the rest manually
$app->tpl_defaults();
$parsed_tpl = $app->tpl->grab();
// ISPConfig has a very old and functionally limited template engine. We have to style parts on our own...
// Print the domain list
$domains_tpl = '';
if(!empty($domains))
{
    $set = array();
    $set[] = '<select name="main_domain" id="main_domain" class="selectInput">';
    foreach($domains as $domain)
    {
        $selected = '';
        if((count($_POST) > 1)
        && (isset($result['input']['main_domain']))
        && ($result['input']['main_domain'] == $domain))
            $selected = ' selected ';
        $set[] = '<option value="'.$domain.'" '.$selected.'>'.$domain.'</option>';
    }
    $set[] = '</select>';
    $domains_tpl = implode("\n", $set);
}
$parsed_tpl = str_replace('DOMAIN_LIST_SPACE', $domains_tpl, $parsed_tpl);
// Print the packgae settings
$settings_tpl = '';
if(!empty($settings))
{
    $set = array();
    $set[] = '<legend>'.$app->lng('package_settings_txt').'</legend>';
    foreach($settings as $setting)
    {
        $set[] = '<div class="ctrlHolder">';
        $set[] = '<label for="'.$setting['SettingID'].'">'.$setting['SettingName'].'</label>';
        if($setting['SettingInputType'] == 'string' || $setting['SettingInputType'] == 'password')
        {
            $input_type = ($setting['SettingInputType'] == 'string') ? 'text' : 'password';
            $input_value = '';
            if((count($_POST) > 1)
            && (isset($result['input'][$setting['SettingID']])))
                $input_value = $result['input'][$setting['SettingID']];
            else $input_value = @$setting['SettingDefaultValue'];
            $set[] = '<input type="'.$input_type.'" class="textInput" name="'.$setting['SettingID'].'" maxlength="'.$setting['SettingMaxLength'].'" id="'.$setting['SettingID'].'" value="'.$input_value.'" />
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        else if($setting['SettingInputType'] == 'checkbox')
        {
            $checked = '';
            if((count($_POST) > 1)
            && (isset($result['input'][$setting['SettingID']])
            && ($result['input'][$setting['SettingID']] == 'true')))
                $checked = 'checked ';
            else if($setting['SettingDefaultValue'] == '1') $checked = 'checked ';
            $set[] = '<input type="checkbox" id="'.$setting['SettingID'].'" name="'.$setting['SettingID'].'" '.$checked.'/>
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        else if($setting['SettingInputType'] == 'select')
        {
            $set[] =  '<select size="1" class="selectInput" name="'.$setting['SettingID'].'">';
            foreach($setting['SettingChoices'] as $choice)
            {
                $selected = '';
                if((count($_POST) > 1)
                && (isset($result['input'][$setting['SettingID']])))
                {
                    if($result['input'][$setting['SettingID']] == $choice['EnumID'])
                        $selected = 'selected ';
                }
                else if($setting['SettingDefaultValue'] == $choice['EnumID']) $selected = 'selected ';
                $set[] = '<option value="'.$choice['EnumID'].'" '.$selected.'>'.$choice['EnumName'].'</option>';
            }
            $set[] = '</select>
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        $set[] = '</div>';
    }
    $settings_tpl = implode("\n", $set);
}
$parsed_tpl = str_replace('PKG_SETTINGS_SPACE', $settings_tpl, $parsed_tpl);
echo $parsed_tpl;
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.guicontroller.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl,tform');
$app->tpl->newTemplate("form.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/aps_install_package.htm');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
require_once($lngfile);
$app->tpl->setVar($wb);
$app->load_language_file('web/sites/'.$lngfile);
// we will check only users, not admins
if($_SESSION["s"]["user"]["typ"] == 'user') {
    $app->tform->formDef['db_table_idx'] = 'client_id';
    $app->tform->formDef['db_table'] = 'client';
    if(!$app->tform->checkClientLimit('limit_aps')) {
        $app->error($app->lng("limit_aps_txt"));
    }
    if(!$app->tform->checkResellerLimit('limit_aps')) {
        $app->error('Reseller: '.$wb["limit_aps_txt"]);
    }
}
$adminflag = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
$gui = new ApsGUIController($app);
$pkg_id = (isset($_GET['id'])) ? $app->db->quote($_GET['id']) : '';
// Check if a newer version is available for the current package
// Note: It's intended that here is no strict ID check (see below)
if(isset($pkg_id))
{
    $newest_pkg_id = $gui->getNewestPackageID($pkg_id);
    if($newest_pkg_id != 0) $pkg_id = $newest_pkg_id;
}
// Make sure an integer ID is given
if(!isset($pkg_id) || !$gui->isValidPackageID($pkg_id, $adminflag))
    $app->error($app->lng('Invalid ID'));
// Get package details
$details = $gui->getPackageDetails($pkg_id);
if(isset($details['error'])) $app->error($details['error']);
$settings = $gui->getPackageSettings($pkg_id);
if(isset($settings['error'])) $app->error($settings['error']);
// Get domain list
$domains = array();
$domain_for_user = '';
if(!$adminflag) $domain_for_user = "AND (sys_userid = '".$app->db->quote($_SESSION['s']['user']['userid'])."'
    OR sys_groupid = '".$app->db->quote($_SESSION['s']['user']['userid'])."' )";
$domains_assoc = $app->db->queryAllRecords("SELECT domain FROM web_domain WHERE document_root != '' AND (type = 'vhost' OR type = 'vhostsubdomain') AND active = 'y' ".$domain_for_user." ORDER BY domain;");
if(!empty($domains_assoc)) foreach($domains_assoc as $domain) $domains[] = $domain['domain'];
// If data has been submitted, validate it
$result['input'] = array();
if(count($_POST) > 1)
{
    $result = $gui->validateInstallerInput($_POST, $details, $domains, $settings);
    if(empty($result['error']))
    {
        $gui->createPackageInstance($result['input'], $pkg_id);
        @header('Location:aps_installedpackages_list.php');
    }
    else
    {
        $app->tpl->setVar('error', implode('<br />', $result['error']));
        // Set memorized values (license, db password, install location)
        if(!empty($result['input']))
            foreach($result['input'] as $key => $value) $app->tpl->setVar('inp_'.$key, $value);
    }
}
else $app->tpl->setVar('inp_main_database_password', ucfirst(substr(md5(crypt(rand(0, 10))), 0, 16)));
// Pass the package details to the template
foreach($details as $key => $value)
{
    if(!is_array($value)) $app->tpl->setVar('pkg_'.str_replace(' ', '_', strtolower($key)), $value);
    else if($key == 'Requirements PHP settings') $app->tpl->setLoop('pkg_requirements_php_settings', $details['Requirements PHP settings']);
}
// Parse the template as far as possible, then do the rest manually
$app->tpl_defaults();
$parsed_tpl = $app->tpl->grab();
// ISPConfig has a very old and functionally limited template engine. We have to style parts on our own...
// Print the domain list
$domains_tpl = '';
if(!empty($domains))
{
    $set = array();
    $set[] = '<select name="main_domain" id="main_domain" class="selectInput">';
    foreach($domains as $domain)
    {
        $selected = '';
        if((count($_POST) > 1)
        && (isset($result['input']['main_domain']))
        && ($result['input']['main_domain'] == $domain))
            $selected = ' selected ';
        $set[] = '<option value="'.$domain.'" '.$selected.'>'.$domain.'</option>';
    }
    $set[] = '</select>';
    $domains_tpl = implode("\n", $set);
}
$parsed_tpl = str_replace('DOMAIN_LIST_SPACE', $domains_tpl, $parsed_tpl);
// Print the packgae settings
$settings_tpl = '';
if(!empty($settings))
{
    $set = array();
    $set[] = '<legend>'.$app->lng('package_settings_txt').'</legend>';
    foreach($settings as $setting)
    {
        $set[] = '<div class="ctrlHolder">';
        $set[] = '<label for="'.$setting['SettingID'].'">'.$setting['SettingName'].'</label>';
        if($setting['SettingInputType'] == 'string' || $setting['SettingInputType'] == 'password')
        {
            $input_type = ($setting['SettingInputType'] == 'string') ? 'text' : 'password';
            $input_value = '';
            if((count($_POST) > 1)
            && (isset($result['input'][$setting['SettingID']])))
                $input_value = $result['input'][$setting['SettingID']];
            else $input_value = @$setting['SettingDefaultValue'];
            $set[] = '<input type="'.$input_type.'" class="textInput" name="'.$setting['SettingID'].'" maxlength="'.$setting['SettingMaxLength'].'" id="'.$setting['SettingID'].'" value="'.$input_value.'" />
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        else if($setting['SettingInputType'] == 'checkbox')
        {
            $checked = '';
            if((count($_POST) > 1)
            && (isset($result['input'][$setting['SettingID']])
            && ($result['input'][$setting['SettingID']] == 'true')))
                $checked = 'checked ';
            else if($setting['SettingDefaultValue'] == '1') $checked = 'checked ';
            $set[] = '<input type="checkbox" id="'.$setting['SettingID'].'" name="'.$setting['SettingID'].'" '.$checked.'/>
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        else if($setting['SettingInputType'] == 'select')
        {
            $set[] =  '<select size="1" class="selectInput" name="'.$setting['SettingID'].'">';
            foreach($setting['SettingChoices'] as $choice)
            {
                $selected = '';
                if((count($_POST) > 1)
                && (isset($result['input'][$setting['SettingID']])))
                {
                    if($result['input'][$setting['SettingID']] == $choice['EnumID'])
                        $selected = 'selected ';
                }
                else if($setting['SettingDefaultValue'] == $choice['EnumID']) $selected = 'selected ';
                $set[] = '<option value="'.$choice['EnumID'].'" '.$selected.'>'.$choice['EnumName'].'</option>';
            }
            $set[] = '</select>
                <p class="formHint">'.$setting['SettingDescription'].'</p>';
        }
        $set[] = '</div>';
    }
    $settings_tpl = implode("\n", $set);
}
$parsed_tpl = str_replace('PKG_SETTINGS_SPACE', $settings_tpl, $parsed_tpl);
echo $parsed_tpl;
?>
interface/web/sites/aps_installedpackages_list.php
@@ -1,142 +1,142 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.base.php'); // for constants
$app->load('aps_base');
// Path to the list definition file
$list_def_file = "list/aps_installedpackages.list.php";
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl,tform,listform,listform_actions');
// Show further information only to admins or resellers
if($_SESSION['s']['user']['typ'] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid']))
    $app->tpl->setVar('is_noclient', 1);
// Show each user the own packages (if not admin)
$client_ext = '';
$is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
if(!$is_admin)
{
    $cid = $app->db->queryOneRecord('SELECT client_id FROM client WHERE username = "'.$app->db->quote($_SESSION['s']['user']['username']).'";');
    //$client_ext = ' AND aps_instances.customer_id = '.$cid['client_id'];
    $client_ext = ' AND '.$app->tform->getAuthSQL('r', 'aps_instances');
}
$app->listform_actions->SQLExtWhere = 'aps_instances.package_id = aps_packages.id'.$client_ext;
$app->listform_actions->SQLOrderBy = 'ORDER BY package_name';
// We are using parts of listform_actions because ISPConfig doesn't allow
// queries over multiple tables so we construct them ourselves
$_SESSION['s']['form']['return_to'] = '';
// Load the list template
$app->listform->loadListDef($list_def_file);
if(!is_file('templates/'.$app->listform->listDef["name"].'_list.htm'))
{
$app->uses('listform_tpl_generator');
$app->listform_tpl_generator->buildHTML($app->listform->listDef);
}
$app->tpl->newTemplate("listpage.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/'.$app->listform->listDef["name"].'_list.htm');
// Build the WHERE query for search
$sql_where = '';
if($app->listform_actions->SQLExtWhere != '')
  $sql_where .= ' '.$app->listform_actions->SQLExtWhere.' and';
$sql_where = $app->listform->getSearchSQL($sql_where);
$app->tpl->setVar($app->listform->searchValues);
// Paging
$limit_sql = $app->listform->getPagingSQL($sql_where);
$app->tpl->setVar('paging', $app->listform->pagingHTML);
if(!$is_admin) {
// Our query over multiple tables
$query = "SELECT aps_instances.id AS id, aps_instances.package_id AS package_id,
                 aps_instances.customer_id AS customer_id, client.username AS customer_name,
                 aps_instances.instance_status AS instance_status, aps_packages.name AS package_name,
                 aps_packages.version AS package_version, aps_packages.release AS package_release,
                 aps_packages.package_status AS package_status,
              CONCAT ((SELECT value FROM aps_instances_settings WHERE name='main_domain' AND instance_id = aps_instances.id),
                 '/', (SELECT value FROM aps_instances_settings WHERE name='main_location' AND instance_id = aps_instances.id))
                  AS install_location
          FROM aps_instances, aps_packages, client
          WHERE client.client_id = aps_instances.customer_id AND ".$sql_where." ".$app->listform_actions->SQLOrderBy." ".$limit_sql;
} else {
$query = "SELECT aps_instances.id AS id, aps_instances.package_id AS package_id,
                 aps_instances.customer_id AS customer_id, sys_group.name AS customer_name,
                 aps_instances.instance_status AS instance_status, aps_packages.name AS package_name,
                 aps_packages.version AS package_version, aps_packages.release AS package_release,
                 aps_packages.package_status AS package_status,
              CONCAT ((SELECT value FROM aps_instances_settings WHERE name='main_domain' AND instance_id = aps_instances.id),
                 '/', (SELECT value FROM aps_instances_settings WHERE name='main_location' AND instance_id = aps_instances.id))
                  AS install_location
          FROM aps_instances, aps_packages, sys_group
          WHERE sys_group.client_id = aps_instances.customer_id AND ".$sql_where." ".$app->listform_actions->SQLOrderBy." ".$limit_sql;
}
$records = $app->db->queryAllRecords($query);
$app->listform_actions->DataRowColor = '#FFFFFF';
// Re-form all result entries and add extra entries
$records_new = '';
if(is_array($records))
{
    $app->listform_actions->idx_key = $app->listform->listDef["table_idx"];
    foreach($records as $rec)
    {
        // Set an abbreviated install location to beware the page layout
        $ils = '';
        if(strlen($rec['Install_location']) >= 38) $ils = substr($rec['Install_location'], 0,  35).'...';
        else $ils = $rec['install_location'];
        $rec['install_location_short'] = $ils;
        // Also set a boolean-like variable for the reinstall button (vlibTemplate doesn't allow variable comparisons)
        // For a reinstall, the package must be already installed successfully and (still be) enabled
        if($rec['instance_status'] == INSTANCE_SUCCESS && $rec['package_status'] == PACKAGE_ENABLED)
            $rec['reinstall_possible'] = 'true';
        // Of course an instance can only then be removed when it's not already tagged for removal
        if($rec['instance_status'] != INSTANCE_REMOVE && $rec['instance_status'] != INSTANCE_INSTALL)
            $rec['delete_possible'] = 'true';
        $records_new[] = $app->listform_actions->prepareDataRow($rec);
    }
}
$app->tpl->setLoop('records', $records_new);
$app->listform_actions->onShow();
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.base.php'); // for constants
$app->load('aps_base');
// Path to the list definition file
$list_def_file = "list/aps_installedpackages.list.php";
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl,tform,listform,listform_actions');
// Show further information only to admins or resellers
if($_SESSION['s']['user']['typ'] == 'admin' || $app->auth->has_clients($_SESSION['s']['user']['userid']))
    $app->tpl->setVar('is_noclient', 1);
// Show each user the own packages (if not admin)
$client_ext = '';
$is_admin = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
if(!$is_admin)
{
    $cid = $app->db->queryOneRecord('SELECT client_id FROM client WHERE username = "'.$app->db->quote($_SESSION['s']['user']['username']).'";');
    //$client_ext = ' AND aps_instances.customer_id = '.$cid['client_id'];
    $client_ext = ' AND '.$app->tform->getAuthSQL('r', 'aps_instances');
}
$app->listform_actions->SQLExtWhere = 'aps_instances.package_id = aps_packages.id'.$client_ext;
$app->listform_actions->SQLOrderBy = 'ORDER BY package_name';
// We are using parts of listform_actions because ISPConfig doesn't allow
// queries over multiple tables so we construct them ourselves
$_SESSION['s']['form']['return_to'] = '';
// Load the list template
$app->listform->loadListDef($list_def_file);
if(!is_file('templates/'.$app->listform->listDef["name"].'_list.htm'))
{
$app->uses('listform_tpl_generator');
$app->listform_tpl_generator->buildHTML($app->listform->listDef);
}
$app->tpl->newTemplate("listpage.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/'.$app->listform->listDef["name"].'_list.htm');
// Build the WHERE query for search
$sql_where = '';
if($app->listform_actions->SQLExtWhere != '')
  $sql_where .= ' '.$app->listform_actions->SQLExtWhere.' and';
$sql_where = $app->listform->getSearchSQL($sql_where);
$app->tpl->setVar($app->listform->searchValues);
// Paging
$limit_sql = $app->listform->getPagingSQL($sql_where);
$app->tpl->setVar('paging', $app->listform->pagingHTML);
if(!$is_admin) {
// Our query over multiple tables
$query = "SELECT aps_instances.id AS id, aps_instances.package_id AS package_id,
                 aps_instances.customer_id AS customer_id, client.username AS customer_name,
                 aps_instances.instance_status AS instance_status, aps_packages.name AS package_name,
                 aps_packages.version AS package_version, aps_packages.release AS package_release,
                 aps_packages.package_status AS package_status,
              CONCAT ((SELECT value FROM aps_instances_settings WHERE name='main_domain' AND instance_id = aps_instances.id),
                 '/', (SELECT value FROM aps_instances_settings WHERE name='main_location' AND instance_id = aps_instances.id))
                  AS install_location
          FROM aps_instances, aps_packages, client
          WHERE client.client_id = aps_instances.customer_id AND ".$sql_where." ".$app->listform_actions->SQLOrderBy." ".$limit_sql;
} else {
$query = "SELECT aps_instances.id AS id, aps_instances.package_id AS package_id,
                 aps_instances.customer_id AS customer_id, sys_group.name AS customer_name,
                 aps_instances.instance_status AS instance_status, aps_packages.name AS package_name,
                 aps_packages.version AS package_version, aps_packages.release AS package_release,
                 aps_packages.package_status AS package_status,
              CONCAT ((SELECT value FROM aps_instances_settings WHERE name='main_domain' AND instance_id = aps_instances.id),
                 '/', (SELECT value FROM aps_instances_settings WHERE name='main_location' AND instance_id = aps_instances.id))
                  AS install_location
          FROM aps_instances, aps_packages, sys_group
          WHERE sys_group.client_id = aps_instances.customer_id AND ".$sql_where." ".$app->listform_actions->SQLOrderBy." ".$limit_sql;
}
$records = $app->db->queryAllRecords($query);
$app->listform_actions->DataRowColor = '#FFFFFF';
// Re-form all result entries and add extra entries
$records_new = '';
if(is_array($records))
{
    $app->listform_actions->idx_key = $app->listform->listDef["table_idx"];
    foreach($records as $rec)
    {
        // Set an abbreviated install location to beware the page layout
        $ils = '';
        if(strlen($rec['Install_location']) >= 38) $ils = substr($rec['Install_location'], 0,  35).'...';
        else $ils = $rec['install_location'];
        $rec['install_location_short'] = $ils;
        // Also set a boolean-like variable for the reinstall button (vlibTemplate doesn't allow variable comparisons)
        // For a reinstall, the package must be already installed successfully and (still be) enabled
        if($rec['instance_status'] == INSTANCE_SUCCESS && $rec['package_status'] == PACKAGE_ENABLED)
            $rec['reinstall_possible'] = 'true';
        // Of course an instance can only then be removed when it's not already tagged for removal
        if($rec['instance_status'] != INSTANCE_REMOVE && $rec['instance_status'] != INSTANCE_INSTALL)
            $rec['delete_possible'] = 'true';
        $records_new[] = $app->listform_actions->prepareDataRow($rec);
    }
}
$app->tpl->setLoop('records', $records_new);
$app->listform_actions->onShow();
?>
interface/web/sites/aps_packagedetails_show.php
@@ -1,100 +1,100 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.guicontroller.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl');
$app->tpl->newTemplate("listpage.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/aps_packagedetails_show.htm');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
require_once($lngfile);
$app->tpl->setVar($wb);
$gui = new ApsGUIController($app);
$pkg_id = (isset($_GET['id'])) ? $app->db->quote($_GET['id']) : '';
// Check if a newer version is available for the current package
// Note: It's intended that here is no strict ID check (see below)
if(isset($pkg_id))
{
    $newest_pkg_id = $gui->getNewestPackageID($pkg_id);
    if($newest_pkg_id != 0) $pkg_id = $newest_pkg_id;
}
// Make sure an integer ID is given
$adminflag = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
if(!isset($pkg_id) || !$gui->isValidPackageID($pkg_id, $adminflag))
    $app->error($app->lng('Invalid ID'));
// Get package details
$details = $gui->getPackageDetails($pkg_id);
if(isset($details['error'])) $app->error($details['error']);
// Set the active and default tab
$next_tab = 'details';
if(isset($_POST['next_tab']) || isset($_GET['next_tab']))
{
    $tab = (isset($_POST['next_tab']) ? $_POST['next_tab'] : $_GET['next_tab']);
    switch($tab)
    {
        case 'details': $next_tab = 'details'; break;
        case 'settings': $next_tab = 'settings'; break;
        case 'changelog': $next_tab = 'changelog'; break;
        case 'screenshots': $next_tab = 'screenshots'; break;
        default: $next_tab = 'details';
    }
}
$app->tpl->setVar('next_tab', $next_tab);
// Parse the package details to the template
foreach($details as $key => $value)
{
    if(!is_array($value)) $app->tpl->setVar('pkg_'.str_replace(' ', '_', strtolower($key)), $value);
    else // Special cases
    {
        if($key == 'Changelog') $app->tpl->setLoop('pkg_changelog', $details['Changelog']);
        elseif($key == 'Screenshots') $app->tpl->setLoop('pkg_screenshots', $details['Screenshots']);
        elseif($key == 'Requirements PHP settings') $app->tpl->setLoop('pkg_requirements_php_settings', $details['Requirements PHP settings']);
    }
}
//print_r($details['Requirements PHP settings']);
$app->tpl_defaults();
$app->tpl->pparse();
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('../../lib/config.inc.php');
require_once('../../lib/app.inc.php');
//require_once('classes/class.guicontroller.php');
$app->load('aps_guicontroller');
// Check the module permissions
$app->auth->check_module_permissions('sites');
// Load needed classes
$app->uses('tpl');
$app->tpl->newTemplate("listpage.tpl.htm");
$app->tpl->setInclude('content_tpl', 'templates/aps_packagedetails_show.htm');
// Load the language file
$lngfile = 'lib/lang/'.$_SESSION['s']['language'].'_aps.lng';
require_once($lngfile);
$app->tpl->setVar($wb);
$gui = new ApsGUIController($app);
$pkg_id = (isset($_GET['id'])) ? $app->db->quote($_GET['id']) : '';
// Check if a newer version is available for the current package
// Note: It's intended that here is no strict ID check (see below)
if(isset($pkg_id))
{
    $newest_pkg_id = $gui->getNewestPackageID($pkg_id);
    if($newest_pkg_id != 0) $pkg_id = $newest_pkg_id;
}
// Make sure an integer ID is given
$adminflag = ($_SESSION['s']['user']['typ'] == 'admin') ? true : false;
if(!isset($pkg_id) || !$gui->isValidPackageID($pkg_id, $adminflag))
    $app->error($app->lng('Invalid ID'));
// Get package details
$details = $gui->getPackageDetails($pkg_id);
if(isset($details['error'])) $app->error($details['error']);
// Set the active and default tab
$next_tab = 'details';
if(isset($_POST['next_tab']) || isset($_GET['next_tab']))
{
    $tab = (isset($_POST['next_tab']) ? $_POST['next_tab'] : $_GET['next_tab']);
    switch($tab)
    {
        case 'details': $next_tab = 'details'; break;
        case 'settings': $next_tab = 'settings'; break;
        case 'changelog': $next_tab = 'changelog'; break;
        case 'screenshots': $next_tab = 'screenshots'; break;
        default: $next_tab = 'details';
    }
}
$app->tpl->setVar('next_tab', $next_tab);
// Parse the package details to the template
foreach($details as $key => $value)
{
    if(!is_array($value)) $app->tpl->setVar('pkg_'.str_replace(' ', '_', strtolower($key)), $value);
    else // Special cases
    {
        if($key == 'Changelog') $app->tpl->setLoop('pkg_changelog', $details['Changelog']);
        elseif($key == 'Screenshots') $app->tpl->setLoop('pkg_screenshots', $details['Screenshots']);
        elseif($key == 'Requirements PHP settings') $app->tpl->setLoop('pkg_requirements_php_settings', $details['Requirements PHP settings']);
    }
}
//print_r($details['Requirements PHP settings']);
$app->tpl_defaults();
$app->tpl->pparse();
?>
interface/web/sites/lib/lang/ar_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/bg_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/br_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/cz_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/el_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/en_aps.lng
@@ -1,58 +1,58 @@
<?php
$wb['overview_txt'] = 'Overview';
$wb['administration_txt'] = 'Administration';
$wb['available_packages_txt'] = 'Available packages';
$wb['installed_packages_txt'] = 'Installed packages';
$wb['yes_txt'] = 'Yes';
$wb['no_txt'] = 'No';
$wb['invalid_id_txt'] = 'No valid ID has been provided.';
$wb['details_txt'] = 'Details';
$wb['version_txt'] = 'Version';
$wb['category_txt'] = 'Category';
$wb['homepage_txt'] = 'Homepage';
$wb['supported_languages_txt'] = 'Supported languages';
$wb['description_txt'] = 'Description';
$wb['config_script_txt'] = 'Configuration script';
$wb['installed_size_txt'] = 'Size after installation';
$wb['license_txt'] = 'License';
$wb['screenshots_txt'] = 'Screenshots';
$wb['changelog_txt'] = 'Changelog';
$wb['server_requirements_txt'] = 'Server requirements';
$wb['php_extensions_txt'] = 'PHP extensions';
$wb['php_settings_txt'] = 'PHP settings';
$wb['supported_php_versions_txt'] = 'Supported PHP versions';
$wb['database_txt'] = 'Database';
$wb['settings_txt'] = 'Settings';
$wb['install_package_txt'] = 'Install this package';
$wb['installation_txt'] = 'Installation';
$wb['install_location_txt'] = 'Install location';
$wb['btn_install_txt'] = 'Install';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['acceptance_txt'] = 'Acceptance';
$wb['acceptance_text_txt'] = 'Yes, i\'ve read the license and agree.';
$wb['install_language_txt'] = 'Interface language';
$wb['new_database_password_txt'] = 'New database password';
$wb['basic_settings_txt'] = 'Basic settings';
$wb['package_settings_txt'] = 'Package settings';
$wb['error_main_domain'] = 'The domain of the installation path is invalid.';
$wb['error_no_main_location'] = 'You have provided no valid installation path.';
$wb['error_inv_main_location'] = 'The given install location folder is invalid.';
$wb['error_license_agreement'] = 'In order to continue you have to accept the license agreement.';
$wb['error_no_database_pw'] = 'You have provided no valid database password.';
$wb['error_short_database_pw'] = 'Please choose a longer database password.';
$wb['error_no_value_for'] = 'The field "%s" must not be empty.';
$wb['error_short_value_for'] = 'The field "%s" requires a longer input value.';
$wb['error_long_value_for'] = 'The field "%s" requires a shorter input value.';
$wb['error_inv_value_for'] = 'You have entered an invalid value for the field "%s".';
$wb['error_inv_email_for'] = 'You have entered an invalid mail address for the field "%s".';
$wb['error_inv_domain_for'] = 'You have entered an invalid domain for the field "%s".';
$wb['error_inv_integer_for'] = 'You have entered an invalid number for the field "%s".';
$wb['error_inv_float_for'] = 'You have entered an invalid floating point number for the field "%s".';
$wb['error_used_location'] = 'The installation path already contains a package installation.';
$wb['installation_task_txt'] = 'Install planned';
$wb['installation_error_txt'] = 'Install error';
$wb['installation_success_txt'] = 'Installed';
$wb['installation_remove_txt'] = 'Removal planned';
$wb['packagelist_update_finished_txt'] = 'APS Packagelist update finished.';
$wb["limit_aps_txt"] = 'The max. number of APS instances for your account is reached.';
<?php
$wb['overview_txt'] = 'Overview';
$wb['administration_txt'] = 'Administration';
$wb['available_packages_txt'] = 'Available packages';
$wb['installed_packages_txt'] = 'Installed packages';
$wb['yes_txt'] = 'Yes';
$wb['no_txt'] = 'No';
$wb['invalid_id_txt'] = 'No valid ID has been provided.';
$wb['details_txt'] = 'Details';
$wb['version_txt'] = 'Version';
$wb['category_txt'] = 'Category';
$wb['homepage_txt'] = 'Homepage';
$wb['supported_languages_txt'] = 'Supported languages';
$wb['description_txt'] = 'Description';
$wb['config_script_txt'] = 'Configuration script';
$wb['installed_size_txt'] = 'Size after installation';
$wb['license_txt'] = 'License';
$wb['screenshots_txt'] = 'Screenshots';
$wb['changelog_txt'] = 'Changelog';
$wb['server_requirements_txt'] = 'Server requirements';
$wb['php_extensions_txt'] = 'PHP extensions';
$wb['php_settings_txt'] = 'PHP settings';
$wb['supported_php_versions_txt'] = 'Supported PHP versions';
$wb['database_txt'] = 'Database';
$wb['settings_txt'] = 'Settings';
$wb['install_package_txt'] = 'Install this package';
$wb['installation_txt'] = 'Installation';
$wb['install_location_txt'] = 'Install location';
$wb['btn_install_txt'] = 'Install';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['acceptance_txt'] = 'Acceptance';
$wb['acceptance_text_txt'] = 'Yes, i\'ve read the license and agree.';
$wb['install_language_txt'] = 'Interface language';
$wb['new_database_password_txt'] = 'New database password';
$wb['basic_settings_txt'] = 'Basic settings';
$wb['package_settings_txt'] = 'Package settings';
$wb['error_main_domain'] = 'The domain of the installation path is invalid.';
$wb['error_no_main_location'] = 'You have provided no valid installation path.';
$wb['error_inv_main_location'] = 'The given install location folder is invalid.';
$wb['error_license_agreement'] = 'In order to continue you have to accept the license agreement.';
$wb['error_no_database_pw'] = 'You have provided no valid database password.';
$wb['error_short_database_pw'] = 'Please choose a longer database password.';
$wb['error_no_value_for'] = 'The field "%s" must not be empty.';
$wb['error_short_value_for'] = 'The field "%s" requires a longer input value.';
$wb['error_long_value_for'] = 'The field "%s" requires a shorter input value.';
$wb['error_inv_value_for'] = 'You have entered an invalid value for the field "%s".';
$wb['error_inv_email_for'] = 'You have entered an invalid mail address for the field "%s".';
$wb['error_inv_domain_for'] = 'You have entered an invalid domain for the field "%s".';
$wb['error_inv_integer_for'] = 'You have entered an invalid number for the field "%s".';
$wb['error_inv_float_for'] = 'You have entered an invalid floating point number for the field "%s".';
$wb['error_used_location'] = 'The installation path already contains a package installation.';
$wb['installation_task_txt'] = 'Install planned';
$wb['installation_error_txt'] = 'Install error';
$wb['installation_success_txt'] = 'Installed';
$wb['installation_remove_txt'] = 'Removal planned';
$wb['packagelist_update_finished_txt'] = 'APS Packagelist update finished.';
$wb["limit_aps_txt"] = 'The max. number of APS instances for your account is reached.';
?>
interface/web/sites/lib/lang/en_aps_instances_list.lng
@@ -1,13 +1,13 @@
<?php
$wb['list_head_txt'] = 'Installed packages';
$wb['name_txt'] = 'Name';
$wb['version_txt'] = 'Version';
$wb['customer_txt'] = 'Client';
$wb['status_txt'] = 'Status';
$wb['install_location_txt'] = 'Install location';
$wb['pkg_delete_confirmation'] = 'Do you really want to delete this installation?';
$wb['pkg_reinstall_confirmation'] = 'Do you really want to reinstall this package with the same settings?';
$wb['filter_txt'] = 'Search';
$wb['delete_txt'] = 'Delete';
$wb['reinstall_txt'] = 'Reinstall';
<?php
$wb['list_head_txt'] = 'Installed packages';
$wb['name_txt'] = 'Name';
$wb['version_txt'] = 'Version';
$wb['customer_txt'] = 'Client';
$wb['status_txt'] = 'Status';
$wb['install_location_txt'] = 'Install location';
$wb['pkg_delete_confirmation'] = 'Do you really want to delete this installation?';
$wb['pkg_reinstall_confirmation'] = 'Do you really want to reinstall this package with the same settings?';
$wb['filter_txt'] = 'Search';
$wb['delete_txt'] = 'Delete';
$wb['reinstall_txt'] = 'Reinstall';
?>
interface/web/sites/lib/lang/en_aps_packages_list.lng
@@ -1,8 +1,8 @@
<?php
$wb['list_head_txt'] = 'Available packages';
$wb['name_txt'] = 'Name';
$wb['version_txt'] = 'Version';
$wb['category_txt'] = 'Category';
$wb['status_txt'] = 'Unlocked';
$wb['filter_txt'] = 'Search';
<?php
$wb['list_head_txt'] = 'Available packages';
$wb['name_txt'] = 'Name';
$wb['version_txt'] = 'Version';
$wb['category_txt'] = 'Category';
$wb['status_txt'] = 'Unlocked';
$wb['filter_txt'] = 'Search';
?>
interface/web/sites/lib/lang/en_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/es_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/fi_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/fr_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/hr_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/hu_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/id_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/it_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/nl_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/pl_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/pt_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/ro_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/ru_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/se_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/sk_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/lib/lang/tr_aps_update_packagelist.lng
@@ -1,7 +1,7 @@
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
<?php
$wb['head_txt'] = 'Update Packagelist';
$wb['list_desc_txt'] = '';
$wb['btn_start_txt'] = 'Update Packagelist';
$wb['btn_cancel_txt'] = 'Cancel';
$wb['legend_txt'] = 'Here you can update the list of available packages. Please note that this can take up to five minutes. You can leave this page if you like; the process will continue in the background.';
?>
interface/web/sites/list/aps_availablepackages.list.php
@@ -1,86 +1,86 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$liste['name'] = 'aps_packages'; // Name of the list
$liste['table'] = 'aps_packages'; // Database table
$liste['table_idx'] = 'id'; // Table index
$liste["search_prefix"] = 'search_'; // Search field prefix
$liste['records_per_page'] = 15; // Records per page
$liste['file'] = 'aps_availablepackages_list.php'; // Script file for this list
$liste['edit_file']    = ''; // Script file to edit
$liste['delete_file'] = ''; // Script file to delete
$liste['paging_tpl'] = 'templates/paging.tpl.htm'; // Paging template
$liste['auth'] = 'no'; // Handling it myself (check for admin)
// Search fields
$liste["item"][] = array('field'    => 'name',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'version',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'category',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'datasource' => array('type' => 'SQL',
                                               'querystring' => 'SELECT category FROM aps_packages ORDER BY category',
                                               'keyfield' => 'category',
                                               'valuefield' => 'category'),
                         'width'    => '',
                         'value'    => '');
if($_SESSION['s']['user']['typ'] == 'admin')
{
$liste['item'][] = array('field'    => 'package_status',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => array(PACKAGE_ENABLED => '<div class="swap" id="ir-Yes"><span>'.$app->lng('Yes').'</span></div>',
                                             PACKAGE_LOCKED => '<div class="swap" id="ir-No"><span>'.$app->lng('No').'</span></div>'));
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$liste['name'] = 'aps_packages'; // Name of the list
$liste['table'] = 'aps_packages'; // Database table
$liste['table_idx'] = 'id'; // Table index
$liste["search_prefix"] = 'search_'; // Search field prefix
$liste['records_per_page'] = 15; // Records per page
$liste['file'] = 'aps_availablepackages_list.php'; // Script file for this list
$liste['edit_file']    = ''; // Script file to edit
$liste['delete_file'] = ''; // Script file to delete
$liste['paging_tpl'] = 'templates/paging.tpl.htm'; // Paging template
$liste['auth'] = 'no'; // Handling it myself (check for admin)
// Search fields
$liste["item"][] = array('field'    => 'name',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'version',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'category',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'datasource' => array('type' => 'SQL',
                                               'querystring' => 'SELECT category FROM aps_packages ORDER BY category',
                                               'keyfield' => 'category',
                                               'valuefield' => 'category'),
                         'width'    => '',
                         'value'    => '');
if($_SESSION['s']['user']['typ'] == 'admin')
{
$liste['item'][] = array('field'    => 'package_status',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => array(PACKAGE_ENABLED => '<div class="swap" id="ir-Yes"><span>'.$app->lng('Yes').'</span></div>',
                                             PACKAGE_LOCKED => '<div class="swap" id="ir-No"><span>'.$app->lng('No').'</span></div>'));
}
?>
interface/web/sites/list/aps_installedpackages.list.php
@@ -1,83 +1,83 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$liste['name'] = 'aps_instances'; // Name of the list
$liste['table'] = 'aps_instances,aps_packages'; // Database table
$liste['table_idx'] = 'id'; // Table index
$liste["search_prefix"] = 'search_'; // Search field prefix
$liste['records_per_page'] = 15; // Records per page
$liste['file'] = 'aps_installedpackages_list.php'; // Script file for this list
$liste['edit_file']    = ''; // Script file to edit
$liste['delete_file'] = ''; // Script file to delete
$liste['paging_tpl'] = 'templates/paging.tpl.htm'; // Paging template
$liste['auth'] = 'no'; // Handling it myself (check for admin)
// Search fields
$liste["item"][] = array('field'    => 'name',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'LIKE',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'version',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
 /*
$liste["item"][] = array('field'    => 'customer_id',
                         'datatype' => 'INTEGER',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => '');
*/
$liste["item"][] = array('field'    => 'instance_status',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => array(INSTANCE_INSTALL => $app->lng('Installation_task'),
                                             INSTANCE_ERROR => $app->lng('Installation_error'),
                                             INSTANCE_SUCCESS => $app->lng('Installation_success'),
                                             INSTANCE_REMOVE => $app->lng('Installation_remove')));
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
$liste['name'] = 'aps_instances'; // Name of the list
$liste['table'] = 'aps_instances,aps_packages'; // Database table
$liste['table_idx'] = 'id'; // Table index
$liste["search_prefix"] = 'search_'; // Search field prefix
$liste['records_per_page'] = 15; // Records per page
$liste['file'] = 'aps_installedpackages_list.php'; // Script file for this list
$liste['edit_file']    = ''; // Script file to edit
$liste['delete_file'] = ''; // Script file to delete
$liste['paging_tpl'] = 'templates/paging.tpl.htm'; // Paging template
$liste['auth'] = 'no'; // Handling it myself (check for admin)
// Search fields
$liste["item"][] = array('field'    => 'name',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'LIKE',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
$liste["item"][] = array('field'    => 'version',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'TEXT',
                         'op'       => 'like',
                         'prefix'   => '%',
                         'suffix'   => '%',
                         'width'    => '',
                         'value'    => '');
 /*
$liste["item"][] = array('field'    => 'customer_id',
                         'datatype' => 'INTEGER',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => '');
*/
$liste["item"][] = array('field'    => 'instance_status',
                         'datatype' => 'VARCHAR',
                         'formtype' => 'SELECT',
                         'op'       => '=',
                         'prefix'   => '',
                         'suffix'   => '',
                         'width'    => '',
                         'value'    => array(INSTANCE_INSTALL => $app->lng('Installation_task'),
                                             INSTANCE_ERROR => $app->lng('Installation_error'),
                                             INSTANCE_SUCCESS => $app->lng('Installation_success'),
                                             INSTANCE_REMOVE => $app->lng('Installation_remove')));
?>
interface/web/sites/templates/aps_install_package.htm
@@ -1,56 +1,56 @@
<h2>
    {tmpl_var name='installation_txt'}: {tmpl_var name='pkg_name'} {tmpl_var name='pkg_version'}-{tmpl_var name='pkg_release'}
    <span style="float:right">
        <tmpl_if name='pkg_icon' op='!=' value=''>
            <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
        </tmpl_if>
    </span>
</h2>
<tmpl_if name='error'>
    <div id="errorMsg"><h3>ERROR</h3><ol>{tmpl_var name='error'}</ol></div>
</tmpl_if>
<div class="panel panel_install_package">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <legend>{tmpl_var name='basic_settings_txt'}</legend>
            <div class="ctrlHolder">
                <label for="main_domain">{tmpl_var name='install_location_txt'}</label>
                <div class="resetButton">http(s)://&nbsp;</div>DOMAIN_LIST_SPACE<div style="float:left;">&nbsp;/&nbsp;</div>
                <input type="text" name="main_location" id="main_location" value="{tmpl_var name='inp_main_location'}" maxlength="255" class="textInput formLengthHalf" />
            </div>
            <tmpl_if name='pkg_requirements_database' op='!=' value=''>
                <div class="ctrlHolder">
                    <label for="main_database_password">{tmpl_var name='new_database_password_txt'}</label>
                    <input type="text" class="textInput" name="main_database_password" id="main_database_password" value="{tmpl_var name='inp_main_database_password'}" size="10" maxlength="255" />
                </div>
            </tmpl_if>
            PKG_SETTINGS_SPACE
            <legend>{tmpl_var name='license_txt'}</legend>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='license_txt'}</label>
                <tmpl_if name='pkg_license_content' op='==' value=''>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                <tmpl_if name='pkg_license_type' op='==' value='url'>
                    <a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                    <tmpl_elseif name='pkg_license_content'>
                        <textarea rows="10" cols="80" id="license_text">{tmpl_var name='pkg_license_content'}</textarea>
                </tmpl_if>
            </div>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='acceptance_txt'}</label>
                <input type="checkbox" name="license" id="license" <tmpl_if name='inp_license' op='==' value='true'>checked</tmpl_if> />&nbsp;&nbsp;{tmpl_var name='acceptance_text'}
            </div>
        </fieldset>
        <input type="hidden" name="install" value="0" />
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_install_txt'}" name="btn_install" onclick="document.pageForm.install.value=1; submitForm('pageForm','sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');"><span>{tmpl_var name='btn_install_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('aps/availablepackages_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
<h2>
    {tmpl_var name='installation_txt'}: {tmpl_var name='pkg_name'} {tmpl_var name='pkg_version'}-{tmpl_var name='pkg_release'}
    <span style="float:right">
        <tmpl_if name='pkg_icon' op='!=' value=''>
            <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
        </tmpl_if>
    </span>
</h2>
<tmpl_if name='error'>
    <div id="errorMsg"><h3>ERROR</h3><ol>{tmpl_var name='error'}</ol></div>
</tmpl_if>
<div class="panel panel_install_package">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <legend>{tmpl_var name='basic_settings_txt'}</legend>
            <div class="ctrlHolder">
                <label for="main_domain">{tmpl_var name='install_location_txt'}</label>
                <div class="resetButton">http(s)://&nbsp;</div>DOMAIN_LIST_SPACE<div style="float:left;">&nbsp;/&nbsp;</div>
                <input type="text" name="main_location" id="main_location" value="{tmpl_var name='inp_main_location'}" maxlength="255" class="textInput formLengthHalf" />
            </div>
            <tmpl_if name='pkg_requirements_database' op='!=' value=''>
                <div class="ctrlHolder">
                    <label for="main_database_password">{tmpl_var name='new_database_password_txt'}</label>
                    <input type="text" class="textInput" name="main_database_password" id="main_database_password" value="{tmpl_var name='inp_main_database_password'}" size="10" maxlength="255" />
                </div>
            </tmpl_if>
            PKG_SETTINGS_SPACE
            <legend>{tmpl_var name='license_txt'}</legend>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='license_txt'}</label>
                <tmpl_if name='pkg_license_content' op='==' value=''>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                <tmpl_if name='pkg_license_type' op='==' value='url'>
                    <a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                    <tmpl_elseif name='pkg_license_content'>
                        <textarea rows="10" cols="80" id="license_text">{tmpl_var name='pkg_license_content'}</textarea>
                </tmpl_if>
            </div>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='acceptance_txt'}</label>
                <input type="checkbox" name="license" id="license" <tmpl_if name='inp_license' op='==' value='true'>checked</tmpl_if> />&nbsp;&nbsp;{tmpl_var name='acceptance_text'}
            </div>
        </fieldset>
        <input type="hidden" name="install" value="0" />
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_install_txt'}" name="btn_install" onclick="document.pageForm.install.value=1; submitForm('pageForm','sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');"><span>{tmpl_var name='btn_install_txt'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('aps/availablepackages_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
        </div>
    </div>
</div>
interface/web/sites/templates/aps_instances_list.htm
@@ -1,62 +1,62 @@
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_instances">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"}</legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <tmpl_if name='is_noclient'>
                        <!--<th class="tbl_col_customer" scope="col">{tmpl_var name='customer_txt'}</th>-->
                        </tmpl_if>
                        <th class="tbl_col_installlocation" scope="col">{tmpl_var name='install_location_txt'}</th>
                        <th class="tbl_col_instancestatus" scope="col">{tmpl_var name='status_txt'}</th>
                        <th class="tbl_col_limit" scope="col" >&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <tmpl_if name='is_noclient'>
                        <!--<td class="tbl_col_customer"><input type="text" name="search_customer_name" value="{tmpl_var name='search_customer_name'}" /></td>-->
                        </tmpl_if>
                        <td class="tbl_col_installlocation">&nbsp;</td>
                        <td class="tbl_col_instancestatus"><select name="search_instance_status" onChange="submitForm('pageForm','sites/aps_installedpackages_list.php');">{tmpl_var name='search_instance_status'}</select></td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onclick="submitForm('pageForm','sites/aps_installedpackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='package_name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='package_version'}-{tmpl_var name='package_release'}</td>
                            <tmpl_if name='is_noclient'>
                                <!--<td class="tbl_col_customer"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='customer_name'}</a></td>-->
                            </tmpl_if>
                            <td class="tbl_col_installlocation"><a href="http://{tmpl_var name='install_location'}" target="_blank">{tmpl_var name='install_location_short'}</a></td>
                            <td class="tbl_col_instancestatus"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='instance_status'}</span></td>
                            <td class="tbl_col_buttons">
                                <tmpl_if name='delete_possible'>
                                    <a class="button icons16 icoDelete" href="javascript: del_record('sites/aps_do_operation.php?action=delete_instance&id={tmpl_var name='id'}','{tmpl_var name='pkg_delete_confirmation'}')"><span>{tmpl_var name='delete_txt'}</span></a>
                                </tmpl_if>
                                <tmpl_if name='reinstall_possible'>
                                    <a class="button icons16 icoEdit" href="javascript: del_record('sites/aps_do_operation.php?action=reinstall_instance&id={tmpl_var name='id'}','{tmpl_var name='pkg_reinstall_confirmation'}')"><span>{tmpl_var name='reinstall_txt'}</span></a>
                                </tmpl_if>
                            </td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="6">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_instances">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"}</legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <tmpl_if name='is_noclient'>
                        <!--<th class="tbl_col_customer" scope="col">{tmpl_var name='customer_txt'}</th>-->
                        </tmpl_if>
                        <th class="tbl_col_installlocation" scope="col">{tmpl_var name='install_location_txt'}</th>
                        <th class="tbl_col_instancestatus" scope="col">{tmpl_var name='status_txt'}</th>
                        <th class="tbl_col_limit" scope="col" >&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <tmpl_if name='is_noclient'>
                        <!--<td class="tbl_col_customer"><input type="text" name="search_customer_name" value="{tmpl_var name='search_customer_name'}" /></td>-->
                        </tmpl_if>
                        <td class="tbl_col_installlocation">&nbsp;</td>
                        <td class="tbl_col_instancestatus"><select name="search_instance_status" onChange="submitForm('pageForm','sites/aps_installedpackages_list.php');">{tmpl_var name='search_instance_status'}</select></td>
                        <td class="tbl_col_buttons">
                            <button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onclick="submitForm('pageForm','sites/aps_installedpackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='package_name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='package_version'}-{tmpl_var name='package_release'}</td>
                            <tmpl_if name='is_noclient'>
                                <!--<td class="tbl_col_customer"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='customer_name'}</a></td>-->
                            </tmpl_if>
                            <td class="tbl_col_installlocation"><a href="http://{tmpl_var name='install_location'}" target="_blank">{tmpl_var name='install_location_short'}</a></td>
                            <td class="tbl_col_instancestatus"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='instance_status'}</span></td>
                            <td class="tbl_col_buttons">
                                <tmpl_if name='delete_possible'>
                                    <a class="button icons16 icoDelete" href="javascript: del_record('sites/aps_do_operation.php?action=delete_instance&id={tmpl_var name='id'}','{tmpl_var name='pkg_delete_confirmation'}')"><span>{tmpl_var name='delete_txt'}</span></a>
                                </tmpl_if>
                                <tmpl_if name='reinstall_possible'>
                                    <a class="button icons16 icoEdit" href="javascript: del_record('sites/aps_do_operation.php?action=reinstall_instance&id={tmpl_var name='id'}','{tmpl_var name='pkg_reinstall_confirmation'}')"><span>{tmpl_var name='reinstall_txt'}</span></a>
                                </tmpl_if>
                            </td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="6">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/sites/templates/aps_packagedetails_show.htm
@@ -1,141 +1,141 @@
<h2>
    <tmpl_if name='pkg_icon' op='!=' value=''>
        <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
    </tmpl_if>
    {tmpl_var name='pkg_name'}
</h2>
<b>{tmpl_var name='pkg_summary'}</b>
<p>&nbsp;</p>
<div class="pnl_toolsarea">
    <fieldset>
        <div class="buttons">
            <button class="button iconstxt icoAdd" type="button" onclick="loadContent('sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');">
                <span>{tmpl_var name="install_package_txt"}</span>
            </button>
        </div>
    </fieldset>
</div>
<p>&nbsp;</p><p>&nbsp;</p>
<div class="tabbox_tabs">
    <input type="hidden" name="next_tab" value="" />
    <ul>
        <li<tmpl_if name='next_tab' op='==' value='details'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('details', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='details_txt'}</a>
        </li>
        <tmpl_if name='pkg_screenshots'>
        <li<tmpl_if name='next_tab' op='==' value='screenshots'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('screenshots', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='screenshots_txt'}</a>
        </li></tmpl_if>
        <tmpl_if name='pkg_changelog'>
        <li<tmpl_if name='next_tab' op='==' value='changelog'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('changelog', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='changelog_txt'}</a>
        </li></tmpl_if>
        <li<tmpl_if name='next_tab' op='==' value='settings'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('settings', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='settings_txt'}</a>
        </li>
    </ul>
</div>
<p>&nbsp;</p>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <table class="list">
            <tbody>
                <tmpl_if name='next_tab' op='==' value='details'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='version_txt'}</td>
                        <td>{tmpl_var name='pkg_version'} (Release {tmpl_var name='pkg_release'})</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='category_txt'}</td>
                        <td>{tmpl_var name='pkg_category'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='description_txt'}</td>
                        <td>{tmpl_var name='pkg_description'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='homepage_txt'}</td>
                        <td>
                            <a href="{tmpl_var name='pkg_homepage'}" target="_blank">{tmpl_var name='pkg_homepage'}</a>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='installed_size_txt'}</td>
                        <td>{tmpl_var name='pkg_installed_size'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='supported_languages_txt'}</td>
                        <td>{tmpl_var name='pkg_languages'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='config_script_txt'}</td>
                        <td>{tmpl_var name='pkg_config_script'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='license_txt'}</td>
                        <td>
                            <tmpl_if name='pkg_license_name'>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                            <tmpl_if name='pkg_license_type' op='==' value='url'><a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                            <tmpl_elseif name='pkg_license_content'>
                                <textarea rows="10" cols="80">{tmpl_var name='pkg_license_content'}</textarea>
                            </tmpl_if>
                        </td>
                    </tr>
                <tmpl_elseif name='next_tab' op='==' value='screenshots'>
                    <tmpl_if name='pkg_screenshots'>
                        <tr class="tbl_row_even">
                            <td style="text-align:center;">
                                <tmpl_loop name='pkg_screenshots'>
                                    <img src="{tmpl_var name='ScreenPath'}" alt="{tmpl_var name='ScreenDescription'}" /><br />
                                    <em>{tmpl_var name='ScreenDescription'}</em><br /><br />
                                </tmpl_loop>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='changelog'>
                    <tmpl_if name='pkg_changelog'>
                        <tr class="tbl_row_even">
                            <td>
                                <ul>
                                    <tmpl_loop name='pkg_changelog'>
                                    <li>{tmpl_var name='ChangelogVersion'}</li>
                                <ul>
                                    <tmpl_if name='ChangelogDescription'>
                                    <li>{tmpl_var name='ChangelogDescription'}</li>
                                    </tmpl_if>
                                </ul>
                                    </tmpl_loop>
                                </ul>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='settings'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='php_extensions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_php_extensions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='php_settings_txt'}</td>
                        <td>
                            <tmpl_loop name='pkg_requirements_php_settings'>{tmpl_var name='PHPSettingName'} = {tmpl_var name='PHPSettingValue'}<br /></tmpl_loop>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='supported_php_versions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_supported_php_versions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='database_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_database'}</a></td>
                    </tr>
                </tmpl_if>
            </tbody>
        </table>
    </div>
<h2>
    <tmpl_if name='pkg_icon' op='!=' value=''>
        <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
    </tmpl_if>
    {tmpl_var name='pkg_name'}
</h2>
<b>{tmpl_var name='pkg_summary'}</b>
<p>&nbsp;</p>
<div class="pnl_toolsarea">
    <fieldset>
        <div class="buttons">
            <button class="button iconstxt icoAdd" type="button" onclick="loadContent('sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');">
                <span>{tmpl_var name="install_package_txt"}</span>
            </button>
        </div>
    </fieldset>
</div>
<p>&nbsp;</p><p>&nbsp;</p>
<div class="tabbox_tabs">
    <input type="hidden" name="next_tab" value="" />
    <ul>
        <li<tmpl_if name='next_tab' op='==' value='details'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('details', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='details_txt'}</a>
        </li>
        <tmpl_if name='pkg_screenshots'>
        <li<tmpl_if name='next_tab' op='==' value='screenshots'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('screenshots', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='screenshots_txt'}</a>
        </li></tmpl_if>
        <tmpl_if name='pkg_changelog'>
        <li<tmpl_if name='next_tab' op='==' value='changelog'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('changelog', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='changelog_txt'}</a>
        </li></tmpl_if>
        <li<tmpl_if name='next_tab' op='==' value='settings'> class="active"</tmpl_if>>
            <a href="#" onclick="return changeTab('settings', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='settings_txt'}</a>
        </li>
    </ul>
</div>
<p>&nbsp;</p>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <table class="list">
            <tbody>
                <tmpl_if name='next_tab' op='==' value='details'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='version_txt'}</td>
                        <td>{tmpl_var name='pkg_version'} (Release {tmpl_var name='pkg_release'})</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='category_txt'}</td>
                        <td>{tmpl_var name='pkg_category'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='description_txt'}</td>
                        <td>{tmpl_var name='pkg_description'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='homepage_txt'}</td>
                        <td>
                            <a href="{tmpl_var name='pkg_homepage'}" target="_blank">{tmpl_var name='pkg_homepage'}</a>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='installed_size_txt'}</td>
                        <td>{tmpl_var name='pkg_installed_size'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='supported_languages_txt'}</td>
                        <td>{tmpl_var name='pkg_languages'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='config_script_txt'}</td>
                        <td>{tmpl_var name='pkg_config_script'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='license_txt'}</td>
                        <td>
                            <tmpl_if name='pkg_license_name'>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                            <tmpl_if name='pkg_license_type' op='==' value='url'><a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                            <tmpl_elseif name='pkg_license_content'>
                                <textarea rows="10" cols="80">{tmpl_var name='pkg_license_content'}</textarea>
                            </tmpl_if>
                        </td>
                    </tr>
                <tmpl_elseif name='next_tab' op='==' value='screenshots'>
                    <tmpl_if name='pkg_screenshots'>
                        <tr class="tbl_row_even">
                            <td style="text-align:center;">
                                <tmpl_loop name='pkg_screenshots'>
                                    <img src="{tmpl_var name='ScreenPath'}" alt="{tmpl_var name='ScreenDescription'}" /><br />
                                    <em>{tmpl_var name='ScreenDescription'}</em><br /><br />
                                </tmpl_loop>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='changelog'>
                    <tmpl_if name='pkg_changelog'>
                        <tr class="tbl_row_even">
                            <td>
                                <ul>
                                    <tmpl_loop name='pkg_changelog'>
                                    <li>{tmpl_var name='ChangelogVersion'}</li>
                                <ul>
                                    <tmpl_if name='ChangelogDescription'>
                                    <li>{tmpl_var name='ChangelogDescription'}</li>
                                    </tmpl_if>
                                </ul>
                                    </tmpl_loop>
                                </ul>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='settings'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='php_extensions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_php_extensions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='php_settings_txt'}</td>
                        <td>
                            <tmpl_loop name='pkg_requirements_php_settings'>{tmpl_var name='PHPSettingName'} = {tmpl_var name='PHPSettingValue'}<br /></tmpl_loop>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='supported_php_versions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_supported_php_versions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='database_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_database'}</a></td>
                    </tr>
                </tmpl_if>
            </tbody>
        </table>
    </div>
</div>
interface/web/sites/templates/aps_packages_list.htm
@@ -1,55 +1,55 @@
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"} ({tmpl_var name='package_count'})</legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <th class="tbl_col_category" scope="col">{tmpl_var name='category_txt'}</th>
                            <tmpl_if name='is_admin'>
                                <th class="tbl_col_package_status" scope="col">{tmpl_var name='status_txt'}</th>
                            </tmpl_if>
                        <th class="tbl_col_limit" scope="col">&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <td class="tbl_col_customerid"><select name="search_category" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_category'}</select></td>
                            <tmpl_if name='is_admin'>
                                <td class="tbl_col_status"><select name="search_package_status" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_package_status'}</select></td>
                            </tmpl_if>
                        <td class="tbl_col_buttons"><button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onclick="submitForm('pageForm','sites/aps_availablepackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button></td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='id'}');">{tmpl_var name='name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='version'}-{tmpl_var name='release'}</td>
                            <td class="tbl_col_category">{tmpl_var name='category'}</td>
                                <tmpl_if name='is_admin'>
                                    <td class="tbl_col_status"><a href="javascript:loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=change_status&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}');"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='package_status'}</span></a></td>
                                </tmpl_if>
                            <td class="tbl_col_buttons">&nbsp;</td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="4">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"} ({tmpl_var name='package_count'})</legend>
            <table class="list">
                <thead>
                    <tr class="caption">
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <th class="tbl_col_category" scope="col">{tmpl_var name='category_txt'}</th>
                            <tmpl_if name='is_admin'>
                                <th class="tbl_col_package_status" scope="col">{tmpl_var name='status_txt'}</th>
                            </tmpl_if>
                        <th class="tbl_col_limit" scope="col">&nbsp;</th>
                    </tr>
                    <tr class="filter">
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <td class="tbl_col_customerid"><select name="search_category" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_category'}</select></td>
                            <tmpl_if name='is_admin'>
                                <td class="tbl_col_status"><select name="search_package_status" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_package_status'}</select></td>
                            </tmpl_if>
                        <td class="tbl_col_buttons"><button type="button" class="button icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onclick="submitForm('pageForm','sites/aps_availablepackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button></td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onclick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='id'}');">{tmpl_var name='name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='version'}-{tmpl_var name='release'}</td>
                            <td class="tbl_col_category">{tmpl_var name='category'}</td>
                                <tmpl_if name='is_admin'>
                                    <td class="tbl_col_status"><a href="javascript:loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=change_status&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}');"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='package_status'}</span></a></td>
                                </tmpl_if>
                            <td class="tbl_col_buttons">&nbsp;</td>
                        </tr>
                    </tmpl_loop>
                    <tmpl_unless name="records">
                        <tr class="tbl_row_noresults tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td colspan="4">{tmpl_var name='globalsearch_noresults_text_txt'}</td>
                        </tr>
                    </tmpl_unless>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/sites/templates/web_aliasdomain_advanced.htm
@@ -1,37 +1,37 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_web_domain">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels"><legend>Options</legend>
      <div class="ctrlHolder proxy">
                <label for="proxy_directives">{tmpl_var name='proxy_directives_txt'}</label>
                <textarea name="proxy_directives" id="proxy_directives" rows='10' cols='50' style="width:400px;">{tmpl_var name='proxy_directives'}</textarea>&nbsp;<b>{tmpl_var name="available_proxy_directive_snippets_txt"}</b><br><br>&nbsp;{tmpl_var name="proxy_directive_snippets_txt"}
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','sites/web_aliasdomain_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('sites/web_aliasdomain_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
<script language="JavaScript" type="text/javascript">
    var webId = jQuery('input[name="id"]').val();
    adjustForm();
    function adjustForm(){
        jQuery.getJSON('sites/ajax_get_json.php'+ '?' + Math.round(new Date().getTime()), {web_id : webId, type : "getredirecttype"}, function(data) {
            if(data.redirecttype == "proxy"){
                jQuery('.proxy').show();
            } else {
                jQuery('.proxy').hide();
            }
        });
    }
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_web_domain">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels"><legend>Options</legend>
      <div class="ctrlHolder proxy">
                <label for="proxy_directives">{tmpl_var name='proxy_directives_txt'}</label>
                <textarea name="proxy_directives" id="proxy_directives" rows='10' cols='50' style="width:400px;">{tmpl_var name='proxy_directives'}</textarea>&nbsp;<b>{tmpl_var name="available_proxy_directive_snippets_txt"}</b><br><br>&nbsp;{tmpl_var name="proxy_directive_snippets_txt"}
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','sites/web_aliasdomain_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('sites/web_aliasdomain_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
<script language="JavaScript" type="text/javascript">
    var webId = jQuery('input[name="id"]').val();
    adjustForm();
    function adjustForm(){
        jQuery.getJSON('sites/ajax_get_json.php'+ '?' + Math.round(new Date().getTime()), {web_id : webId, type : "getredirecttype"}, function(data) {
            if(data.redirecttype == "proxy"){
                jQuery('.proxy').show();
            } else {
                jQuery('.proxy').hide();
            }
        });
    }
</script>
interface/web/sites/templates/web_subdomain_advanced.htm
@@ -1,37 +1,37 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_web_subdomain">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels"><legend>Options</legend>
      <div class="ctrlHolder proxy">
                <label for="proxy_directives">{tmpl_var name='proxy_directives_txt'}</label>
                <textarea name="proxy_directives" id="proxy_directives" rows='10' cols='50' style="width:400px;">{tmpl_var name='proxy_directives'}</textarea>&nbsp;<b>{tmpl_var name="available_proxy_directive_snippets_txt"}</b><br><br>&nbsp;{tmpl_var name="proxy_directive_snippets_txt"}
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','sites/web_subdomain_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('sites/web_subdomain_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
<script language="JavaScript" type="text/javascript">
    var webId = jQuery('input[name="id"]').val();
    adjustForm();
    function adjustForm(){
        jQuery.getJSON('sites/ajax_get_json.php'+ '?' + Math.round(new Date().getTime()), {web_id : webId, type : "getredirecttype"}, function(data) {
            if(data.redirecttype == "proxy"){
                jQuery('.proxy').show();
            } else {
                jQuery('.proxy').hide();
            }
        });
    }
</script>
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_web_subdomain">
  <div class="pnl_formsarea">
    <fieldset class="inlineLabels"><legend>Options</legend>
      <div class="ctrlHolder proxy">
                <label for="proxy_directives">{tmpl_var name='proxy_directives_txt'}</label>
                <textarea name="proxy_directives" id="proxy_directives" rows='10' cols='50' style="width:400px;">{tmpl_var name='proxy_directives'}</textarea>&nbsp;<b>{tmpl_var name="available_proxy_directive_snippets_txt"}</b><br><br>&nbsp;{tmpl_var name="proxy_directive_snippets_txt"}
            </div>
    </fieldset>
    <input type="hidden" name="id" value="{tmpl_var name='id'}">
    <div class="buttonHolder buttons">
      <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_save_txt'}" onclick="submitForm('pageForm','sites/web_subdomain_edit.php');"><span>{tmpl_var name='btn_save_txt'}</span></button>
      <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel_txt'}" onclick="loadContent('sites/web_subdomain_list.php');"><span>{tmpl_var name='btn_cancel_txt'}</span></button>
    </div>
  </div>
</div>
<script language="JavaScript" type="text/javascript">
    var webId = jQuery('input[name="id"]').val();
    adjustForm();
    function adjustForm(){
        jQuery.getJSON('sites/ajax_get_json.php'+ '?' + Math.round(new Date().getTime()), {web_id : webId, type : "getredirecttype"}, function(data) {
            if(data.redirecttype == "proxy"){
                jQuery('.proxy').show();
            } else {
                jQuery('.proxy').hide();
            }
        });
    }
</script>
interface/web/themes/default-304/css/screen/redmond/jquery-ui-1.8.16.custom.css
@@ -1,444 +1,444 @@
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 *
 * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=0px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=0px
 */
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }/*
 * jQuery UI Autocomplete 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Autocomplete#theming
 */
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
 * jQuery UI Menu 1.8.16
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu#theming
 */
.ui-menu {
    list-style:none;
    padding: 2px;
    margin: 0;
    display:block;
    float: left;
}
.ui-menu .ui-menu {
    margin-top: -3px;
}
.ui-menu .ui-menu-item {
    margin:0;
    padding: 0;
    zoom: 1;
    float: left;
    clear: left;
    width: 100%;
}
.ui-menu .ui-menu-item a {
    text-decoration:none;
    display:block;
    padding:.2em .4em;
    line-height:1.5;
    zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
    font-weight: normal;
    margin: -1px;
}
/*
 * jQuery UI Button 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button#theming
 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4;  }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
 * jQuery UI Datepicker 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker#theming
 */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
    display: none; /*sorry for IE5*/
    display/**/: block; /*sorry for IE5*/
    position: absolute; /*must have*/
    z-index: -1; /*must have*/
    filter: mask(); /*must have*/
    top: -4px; /*must have*/
    left: -4px; /*must have*/
    width: 200px; /*must have*/
    height: 200px; /*must have*/
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 *
 * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=0px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=0px
 */
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }/*
 * jQuery UI Autocomplete 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Autocomplete#theming
 */
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
 * jQuery UI Menu 1.8.16
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu#theming
 */
.ui-menu {
    list-style:none;
    padding: 2px;
    margin: 0;
    display:block;
    float: left;
}
.ui-menu .ui-menu {
    margin-top: -3px;
}
.ui-menu .ui-menu-item {
    margin:0;
    padding: 0;
    zoom: 1;
    float: left;
    clear: left;
    width: 100%;
}
.ui-menu .ui-menu-item a {
    text-decoration:none;
    display:block;
    padding:.2em .4em;
    line-height:1.5;
    zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
    font-weight: normal;
    margin: -1px;
}
/*
 * jQuery UI Button 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button#theming
 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4;  }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
 * jQuery UI Datepicker 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker#theming
 */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
    display: none; /*sorry for IE5*/
    display/**/: block; /*sorry for IE5*/
    position: absolute; /*must have*/
    z-index: -1; /*must have*/
    filter: mask(); /*must have*/
    top: -4px; /*must have*/
    left: -4px; /*must have*/
    width: 200px; /*must have*/
    height: 200px; /*must have*/
}
interface/web/themes/default-304/css/screen/tipsy.css
@@ -1,25 +1,25 @@
.tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; }
  .tipsy-inner { background-color: #000; color: #FFF; max-width: 350px; padding: 5px 8px 4px 8px; text-align: left; }
  /* Rounded corners */
  .tipsy-inner { border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; }
  /* Uncomment for shadow */
  /*.tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }*/
  .tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #000; }
  /* Rules to colour arrows */
  .tipsy-arrow-n { border-bottom-color: #000; }
  .tipsy-arrow-s { border-top-color: #000; }
  .tipsy-arrow-e { border-left-color: #000; }
  .tipsy-arrow-w { border-right-color: #000; }
    .tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
    .tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
    .tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none;  border-left-color: transparent; border-right-color: transparent;}
  .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
    .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
    .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
  .tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
  .tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
.tipsy { font-size: 10px; position: absolute; padding: 5px; z-index: 100000; }
  .tipsy-inner { background-color: #000; color: #FFF; max-width: 350px; padding: 5px 8px 4px 8px; text-align: left; }
  /* Rounded corners */
  .tipsy-inner { border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; }
  /* Uncomment for shadow */
  /*.tipsy-inner { box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; }*/
  .tipsy-arrow { position: absolute; width: 0; height: 0; line-height: 0; border: 5px dashed #000; }
  /* Rules to colour arrows */
  .tipsy-arrow-n { border-bottom-color: #000; }
  .tipsy-arrow-s { border-top-color: #000; }
  .tipsy-arrow-e { border-left-color: #000; }
  .tipsy-arrow-w { border-right-color: #000; }
    .tipsy-n .tipsy-arrow { top: 0px; left: 50%; margin-left: -5px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent; }
    .tipsy-nw .tipsy-arrow { top: 0; left: 10px; border-bottom-style: solid; border-top: none; border-left-color: transparent; border-right-color: transparent;}
    .tipsy-ne .tipsy-arrow { top: 0; right: 10px; border-bottom-style: solid; border-top: none;  border-left-color: transparent; border-right-color: transparent;}
  .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
    .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; border-top-style: solid; border-bottom: none;  border-left-color: transparent; border-right-color: transparent; }
    .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; border-top-style: solid; border-bottom: none; border-left-color: transparent; border-right-color: transparent; }
  .tipsy-e .tipsy-arrow { right: 0; top: 50%; margin-top: -5px; border-left-style: solid; border-right: none; border-top-color: transparent; border-bottom-color: transparent; }
  .tipsy-w .tipsy-arrow { left: 0; top: 50%; margin-top: -5px; border-right-style: solid; border-left: none; border-top-color: transparent; border-bottom-color: transparent; }
interface/web/themes/default-304/templates/monitor/show_sys_state.htm
@@ -1,25 +1,25 @@
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_sys_state">
    <div class="pnl_toolsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="monTransRefreshsq"></legend>
            <div class="buttons">
                <div class="ctrlHolder">
                    <label for="refreshinterval">{tmpl_var name='refreshinterval_txt'}</label>
                    <select name="refreshinterval" id="refreshinterval" class="selectInput withicons" onChange="loadContentRefresh('monitor/show_sys_state.php?state={tmpl_var name="state_type"}')">
                        {tmpl_var name='refresh'}
                    </select>
                </div>
            </div>
        </fieldset>
    </div>
    <div class="pnl_formarea">
        <fieldset><legend></legend>
            <div class="stateview"><tmpl_var name="state_data"></div>
        </fieldset>
    </div>
<h2><tmpl_var name="list_head_txt"></h2>
<p><tmpl_var name="list_desc_txt"></p>
<div class="panel panel_sys_state">
    <div class="pnl_toolsarea">
        <fieldset class="inlineLabels"><legend><tmpl_var name="monTransRefreshsq"></legend>
            <div class="buttons">
                <div class="ctrlHolder">
                    <label for="refreshinterval">{tmpl_var name='refreshinterval_txt'}</label>
                    <select name="refreshinterval" id="refreshinterval" class="selectInput withicons" onChange="loadContentRefresh('monitor/show_sys_state.php?state={tmpl_var name="state_type"}')">
                        {tmpl_var name='refresh'}
                    </select>
                </div>
            </div>
        </fieldset>
    </div>
    <div class="pnl_formarea">
        <fieldset><legend></legend>
            <div class="stateview"><tmpl_var name="state_data"></div>
        </fieldset>
    </div>
</div>
interface/web/themes/default-304/templates/sites/aps_install_package.htm
@@ -1,56 +1,56 @@
<h2>
    {tmpl_var name='installation_txt'}: {tmpl_var name='pkg_name'} {tmpl_var name='pkg_version'}-{tmpl_var name='pkg_release'}
    <span style="float:right">
        <tmpl_if name='pkg_icon' op='!=' value=''>
            <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
        </tmpl_if>
    </span>
</h2>
<tmpl_if name='error'>
    <div id="errorMsg"><h3>ERROR</h3><ol>{tmpl_var name='error'}</ol></div>
</tmpl_if>
<div class="panel panel_install_package">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <legend>{tmpl_var name='basic_settings_txt'}</legend>
            <div class="ctrlHolder">
                <label for="main_domain">{tmpl_var name='install_location_txt'}</label>
                <div class="resetButton">http(s)://&nbsp;</div>DOMAIN_LIST_SPACE<div style="float:left;">&nbsp;/&nbsp;</div>
                <input type="text" name="main_location" id="main_location" value="{tmpl_var name='inp_main_location'}" maxlength="255" class="textInput formLengthHalf" />
            </div>
            <tmpl_if name='pkg_requirements_database' op='!=' value=''>
                <div class="ctrlHolder">
                    <label for="main_database_password">{tmpl_var name='new_database_password_txt'}</label>
                    <input type="text" class="textInput" name="main_database_password" id="main_database_password" value="{tmpl_var name='inp_main_database_password'}" size="10" maxlength="255" />
                </div>
            </tmpl_if>
            PKG_SETTINGS_SPACE
            <legend>{tmpl_var name='license_txt'}</legend>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='license_txt'}</label>
                <tmpl_if name='pkg_license_content' op='==' value=''>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                <tmpl_if name='pkg_license_type' op='==' value='url'>
                    <a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                    <tmpl_elseif name='pkg_license_content'>
                        <textarea rows="10" cols="80" id="license_text">{tmpl_var name='pkg_license_content'}</textarea>
                </tmpl_if>
            </div>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='acceptance_txt'}</label>
                <input type="checkbox" name="license" id="license" <tmpl_if name='inp_license' op='==' value='true'>checked</tmpl_if> />&nbsp;&nbsp;{tmpl_var name='acceptance_text'}
            </div>
        </fieldset>
        <input type="hidden" name="install" value="0" />
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_install'}" name="btn_install" onClick="document.pageForm.install.value=1; submitForm('pageForm','sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');"><span>{tmpl_var name='btn_install'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel'}" onClick="loadContent('aps/availablepackages_list.php');"><span>{tmpl_var name='btn_cancel'}</span></button>
        </div>
    </div>
<h2>
    {tmpl_var name='installation_txt'}: {tmpl_var name='pkg_name'} {tmpl_var name='pkg_version'}-{tmpl_var name='pkg_release'}
    <span style="float:right">
        <tmpl_if name='pkg_icon' op='!=' value=''>
            <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
        </tmpl_if>
    </span>
</h2>
<tmpl_if name='error'>
    <div id="errorMsg"><h3>ERROR</h3><ol>{tmpl_var name='error'}</ol></div>
</tmpl_if>
<div class="panel panel_install_package">
    <div class="pnl_formsarea">
        <fieldset class="inlineLabels">
            <legend>{tmpl_var name='basic_settings_txt'}</legend>
            <div class="ctrlHolder">
                <label for="main_domain">{tmpl_var name='install_location_txt'}</label>
                <div class="resetButton">http(s)://&nbsp;</div>DOMAIN_LIST_SPACE<div style="float:left;">&nbsp;/&nbsp;</div>
                <input type="text" name="main_location" id="main_location" value="{tmpl_var name='inp_main_location'}" maxlength="255" class="textInput formLengthHalf" />
            </div>
            <tmpl_if name='pkg_requirements_database' op='!=' value=''>
                <div class="ctrlHolder">
                    <label for="main_database_password">{tmpl_var name='new_database_password_txt'}</label>
                    <input type="text" class="textInput" name="main_database_password" id="main_database_password" value="{tmpl_var name='inp_main_database_password'}" size="10" maxlength="255" />
                </div>
            </tmpl_if>
            PKG_SETTINGS_SPACE
            <legend>{tmpl_var name='license_txt'}</legend>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='license_txt'}</label>
                <tmpl_if name='pkg_license_content' op='==' value=''>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                <tmpl_if name='pkg_license_type' op='==' value='url'>
                    <a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                    <tmpl_elseif name='pkg_license_content'>
                        <textarea rows="10" cols="80" id="license_text">{tmpl_var name='pkg_license_content'}</textarea>
                </tmpl_if>
            </div>
            <div class="ctrlHolder">
                <label for="license">{tmpl_var name='acceptance_txt'}</label>
                <input type="checkbox" name="license" id="license" <tmpl_if name='inp_license' op='==' value='true'>checked</tmpl_if> />&nbsp;&nbsp;{tmpl_var name='acceptance_text'}
            </div>
        </fieldset>
        <input type="hidden" name="install" value="0" />
        <div class="buttonHolder buttons">
            <button class="positive iconstxt icoPositive" type="button" value="{tmpl_var name='btn_install'}" name="btn_install" onClick="document.pageForm.install.value=1; submitForm('pageForm','sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');"><span>{tmpl_var name='btn_install'}</span></button>
            <button class="negative iconstxt icoNegative" type="button" value="{tmpl_var name='btn_cancel'}" onClick="loadContent('aps/availablepackages_list.php');"><span>{tmpl_var name='btn_cancel'}</span></button>
        </div>
    </div>
</div>
interface/web/themes/default-304/templates/sites/aps_instances_list.htm
@@ -1,62 +1,62 @@
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_instances">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"}</legend>
            <table class="list">
                <thead>
                    <tr>
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <tmpl_if name='is_noclient'>
                        <th class="tbl_col_customer" scope="col">{tmpl_var name='customer_txt'}</th>
                        </tmpl_if>
                        <th class="tbl_col_installlocation" scope="col">{tmpl_var name='install_location_txt'}</th>
                        <th class="tbl_col_instancestatus" scope="col">{tmpl_var name='status_txt'}</th>
                        <th class="tbl_col_buttons" scope="col" >&nbsp;</th>
                    </tr>
                    <tr>
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <tmpl_if name='is_noclient'>
                        <td class="tbl_col_customer"><input type="text" name="search_customer_name" value="{tmpl_var name='search_customer_name'}" /></td>
                        </tmpl_if>
                        <td class="tbl_col_installlocation">&nbsp;</td>
                        <td class="tbl_col_instancestatus"><select name="search_instance_status" onChange="submitForm('pageForm','sites/aps_installedpackages_list.php');">{tmpl_var name='search_instance_status'}</select></td>
                        <td class="tbl_col_buttons">
                        <button type="button" class="icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onClick="submitForm('pageForm','sites/aps_installedpackages_list.php');">
                            <span>{tmpl_var name='filter_txt'}</span>
                        </button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onClick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='package_name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='package_version'}-{tmpl_var name='package_release'}</td>
                            <tmpl_if name='is_noclient'>
                                <td class="tbl_col_customer"><a href="#" onClick="loadContent('client/client_edit.php?id={tmpl_var name='CustomerID'}');">{tmpl_var name='customer_name'}</a></td>
                            </tmpl_if>
                            <td class="tbl_col_installlocation"><a href="http://{tmpl_var name='install_location'}" target="_blank">{tmpl_var name='install_location_short'}</a></td>
                            <td class="tbl_col_instancestatus"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='instance_status'}</span></td>
                            <td class="tbl_col_buttons">
                                <div class="buttons icons16" style="width:60px;">
                                    <tmpl_if name='delete_possible'><a class="icons16 icoDelete" href="javascript:if(window.confirm('{tmpl_var name='pkg_delete_confirmation'}')){ loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=delete_instance&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}'); }"><span>{tmpl_var name='delete_txt'}</span></a></tmpl_if>
                                    <tmpl_if name='reinstall_possible'><a class="icons16 icoEdit" href="javascript:if(window.confirm('{tmpl_var name='pkg_reinstall_confirmation'}')){ loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=reinstall_instance&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}'); }"><span>{tmpl_var name='reinstall_txt'}</span></a></tmpl_if>
                                </div>
                            </td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="6">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_instances">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"}</legend>
            <table class="list">
                <thead>
                    <tr>
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <tmpl_if name='is_noclient'>
                        <th class="tbl_col_customer" scope="col">{tmpl_var name='customer_txt'}</th>
                        </tmpl_if>
                        <th class="tbl_col_installlocation" scope="col">{tmpl_var name='install_location_txt'}</th>
                        <th class="tbl_col_instancestatus" scope="col">{tmpl_var name='status_txt'}</th>
                        <th class="tbl_col_buttons" scope="col" >&nbsp;</th>
                    </tr>
                    <tr>
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <tmpl_if name='is_noclient'>
                        <td class="tbl_col_customer"><input type="text" name="search_customer_name" value="{tmpl_var name='search_customer_name'}" /></td>
                        </tmpl_if>
                        <td class="tbl_col_installlocation">&nbsp;</td>
                        <td class="tbl_col_instancestatus"><select name="search_instance_status" onChange="submitForm('pageForm','sites/aps_installedpackages_list.php');">{tmpl_var name='search_instance_status'}</select></td>
                        <td class="tbl_col_buttons">
                        <button type="button" class="icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onClick="submitForm('pageForm','sites/aps_installedpackages_list.php');">
                            <span>{tmpl_var name='filter_txt'}</span>
                        </button>
                        </td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onClick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='package_id'}');">{tmpl_var name='package_name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='package_version'}-{tmpl_var name='package_release'}</td>
                            <tmpl_if name='is_noclient'>
                                <td class="tbl_col_customer"><a href="#" onClick="loadContent('client/client_edit.php?id={tmpl_var name='CustomerID'}');">{tmpl_var name='customer_name'}</a></td>
                            </tmpl_if>
                            <td class="tbl_col_installlocation"><a href="http://{tmpl_var name='install_location'}" target="_blank">{tmpl_var name='install_location_short'}</a></td>
                            <td class="tbl_col_instancestatus"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='instance_status'}</span></td>
                            <td class="tbl_col_buttons">
                                <div class="buttons icons16" style="width:60px;">
                                    <tmpl_if name='delete_possible'><a class="icons16 icoDelete" href="javascript:if(window.confirm('{tmpl_var name='pkg_delete_confirmation'}')){ loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=delete_instance&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}'); }"><span>{tmpl_var name='delete_txt'}</span></a></tmpl_if>
                                    <tmpl_if name='reinstall_possible'><a class="icons16 icoEdit" href="javascript:if(window.confirm('{tmpl_var name='pkg_reinstall_confirmation'}')){ loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=reinstall_instance&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}'); }"><span>{tmpl_var name='reinstall_txt'}</span></a></tmpl_if>
                                </div>
                            </td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="6">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/themes/default-304/templates/sites/aps_packagedetails_show.htm
@@ -1,139 +1,139 @@
<h2>
    <tmpl_if name='pkg_icon' op='!=' value=''>
        <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
    </tmpl_if>
    {tmpl_var name='pkg_name'}
</h2>
<b>{tmpl_var name='pkg_summary'}</b>
<p>&nbsp;</p>
<div class="pnl_toolsarea">
    <div class="buttons">
        <button class="iconstxt icoAdd" type="button" onClick="loadContent('sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');">
            <span>{tmpl_var name='install_package_txt'}</span>
        </button>
    </div>
    <p>&nbsp;</p><p>&nbsp;</p>
</div>
<div class="tabbox_tabs">
    <input type="hidden" name="next_tab" value="" />
    <ul>
        <li<tmpl_if name='next_tab' op='==' value='details'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('details', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='details_txt'}</a>
        </li>
        <tmpl_if name='pkg_screenshots'>
        <li<tmpl_if name='next_tab' op='==' value='screenshots'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('screenshots', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='screenshots_txt'}</a>
        </li></tmpl_if>
        <tmpl_if name='pkg_changelog'>
        <li<tmpl_if name='next_tab' op='==' value='changelog'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('changelog', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='changelog_txt'}</a>
        </li></tmpl_if>
        <li<tmpl_if name='next_tab' op='==' value='settings'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('settings', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='settings_txt'}</a>
        </li>
    </ul>
</div>
<p>&nbsp;</p>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <table class="list">
            <tbody>
                <tmpl_if name='next_tab' op='==' value='details'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='version_txt'}</td>
                        <td>{tmpl_var name='pkg_version'} (Release {tmpl_var name='pkg_release'})</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='category_txt'}</td>
                        <td>{tmpl_var name='pkg_category'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='description_txt'}</td>
                        <td>{tmpl_var name='pkg_description'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='homepage_txt'}</td>
                        <td>
                            <a href="{tmpl_var name='pkg_homepage'}" target="_blank">{tmpl_var name='pkg_homepage'}</a>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='installed_size_txt'}</td>
                        <td>{tmpl_var name='pkg_installed_size'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='supported_languages_txt'}</td>
                        <td>{tmpl_var name='pkg_languages'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='config_script_txt'}</td>
                        <td>{tmpl_var name='pkg_config_script'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='license_txt'}</td>
                        <td>
                            <tmpl_if name='pkg_license_name'>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                            <tmpl_if name='pkg_license_type' op='==' value='url'><a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                            <tmpl_elseif name='pkg_license_content'>
                                <textarea rows="10" cols="80">{tmpl_var name='pkg_license_content'}</textarea>
                            </tmpl_if>
                        </td>
                    </tr>
                <tmpl_elseif name='next_tab' op='==' value='screenshots'>
                    <tmpl_if name='pkg_screenshots'>
                        <tr class="tbl_row_even">
                            <td style="text-align:center;">
                                <tmpl_loop name='pkg_screenshots'>
                                    <img src="{tmpl_var name='ScreenPath'}" alt="{tmpl_var name='ScreenDescription'}" /><br />
                                    <em>{tmpl_var name='ScreenDescription'}</em><br /><br />
                                </tmpl_loop>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='changelog'>
                    <tmpl_if name='pkg_changelog'>
                        <tr class="tbl_row_even">
                            <td>
                                <ul>
                                    <tmpl_loop name='pkg_changelog'>
                                    <li>{tmpl_var name='ChangelogVersion'}</li>
                                <ul>
                                    <tmpl_if name='ChangelogDescription'>
                                    <li>{tmpl_var name='ChangelogDescription'}</li>
                                    </tmpl_if>
                                </ul>
                                    </tmpl_loop>
                                </ul>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='settings'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='php_extensions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_php_extensions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='php_settings_txt'}</td>
                        <td>
                            <tmpl_loop name='pkg_requirements_php_settings'>{tmpl_var name='PHPSettingName'} = {tmpl_var name='PHPSettingValue'}<br /></tmpl_loop>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='supported_php_versions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_supported_php_versions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='database_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_database'}</a></td>
                    </tr>
                </tmpl_if>
            </tbody>
        </table>
    </div>
<h2>
    <tmpl_if name='pkg_icon' op='!=' value=''>
        <img src="{tmpl_var name='pkg_icon'}" height="32" width="32" alt="{tmpl_var name='pkg_name'}" style="vertical-align:text-bottom;" />
    </tmpl_if>
    {tmpl_var name='pkg_name'}
</h2>
<b>{tmpl_var name='pkg_summary'}</b>
<p>&nbsp;</p>
<div class="pnl_toolsarea">
    <div class="buttons">
        <button class="iconstxt icoAdd" type="button" onClick="loadContent('sites/aps_install_package.php?id={tmpl_var name='pkg_id'}');">
            <span>{tmpl_var name='install_package_txt'}</span>
        </button>
    </div>
    <p>&nbsp;</p><p>&nbsp;</p>
</div>
<div class="tabbox_tabs">
    <input type="hidden" name="next_tab" value="" />
    <ul>
        <li<tmpl_if name='next_tab' op='==' value='details'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('details', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='details_txt'}</a>
        </li>
        <tmpl_if name='pkg_screenshots'>
        <li<tmpl_if name='next_tab' op='==' value='screenshots'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('screenshots', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='screenshots_txt'}</a>
        </li></tmpl_if>
        <tmpl_if name='pkg_changelog'>
        <li<tmpl_if name='next_tab' op='==' value='changelog'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('changelog', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='changelog_txt'}</a>
        </li></tmpl_if>
        <li<tmpl_if name='next_tab' op='==' value='settings'> class="active"</tmpl_if>>
            <a href="javascript:changeTab('settings', 'sites/aps_packagedetails_show.php?id={tmpl_var name='pkg_id'}');">{tmpl_var name='settings_txt'}</a>
        </li>
    </ul>
</div>
<p>&nbsp;</p>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <table class="list">
            <tbody>
                <tmpl_if name='next_tab' op='==' value='details'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='version_txt'}</td>
                        <td>{tmpl_var name='pkg_version'} (Release {tmpl_var name='pkg_release'})</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='category_txt'}</td>
                        <td>{tmpl_var name='pkg_category'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='description_txt'}</td>
                        <td>{tmpl_var name='pkg_description'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='homepage_txt'}</td>
                        <td>
                            <a href="{tmpl_var name='pkg_homepage'}" target="_blank">{tmpl_var name='pkg_homepage'}</a>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='installed_size_txt'}</td>
                        <td>{tmpl_var name='pkg_installed_size'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='supported_languages_txt'}</td>
                        <td>{tmpl_var name='pkg_languages'}</td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='config_script_txt'}</td>
                        <td>{tmpl_var name='pkg_config_script'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='license_txt'}</td>
                        <td>
                            <tmpl_if name='pkg_license_name'>{tmpl_var name='pkg_license_name'}<br /></tmpl_if>
                            <tmpl_if name='pkg_license_type' op='==' value='url'><a href="{tmpl_var name='pkg_license_content'}" target="_blank">{tmpl_var name='pkg_license_content'}</a>
                            <tmpl_elseif name='pkg_license_content'>
                                <textarea rows="10" cols="80">{tmpl_var name='pkg_license_content'}</textarea>
                            </tmpl_if>
                        </td>
                    </tr>
                <tmpl_elseif name='next_tab' op='==' value='screenshots'>
                    <tmpl_if name='pkg_screenshots'>
                        <tr class="tbl_row_even">
                            <td style="text-align:center;">
                                <tmpl_loop name='pkg_screenshots'>
                                    <img src="{tmpl_var name='ScreenPath'}" alt="{tmpl_var name='ScreenDescription'}" /><br />
                                    <em>{tmpl_var name='ScreenDescription'}</em><br /><br />
                                </tmpl_loop>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='changelog'>
                    <tmpl_if name='pkg_changelog'>
                        <tr class="tbl_row_even">
                            <td>
                                <ul>
                                    <tmpl_loop name='pkg_changelog'>
                                    <li>{tmpl_var name='ChangelogVersion'}</li>
                                <ul>
                                    <tmpl_if name='ChangelogDescription'>
                                    <li>{tmpl_var name='ChangelogDescription'}</li>
                                    </tmpl_if>
                                </ul>
                                    </tmpl_loop>
                                </ul>
                            </td>
                        </tr>
                    </tmpl_if>
                <tmpl_elseif name='next_tab' op='==' value='settings'>
                    <tr class="tbl_row_uneven">
                        <td width="25%">{tmpl_var name='php_extensions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_php_extensions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='php_settings_txt'}</td>
                        <td>
                            <tmpl_loop name='pkg_requirements_php_settings'>{tmpl_var name='PHPSettingName'} = {tmpl_var name='PHPSettingValue'}<br /></tmpl_loop>
                        </td>
                    </tr>
                    <tr class="tbl_row_uneven">
                        <td>{tmpl_var name='supported_php_versions_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_supported_php_versions'}</td>
                    </tr>
                    <tr class="tbl_row_even">
                        <td>{tmpl_var name='database_txt'}</td>
                        <td>{tmpl_var name='pkg_requirements_database'}</a></td>
                    </tr>
                </tmpl_if>
            </tbody>
        </table>
    </div>
</div>
interface/web/themes/default-304/templates/sites/aps_packages_list.htm
@@ -1,50 +1,50 @@
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"} ({tmpl_var name='package_count'})</legend>
            <table class="list">
                <thead>
                    <tr>
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <th class="tbl_col_category" scope="col">{tmpl_var name='category_txt'}</th>
                            <tmpl_if name='is_admin'>
                                <th class="tbl_col_status" scope="col">{tmpl_var name='status_txt'}</th>
                            </tmpl_if>
                        <th class="tbl_col_buttons" scope="col" width="60px;">&nbsp;</th>
                    </tr>
                    <tr>
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <td class="tbl_col_customerid"><select name="search_category" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_category'}</select></td>
                            <tmpl_if name='is_admin'>
                                <td class="tbl_col_status"><select name="search_package_status" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_package_status'}</select></td>
                            </tmpl_if>
                        <td class="tbl_col_buttons"><button type="button" class="icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onClick="submitForm('pageForm','sites/aps_availablepackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button></td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onClick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='id'}');">{tmpl_var name='name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='version'}-{tmpl_var name='release'}</td>
                            <td class="tbl_col_category">{tmpl_var name='category'}</td>
                                <tmpl_if name='is_admin'>
                                    <td class="tbl_col_status"><a href="javascript:loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=change_status&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}');"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='package_status'}</span></a></td>
                                </tmpl_if>
                            <td>&nbsp;</td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
<h2>{tmpl_var name="list_head_txt"}</h2>
<div class="panel panel_list_packages">
    <div class="pnl_listarea">
        <fieldset><legend>{tmpl_var name="list_head_txt"} ({tmpl_var name='package_count'})</legend>
            <table class="list">
                <thead>
                    <tr>
                        <th class="tbl_col_name" scope="col">{tmpl_var name='name_txt'}</th>
                        <th class="tbl_col_version" scope="col">{tmpl_var name='version_txt'}</th>
                        <th class="tbl_col_category" scope="col">{tmpl_var name='category_txt'}</th>
                            <tmpl_if name='is_admin'>
                                <th class="tbl_col_status" scope="col">{tmpl_var name='status_txt'}</th>
                            </tmpl_if>
                        <th class="tbl_col_buttons" scope="col" width="60px;">&nbsp;</th>
                    </tr>
                    <tr>
                        <td class="tbl_col_name"><input type="text" name="search_name" value="{tmpl_var name='search_name'}" /></td>
                        <td class="tbl_col_version"><input type="text" name="search_version" value="{tmpl_var name='search_version'}" /></td>
                        <td class="tbl_col_customerid"><select name="search_category" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_category'}</select></td>
                            <tmpl_if name='is_admin'>
                                <td class="tbl_col_status"><select name="search_package_status" onChange="submitForm('pageForm','sites/aps_availablepackages_list.php');">{tmpl_var name='search_package_status'}</select></td>
                            </tmpl_if>
                        <td class="tbl_col_buttons"><button type="button" class="icons16 icoFilter" name="Filter" id="Filter" value="{tmpl_var name='filter_txt'}" onClick="submitForm('pageForm','sites/aps_availablepackages_list.php');"><span>{tmpl_var name='filter_txt'}</span></button></td>
                    </tr>
                </thead>
                <tbody>
                    <tmpl_loop name='records'>
                        <tr class="tbl_row_<tmpl_if name='__EVEN__'}even<tmpl_else>uneven</tmpl_if>">
                            <td class="tbl_col_name"><a href="#" onClick="loadContent('sites/aps_packagedetails_show.php?id={tmpl_var name='id'}');">{tmpl_var name='name'}</a></td>
                            <td class="tbl_col_version">{tmpl_var name='version'}-{tmpl_var name='release'}</td>
                            <td class="tbl_col_category">{tmpl_var name='category'}</td>
                                <tmpl_if name='is_admin'>
                                    <td class="tbl_col_status"><a href="javascript:loadContentInto('status_content{tmpl_var name='__ROWNUM__'}', 'sites/aps_do_operation.php?action=change_status&id={tmpl_var name='id'}&phpsessid={tmpl_var name='phpsessid'}');"><span id="status_content{tmpl_var name='__ROWNUM__'}">{tmpl_var name='package_status'}</span></a></td>
                                </tmpl_if>
                            <td>&nbsp;</td>
                        </tr>
                    </tmpl_loop>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="tbl_footer tbl_paging" colspan="5">{tmpl_var name='paging'}</td>
                    </tr>
                </tfoot>
            </table>
        </fieldset>
    </div>
</div>
interface/web/themes/default/CHANGELOG
@@ -1,32 +1,32 @@
CHANGELOG
default -> default-v2
source: default $3241 07/06/2012 @ 12:00 UTC+2
resources @ https://github.com/foe-services/ispc-resources
- changed doctype to <!DOCTYPE html> (HTML5)
- rm yaml/*
- rm css/patches/*
- cp yaml/patches/iehacks.css css/*
- rm <!--[if lte ie 6]> from templates/main.tpl.htm
- rm IE6 support from css/iehacks.css
- mv css/nav/* into css/style.css
- mv css/print/* into css/print.css
- add css/print.css to templates/main.tpl.htm
- rm css/print/*
- rm css/nav/*
- rm css projection-type support
- mv css/screen/redmond/* css/*
- rm css/screen/*
- mv css media-recognition from css-files to <head>-link tag
- change most div-containers to new html5 tags in main.tpl.htm
- rm dom elements from main.tpl.htm
- add html5shiv.js (https://github.com/aFarkas/html5shiv) for better HTML5-compatibility
- reduction of dom elements
- reduction of css rules
- removed all single icons
    - all icons separate:  https://github.com/downloads/foe-services/ispc-larry/ispc-default_separate.zip
    - all used icons as layers and sprite as .psd: https://github.com/downloads/foe-services/ispc-larry/ispc-default_psd.zip
- added sprites for (nearly) all used icons where suitable
- added flags for country text in lists
- added some list column widths
CHANGELOG
default -> default-v2
source: default $3241 07/06/2012 @ 12:00 UTC+2
resources @ https://github.com/foe-services/ispc-resources
- changed doctype to <!DOCTYPE html> (HTML5)
- rm yaml/*
- rm css/patches/*
- cp yaml/patches/iehacks.css css/*
- rm <!--[if lte ie 6]> from templates/main.tpl.htm
- rm IE6 support from css/iehacks.css
- mv css/nav/* into css/style.css
- mv css/print/* into css/print.css
- add css/print.css to templates/main.tpl.htm
- rm css/print/*
- rm css/nav/*
- rm css projection-type support
- mv css/screen/redmond/* css/*
- rm css/screen/*
- mv css media-recognition from css-files to <head>-link tag
- change most div-containers to new html5 tags in main.tpl.htm
- rm dom elements from main.tpl.htm
- add html5shiv.js (https://github.com/aFarkas/html5shiv) for better HTML5-compatibility
- reduction of dom elements
- reduction of css rules
- removed all single icons
    - all icons separate:  https://github.com/downloads/foe-services/ispc-larry/ispc-default_separate.zip
    - all used icons as layers and sprite as .psd: https://github.com/downloads/foe-services/ispc-larry/ispc-default_psd.zip
- added sprites for (nearly) all used icons where suitable
- added flags for country text in lists
- added some list column widths
- limited height (500px) for the globalsearch results
interface/web/themes/default/TODO
@@ -1,8 +1,8 @@
TODO
- css/print.css is useless in current state
- css/iehacks.css is useless in current state
- some more icons need to be changed into sprites
- <html dir="ltr" lang="en-US"> set lang variable with data from the user data or config data
TODO
- css/print.css is useless in current state
- css/iehacks.css is useless in current state
- some more icons need to be changed into sprites
- <html dir="ltr" lang="en-US"> set lang variable with data from the user data or config data
- Lists of servers in monitor module break in IE7 + IE8
interface/web/themes/default/css/jquery-ui-1.8.16.custom.css
@@ -1,446 +1,446 @@
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 *
 * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=0px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=0px
 */
/* Component containers
----------------------------------*/
/*.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }*/
.ui-widget { font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; /*color: #2e6e9e;*/ }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }/*
 * jQuery UI Autocomplete 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Autocomplete#theming
 */
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
 * jQuery UI Menu 1.8.16
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu#theming
 */
.ui-menu {
    list-style:none;
    padding: 2px;
    margin: 0;
    display:block;
    float: left;
}
.ui-menu .ui-menu {
    margin-top: -3px;
}
.ui-menu .ui-menu-item {
    margin:0;
    padding: 0;
    zoom: 1;
    float: left;
    clear: left;
    width: 100%;
}
.ui-menu .ui-menu-item a {
    text-decoration:none;
    display:block;
    padding:.2em .4em;
    line-height:1.5;
    white-space: nowrap;
    zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
    font-weight: normal;
    margin: -1px;
}
/*
 * jQuery UI Button 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button#theming
 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4;  }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
 * jQuery UI Datepicker 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker#theming
 */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
    display: none; /*sorry for IE5*/
    display/**/: block; /*sorry for IE5*/
    position: absolute; /*must have*/
    z-index: -1; /*must have*/
    filter: mask(); /*must have*/
    top: -4px; /*must have*/
    left: -4px; /*must have*/
    width: 200px; /*must have*/
    height: 200px; /*must have*/
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
 * jQuery UI CSS Framework 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Theming/API
 *
 * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=0px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=0px
 */
/* Component containers
----------------------------------*/
/*.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }*/
.ui-widget { font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; /*color: #2e6e9e;*/ }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }/*
 * jQuery UI Autocomplete 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Autocomplete#theming
 */
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
 * jQuery UI Menu 1.8.16
 *
 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menu#theming
 */
.ui-menu {
    list-style:none;
    padding: 2px;
    margin: 0;
    display:block;
    float: left;
}
.ui-menu .ui-menu {
    margin-top: -3px;
}
.ui-menu .ui-menu-item {
    margin:0;
    padding: 0;
    zoom: 1;
    float: left;
    clear: left;
    width: 100%;
}
.ui-menu .ui-menu-item a {
    text-decoration:none;
    display:block;
    padding:.2em .4em;
    line-height:1.5;
    white-space: nowrap;
    zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
    font-weight: normal;
    margin: -1px;
}
/*
 * jQuery UI Button 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button#theming
 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4;  }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
 * jQuery UI Datepicker 1.8.16
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Datepicker#theming
 */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
    display: none; /*sorry for IE5*/
    display/**/: block; /*sorry for IE5*/
    position: absolute; /*must have*/
    z-index: -1; /*must have*/
    filter: mask(); /*must have*/
    top: -4px; /*must have*/
    left: -4px; /*must have*/
    width: 200px; /*must have*/
    height: 200px; /*must have*/
}
interface/web/tools/lib/interface.d/tpl_default.menu.php
@@ -1,8 +1,8 @@
<?php
// No settings yet
//$items[] = array(   'title'     => 'Default Theme',
//                    'target'     => 'content',
//                    'link'    => 'tools/tpl_default.php',
//                    'html_id'   => 'tpl_default');
?>
<?php
// No settings yet
//$items[] = array(   'title'     => 'Default Theme',
//                    'target'     => 'content',
//                    'link'    => 'tools/tpl_default.php',
//                    'html_id'   => 'tpl_default');
?>
server/lib/classes/aps_base.inc.php
@@ -1,103 +1,103 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Constants describing instances
define('INSTANCE_PENDING', 0);
define('INSTANCE_INSTALL', 1);
define('INSTANCE_ERROR', 2);
define('INSTANCE_SUCCESS', 3);
define('INSTANCE_REMOVE', 4);
// Constants describing packages
define('PACKAGE_LOCKED', 1);
define('PACKAGE_ENABLED', 2);
define('PACKAGE_OUTDATED', 3);
define('PACKAGE_ERROR_NOMETA', 4);
class ApsBase
{
    protected $log_prefix = '';
    protected $fetch_url = '';
    protected $aps_version = '';
    protected $packages_dir = '';
    protected $temp_pkg_dir = '';
    protected $interface_pkg_dir = '';
    protected $interface_mode = false; // server mode by default
    /**
     * Constructor
     *
     * @param $app the application instance (db handle + log method)
     * @param $interface_mode act in interface (true) or server mode (false)
     * @param $log_prefix a prefix to set before all log entries
     */
    public function __construct($app, $log_prefix = 'APS: ', $interface_mode = false)
    {
        $this->log_prefix = $log_prefix;
        $this->interface_mode = $interface_mode;
        $this->fetch_url = 'apscatalog.com';
        $this->aps_version = '1';
        $this->packages_dir = ISPC_ROOT_PATH.'/aps_packages';
        $this->interface_pkg_dir = ISPC_ROOT_PATH.'/web/sites/aps_meta_packages';
    }
    /**
     * Converts a given value to it's native representation in 1024 units
     *
     * @param $value the size to convert
     * @return integer and string
     */
    public function convertSize($value)
    {
        $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
        return @round($value/pow(1024, ($i = floor(log($value, 1024)))), 2).' '.$unit[$i];
    }
    /**
     * Determine a specific xpath from a given SimpleXMLElement handle. If the
     * element is found, it's string representation is returned. If not,
     * the return value will stay empty
     *
     * @param $xml_handle the SimpleXMLElement handle
     * @param $query the XPath query
     * @param $array define whether to return an array or a string
     * @return $ret the return string
     */
    protected function getXPathValue($xml_handle, $query, $array = false)
    {
        $ret = '';
        $xp_result = @($xml_handle->xpath($query)) ? $xml_handle->xpath($query) : false;
        if($xp_result !== false) $ret = (($array === false) ? (string)$xp_result[0] : $xp_result);
        return $ret;
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Constants describing instances
define('INSTANCE_PENDING', 0);
define('INSTANCE_INSTALL', 1);
define('INSTANCE_ERROR', 2);
define('INSTANCE_SUCCESS', 3);
define('INSTANCE_REMOVE', 4);
// Constants describing packages
define('PACKAGE_LOCKED', 1);
define('PACKAGE_ENABLED', 2);
define('PACKAGE_OUTDATED', 3);
define('PACKAGE_ERROR_NOMETA', 4);
class ApsBase
{
    protected $log_prefix = '';
    protected $fetch_url = '';
    protected $aps_version = '';
    protected $packages_dir = '';
    protected $temp_pkg_dir = '';
    protected $interface_pkg_dir = '';
    protected $interface_mode = false; // server mode by default
    /**
     * Constructor
     *
     * @param $app the application instance (db handle + log method)
     * @param $interface_mode act in interface (true) or server mode (false)
     * @param $log_prefix a prefix to set before all log entries
     */
    public function __construct($app, $log_prefix = 'APS: ', $interface_mode = false)
    {
        $this->log_prefix = $log_prefix;
        $this->interface_mode = $interface_mode;
        $this->fetch_url = 'apscatalog.com';
        $this->aps_version = '1';
        $this->packages_dir = ISPC_ROOT_PATH.'/aps_packages';
        $this->interface_pkg_dir = ISPC_ROOT_PATH.'/web/sites/aps_meta_packages';
    }
    /**
     * Converts a given value to it's native representation in 1024 units
     *
     * @param $value the size to convert
     * @return integer and string
     */
    public function convertSize($value)
    {
        $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
        return @round($value/pow(1024, ($i = floor(log($value, 1024)))), 2).' '.$unit[$i];
    }
    /**
     * Determine a specific xpath from a given SimpleXMLElement handle. If the
     * element is found, it's string representation is returned. If not,
     * the return value will stay empty
     *
     * @param $xml_handle the SimpleXMLElement handle
     * @param $query the XPath query
     * @param $array define whether to return an array or a string
     * @return $ret the return string
     */
    protected function getXPathValue($xml_handle, $query, $array = false)
    {
        $ret = '';
        $xp_result = @($xml_handle->xpath($query)) ? $xml_handle->xpath($query) : false;
        if($xp_result !== false) $ret = (($array === false) ? (string)$xp_result[0] : $xp_result);
        return $ret;
    }
}
?>
server/lib/classes/aps_installer.inc.php
@@ -1,710 +1,710 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
@set_time_limit(0);
@ignore_user_abort(1);
class ApsInstaller extends ApsBase
{
    private $handle_type = '';
    private $domain = '';
    private $document_root = '';
    private $sublocation = '';
    private $local_installpath = '';
    private $dbhost = '';
    private $newdb_name = '';
    private $newdb_user = '';
    private $file_owner_user = '';
    private $file_owner_group = '';
    private $putenv = array();
   /**
    * Constructor
    *
    * @param $app the application instance (db handle + log method)
    * @param $interface_mode act in interface (true) or server mode (false)
    */
    public function __construct($app, $interface_mode = false)
    {
        parent::__construct($app, 'APS installer: ', $interface_mode);
    }
    /**
     * Before the cron is executed, make sure all necessary options are set
     * and all functions are available
     */
    private function checkRequirements()
    {
        global $app;
        try
        {
            // Check if exec() is not disabled
            $disabled_func = explode(',', @ini_get('disable_functions'));
            if(in_array('exec', $disabled_func)) throw new Exception('the call of exec() is disabled');
            // Check if safe_mode is disabled (needed for correct putenv, chmod, chown handling)
            if(@ini_get('safe_mode')) throw new Exception('the safe_mode restriction is on');
            return true;
        }
        catch(Exception $e)
        {
            $app->log('Aborting execution because '.$e->getMessage(), 1);
            return false;
        }
    }
    /**
     * Get a file from a ZIP archive and either return it's content or
     * extract it to a given destination
     *
     * @param $zipfile the ZIP file to work with
     * @param $subfile the file from which to get the content
     * @param $destfolder the optional extraction destination
     * @param $destname the optional target file name when extracting
     * @return string or boolean
     */
    private function getContentFromZIP($zipfile, $subfile, $destfolder = '', $destname = '')
    {
        try
        {
            $zip = new ZipArchive;
            $res = $zip->open(realpath($zipfile));
            if(!$res) throw new Exception('Cannot open ZIP file '.$zipfile);
            // If no destination is given, the content is returned, otherwise
            // the $subfile is extracted to $destination
            if($destfolder == '')
            {
                $fh = $zip->getStream($subfile);
                if(!$fh) throw new Exception('Cannot read '.$subfile.' from '.$zipfile);
                $subfile_content = '';
                while(!feof($fh)) $subfile_content .= fread($fh, 8192);
                fclose($fh);
                return $subfile_content;
            }
            else
            {
                // extractTo would be suitable but has no target name parameter
                //$ind = $zip->locateName($subfile);
                //$ex = $zip->extractTo($destination, array($zip->getNameIndex($ind)));
                if($destname == '') $destname = basename($subfile);
                $ex = @copy('zip://'.$zipfile.'#'.$subfile, $destfolder.$destname);
                if(!$ex) throw new Exception('Cannot extract '.$subfile.' to '.$destfolder);
            }
            $zip->close();
        }
        catch(Exception $e)
        {
            // The exception message is only interesting for debugging reasons
            // echo $e->getMessage();
            return false;
        }
    }
    /**
     * Extract the complete directory of a ZIP file
     *
     * @param $filename the file to unzip
     * @param $directory the ZIP inside directory to unzip
     * @param $destination the place where to extract the data
     * @return boolean
     */
    private function extractZip($filename, $directory, $destination)
    {
        if(!file_exists($filename)) return false;
        // Fix the paths
        if(substr($directory, -1) == '/') $directory = substr($directory, 0, strlen($directory) - 1);
        if(substr($destination, -1) != '/') $destination .= '/';
        // Read and extract the ZIP file
        $ziphandle = zip_open(realpath($filename));
        if(is_resource($ziphandle))
        {
            while($entry = zip_read($ziphandle))
            {
                if(substr(zip_entry_name($entry), 0, strlen($directory)) == $directory)
                {
                    // Modify the relative ZIP file path
                    $new_path = substr(zip_entry_name($entry), strlen($directory));
                    if(substr($new_path, -1) == '/') // Identifier for directories
                    {
                        if(!file_exists($destination.$new_path)) mkdir($destination.$new_path, 0777, true);
                    }
                    else // Handle files
                    {
                        if(zip_entry_open($ziphandle, $entry))
                        {
                            $new_dir = dirname($destination.$new_path);
                            if(!file_exists($new_dir)) mkdir($new_dir, 0777, true);
                            $file = fopen($destination.$new_path, 'wb');
                            if($file)
                            {
                                while($line = zip_entry_read($entry)) fwrite($file, $line);
                                fclose($file);
                            }
                            else return false;
                        }
                    }
                }
            }
            zip_close($ziphandle);
            return true;
        }
        return false;
    }
    /**
     * Setup the path environment variables for the install script
     *
     * @param $parent_mapping the SimpleXML instance with the current mapping position
     * @param $url the relative path within the mapping tree
     * @param $path the absolute path within the mapping tree
     */
    private function processMappings($parent_mapping, $url, $path)
    {
        if($parent_mapping && $parent_mapping != null)
        {
            $writable = parent::getXPathValue($parent_mapping, 'php:permissions/@writable');
            $readable = parent::getXPathValue($parent_mapping, 'php:permissions/@readable');
            // set the write permission
            if($writable == 'true')
            {
                if(is_dir($path)) chmod($path, 0775);
                else chmod($path, 0664);
            }
            // set non-readable permission
            if($readable == 'false')
            {
                if(is_dir($path)) chmod($path, 0333);
                else chmod($path, 0222);
            }
        }
        // Set the environment variables
        $env = str_replace('/', '_', $url);
        $this->putenv[] = 'WEB_'.$env.'_DIR='.$path;
        // Step recursively into further mappings
        if($parent_mapping && $parent_mapping != null)
        {
            foreach($parent_mapping->mapping as $mapping)
            {
                if($url == '/') $this->processMappings($mapping, $url.$mapping['url'], $path.$mapping['url']);
                else $this->processMappings($mapping, $url.'/'.$mapping['url'], $path.'/'.$mapping['url']);
            }
        }
    }
    /**
     * Setup the environment with data for the install location
     *
     * @param $task an array containing all install related data
     */
    private function prepareLocation($task)
    {
        global $app;
        // Get the domain name to use for the installation
        // Would be possible in one query too, but we use 2 for easier debugging
        $main_domain = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
            WHERE name = 'main_domain' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $this->domain = $main_domain['value'];
        // Get the document root
        $domain_res = $app->db->queryOneRecord("SELECT document_root, web_folder, type FROM web_domain
            WHERE domain = '".$app->db->quote($this->domain)."';");
        $this->document_root = $domain_res['document_root'];
        // Get the sub location
        $location_res = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
            WHERE name = 'main_location' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $this->sublocation = $location_res['value'];
        // Make sure the document_root ends with /
        if(substr($this->document_root, -1) != '/') $this->document_root .= '/';
        // Attention: ISPConfig Special: web files are in subfolder 'web' -> append it:
        if($domain_res['type'] == 'vhostsubdomain') $this->document_root .= $domain_res['web_folder'] . '/';
        else $this->document_root .= 'web/';
        // If a subfolder is given, make sure it's path doesn't begin with / i.e. /phpbb
        if(substr($this->sublocation, 0, 1) == '/') $this->sublocation = substr($this->sublocation, 1);
        // If the package isn't installed to a subfolder, remove the / at the end of the document root
        if(empty($this->sublocation)) $this->document_root = substr($this->document_root, 0, strlen($this->document_root) - 1);
        // Set environment variables, later processed by the package install script
        $this->putenv[] = 'BASE_URL_SCHEME=http';
        // putenv('BASE_URL_PORT') -> omitted as it's 80 by default
        $this->putenv[] = 'BASE_URL_HOST='.$this->domain;
        $this->putenv[] = 'BASE_URL_PATH='.$this->sublocation.'/';
    }
    /**
     * Setup a database (if needed) and the appropriate environment variables
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     */
    private function prepareDatabase($task, $sxe)
    {
        global $app;
        $db_id = parent::getXPathValue($sxe, '//db:id');
        if(empty($db_id)) return; // No database needed
        /* WARNING: if this will ever be uncommented please check the updated prefix handling for user and db names!!!
         *
        // Set the database owner to the domain owner
        // ISPConfig identifies the owner by the sys_groupid (not sys_userid!)
        // so sys_userid can be set to any value
        $perm = $app->db->queryOneRecord("SELECT sys_groupid, server_id FROM web_domain
            WHERE domain = '".$this->domain."';");
        $task['sys_groupid'] = $perm['sys_groupid'];
        $serverid = $perm['server_id'];
        // Get the database prefix and db user prefix
        $app->uses('getconf');
        $global_config = $app->getconf->get_global_config('sites');
        $dbname_prefix = str_replace('[CLIENTID]', '', $global_config['dbname_prefix']);
        $dbuser_prefix = str_replace('[CLIENTID]', '', $global_config['dbuser_prefix']);
        $this->dbhost = DB_HOST; // Taken from config.inc.php
        if(empty($this->dbhost)) $this->dbhost = 'localhost'; // Just to ensure any hostname... ;)
        $this->newdb_name = $dbname_prefix.$task['CustomerID'].'aps'.$task['InstanceID'];
        $this->newdb_user = $dbuser_prefix.$task['CustomerID'].'aps'.$task['InstanceID'];
        $dbpw_res = $app->db->queryOneRecord("SELECT Value FROM aps_instances_settings
            WHERE Name = 'main_database_password' AND InstanceID = '".$app->db->quote($task['InstanceID'])."';");
        $newdb_pw = $dbpw_res['Value'];
        // In any case delete an existing database (install and removal procedure)
        $app->db->query('DROP DATABASE IF EXISTS `'.$app->db->quote($this->newdb_name).'`;');
        // Delete an already existing database with this name
        $app->db->query("DELETE FROM web_database WHERE database_name = '".$app->db->quote($this->newdb_name)."';");
        // Create the new database and assign it to a user
        if($this->handle_type == 'install')
        {
            $app->db->query('CREATE DATABASE IF NOT EXISTS `'.$app->db->quote($this->newdb_name).'`;');
            $app->db->query('GRANT ALL PRIVILEGES ON '.$app->db->quote($this->newdb_name).'.* TO '.$app->db->quote($this->newdb_user).'@'.$app->db->quote($this->dbhost).' IDENTIFIED BY \'password\';');
            $app->db->query('SET PASSWORD FOR '.$app->db->quote($this->newdb_user).'@'.$app->db->quote($this->dbhost).' = PASSWORD(\''.$newdb_pw.'\');');
            $app->db->query('FLUSH PRIVILEGES;');
            // Add the new database to the customer databases
            // Assumes: charset = utf8
            $app->db->query('INSERT INTO web_database (sys_userid, sys_groupid, sys_perm_user, sys_perm_group, sys_perm_other, server_id,
                type, database_name, database_user, database_password, database_charset, remote_access, remote_ips, active)
                VALUES ('.$task['sys_userid'].', '.$task['sys_groupid'].', "'.$task['sys_perm_user'].'", "'.$task['sys_perm_group'].'",
                "'.$task['sys_perm_other'].'", '.$app->db->quote($serverid).', "mysql", "'.$app->db->quote($this->newdb_name).'",
                "'.$app->db->quote($this->newdb_user).'", "'.$app->db->quote($newdb_pw).'", "utf8", "n", "", "y");');
        }
        */
        $mysqlver_res = $app->db->queryOneRecord('SELECT VERSION() as ver;');
        $mysqlver = $mysqlver_res['ver'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_password' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_pw = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_host' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_host = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_name' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_name = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_login' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_login = $tmp['value'];
        $this->putenv[] = 'DB_'.$db_id.'_TYPE=mysql';
        $this->putenv[] = 'DB_'.$db_id.'_NAME='.$newdb_name;
        $this->putenv[] = 'DB_'.$db_id.'_LOGIN='.$newdb_login;
        $this->putenv[] = 'DB_'.$db_id.'_PASSWORD='.$newdb_pw;
        $this->putenv[] = 'DB_'.$db_id.'_HOST='.$newdb_host;
        $this->putenv[] = 'DB_'.$db_id.'_PORT=3306';
        $this->putenv[] = 'DB_'.$db_id.'_VERSION='.$mysqlver;
    }
    /**
     * Extract all needed files from the package
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     * @return boolean
     */
    private function prepareFiles($task, $sxe)
    {
        global $app;
        // Basically set the mapping for APS version 1.0, if not available -> newer way
        $mapping = $sxe->mapping;
        $mapping_path = $sxe->mapping['path'];
        $mapping_url = $sxe->mapping['url'];
        if(empty($mapping))
        {
            $mapping = $sxe->service->provision->{'url-mapping'}->mapping;
            $mapping_path = $sxe->service->provision->{'url-mapping'}->mapping['path'];
            $mapping_url = $sxe->service->provision->{'url-mapping'}->mapping['url'];
        }
        try
        {
            // Make sure we have a valid mapping path (at least /)
            if(empty($mapping_path)) throw new Exception('Unable to determine a mapping path');
            $this->local_installpath = $this->document_root.$this->sublocation.'/';
            // Now delete an existing folder (affects install and removal in the same way)
            @chdir($this->local_installpath);
            if(file_exists($this->local_installpath)){
                // make sure we don't delete error and stats folders
                if($this->local_installpath == $this->document_root.'/'){
                    if(is_dir($this->document_root)){
                        $files = array_diff(scandir($this->document_root), array('.','..','error','stats'));
                        foreach($files as $file){
                            if(is_dir($this->document_root.'/'.$file)){
                                $app->file->removeDirectory($this->document_root.'/'.$file);
                            } else {
                                @unlink($this->document_root.'/'.$file);
                            }
                        }
                    } else {
                        @unlink($this->document_root);
                        mkdir($this->document_root, 0777, true);
                    }
                } else {
                    exec("rm -Rf ".escapeshellarg($this->local_installpath).'*');
                }
            } else {
                mkdir($this->local_installpath, 0777, true);
            }
            if($this->handle_type == 'install')
            {
                // Now check if the needed folder is there
                if(!file_exists($this->local_installpath))
                    throw new Exception('Unable to create a new folder for the package '.$task['path']);
                // Extract all files and assign them a new owner
                if( ($this->extractZip($this->packages_dir.'/'.$task['path'], $mapping_path, $this->local_installpath) === false)
                 || ($this->extractZip($this->packages_dir.'/'.$task['path'], 'scripts', $this->local_installpath.'install_scripts/') === false) )
                {
                    // Clean already extracted data
                    exec("rm -Rf ".escapeshellarg($this->local_installpath).'*');
                    throw new Exception('Unable to extract the package '.$task['path']);
                }
                $this->processMappings($mapping, $mapping_url, $this->local_installpath);
                // Set the appropriate file owner
                $main_domain = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
                    WHERE name = 'main_domain' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
                $owner_res = $app->db->queryOneRecord("SELECT system_user, system_group FROM web_domain
                        WHERE domain = '".$app->db->quote($main_domain['value'])."';");
                $this->file_owner_user = $owner_res['system_user'];
                $this->file_owner_group = $owner_res['system_group'];
                exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
            }
        }
        catch(Exception $e)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log($e->getMessage(), 1);
            return false;
        }
        return true;
    }
    /**
     * Get all user config variables and set them to environment variables
     *
     * @param $task an array containing all install related data
     */
    private function prepareUserInputData($task)
    {
        global $app;
        $userdata = $app->db->queryAllRecords("SELECT name, value FROM aps_instances_settings
            WHERE instance_id = '".$app->db->quote($task['instance_id'])."';");
        if(empty($userdata)) return false;
        foreach($userdata as $data)
        {
            // Skip unnecessary data
            if($data['name'] == 'main_location'
            || $data['name'] == 'main_domain'
            || $data['name'] == 'main_database_password'
            || $data['name'] == 'main_database_name'
            || $data['name'] == 'main_database_host'
            || $data['name'] == 'main_database_login'
            || $data['name'] == 'license') continue;
            $this->putenv[] = 'SETTINGS_'.$data['name'].'='.$data['value'];
        }
    }
    /**
     * Fetch binary data from a given array
     * The data is retrieved in binary mode and
     * then directly written to an output file
     *
     * @param $input a specially structed array
     * @see $this->startUpdate()
     */
    private function fetchFiles($input)
    {
        $fh = array();
        $url = array();
        $conn = array();
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        // Process each app
        for($i = 0; $i < count($input); $i++)
        {
            $conn[$i] = curl_init($input[$i]['url']);
            $fh[$i] = fopen($input[$i]['localtarget'], 'wb');
            curl_setopt($conn[$i], CURLOPT_BINARYTRANSFER, true);
            curl_setopt($conn[$i], CURLOPT_FILE, $fh[$i]);
            curl_setopt($conn[$i], CURLOPT_TIMEOUT, 0);
            curl_setopt($conn[$i], CURLOPT_FAILONERROR, 1);
            curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, 1);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Close the handles
        for($i = 0; $i < count($input); $i++)
        {
            fclose($fh[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
    }
    /**
     * The installation script should be executed
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     * @return boolean
     */
    private function doInstallation($task, $sxe)
    {
        global $app;
        try
        {
            // Check if the install directory exists
            if(!is_dir($this->local_installpath.'install_scripts/'))
                throw new Exception('The install directory '.$this->local_installpath.' is not existing');
            // Set the executable bit to the configure script
            $cfgscript = @(string)$sxe->service->provision->{'configuration-script'}['name'];
            if(!$cfgscript) $cfgscript = 'configure';
            chmod($this->local_installpath.'install_scripts/'.$cfgscript, 0755);
            // Change to the install folder (import for the exec() below!)
            //exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
            chdir($this->local_installpath.'install_scripts/');
            // Set the enviroment variables
            foreach($this->putenv as $var) {
                putenv($var);
            }
            $shell_retcode = true;
            $shell_ret = array();
             exec('php '.escapeshellarg($this->local_installpath.'install_scripts/'.$cfgscript).' install 2>&1', $shell_ret, $shell_retcode);
            $shell_ret = array_filter($shell_ret);
            $shell_ret_str = implode("\n", $shell_ret);
            // Although $shell_retcode might be 0, there can be PHP errors. Filter them:
            if(substr_count($shell_ret_str, 'Warning: ') > 0) $shell_retcode = 1;
            // If an error has occurred, the return code is != 0
            if($shell_retcode != 0) throw new Exception($shell_ret_str);
            else
            {
                // The install succeeded, chown newly created files too
                exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
                $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_SUCCESS.'"
                    WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            }
        }
        catch(Exception $e)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log($e->getMessage(), 1);
            return false;
        }
        return true;
    }
    /**
     * Cleanup: Remove install scripts, remove tasks and update the database
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     */
    private function cleanup($task, $sxe)
    {
        chdir($this->local_installpath);
        exec("rm -Rf ".escapeshellarg($this->local_installpath).'install_scripts');
    }
    /**
     * The main method which performs the actual package installation
     *
     * @param $instanceid the instanceID to install
     * @param $type the type of task to perform (installation, removal)
     */
    public function installHandler($instanceid, $type)
    {
        global $app;
        // Set the given handle type, currently supported: install, delete
        if($type == 'install' || $type == 'delete') $this->handle_type = $type;
        else return false;
        // Get all instance metadata
        /*
        $task = $app->db->queryOneRecord("SELECT * FROM aps_instances AS i
            INNER JOIN aps_packages AS p ON i.package_id = p.id
            INNER JOIN client AS c ON i.customer_id = c.client_id
            WHERE i.id = ".$instanceid.";");
        */
        $task = $app->db->queryOneRecord("SELECT * FROM aps_instances AS i
            INNER JOIN aps_packages AS p ON i.package_id = p.id
            WHERE i.id = ".$instanceid.";");
        if(!$task) return false;  // formerly: throw new Exception('The InstanceID doesn\'t exist.');
        if(!isset($task['instance_id'])) $task['instance_id'] = $instanceid;
        // Download aps package
        if(!file_exists($this->packages_dir.'/'.$task['path']) || filesize($this->packages_dir.'/'.$task['path']) == 0) {
            $ch = curl_init();
            $fh = fopen($this->packages_dir.'/'.$task['path'], 'wb');
            curl_setopt($ch, CURLOPT_FILE, $fh);
            //curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_URL, $task['package_url']);
            curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 0);
            curl_setopt($ch, CURLOPT_FAILONERROR, 1);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            if(curl_exec($ch) === false) $app->log(curl_error ($ch),1);
            fclose($fh);
            curl_close($ch);
        }
        /*
        $app_to_dl[] = array('name' => $task['path'],
                            'url' => $task['package_url'],
                            'filesize' => 0,
                            'localtarget' => $this->packages_dir.'/'.$task['path']);
        $this->fetchFiles($app_to_dl);
        */
        // Make sure the requirements are given so that this script can execute
        $req_ret = $this->checkRequirements();
        if(!$req_ret) return false;
        $metafile = $this->getContentFromZIP($this->packages_dir.'/'.$task['path'], 'APP-META.xml');
        // Check if the meta file is existing
        if(!$metafile)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log('Unable to find the meta data file of package '.$task['path'], 1);
            return false;
        }
        // Rename namespaces and register them
        $metadata = str_replace("xmlns=", "ns=", $metafile);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        // Setup the environment with data for the install location
        $this->prepareLocation($task);
        // Create the database if necessary
        $this->prepareDatabase($task, $sxe);
        // Unpack the install scripts from the packages
        if($this->prepareFiles($task, $sxe) && $this->handle_type == 'install')
        {
            // Setup the variables from the install script
            $this->prepareUserInputData($task);
            // Do the actual installation
            $this->doInstallation($task, $sxe);
            // Remove temporary files
            $this->cleanup($task, $sxe);
        }
        // Finally delete the instance entry + settings
        if($this->handle_type == 'delete')
        {
            $app->db->query('DELETE FROM aps_instances WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->db->query('DELETE FROM aps_instances_settings WHERE instance_id = "'.$app->db->quote($task['instance_id']).'";');
        }
        unset($sxe);
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
require_once('aps_base.inc.php');
@set_time_limit(0);
@ignore_user_abort(1);
class ApsInstaller extends ApsBase
{
    private $handle_type = '';
    private $domain = '';
    private $document_root = '';
    private $sublocation = '';
    private $local_installpath = '';
    private $dbhost = '';
    private $newdb_name = '';
    private $newdb_user = '';
    private $file_owner_user = '';
    private $file_owner_group = '';
    private $putenv = array();
   /**
    * Constructor
    *
    * @param $app the application instance (db handle + log method)
    * @param $interface_mode act in interface (true) or server mode (false)
    */
    public function __construct($app, $interface_mode = false)
    {
        parent::__construct($app, 'APS installer: ', $interface_mode);
    }
    /**
     * Before the cron is executed, make sure all necessary options are set
     * and all functions are available
     */
    private function checkRequirements()
    {
        global $app;
        try
        {
            // Check if exec() is not disabled
            $disabled_func = explode(',', @ini_get('disable_functions'));
            if(in_array('exec', $disabled_func)) throw new Exception('the call of exec() is disabled');
            // Check if safe_mode is disabled (needed for correct putenv, chmod, chown handling)
            if(@ini_get('safe_mode')) throw new Exception('the safe_mode restriction is on');
            return true;
        }
        catch(Exception $e)
        {
            $app->log('Aborting execution because '.$e->getMessage(), 1);
            return false;
        }
    }
    /**
     * Get a file from a ZIP archive and either return it's content or
     * extract it to a given destination
     *
     * @param $zipfile the ZIP file to work with
     * @param $subfile the file from which to get the content
     * @param $destfolder the optional extraction destination
     * @param $destname the optional target file name when extracting
     * @return string or boolean
     */
    private function getContentFromZIP($zipfile, $subfile, $destfolder = '', $destname = '')
    {
        try
        {
            $zip = new ZipArchive;
            $res = $zip->open(realpath($zipfile));
            if(!$res) throw new Exception('Cannot open ZIP file '.$zipfile);
            // If no destination is given, the content is returned, otherwise
            // the $subfile is extracted to $destination
            if($destfolder == '')
            {
                $fh = $zip->getStream($subfile);
                if(!$fh) throw new Exception('Cannot read '.$subfile.' from '.$zipfile);
                $subfile_content = '';
                while(!feof($fh)) $subfile_content .= fread($fh, 8192);
                fclose($fh);
                return $subfile_content;
            }
            else
            {
                // extractTo would be suitable but has no target name parameter
                //$ind = $zip->locateName($subfile);
                //$ex = $zip->extractTo($destination, array($zip->getNameIndex($ind)));
                if($destname == '') $destname = basename($subfile);
                $ex = @copy('zip://'.$zipfile.'#'.$subfile, $destfolder.$destname);
                if(!$ex) throw new Exception('Cannot extract '.$subfile.' to '.$destfolder);
            }
            $zip->close();
        }
        catch(Exception $e)
        {
            // The exception message is only interesting for debugging reasons
            // echo $e->getMessage();
            return false;
        }
    }
    /**
     * Extract the complete directory of a ZIP file
     *
     * @param $filename the file to unzip
     * @param $directory the ZIP inside directory to unzip
     * @param $destination the place where to extract the data
     * @return boolean
     */
    private function extractZip($filename, $directory, $destination)
    {
        if(!file_exists($filename)) return false;
        // Fix the paths
        if(substr($directory, -1) == '/') $directory = substr($directory, 0, strlen($directory) - 1);
        if(substr($destination, -1) != '/') $destination .= '/';
        // Read and extract the ZIP file
        $ziphandle = zip_open(realpath($filename));
        if(is_resource($ziphandle))
        {
            while($entry = zip_read($ziphandle))
            {
                if(substr(zip_entry_name($entry), 0, strlen($directory)) == $directory)
                {
                    // Modify the relative ZIP file path
                    $new_path = substr(zip_entry_name($entry), strlen($directory));
                    if(substr($new_path, -1) == '/') // Identifier for directories
                    {
                        if(!file_exists($destination.$new_path)) mkdir($destination.$new_path, 0777, true);
                    }
                    else // Handle files
                    {
                        if(zip_entry_open($ziphandle, $entry))
                        {
                            $new_dir = dirname($destination.$new_path);
                            if(!file_exists($new_dir)) mkdir($new_dir, 0777, true);
                            $file = fopen($destination.$new_path, 'wb');
                            if($file)
                            {
                                while($line = zip_entry_read($entry)) fwrite($file, $line);
                                fclose($file);
                            }
                            else return false;
                        }
                    }
                }
            }
            zip_close($ziphandle);
            return true;
        }
        return false;
    }
    /**
     * Setup the path environment variables for the install script
     *
     * @param $parent_mapping the SimpleXML instance with the current mapping position
     * @param $url the relative path within the mapping tree
     * @param $path the absolute path within the mapping tree
     */
    private function processMappings($parent_mapping, $url, $path)
    {
        if($parent_mapping && $parent_mapping != null)
        {
            $writable = parent::getXPathValue($parent_mapping, 'php:permissions/@writable');
            $readable = parent::getXPathValue($parent_mapping, 'php:permissions/@readable');
            // set the write permission
            if($writable == 'true')
            {
                if(is_dir($path)) chmod($path, 0775);
                else chmod($path, 0664);
            }
            // set non-readable permission
            if($readable == 'false')
            {
                if(is_dir($path)) chmod($path, 0333);
                else chmod($path, 0222);
            }
        }
        // Set the environment variables
        $env = str_replace('/', '_', $url);
        $this->putenv[] = 'WEB_'.$env.'_DIR='.$path;
        // Step recursively into further mappings
        if($parent_mapping && $parent_mapping != null)
        {
            foreach($parent_mapping->mapping as $mapping)
            {
                if($url == '/') $this->processMappings($mapping, $url.$mapping['url'], $path.$mapping['url']);
                else $this->processMappings($mapping, $url.'/'.$mapping['url'], $path.'/'.$mapping['url']);
            }
        }
    }
    /**
     * Setup the environment with data for the install location
     *
     * @param $task an array containing all install related data
     */
    private function prepareLocation($task)
    {
        global $app;
        // Get the domain name to use for the installation
        // Would be possible in one query too, but we use 2 for easier debugging
        $main_domain = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
            WHERE name = 'main_domain' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $this->domain = $main_domain['value'];
        // Get the document root
        $domain_res = $app->db->queryOneRecord("SELECT document_root, web_folder, type FROM web_domain
            WHERE domain = '".$app->db->quote($this->domain)."';");
        $this->document_root = $domain_res['document_root'];
        // Get the sub location
        $location_res = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
            WHERE name = 'main_location' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $this->sublocation = $location_res['value'];
        // Make sure the document_root ends with /
        if(substr($this->document_root, -1) != '/') $this->document_root .= '/';
        // Attention: ISPConfig Special: web files are in subfolder 'web' -> append it:
        if($domain_res['type'] == 'vhostsubdomain') $this->document_root .= $domain_res['web_folder'] . '/';
        else $this->document_root .= 'web/';
        // If a subfolder is given, make sure it's path doesn't begin with / i.e. /phpbb
        if(substr($this->sublocation, 0, 1) == '/') $this->sublocation = substr($this->sublocation, 1);
        // If the package isn't installed to a subfolder, remove the / at the end of the document root
        if(empty($this->sublocation)) $this->document_root = substr($this->document_root, 0, strlen($this->document_root) - 1);
        // Set environment variables, later processed by the package install script
        $this->putenv[] = 'BASE_URL_SCHEME=http';
        // putenv('BASE_URL_PORT') -> omitted as it's 80 by default
        $this->putenv[] = 'BASE_URL_HOST='.$this->domain;
        $this->putenv[] = 'BASE_URL_PATH='.$this->sublocation.'/';
    }
    /**
     * Setup a database (if needed) and the appropriate environment variables
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     */
    private function prepareDatabase($task, $sxe)
    {
        global $app;
        $db_id = parent::getXPathValue($sxe, '//db:id');
        if(empty($db_id)) return; // No database needed
        /* WARNING: if this will ever be uncommented please check the updated prefix handling for user and db names!!!
         *
        // Set the database owner to the domain owner
        // ISPConfig identifies the owner by the sys_groupid (not sys_userid!)
        // so sys_userid can be set to any value
        $perm = $app->db->queryOneRecord("SELECT sys_groupid, server_id FROM web_domain
            WHERE domain = '".$this->domain."';");
        $task['sys_groupid'] = $perm['sys_groupid'];
        $serverid = $perm['server_id'];
        // Get the database prefix and db user prefix
        $app->uses('getconf');
        $global_config = $app->getconf->get_global_config('sites');
        $dbname_prefix = str_replace('[CLIENTID]', '', $global_config['dbname_prefix']);
        $dbuser_prefix = str_replace('[CLIENTID]', '', $global_config['dbuser_prefix']);
        $this->dbhost = DB_HOST; // Taken from config.inc.php
        if(empty($this->dbhost)) $this->dbhost = 'localhost'; // Just to ensure any hostname... ;)
        $this->newdb_name = $dbname_prefix.$task['CustomerID'].'aps'.$task['InstanceID'];
        $this->newdb_user = $dbuser_prefix.$task['CustomerID'].'aps'.$task['InstanceID'];
        $dbpw_res = $app->db->queryOneRecord("SELECT Value FROM aps_instances_settings
            WHERE Name = 'main_database_password' AND InstanceID = '".$app->db->quote($task['InstanceID'])."';");
        $newdb_pw = $dbpw_res['Value'];
        // In any case delete an existing database (install and removal procedure)
        $app->db->query('DROP DATABASE IF EXISTS `'.$app->db->quote($this->newdb_name).'`;');
        // Delete an already existing database with this name
        $app->db->query("DELETE FROM web_database WHERE database_name = '".$app->db->quote($this->newdb_name)."';");
        // Create the new database and assign it to a user
        if($this->handle_type == 'install')
        {
            $app->db->query('CREATE DATABASE IF NOT EXISTS `'.$app->db->quote($this->newdb_name).'`;');
            $app->db->query('GRANT ALL PRIVILEGES ON '.$app->db->quote($this->newdb_name).'.* TO '.$app->db->quote($this->newdb_user).'@'.$app->db->quote($this->dbhost).' IDENTIFIED BY \'password\';');
            $app->db->query('SET PASSWORD FOR '.$app->db->quote($this->newdb_user).'@'.$app->db->quote($this->dbhost).' = PASSWORD(\''.$newdb_pw.'\');');
            $app->db->query('FLUSH PRIVILEGES;');
            // Add the new database to the customer databases
            // Assumes: charset = utf8
            $app->db->query('INSERT INTO web_database (sys_userid, sys_groupid, sys_perm_user, sys_perm_group, sys_perm_other, server_id,
                type, database_name, database_user, database_password, database_charset, remote_access, remote_ips, active)
                VALUES ('.$task['sys_userid'].', '.$task['sys_groupid'].', "'.$task['sys_perm_user'].'", "'.$task['sys_perm_group'].'",
                "'.$task['sys_perm_other'].'", '.$app->db->quote($serverid).', "mysql", "'.$app->db->quote($this->newdb_name).'",
                "'.$app->db->quote($this->newdb_user).'", "'.$app->db->quote($newdb_pw).'", "utf8", "n", "", "y");');
        }
        */
        $mysqlver_res = $app->db->queryOneRecord('SELECT VERSION() as ver;');
        $mysqlver = $mysqlver_res['ver'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_password' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_pw = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_host' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_host = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_name' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_name = $tmp['value'];
        $tmp = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings WHERE name = 'main_database_login' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
        $newdb_login = $tmp['value'];
        $this->putenv[] = 'DB_'.$db_id.'_TYPE=mysql';
        $this->putenv[] = 'DB_'.$db_id.'_NAME='.$newdb_name;
        $this->putenv[] = 'DB_'.$db_id.'_LOGIN='.$newdb_login;
        $this->putenv[] = 'DB_'.$db_id.'_PASSWORD='.$newdb_pw;
        $this->putenv[] = 'DB_'.$db_id.'_HOST='.$newdb_host;
        $this->putenv[] = 'DB_'.$db_id.'_PORT=3306';
        $this->putenv[] = 'DB_'.$db_id.'_VERSION='.$mysqlver;
    }
    /**
     * Extract all needed files from the package
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     * @return boolean
     */
    private function prepareFiles($task, $sxe)
    {
        global $app;
        // Basically set the mapping for APS version 1.0, if not available -> newer way
        $mapping = $sxe->mapping;
        $mapping_path = $sxe->mapping['path'];
        $mapping_url = $sxe->mapping['url'];
        if(empty($mapping))
        {
            $mapping = $sxe->service->provision->{'url-mapping'}->mapping;
            $mapping_path = $sxe->service->provision->{'url-mapping'}->mapping['path'];
            $mapping_url = $sxe->service->provision->{'url-mapping'}->mapping['url'];
        }
        try
        {
            // Make sure we have a valid mapping path (at least /)
            if(empty($mapping_path)) throw new Exception('Unable to determine a mapping path');
            $this->local_installpath = $this->document_root.$this->sublocation.'/';
            // Now delete an existing folder (affects install and removal in the same way)
            @chdir($this->local_installpath);
            if(file_exists($this->local_installpath)){
                // make sure we don't delete error and stats folders
                if($this->local_installpath == $this->document_root.'/'){
                    if(is_dir($this->document_root)){
                        $files = array_diff(scandir($this->document_root), array('.','..','error','stats'));
                        foreach($files as $file){
                            if(is_dir($this->document_root.'/'.$file)){
                                $app->file->removeDirectory($this->document_root.'/'.$file);
                            } else {
                                @unlink($this->document_root.'/'.$file);
                            }
                        }
                    } else {
                        @unlink($this->document_root);
                        mkdir($this->document_root, 0777, true);
                    }
                } else {
                    exec("rm -Rf ".escapeshellarg($this->local_installpath).'*');
                }
            } else {
                mkdir($this->local_installpath, 0777, true);
            }
            if($this->handle_type == 'install')
            {
                // Now check if the needed folder is there
                if(!file_exists($this->local_installpath))
                    throw new Exception('Unable to create a new folder for the package '.$task['path']);
                // Extract all files and assign them a new owner
                if( ($this->extractZip($this->packages_dir.'/'.$task['path'], $mapping_path, $this->local_installpath) === false)
                 || ($this->extractZip($this->packages_dir.'/'.$task['path'], 'scripts', $this->local_installpath.'install_scripts/') === false) )
                {
                    // Clean already extracted data
                    exec("rm -Rf ".escapeshellarg($this->local_installpath).'*');
                    throw new Exception('Unable to extract the package '.$task['path']);
                }
                $this->processMappings($mapping, $mapping_url, $this->local_installpath);
                // Set the appropriate file owner
                $main_domain = $app->db->queryOneRecord("SELECT value FROM aps_instances_settings
                    WHERE name = 'main_domain' AND instance_id = '".$app->db->quote($task['instance_id'])."';");
                $owner_res = $app->db->queryOneRecord("SELECT system_user, system_group FROM web_domain
                        WHERE domain = '".$app->db->quote($main_domain['value'])."';");
                $this->file_owner_user = $owner_res['system_user'];
                $this->file_owner_group = $owner_res['system_group'];
                exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
            }
        }
        catch(Exception $e)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log($e->getMessage(), 1);
            return false;
        }
        return true;
    }
    /**
     * Get all user config variables and set them to environment variables
     *
     * @param $task an array containing all install related data
     */
    private function prepareUserInputData($task)
    {
        global $app;
        $userdata = $app->db->queryAllRecords("SELECT name, value FROM aps_instances_settings
            WHERE instance_id = '".$app->db->quote($task['instance_id'])."';");
        if(empty($userdata)) return false;
        foreach($userdata as $data)
        {
            // Skip unnecessary data
            if($data['name'] == 'main_location'
            || $data['name'] == 'main_domain'
            || $data['name'] == 'main_database_password'
            || $data['name'] == 'main_database_name'
            || $data['name'] == 'main_database_host'
            || $data['name'] == 'main_database_login'
            || $data['name'] == 'license') continue;
            $this->putenv[] = 'SETTINGS_'.$data['name'].'='.$data['value'];
        }
    }
    /**
     * Fetch binary data from a given array
     * The data is retrieved in binary mode and
     * then directly written to an output file
     *
     * @param $input a specially structed array
     * @see $this->startUpdate()
     */
    private function fetchFiles($input)
    {
        $fh = array();
        $url = array();
        $conn = array();
        // Build the single cURL handles and add them to a multi handle
        $mh = curl_multi_init();
        // Process each app
        for($i = 0; $i < count($input); $i++)
        {
            $conn[$i] = curl_init($input[$i]['url']);
            $fh[$i] = fopen($input[$i]['localtarget'], 'wb');
            curl_setopt($conn[$i], CURLOPT_BINARYTRANSFER, true);
            curl_setopt($conn[$i], CURLOPT_FILE, $fh[$i]);
            curl_setopt($conn[$i], CURLOPT_TIMEOUT, 0);
            curl_setopt($conn[$i], CURLOPT_FAILONERROR, 1);
            curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, 1);
            curl_multi_add_handle($mh, $conn[$i]);
        }
        $active = 0;
        do curl_multi_exec($mh, $active);
        while($active > 0);
        // Close the handles
        for($i = 0; $i < count($input); $i++)
        {
            fclose($fh[$i]);
            curl_multi_remove_handle($mh, $conn[$i]);
            curl_close($conn[$i]);
        }
        curl_multi_close($mh);
    }
    /**
     * The installation script should be executed
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     * @return boolean
     */
    private function doInstallation($task, $sxe)
    {
        global $app;
        try
        {
            // Check if the install directory exists
            if(!is_dir($this->local_installpath.'install_scripts/'))
                throw new Exception('The install directory '.$this->local_installpath.' is not existing');
            // Set the executable bit to the configure script
            $cfgscript = @(string)$sxe->service->provision->{'configuration-script'}['name'];
            if(!$cfgscript) $cfgscript = 'configure';
            chmod($this->local_installpath.'install_scripts/'.$cfgscript, 0755);
            // Change to the install folder (import for the exec() below!)
            //exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
            chdir($this->local_installpath.'install_scripts/');
            // Set the enviroment variables
            foreach($this->putenv as $var) {
                putenv($var);
            }
            $shell_retcode = true;
            $shell_ret = array();
             exec('php '.escapeshellarg($this->local_installpath.'install_scripts/'.$cfgscript).' install 2>&1', $shell_ret, $shell_retcode);
            $shell_ret = array_filter($shell_ret);
            $shell_ret_str = implode("\n", $shell_ret);
            // Although $shell_retcode might be 0, there can be PHP errors. Filter them:
            if(substr_count($shell_ret_str, 'Warning: ') > 0) $shell_retcode = 1;
            // If an error has occurred, the return code is != 0
            if($shell_retcode != 0) throw new Exception($shell_ret_str);
            else
            {
                // The install succeeded, chown newly created files too
                exec('chown -R '.$this->file_owner_user.':'.$this->file_owner_group.' '.escapeshellarg($this->local_installpath));
                $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_SUCCESS.'"
                    WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            }
        }
        catch(Exception $e)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log($e->getMessage(), 1);
            return false;
        }
        return true;
    }
    /**
     * Cleanup: Remove install scripts, remove tasks and update the database
     *
     * @param $task an array containing all install related data
     * @param $sxe a SimpleXMLElement handle, holding APP-META.xml
     */
    private function cleanup($task, $sxe)
    {
        chdir($this->local_installpath);
        exec("rm -Rf ".escapeshellarg($this->local_installpath).'install_scripts');
    }
    /**
     * The main method which performs the actual package installation
     *
     * @param $instanceid the instanceID to install
     * @param $type the type of task to perform (installation, removal)
     */
    public function installHandler($instanceid, $type)
    {
        global $app;
        // Set the given handle type, currently supported: install, delete
        if($type == 'install' || $type == 'delete') $this->handle_type = $type;
        else return false;
        // Get all instance metadata
        /*
        $task = $app->db->queryOneRecord("SELECT * FROM aps_instances AS i
            INNER JOIN aps_packages AS p ON i.package_id = p.id
            INNER JOIN client AS c ON i.customer_id = c.client_id
            WHERE i.id = ".$instanceid.";");
        */
        $task = $app->db->queryOneRecord("SELECT * FROM aps_instances AS i
            INNER JOIN aps_packages AS p ON i.package_id = p.id
            WHERE i.id = ".$instanceid.";");
        if(!$task) return false;  // formerly: throw new Exception('The InstanceID doesn\'t exist.');
        if(!isset($task['instance_id'])) $task['instance_id'] = $instanceid;
        // Download aps package
        if(!file_exists($this->packages_dir.'/'.$task['path']) || filesize($this->packages_dir.'/'.$task['path']) == 0) {
            $ch = curl_init();
            $fh = fopen($this->packages_dir.'/'.$task['path'], 'wb');
            curl_setopt($ch, CURLOPT_FILE, $fh);
            //curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_URL, $task['package_url']);
            curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 0);
            curl_setopt($ch, CURLOPT_FAILONERROR, 1);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            if(curl_exec($ch) === false) $app->log(curl_error ($ch),1);
            fclose($fh);
            curl_close($ch);
        }
        /*
        $app_to_dl[] = array('name' => $task['path'],
                            'url' => $task['package_url'],
                            'filesize' => 0,
                            'localtarget' => $this->packages_dir.'/'.$task['path']);
        $this->fetchFiles($app_to_dl);
        */
        // Make sure the requirements are given so that this script can execute
        $req_ret = $this->checkRequirements();
        if(!$req_ret) return false;
        $metafile = $this->getContentFromZIP($this->packages_dir.'/'.$task['path'], 'APP-META.xml');
        // Check if the meta file is existing
        if(!$metafile)
        {
            $app->dbmaster->query('UPDATE aps_instances SET instance_status = "'.INSTANCE_ERROR.'"
                WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->log('Unable to find the meta data file of package '.$task['path'], 1);
            return false;
        }
        // Rename namespaces and register them
        $metadata = str_replace("xmlns=", "ns=", $metafile);
        $sxe = new SimpleXMLElement($metadata);
        $namespaces = $sxe->getDocNamespaces(true);
        foreach($namespaces as $ns => $url) $sxe->registerXPathNamespace($ns, $url);
        // Setup the environment with data for the install location
        $this->prepareLocation($task);
        // Create the database if necessary
        $this->prepareDatabase($task, $sxe);
        // Unpack the install scripts from the packages
        if($this->prepareFiles($task, $sxe) && $this->handle_type == 'install')
        {
            // Setup the variables from the install script
            $this->prepareUserInputData($task);
            // Do the actual installation
            $this->doInstallation($task, $sxe);
            // Remove temporary files
            $this->cleanup($task, $sxe);
        }
        // Finally delete the instance entry + settings
        if($this->handle_type == 'delete')
        {
            $app->db->query('DELETE FROM aps_instances WHERE id = "'.$app->db->quote($task['instance_id']).'";');
            $app->db->query('DELETE FROM aps_instances_settings WHERE instance_id = "'.$app->db->quote($task['instance_id']).'";');
        }
        unset($sxe);
    }
}
?>
server/plugins-available/apache2_plugin.inc.php
@@ -1410,23 +1410,23 @@
            if(count($alias_seo_redirects) > 0) $tmp_vhost_arr = $tmp_vhost_arr + array('alias_seo_redirects' => $alias_seo_redirects);
            $vhosts[] = $tmp_vhost_arr;
            unset($tmp_vhost_arr);
            $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
        }
    //* Add vhost for IPv6 IP
    if($data['new']['ipv6_address'] != '') {
        if ($conf['serverconfig']['web']['vhost_rewrite_v6'] == 'y') {
            if (isset($conf['serverconfig']['server']['v6_prefix']) && $conf['serverconfig']['server']['v6_prefix'] <> '') {
                $explode_v6prefix=explode(':',$conf['serverconfig']['server']['v6_prefix']);
                $explode_v6=explode(':',$data['new']['ipv6_address']);
                for ( $i = 0; $i <= count($explode_v6prefix)-3; $i++ ) {
                        $explode_v6[$i] = $explode_v6prefix[$i];
                }
                $data['new']['ipv6_address'] = implode(':',$explode_v6);
            }
        }
            $app->log('Enable SSL for: '.$domain,LOGLEVEL_DEBUG);
        }
    //* Add vhost for IPv6 IP
    if($data['new']['ipv6_address'] != '') {
        if ($conf['serverconfig']['web']['vhost_rewrite_v6'] == 'y') {
            if (isset($conf['serverconfig']['server']['v6_prefix']) && $conf['serverconfig']['server']['v6_prefix'] <> '') {
                $explode_v6prefix=explode(':',$conf['serverconfig']['server']['v6_prefix']);
                $explode_v6=explode(':',$data['new']['ipv6_address']);
                for ( $i = 0; $i <= count($explode_v6prefix)-3; $i++ ) {
                        $explode_v6[$i] = $explode_v6prefix[$i];
                }
                $data['new']['ipv6_address'] = implode(':',$explode_v6);
            }
        }
            $tmp_vhost_arr = array('ip_address' => '['.$data['new']['ipv6_address'].']', 'ssl_enabled' => 0, 'port' => 80);
            if(count($rewrite_rules) > 0)  $tmp_vhost_arr = $tmp_vhost_arr + array('redirects' => $rewrite_rules);
            if(count($alias_seo_redirects) > 0) $tmp_vhost_arr = $tmp_vhost_arr + array('alias_seo_redirects' => $alias_seo_redirects);
server/plugins-available/aps_plugin.inc.php
@@ -1,118 +1,118 @@
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
if(defined('ISPC_ROOT_PATH')) include_once(ISPC_ROOT_PATH.'/lib/classes/aps_installer.inc.php');
//require_once(ISPC_ROOT_PATH.'/lib/classes/class.installer.php');
class aps_plugin
{
    public $plugin_name = 'aps_plugin';
    public $class_name = 'aps_plugin';
    //* This function is called during ispconfig installation to determine
    //  if a symlink shall be created for this plugin.
    function onInstall() {
        global $conf;
        if($conf['services']['web'] == true) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * This method gets called when the plugin is loaded
     */
    public function onLoad()
    {
        global $app;
        // Register the available events
        $app->plugins->registerEvent('aps_instance_insert', $this->plugin_name, 'install');
        $app->plugins->registerEvent('aps_instance_update', $this->plugin_name, 'install');
        $app->plugins->registerEvent('aps_instance_delete', $this->plugin_name, 'delete');
    }
    /**
     * (Re-)install a package
     */
    public function install($event_name, $data)
    {
        global $app, $conf;
        //* dont run the installer on a mirror server to prevent
        //  that the pplication gets installed twice.
        if($conf['mirror_server_id'] > 0) return true;
        $app->log("Starting APS install",LOGLEVEL_DEBUG);
        if(!isset($data['new']['id'])) return false;
        $instanceid = $data['new']['id'];
        if($data['new']['instance_status'] == INSTANCE_INSTALL) {
            $aps = new ApsInstaller($app);
            $app->log("Running installHandler",LOGLEVEL_DEBUG);
            $aps->installHandler($instanceid, 'install');
        }
        if($data['new']['instance_status'] == INSTANCE_REMOVE) {
            $aps = new ApsInstaller($app);
            $app->log("Running installHandler",LOGLEVEL_DEBUG);
            $aps->installHandler($instanceid, 'delete');
        }
    }
    /**
     * Update an existing instance (currently unused)
     */
     /*
    public function update($event_name, $data)
    {
    }
    */
    /**
     * Uninstall an instance
     */
    public function delete($event_name, $data)
    {
        global $app, $conf;
        if(!isset($data['new']['id'])) return false;
        $instanceid = $data['new']['id'];
        if($data['new']['instance_status'] == INSTANCE_REMOVE) {
            $aps = new ApsInstaller($app);
            $aps->installHandler($instanceid, 'install');
        }
    }
}
<?php
/*
Copyright (c) 2012, ISPConfig UG
Contributors: web wack creations,  http://www.web-wack.at
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
if(defined('ISPC_ROOT_PATH')) include_once(ISPC_ROOT_PATH.'/lib/classes/aps_installer.inc.php');
//require_once(ISPC_ROOT_PATH.'/lib/classes/class.installer.php');
class aps_plugin
{
    public $plugin_name = 'aps_plugin';
    public $class_name = 'aps_plugin';
    //* This function is called during ispconfig installation to determine
    //  if a symlink shall be created for this plugin.
    function onInstall() {
        global $conf;
        if($conf['services']['web'] == true) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * This method gets called when the plugin is loaded
     */
    public function onLoad()
    {
        global $app;
        // Register the available events
        $app->plugins->registerEvent('aps_instance_insert', $this->plugin_name, 'install');
        $app->plugins->registerEvent('aps_instance_update', $this->plugin_name, 'install');
        $app->plugins->registerEvent('aps_instance_delete', $this->plugin_name, 'delete');
    }
    /**
     * (Re-)install a package
     */
    public function install($event_name, $data)
    {
        global $app, $conf;
        //* dont run the installer on a mirror server to prevent
        //  that the pplication gets installed twice.
        if($conf['mirror_server_id'] > 0) return true;
        $app->log("Starting APS install",LOGLEVEL_DEBUG);
        if(!isset($data['new']['id'])) return false;
        $instanceid = $data['new']['id'];
        if($data['new']['instance_status'] == INSTANCE_INSTALL) {
            $aps = new ApsInstaller($app);
            $app->log("Running installHandler",LOGLEVEL_DEBUG);
            $aps->installHandler($instanceid, 'install');
        }
        if($data['new']['instance_status'] == INSTANCE_REMOVE) {
            $aps = new ApsInstaller($app);
            $app->log("Running installHandler",LOGLEVEL_DEBUG);
            $aps->installHandler($instanceid, 'delete');
        }
    }
    /**
     * Update an existing instance (currently unused)
     */
     /*
    public function update($event_name, $data)
    {
    }
    */
    /**
     * Uninstall an instance
     */
    public function delete($event_name, $data)
    {
        global $app, $conf;
        if(!isset($data['new']['id'])) return false;
        $instanceid = $data['new']['id'];
        if($data['new']['instance_status'] == INSTANCE_REMOVE) {
            $aps = new ApsInstaller($app);
            $aps->installHandler($instanceid, 'install');
        }
    }
}
?>