From e6bb836e053913ec8a5930a6d51af1fa55eb08e2 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Fri, 25 Feb 2011 11:37:22 -0500
Subject: [PATCH] Create interactive update script with improved DB schema check; udated installer with new features and styles

---
 CHANGELOG                                  |    1 
 installer/styles.css                       |   71 +++-----
 bin/update.sh                              |   55 ++++++
 installer/check.php                        |    1 
 SQL/mysql.update.sql                       |    2 
 UPGRADING                                  |   33 +++-
 program/lib/MDB2/Driver/Reverse/sqlite.php |    2 
 /dev/null                                  |    0 
 program/include/rcube_mdb2.php             |   17 ++
 installer/images/rcube_logo.gif            |    0 
 installer/rcube_install.php                |  170 ++++++++++++++++----
 bin/installto.sh                           |   73 +++++++++
 installer/images/banner_schraffur.gif      |    0 
 SQL/sqlite.update.sql                      |    2 
 installer/test.php                         |   21 +
 SQL/postgres.update.sql                    |    2 
 installer/images/banner_gradient.gif       |    0 
 SQL/mssql.upgrade.sql                      |    2 
 installer/index.php                        |   17 +-
 19 files changed, 358 insertions(+), 111 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 8d20773..e2d27b9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Interactive update script with improved DB schema check
 - jQuery 1.5.1
 - Fix problem with contactgroupmembers table creation on MySQL 4.x, add index on contact_id column
 - Add LDAP SASL bind and proxy authentication (#1486692)
diff --git a/SQL/mssql.upgrade.sql b/SQL/mssql.upgrade.sql
index 8534afd..eacfcf1 100644
--- a/SQL/mssql.upgrade.sql
+++ b/SQL/mssql.upgrade.sql
@@ -97,7 +97,7 @@
 ALTER TABLE [dbo].[contacts] ALTER COLUMN [email] [varchar] (255) COLLATE Latin1_General_CI_AI NOT NULL
 GO
 
--- Updates from version 0.5.x
+-- Updates from version 0.5.1
 
 ALTER TABLE [dbo].[contacts] ADD [words] [text] COLLATE Latin1_General_CI_AI NULL 
 GO
diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql
index d30f037..4cb087e 100644
--- a/SQL/mysql.update.sql
+++ b/SQL/mysql.update.sql
@@ -133,7 +133,7 @@
 
 TRUNCATE TABLE `messages`;
 
--- Updates from version 0.5.*
+-- Updates from version 0.5.1
 
 ALTER TABLE `contacts` ADD `words` TEXT NULL AFTER `vcard`;
 ALTER TABLE `contactgroupmembers` ADD INDEX `contactgroupmembers_contact_index` (`contact_id`);
diff --git a/SQL/postgres.update.sql b/SQL/postgres.update.sql
index e3eb581..91c32f8 100644
--- a/SQL/postgres.update.sql
+++ b/SQL/postgres.update.sql
@@ -90,7 +90,7 @@
 
 TRUNCATE messages;
 
--- Updates from version 0.5.x
+-- Updates from version 0.5.1
 
 ALTER TABLE contacts ADD words TEXT NULL;
 CREATE INDEX contactgroupmembers_contact_id_idx ON contactgroupmembers (contact_id);
diff --git a/SQL/sqlite.update.sql b/SQL/sqlite.update.sql
index 7b5464c..d8a657a 100644
--- a/SQL/sqlite.update.sql
+++ b/SQL/sqlite.update.sql
@@ -183,7 +183,7 @@
 DELETE FROM messages;
 
 
--- Updates from version 0.5.x
+-- Updates from version 0.5.1
 
 CREATE TABLE contacts_tmp (
     contact_id integer NOT NULL PRIMARY KEY,
diff --git a/UPGRADING b/UPGRADING
index 329983d..f203643 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -5,6 +5,26 @@
 of Roundcube Webmail. We recommend to carefully backup the existing
 installation as well as the database before executig the following steps.
 
+Using the update script
+-----------------------
+There is a shell script (for unix based systems) that does the job for you.
+To use it, unpack the archive of the new Roundcube version to a temporary location (don't replace the Roundcube installation you want to update)
+and cd into that directory. From there, run the following command in a shell:
+
+  ./bin/installto.sh <TARGET-FOLDER>
+
+For <TARGET-FOLDER> you specify the path to the Roundcube installation 
+which should be updated. The update script will then copy all new files to the 
+target location and check and update the configuration and database schema.
+After all is done, the temporary folder with the new Roundcube files can be 
+removed again.
+
+
+Updating manually
+-----------------
+If you don't have shell access to the Roundcube instalaltion or if not running 
+it on a unix system, you need to do the following operations by hand:
+
 1. Replace index.php and all files in
    - ./bin/
    - ./SQL/
@@ -14,14 +34,11 @@
    - ./plugins/
 2. Run ./bin/update.sh from the commandline OR
    open http://url-to-roundcube/installer/ in a browser and choose "3 Test config".
-   To enable the latter one, you have to temporary set 'enable_installer' to true
-   in your local config/main.inc.php file.
+   To enable the latter one, you have to temporary set 'enable_installer'
+   to true in your local config/main.inc.php file.
 3. Let the update script/installer check your configuration and
-   update your config files as suggested by the updater.
-4. If suggested by the update script, run all commands in
-   ./SQL/[yourdbtype].update.sql that are superscribed with the
-   currently installed version number.
-5. Make sure 'enable_installer' is set to false again.
-6. Check .htaccess settings (some php settings could become required)
+   update your config files and database schema as suggested by the updater.
+4. Make sure 'enable_installer' is set to false again.
+5. Check .htaccess settings (some php settings could become required)
 
 
diff --git a/bin/installto.sh b/bin/installto.sh
new file mode 100755
index 0000000..f953419
--- /dev/null
+++ b/bin/installto.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env php
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | bin/installto.sh                                                      |
+ |                                                                       |
+ | This file is part of the Roundcube Webmail client                     |
+ | Copyright (C) 2011, The Roundcube Dev Team                            |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Update an existing Roundcube installation with files from           |
+ |   this version                                                        |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+if (php_sapi_name() != 'cli') {
+    die('Not on the "shell" (php-cli).');
+}
+define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/iniset.php';
+
+$target_dir = unslashify($_SERVER['argv'][1]);
+
+if (empty($target_dir) || !is_dir(realpath($target_dir)))
+  die("Invalid target: not a directory\nUsage: installto.sh <TARGET>\n");
+
+// read version from iniset.php
+$iniset = @file_get_contents($target_dir . '/program/include/iniset.php');
+if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)/', $iniset, $m))
+  die("No valid Roundcube installation found at $target_dir\n");
+
+$oldversion = $m[1];
+
+if (version_compare($oldversion, RCMAIL_VERSION, '>='))
+  die("Installation at target location is up-to-date!\n");
+
+echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n";
+$input = trim(fgets(STDIN));
+
+if (strtolower($input) == 'y') {
+  $err = false;
+  echo "Copying files to target location...";
+  foreach (array('program','installer','bin','SQL','plugins','skins/default') as $dir) {
+    if (!system("rsync -avuC " . INSTALL_PATH . "$dir/* $target_dir/$dir/")) {
+      $err = true;
+      break;
+    }
+  }
+  foreach (array('index.php','.htaccess','config/main.inc.php.dist','config/db.inc.php.dist','CHANGELOG','README','UPGRADING') as $file) {
+    if (!system("rsync -avu " . INSTALL_PATH . "$file $target_dir/$file")) {
+      $err = true;
+      break;
+    }
+  }
+  echo "done.\n\n";
+  
+  if (!$err) {
+    echo "Running update script at target...\n";
+    system("cd $target_dir && bin/update.sh --version=$oldversion");
+    echo "All done.\n";
+  }
+}
+else
+  echo "Update cancelled. See ya!\n";
+
+?>
diff --git a/bin/update.sh b/bin/update.sh
index a298887..094e5b7 100755
--- a/bin/update.sh
+++ b/bin/update.sh
@@ -1,12 +1,45 @@
 #!/usr/bin/env php
 <?php
+/*
+ +-----------------------------------------------------------------------+
+ | bin/update.sh                                                         |
+ |                                                                       |
+ | This file is part of the Roundcube Webmail client                     |
+ | Copyright (C) 2010-2011, The Roundcube Dev Team                       |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | PURPOSE:                                                              |
+ |   Check local configuration and database schema after upgrading       |
+ |   to a new version                                                    |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
 if (php_sapi_name() != 'cli') {
     die('Not on the "shell" (php-cli).');
 }
 define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' );
 
-require_once INSTALL_PATH . 'program/include/iniset.php';
+require_once INSTALL_PATH . 'program/include/clisetup.php';
 require_once INSTALL_PATH . 'installer/rcube_install.php';
+
+// get arguments
+$opts = get_opt(array('v' => 'version'));
+
+// ask user if no version is specified
+if (!$opts['version']) {
+  echo "What version are you upgrading from? Type '?' if you don't know.\n";
+  if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z-]*$/', $input))
+    $opts['version'] = $input;
+}
+
+if ($opts['version'] && version_compare($opts['version'], RCMAIL_VERSION, '>'))
+  die("Nothing to be done here. Bye!\n");
+
 
 $RCI = rcube_install::get_instance();
 $RCI->load_config();
@@ -88,7 +121,7 @@
         }
       }
       else {
-        echo "Please update your config files manually according to the above messages.\n";
+        echo "Please update your config files manually according to the above messages.\n\n";
       }
     }
 
@@ -113,12 +146,22 @@
       echo "Error connecting to database: $db_error_msg\n";
       $success = false;
     }
-    else if ($RCI->db_schema_check($DB, false)) {
-      $db_map = array('pgsql' => 'postgres', 'mysqli' => 'mysql', 'sqlsrv' => 'mssql');
-      $updatefile = INSTALL_PATH . 'SQL/' . (isset($db_map[$DB->db_provider]) ? $db_map[$DB->db_provider] : $DB->db_provider) . '.update.sql';
+    else if ($err = $RCI->db_schema_check($DB, false)) {
+      $updatefile = INSTALL_PATH . 'SQL/' . (isset($RCI->db_map[$DB->db_provider]) ? $RCI->db_map[$DB->db_provider] : $DB->db_provider) . '.update.sql';
       echo "WARNING: Database schema needs to be updated!\n";
-      echo "Open $updatefile and execute all queries that are superscribed with the currently installed version number\n";
+      echo join("\n", $err) . "\n\n";
       $success = false;
+      
+      if ($opts['version']) {
+        echo "Do you want to run the update queries to get the schmea fixed? (y/N)\n";
+        $input = trim(fgets(STDIN));
+        if (strtolower($input) == 'y') {
+          $success = $RCI->update_db($DB, $opts['version']);
+        }
+      }
+      
+      if (!$success)
+        echo "Open $updatefile and execute all queries below the comment with the currently installed version number.\n";
     }
   }
   
diff --git a/installer/check.php b/installer/check.php
index 0ba5f58..944d384 100644
--- a/installer/check.php
+++ b/installer/check.php
@@ -22,6 +22,7 @@
     'PEAR'      => 'PEAR.php',
     'MDB2'      => 'MDB2.php',
     'Net_SMTP'  => 'Net/SMTP.php',
+    'Net_IDNA2' => 'Net/IDNA2.php',
     'Mail_mime' => 'Mail/mime.php',
 );
 
diff --git a/installer/images/banner_bg.gif b/installer/images/banner_bg.gif
deleted file mode 100644
index 9cef8a7..0000000
--- a/installer/images/banner_bg.gif
+++ /dev/null
Binary files differ
diff --git a/installer/images/banner_gradient.gif b/installer/images/banner_gradient.gif
new file mode 100644
index 0000000..8ab1b06
--- /dev/null
+++ b/installer/images/banner_gradient.gif
Binary files differ
diff --git a/installer/images/banner_logo.gif b/installer/images/banner_logo.gif
deleted file mode 100644
index a7dd114..0000000
--- a/installer/images/banner_logo.gif
+++ /dev/null
Binary files differ
diff --git a/installer/images/banner_right.gif b/installer/images/banner_right.gif
deleted file mode 100644
index 3248668..0000000
--- a/installer/images/banner_right.gif
+++ /dev/null
Binary files differ
diff --git a/installer/images/banner_schraffur.gif b/installer/images/banner_schraffur.gif
new file mode 100644
index 0000000..50182b4
--- /dev/null
+++ b/installer/images/banner_schraffur.gif
Binary files differ
diff --git a/installer/images/rcube_logo.gif b/installer/images/rcube_logo.gif
new file mode 100644
index 0000000..26f82ff
--- /dev/null
+++ b/installer/images/rcube_logo.gif
Binary files differ
diff --git a/installer/index.php b/installer/index.php
index 1c157da..e09b827 100644
--- a/installer/index.php
+++ b/installer/index.php
@@ -68,14 +68,13 @@
 <body>
 
 <div id="banner">
-  <div id="header">
-    <div class="banner-logo"><a href="http://www.roundcube.net"><img src="images/banner_logo.gif" width="200" height="56" border="0" alt="Roundcube Webmal Project" /></a></div>
-    <div class="banner-right"><img src="images/banner_right.gif" width="10" height="56" alt="" /></div>
-  </div>
-  <div id="topnav">
-    <a href="http://trac.roundcube.net/wiki/Howto_Install">How-to Wiki</a>
-  </div>
- </div>
+  <div class="banner-bg"></div>
+  <div class="banner-logo"><a href="http://roundcube.net"><img src="images/rcube_logo.gif" width="210" height="55" border="0" alt="Roundcube - Open source webmail project" /></a></div>
+</div>
+
+<div id="topnav">
+  <a href="http://trac.roundcube.net/wiki/Howto_Install">How-to Wiki</a>
+</div>
 
 <div id="content">
 
@@ -120,7 +119,7 @@
 </div>
 
 <div id="footer">
-  Installer by the Roundcube Dev Team. Copyright &copy; 2008 - Published under the GNU Public License;&nbsp;
+  Installer by the Roundcube Dev Team. Copyright &copy; 2008-2011 - Published under the GNU Public License;&nbsp;
   Icons by <a href="http://famfamfam.com">famfamfam</a>
 </div>
 </body>
diff --git a/installer/rcube_install.php b/installer/rcube_install.php
index 3f4e607..3f2d1a4 100644
--- a/installer/rcube_install.php
+++ b/installer/rcube_install.php
@@ -29,10 +29,11 @@
   var $config = array();
   var $configured = false;
   var $last_error = null;
+  var $db_map = array('pgsql' => 'postgres', 'mysqli' => 'mysql', 'sqlsrv' => 'mssql');
   var $email_pattern = '([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9])';
   var $bool_config_props = array();
 
-  var $obsolete_config = array('db_backend');
+  var $obsolete_config = array('db_backend', 'double_auth');
   var $replaced_config = array(
     'skin_path' => 'skin',
     'locale_string' => 'language',
@@ -42,7 +43,10 @@
   );
   
   // these config options are required for a working system
-  var $required_config = array('db_dsnw', 'db_table_contactgroups', 'db_table_contactgroupmembers', 'des_key');
+  var $required_config = array(
+    'db_dsnw', 'db_table_contactgroups', 'db_table_contactgroupmembers',
+    'des_key', 'session_lifetime',
+  );
   
   /**
    * Constructor
@@ -294,7 +298,7 @@
     $this->config = array();
     $this->load_defaults();
     
-    foreach ($this->replaced_config as $prop => $replacement)
+    foreach ($this->replaced_config as $prop => $replacement) {
       if (isset($current[$prop])) {
         if ($prop == 'skin_path')
           $this->config[$replacement] = preg_replace('#skins/(\w+)/?$#', '\\1', $current[$prop]);
@@ -302,8 +306,8 @@
           $this->config[$replacement] = $current[$prop] ? 2 : 0;
         else
           $this->config[$replacement] = $current[$prop];
-        
-        unset($current[$prop]);
+      }
+      unset($current[$prop]);
     }
     
     foreach ($this->obsolete_config as $prop) {
@@ -319,6 +323,9 @@
         }
       }
     }
+    
+    if ($current['keep_alive'] && $current['session_lifetime'] < $current['keep_alive'])
+      $current['session_lifetime'] = max(10, ceil($current['keep_alive'] / 60) * 2);
     
     $this->config  = array_merge($this->config, $current);
     
@@ -339,18 +346,8 @@
     if (!$this->configured)
       return false;
     
-    // simple ad hand-made db schema
-    $db_schema = array(
-      'users' => array(),
-      'identities' => array(),
-      'contacts' => array(),
-      'contactgroups' => array(),
-      'contactgroupmembers' => array(),
-      'cache' => array(),
-      'messages' => array(),
-      'session' => array(),
-    );
-    
+    // read reference schema from mysql.initial.sql
+    $db_schema = $this->db_read_schema(INSTALL_PATH . 'SQL/mysql.initial.sql');
     $errors = array();
     
     // check list of tables
@@ -358,13 +355,43 @@
 
     foreach ($db_schema as $table => $cols) {
       $table = !empty($this->config['db_table_'.$table]) ? $this->config['db_table_'.$table] : $table;
-      if (!in_array($table, $existing_tables))
-        $errors[] = "Missing table ".$table;
-      // TODO: check cols and indices
+      if (!in_array($table, $existing_tables)) {
+        $errors[] = "Missing table '".$table."'";
+      }
+      else {  // compare cols
+        $db_cols = $DB->list_cols($table);
+        $diff = array_diff(array_keys($cols), $db_cols);
+        if (!empty($diff))
+          $errors[] = "Missing columns in table '$table': " . join(',', $diff);
+      }
     }
     
     return !empty($errors) ? $errors : false;
   }
+
+  /**
+   * Utility function to read database schema from an .sql file
+   */
+  private function db_read_schema($schemafile)
+  {
+    $lines = file($schemafile);
+    $table_block = false;
+    $schema = array();
+    foreach ($lines as $line) {
+      if (preg_match('/^\s*create table `?([a-z0-9_]+)`?/i', $line, $m)) {
+        $table_block = $m[1];
+      }
+      else if ($table_block && preg_match('/^\s*`?([a-z0-9_-]+)`?\s+([a-z]+)/', $line, $m)) {
+        $col = $m[1];
+        if (!in_array(strtoupper($col), array('PRIMARY','KEY','INDEX','UNIQUE','CONSTRAINT','REFERENCES','FOREIGN'))) {
+          $schema[$table_block][$col] = $m[2];
+        }
+      }
+    }
+    
+    return $schema;
+  }
+  
   
   /**
    * Compare the local database schema with the reference schema
@@ -472,6 +499,16 @@
     }
     
     return $out;
+  }
+  
+  /**
+   * Create a HTML dropdown to select a previous version of Roundcube
+   */
+  function versions_select($attrib = array())
+  {
+    $select = new html_select($attrib);
+    $select->add(array('0.1-stable', '0.1.1', '0.2-alpha', '0.2-beta', '0.2-stable', '0.3-stable', '0.3.1', '0.4-beta', '0.4.2', '0.5-beta', '0.5', '0.5.1'));
+    return $select;
   }
   
   
@@ -592,25 +629,12 @@
    */
   function init_db($DB)
   {
-    $db_map = array('pgsql' => 'postgres', 'mysqli' => 'mysql');
-    $engine = isset($db_map[$DB->db_provider]) ? $db_map[$DB->db_provider] : $DB->db_provider;
+    $engine = isset($this->db_map[$DB->db_provider]) ? $this->db_map[$DB->db_provider] : $DB->db_provider;
     
     // read schema file from /SQL/*
-    $fname = "../SQL/$engine.initial.sql";
-    if ($lines = @file($fname, FILE_SKIP_EMPTY_LINES)) {
-      $buff = '';
-      foreach ($lines as $i => $line) {
-        if (preg_match('/^--/', $line))
-          continue;
-          
-        $buff .= $line . "\n";
-        if (preg_match('/;$/', trim($line))) {
-          $DB->query($buff);
-          $buff = '';
-          if ($this->get_error())
-            break;
-        }
-      }
+    $fname = INSTALL_PATH . "SQL/$engine.initial.sql";
+    if ($sql = @file_get_contents($fname)) {
+      $this->exec_sql($sql, $DB);
     }
     else {
       $this->fail('DB Schema', "Cannot read the schema file: $fname");
@@ -625,6 +649,78 @@
     return true;
   }
   
+  
+  /**
+   * Update database with SQL statements from SQL/*.update.sql
+   *
+   * @param object rcube_db Database connection
+   * @param string Version to update from
+   * @return boolen True on success, False on error
+   */
+  function update_db($DB, $version)
+  {
+    $version = strtolower($version);
+    $engine = isset($this->db_map[$DB->db_provider]) ? $this->db_map[$DB->db_provider] : $DB->db_provider;
+    
+    // read schema file from /SQL/*
+    $fname = INSTALL_PATH . "SQL/$engine.update.sql";
+    if ($lines = @file($fname, FILE_SKIP_EMPTY_LINES)) {
+      $from = false; $sql = '';
+      foreach ($lines as $line) {
+        $is_comment = preg_match('/^--/', $line);
+        if (!$from && $is_comment && preg_match('/from version\s([0-9.]+[a-z-]*)/', $line, $m)) {
+          $v = strtolower($m[1]);
+          if ($v == $version || version_compare($version, $v, '<='))
+            $from = true;
+        }
+        if ($from && !$is_comment)
+          $sql .= $line. "\n";
+      }
+      
+      if ($sql)
+        $this->exec_sql($sql, $DB);
+    }
+    else {
+      $this->fail('DB Schema', "Cannot read the update file: $fname");
+      return false;
+    }
+    
+    if ($err = $this->get_error()) {
+      $this->fail('DB Schema', "Error updating database: $err");
+      return false;
+    }
+
+    return true;
+  }
+  
+  
+  /**
+   * Execute the given SQL queries on the database connection
+   *
+   * @param string SQL queries to execute
+   * @param object rcube_db Database connection
+   * @return boolen True on success, False on error
+   */
+  function exec_sql($sql, $DB)
+  {
+    $buff = '';
+    foreach (explode("\n", $sql) as $line) {
+      if (preg_match('/^--/', $line) || trim($line) == '')
+        continue;
+        
+      $buff .= $line . "\n";
+      if (preg_match('/(;|^GO)$/', trim($line))) {
+        $DB->query($buff);
+        $buff = '';
+        if ($DB->is_error())
+          break;
+      }
+    }
+    
+    return !$DB->is_error();
+  }
+  
+  
   /**
    * Handler for Roundcube errors
    */
diff --git a/installer/styles.css b/installer/styles.css
index 1acdc9c..06f49e3 100644
--- a/installer/styles.css
+++ b/installer/styles.css
@@ -1,62 +1,53 @@
-
 body {
-  margin: 1em 2em 2em 2em;
-  background-color: #fff;
-}
-
-body, td, th, div, p {
-  font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
-  font-size: small;
-  color: #000;
+	background: white;
+	font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+	font-size: small;
+	color: black;
+	margin: 0;
 }
 
 #banner {
-  position: relative;
+	position: relative;
+	height: 58px;
+	margin: 0 0 1em 0;
+	padding: 10px 20px;
+	background: url('images/banner_gradient.gif') top left repeat-x #d8edfd;
+	overflow: hidden;
 }
 
-#header {
-  position: relative;
-  height: 56px;
-  background: url('images/banner_bg.gif') top left repeat-x #fff;
+#banner .banner-bg {
+	position: absolute;
+	top: 0;
+	right: 0;
+	width: 630px;
+	height: 78px;
+	background: url('images/banner_schraffur.gif') top right no-repeat;
+	z-index: 0;
 }
 
-#header div.banner-logo {
-  position: absolute;
-  top: 0px;
-  left: 0px;
-  width: 200px;
-  height: 56px;
+#banner .banner-logo {
+	position: absolute;
+	top: 10px;
+	left: 20px;
+	z-index: 4;
 }
 
-#header div.banner-right {
-  position: absolute;
-  right: 0px;
-  top: 0px;
-  width: 10px;
-  height: 56px;
+#banner .banner-logo a {
+	border: 0;
 }
 
 #topnav {
-  position: absolute;
-  right: 20px;
-  bottom: 8px;
-  text-align: right;
-  color: #ebebeb;
-  font-size: smaller;
+	position: absolute;
+	top: 3.6em;
+	right: 20px;
 }
 
 #topnav a {
-  color: #ebebeb;
-  font-size: 11px;
-  text-decoration: none;
-}
-
-#topnav a:hover {
-  text-decoration: underline;
+	color: #666;
 }
 
 #content {
-  margin: 8px 20px;
+	margin: 2em 20px;
 }
 
 #footer {
diff --git a/installer/test.php b/installer/test.php
index 713edfb..02a1ceb 100644
--- a/installer/test.php
+++ b/installer/test.php
@@ -156,6 +156,14 @@
     }
 }
 
+else if ($db_working && $_POST['updatedb']) {
+  if (!($success = $RCI->update_db($DB, $_POST['version']))) {
+      $updatefile = INSTALL_PATH . 'SQL/' . (isset($RCI->db_map[$DB->db_provider]) ? $RCI->db_map[$DB->db_provider] : $DB->db_provider) . '.update.sql';
+      echo '<p class="warning">Please manually execute the SQL statements from '.$updatefile.' on your database.<br/>';
+      echo 'See comments in the file and execute queries below the comment with the currently installed version number.</p>';
+  }
+}
+
 // test database
 if ($db_working) {
     $db_read = $DB->query("SELECT count(*) FROM {$RCI->config['db_table_users']}");
@@ -164,12 +172,13 @@
         echo '<p><input type="submit" name="initdb" value="Initialize database" /></p>';
         $db_working = false;
     }
-    else if ($RCI->db_schema_check($DB, $update = !empty($_POST['updatedb']))) {
+    else if ($err = $RCI->db_schema_check($DB, $update = !empty($_POST['updatedb']))) {
         $RCI->fail('DB Schema', "Database schema differs");
-        $db_map = array('pgsql' => 'postgres', 'mysqli' => 'mysql', 'sqlsrv' => 'mssql');
-        $updatefile = INSTALL_PATH . 'SQL/' . (isset($db_map[$DB->db_provider]) ? $db_map[$DB->db_provider] : $DB->db_provider) . '.update.sql';
-        echo '<p class="warning">Please manually execute the SQL statements from '.$updatefile.' on your database.<br/>';
-        echo 'See comments in the file and execute queries that are superscribed with the currently installed version number.</p>';
+        echo '<ul style="margin:0"><li>' . join("</li>\n<li>", $err) . "</li></ul>";
+        $select = $RCI->versions_select(array('name' => 'version'));
+        echo '<p class="suggestion">You should run the update queries to get the schmea fixed.<br/><br/>Version to update from: ' . $select->show() . '&nbsp;<input type="submit" name="updatedb" value="Update" /></p>';
+//        echo '<p class="warning">Please manually execute the SQL statements from '.$updatefile.' on your database.<br/>';
+//        echo 'See comments in the file and execute queries that are superscribed with the currently installed version number.</p>';
         $db_working = false;
     }
     else {
@@ -412,7 +421,7 @@
 
 After completing the installation and the final tests please <b>remove</b> the whole
 installer folder from the document root of the webserver or make sure that
-enable_installer option in main.inc.php is disabled.<br />
+<tt>enable_installer</tt> option in config/main.inc.php is disabled.<br />
 <br />
 
 These files may expose sensitive configuration data like server passwords and encryption keys
diff --git a/program/include/rcube_mdb2.php b/program/include/rcube_mdb2.php
index c56a86e..85a70ca 100644
--- a/program/include/rcube_mdb2.php
+++ b/program/include/rcube_mdb2.php
@@ -413,6 +413,23 @@
 
 
     /**
+     * Wrapper for SHOW COLUMNS command
+     *
+     * @param string Table name
+     * @return array List of table cols
+     */
+    function list_cols($table)
+    {
+        $this->db_handle->loadModule('Manager');
+        if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) {
+            return $result;
+        }
+        
+        return null;
+    }
+
+
+    /**
      * Formats input so it can be safely used in a query
      *
      * @param  mixed  $input  Value to quote
diff --git a/program/lib/MDB2/Driver/Reverse/sqlite.php b/program/lib/MDB2/Driver/Reverse/sqlite.php
index c88ad0d..43cec99 100644
--- a/program/lib/MDB2/Driver/Reverse/sqlite.php
+++ b/program/lib/MDB2/Driver/Reverse/sqlite.php
@@ -95,7 +95,7 @@
             return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
                 'unexpected empty table column definition list', __FUNCTION__);
         }
-        $regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i';
+        $regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|TINYINT|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i';
         $regexp2 = '/^\s*([^ ]+) +(PRIMARY|UNIQUE|CHECK)$/i';
         for ($i=0, $j=0; $i<$count; ++$i) {
             if (!preg_match($regexp, trim($column_sql[$i]), $matches)) {

--
Gitblit v1.9.1