Thomas Bruederli
2013-07-12 deb2b8d0804d1d25a3f28266747ce9041495b372
Allow to load config files for different environments (#1487311); keep (non-default) filename in URLs throughout the webmail app
14 files modified
100 ■■■■■ changed files
index.php 2 ●●● patch | view | raw | blame | history
program/include/rcmail.php 12 ●●●● patch | view | raw | blame | history
program/include/rcmail_output_html.php 6 ●●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube.php 9 ●●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_config.php 49 ●●●● patch | view | raw | blame | history
skins/classic/templates/compose.html 2 ●●● patch | view | raw | blame | history
skins/classic/templates/contactadd.html 2 ●●● patch | view | raw | blame | history
skins/classic/templates/contactedit.html 2 ●●● patch | view | raw | blame | history
skins/classic/templates/login.html 2 ●●● patch | view | raw | blame | history
skins/larry/templates/compose.html 2 ●●● patch | view | raw | blame | history
skins/larry/templates/contactedit.html 2 ●●● patch | view | raw | blame | history
skins/larry/templates/login.html 2 ●●● patch | view | raw | blame | history
tests/Selenium/bootstrap.php 4 ●●●● patch | view | raw | blame | history
tests/bootstrap.php 4 ●●●● patch | view | raw | blame | history
index.php
@@ -39,7 +39,7 @@
require_once 'program/include/iniset.php';
// init application, start session, init output class, etc.
$RCMAIL = rcmail::get_instance();
$RCMAIL = rcmail::get_instance($GLOBALS['env']);
// Make the whole PHP output non-cacheable (#1487797)
$RCMAIL->output->nocacheing_headers();
program/include/rcmail.php
@@ -51,6 +51,7 @@
   */
  public $action = '';
  public $comm_path = './';
  public $filename = '';
  private $address_books = array();
  private $action_map = array();
@@ -65,12 +66,13 @@
  /**
   * This implements the 'singleton' design pattern
   *
   * @param string Environment name to run (e.g. live, dev, test)
   * @return rcmail The one and only instance
   */
  static function get_instance()
  static function get_instance($env = '')
  {
    if (!self::$instance || !is_a(self::$instance, 'rcmail')) {
      self::$instance = new rcmail();
      self::$instance = new rcmail($env);
      self::$instance->startup();  // init AFTER object was linked with self::$instance
    }
@@ -85,6 +87,10 @@
  protected function startup()
  {
    $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS);
    // set filename if not index.php
    if (($basename = basename($_SERVER['SCRIPT_FILENAME'])) && $basename != 'index.php')
      $this->filename = $basename;
    // start session
    $this->session_init();
@@ -724,7 +730,7 @@
    $p['_task'] = $task;
    unset($p['task']);
    $url = './';
    $url = './' . $this->filename;
    $delm = '?';
    foreach (array_reverse($p) as $key => $val) {
      if ($val !== '' && $val !== null) {
program/include/rcmail_output_html.php
@@ -1004,7 +1004,9 @@
                }
                return html::quote($value);
                break;
            case 'form':
                return $this->form_tag($attrib);
        }
        return '';
    }
@@ -1432,7 +1434,7 @@
        $attrib['noclose'] = true;
      return html::tag('form',
        $attrib + array('action' => "./", 'method' => "get"),
        $attrib + array('action' => $this->app->comm_path, 'method' => "get"),
        $hidden . $content,
        array('id','class','style','name','method','action','enctype','onsubmit'));
    }
program/lib/Roundcube/rcube.php
@@ -105,13 +105,14 @@
     * This implements the 'singleton' design pattern
     *
     * @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants
     * @param string Environment name to run (e.g. live, dev, test)
     *
     * @return rcube The one and only instance
     */
    static function get_instance($mode = 0)
    static function get_instance($mode = 0, $env = '')
    {
        if (!self::$instance) {
            self::$instance = new rcube();
            self::$instance = new rcube($env);
            self::$instance->init($mode);
        }
@@ -122,10 +123,10 @@
    /**
     * Private constructor
     */
    protected function __construct()
    protected function __construct($env = '')
    {
        // load configuration
        $this->config  = new rcube_config;
        $this->config  = new rcube_config($env);
        $this->plugins = new rcube_dummy_plugin_api;
        register_shutdown_function(array($this, 'shutdown'));
program/lib/Roundcube/rcube_config.php
@@ -26,6 +26,8 @@
{
    const DEFAULT_SKIN = 'larry';
    private $env = '';
    private $basedir = 'config/';
    private $prop = array();
    private $errors = array();
    private $userprefs = array();
@@ -50,9 +52,14 @@
    /**
     * Object constructor
     *
     * @param string Environment suffix for config files to load
     */
    public function __construct()
    public function __construct($env = '')
    {
        $this->env = $env;
        $this->basedir = RCUBE_CONFIG_DIR;
        $this->load();
        // Defaults, that we do not require you to configure,
@@ -70,15 +77,15 @@
    private function load()
    {
        // Load default settings
        if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'defaults.inc.php')) {
        if (!$this->load_from_file('defaults.inc.php')) {
            $this->errors[] = 'defaults.inc.php was not found.';
        }
        // load main config file
        if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'config.inc.php')) {
        if (!$this->load_from_file('config.inc.php')) {
            // Old configuration files
            if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'main.inc.php') ||
                !$this->load_from_file(RCUBE_CONFIG_DIR . 'db.inc.php')) {
            if (!$this->load_from_file('main.inc.php') ||
                !$this->load_from_file('db.inc.php')) {
                $this->errors[] = 'config.inc.php was not found.';
            }
            else if (rand(1,100) == 10) {  // log warning on every 100th request (average)
@@ -87,7 +94,8 @@
        }
        // load host-specific configuration
        $this->load_host_config();
        if (!empty($_SERVER['HTTP_HOST']))
            $this->load_host_config();
        // set skin (with fallback to old 'skin_path' property)
        if (empty($this->prop['skin'])) {
@@ -164,7 +172,7 @@
        }
        if ($fname) {
            $this->load_from_file(RCUBE_CONFIG_DIR . $fname);
            $this->load_from_file($fname);
        }
    }
@@ -173,12 +181,13 @@
     * Read configuration from a file
     * and merge with the already stored config values
     *
     * @param string $fpath Full path to the config file to be loaded
     * @param string $file Name of the config file to be loaded
     * @return booelan True on success, false on failure
     */
    public function load_from_file($fpath)
    public function load_from_file($file)
    {
        if (is_file($fpath) && is_readable($fpath)) {
        $fpath = $this->resolve_path($file);
        if ($fpath && is_file($fpath) && is_readable($fpath)) {
            // use output buffering, we don't need any output here 
            ob_start();
            include($fpath);
@@ -198,6 +207,26 @@
        return false;
    }
    /**
     * Helper method to resolve the absolute path to the given config file.
     * This also takes the 'env' property into account.
     */
    public function resolve_path($file, $use_env = true)
    {
        if (strpos($file, '/') === false) {
            $file = realpath($this->basedir . '/' . $file);
        }
        // check if <file>-env.ini exists
        if ($file && $use_env && !empty($this->env)) {
            $envfile = preg_replace('/\.(inc.php)$/', '-' . $this->env . '.\\1', $file);
            if (is_file($envfile))
                return $envfile;
        }
        return $file;
    }
    /**
     * Getter for a specific config parameter
skins/classic/templates/compose.html
@@ -44,7 +44,7 @@
    <roundcube:button name="messageoptions" id="composemenulink" type="link" class="button messagemenu" title="messageoptions" onclick="rcmail_ui.show_popup('composemenu', true);return false" content=" " />
</div>
<form name="form" action="./" method="post">
<roundcube:form name="form" method="post">
<div id="mainscreen">
skins/classic/templates/contactadd.html
@@ -9,7 +9,7 @@
<div id="contact-title" class="boxtitle"><roundcube:label name="addcontact" /></div>
<div id="contact-details" class="boxcontent">
<form name="editform" method="post" action="./">
<roundcube:form name="editform" method="post">
  <roundcube:if condition="strlen(env:sourcename)" />
    <div id="sourcename"><roundcube:label name="addressbook" />: <roundcube:object name="sourceselector" class="hint" id="sourceselect" /></div>
  <roundcube:endif />
skins/classic/templates/contactedit.html
@@ -9,7 +9,7 @@
<div id="contact-title" class="boxtitle"><roundcube:label name="editcontact" /></div>
<div id="contact-details" class="boxcontent">
<form name="editform" method="post" action="./">
<roundcube:form name="editform" method="post">
  <roundcube:if condition="strlen(env:sourcename)" />
    <div id="sourcename"><roundcube:label name="addressbook" />: <roundcube:var name="env:sourcename" /></div>
  <roundcube:endif />
skins/classic/templates/login.html
@@ -15,7 +15,7 @@
<div class="boxtitle"><roundcube:label name="welcome" /></div>
<div class="boxcontent">
<form name="form" action="./" method="post">
<roundcube:form name="form" method="post">
<roundcube:object name="loginform" form="form" />
<p style="text-align:center;"><input type="submit" class="button mainaction" value="<roundcube:label name='login' />" /></p>
skins/larry/templates/compose.html
@@ -65,7 +65,7 @@
<div id="composeview-right">
<form name="form" action="./" method="post" id="compose-content" class="uibox">
<roundcube:form name="form" method="post" id="compose-content" class="uibox">
<!-- message headers -->
<div id="composeheaders">
skins/larry/templates/contactedit.html
@@ -11,7 +11,7 @@
    <roundcube:else /><roundcube:label name="editcontact" />
<roundcube:endif /></h1>
<form name="editform" method="post" action="./" id="contact-details" class="boxcontent">
<roundcube:form name="editform" method="post" id="contact-details" class="boxcontent">
    <roundcube:if condition="strlen(env:sourcename)" />
        <div id="sourcename"><roundcube:label name="addressbook" />: <roundcube:var name="env:sourcename" condition="env:action!='add'" /><roundcube:object name="sourceselector" id="sourceselect" condition="env:action=='add'" /></div>
    <roundcube:endif />
skins/larry/templates/login.html
@@ -11,7 +11,7 @@
<div class="box-inner">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="logo" border="0" />
<form name="form" action="./" method="post">
<roundcube:form name="form" method="post">
<roundcube:object name="loginform" form="form" size="40" />
<p class="formbuttons"><input type="submit" class="button mainaction" value="<roundcube:label name='login' />" /></p>
tests/Selenium/bootstrap.php
@@ -27,7 +27,7 @@
define('TESTS_DIR', dirname(__FILE__) . '/');
if (@is_dir(TESTS_DIR . 'config')) {
    define('RCMAIL_CONFIG_DIR', TESTS_DIR . 'config');
    define('RCUBE_CONFIG_DIR', TESTS_DIR . 'config');
}
require_once(INSTALL_PATH . 'program/include/iniset.php');
@@ -38,7 +38,7 @@
    die("Fatal error: ini_set/set_include_path does not work.");
}
$rcmail = rcube::get_instance();
$rcmail = rcube::get_instance('test');
define('TESTS_URL',     $rcmail->config->get('tests_url'));
define('TESTS_BROWSER', $rcmail->config->get('tests_browser', 'firefox'));
tests/bootstrap.php
@@ -27,12 +27,12 @@
define('TESTS_DIR', dirname(__FILE__) . '/');
if (@is_dir(TESTS_DIR . 'config')) {
    define('RCMAIL_CONFIG_DIR', TESTS_DIR . 'config');
    define('RCUBE_CONFIG_DIR', TESTS_DIR . 'config');
}
require_once(INSTALL_PATH . 'program/include/iniset.php');
rcmail::get_instance()->config->set('devel_mode', false);
rcmail::get_instance('test')->config->set('devel_mode', false);
// Extend include path so some plugin test won't fail
$include_path = ini_get('include_path') . PATH_SEPARATOR . TESTS_DIR . '..';