From deb2b8d0804d1d25a3f28266747ce9041495b372 Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Fri, 12 Jul 2013 04:17:32 -0400
Subject: [PATCH] Allow to load config files for different environments (#1487311); keep (non-default) filename in URLs throughout the webmail app

---
 program/lib/Roundcube/rcube.php          |    9 ++--
 tests/Selenium/bootstrap.php             |    4 +-
 program/include/rcmail_output_html.php   |    6 ++-
 skins/classic/templates/contactedit.html |    2 
 skins/classic/templates/contactadd.html  |    2 
 skins/larry/templates/contactedit.html   |    2 
 skins/classic/templates/compose.html     |    2 
 tests/bootstrap.php                      |    4 +-
 index.php                                |    2 
 skins/classic/templates/login.html       |    2 
 program/include/rcmail.php               |   12 ++++-
 program/lib/Roundcube/rcube_config.php   |   49 +++++++++++++++++++-----
 skins/larry/templates/login.html         |    2 
 skins/larry/templates/compose.html       |    2 
 14 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/index.php b/index.php
index 5d52571..2d220de 100644
--- a/index.php
+++ b/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();
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index d430cd3..800edda 100644
--- a/program/include/rcmail.php
+++ b/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) {
diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php
index c96a40a..9987795 100644
--- a/program/include/rcmail_output_html.php
+++ b/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'));
     }
diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index 05a94f3..ce97cd0 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/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'));
diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php
index 90bb853..62567a0 100644
--- a/program/lib/Roundcube/rcube_config.php
+++ b/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
diff --git a/skins/classic/templates/compose.html b/skins/classic/templates/compose.html
index 660f354..5e259e1 100644
--- a/skins/classic/templates/compose.html
+++ b/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">
 
diff --git a/skins/classic/templates/contactadd.html b/skins/classic/templates/contactadd.html
index 86bca46..bad6daf 100644
--- a/skins/classic/templates/contactadd.html
+++ b/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 />
diff --git a/skins/classic/templates/contactedit.html b/skins/classic/templates/contactedit.html
index 8ab801d..c51cbf2 100644
--- a/skins/classic/templates/contactedit.html
+++ b/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 />
diff --git a/skins/classic/templates/login.html b/skins/classic/templates/login.html
index cca2bd9..2dacd48 100644
--- a/skins/classic/templates/login.html
+++ b/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>
diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html
index 9cfe7fe..09eafe7 100644
--- a/skins/larry/templates/compose.html
+++ b/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">
diff --git a/skins/larry/templates/contactedit.html b/skins/larry/templates/contactedit.html
index f849366..3467ebe 100644
--- a/skins/larry/templates/contactedit.html
+++ b/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 />
diff --git a/skins/larry/templates/login.html b/skins/larry/templates/login.html
index a605eb7..6e56ee2 100644
--- a/skins/larry/templates/login.html
+++ b/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>
diff --git a/tests/Selenium/bootstrap.php b/tests/Selenium/bootstrap.php
index 6611e8f..e8b186a 100644
--- a/tests/Selenium/bootstrap.php
+++ b/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'));
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 40659eb..192997d 100644
--- a/tests/bootstrap.php
+++ b/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 . '..';

--
Gitblit v1.9.1