From 99f904adcc37d93c90defcd8ce898598e25be212 Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Wed, 11 Mar 2015 16:55:04 +0100 Subject: Lot of plugins --- db_version/CHANGELOG | 21 ++ db_version/LICENSE | 84 +++++++ db_version/README | 8 + db_version/SQL/mssql.initial.sql | 5 + db_version/SQL/mysql.initial.sql | 13 ++ db_version/SQL/pgsql.initial.sql | 12 + db_version/SQL/sqlite.initial.sql | 12 + db_version/db_version.php | 474 ++++++++++++++++++++++++++++++++++++++ db_version/package.xml | 22 ++ db_version/skins/classic/sql.html | 31 +++ db_version/skins/larry/sql.html | 48 ++++ 11 files changed, 730 insertions(+) create mode 100644 db_version/CHANGELOG create mode 100644 db_version/LICENSE create mode 100644 db_version/README create mode 100644 db_version/SQL/mssql.initial.sql create mode 100644 db_version/SQL/mysql.initial.sql create mode 100644 db_version/SQL/pgsql.initial.sql create mode 100644 db_version/SQL/sqlite.initial.sql create mode 100644 db_version/db_version.php create mode 100644 db_version/package.xml create mode 100644 db_version/skins/classic/sql.html create mode 100644 db_version/skins/larry/sql.html (limited to 'db_version') diff --git a/db_version/CHANGELOG b/db_version/CHANGELOG new file mode 100644 index 0000000..a93f7c2 --- /dev/null +++ b/db_version/CHANGELOG @@ -0,0 +1,21 @@ +VERSION COMMENT +----------------------------------------------------------------------------------------------------------------- +1.0 - Initial release +2.0 - Completely recoded from scratch +2.0.1 - 2.0.2 - GUI improvements +2.0.3 - 2.0.5 - Fix for *NIX OS (workaround for case sensitivity of SQL folder) +2.0.6 - Added sqlite3 to database map +2.0.7 - Fixed Roundcube version detection +2.0.8 - 2.0.10 - Prepare for Roundcube 1.0 +3.0 - Support for sqlite (https://code.google.com/p/myroundcube/issues/detail?id=624); +3.1 - Better support for database prefixes +3.1.1 - Implement rcube_db::factory +3.1.2 - Implement rcube_db::limitquery +3.1.3 - 3.1.4 - Don't load plugin if database access to system table fails (should avoid to display + database update prompt to "normal" users in case of database connection failures) +3.1.5 - Don't exit for plugin.plugin_manager_update_notifications action +3.1.6 - Make sure that db_config plugin is always loaded +3.1.7 - Do not load plugin on Plugin Manager Update request +3.1.8 - Always load plugins on about request +3.1.9 - Remove reward logging (MSSQL will be deprecated) +3.1.10 - Better RegEx for custom table names replacement \ No newline at end of file diff --git a/db_version/LICENSE b/db_version/LICENSE new file mode 100644 index 0000000..11b1f5e --- /dev/null +++ b/db_version/LICENSE @@ -0,0 +1,84 @@ + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +dev-team [at] myroundcube [dot] com +http://myroundcube.com + +--- LICENSE DETAILS --- + + + + +TERMS AND CONDITIONS +-------------------- + +User Agreement + +MyRoundcube Developers provides MyRoundcube Plugins (code) shall provide ("MyRoundcube Plugins") to +you ("User") under the terms and conditions of this User Agreement ("the Agreement"). USER UNDERSTANDS +AND ACKNOWLEDGES THAT USER IS ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers AND NOT THE WEB +SITE WITH WHOM ANYTHING HAS ASSOCIATED TO BRING YOU THIS CODE. BY USING ("MyRoundcube Plugins") OR ANY +PART OF ITS CODE YOU ARE AGREEING TO BECOME A PARTY TO THIS AGREEMENT WITH MyRoundcube Developers AND +TO THE TERMS AND CONDITIONS HEREIN AND ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND ANY APPLICABLE +ASSOCIATE STATEMENT IN THIS DOCUMENT. ALL MyRoundcube Developers SERVICES ARE PROVIDED ONLINE. PERSONS +UNDER 13 MAY NOT BE ELEGIBLE TO ENTERING INTO AN AGREEMENT WITH MyRoundcube Developers OR PURCHASE OUR +SERVICES AND CODE DOWNLOADS. + +Acceptable Use Policy + +The following policy governs the use of the MyRoundcube Developers code. User will comply with the terms +and spirit of the Agreement. + +(a) User shall not use MyRoundcube Plugins (code) in a manner that violates any city, state, national +or international law or regulation, or which fails to comply with accepted Internet protocol. User +shall not attempt to interfere in any way with MyRoundcube Plugins networks or network security, or +attempt to use the MyRoundcube Plugins code to gain unauthorized access to any other computer system. +(b) User shall at all times provide MyRoundcube Developers with accurate information. User shall not +interfere in any way with another User's use of, or MyRoundcube Developers provision of the MyRoundcube +Plugins. User shall not resell, rent, lease, grant a security interest in, or make commercial use of +the MyRoundcube Plugins without the express written consent of MyRoundcube Developers. +(c) User agrees not to transfer MyRoundcube Plugins (code) for gain or otherwise. Transfer of such code +will result in termination of contract with end user. + +Limitation of Liability + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, TORT, CONTRACT, OR OTHERWISE, SHALL MyRoundcube +Developers OR ITS LICENSORS OR RESELLERS BE LIABLE TO USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, +INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES RESULTING +FROM THE USE OF OR THE INABILITY TO USE THE MyRoundcube Plugins (code), THE PERFORMANCE OF MyRoundcube +Plugins (code) SERVICE, OR DAMAGES FOR LOSS OF GOODWILL, BUSINESS PROFIT, BUSINESS STOPPAGE, LOSS OF +DATA OR BUSINESS INFORMATION, COMPUTER DAMAGE, OR DAMAGES RESULTING FROM UNAUTHORIZED ACCESS TO OR +CHANGES MADE TO USER'S TRANSMISSIONS OR DATA, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES. +IN NO EVENT WILL MyRoundcube Developers BE LIABLE FOR ANY DAMAGES IN EXCESS OF WHAT ANYTHING MyRoundcube +Developers RECEIVED FROM USER FOR THE MyRoundcube Plugins (code). + +Terms + +You (the User) are permitted to use the code on unlimited servers you may own, rented or leased, as +long as you own, rent or lease the server in which MyRoundcube plugins code is hosted. +Exclusive: You (the User) agree to use the code in one server at a time. Multiple server deployments +(multiserver setup), clusters or any other form of deployment that simultaneously executes MyRoundcube +plugins in a live environment must purchase a separate download per server or installation thereof. + +Warranties + +Our code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Terms Modifications + +We reserve the right to change or modify our Terms and Conditions at any time without prior notice. +For questions, please contact our team at dev-team [at] myroundcube [dot] com. + +Copyright (c) 2012 - 2014 +MyRoundcube.com - A Division of Informative Computing Consultants, LLC. +All rights reserved + +Informative Computing Consultants, LLC. +21741 NW 8th CT +Pembroke Pines +Florida, 33029 +dev-team [at] myroundcube [dot] com +http://myroundcube.com diff --git a/db_version/README b/db_version/README new file mode 100644 index 0000000..1530f52 --- /dev/null +++ b/db_version/README @@ -0,0 +1,8 @@ +db_version +---------- +Documentation: +http://myroundcube.com/myroundcube-plugins/ + + +MyRoundcube Dev Team +www.myroundcube.com \ No newline at end of file diff --git a/db_version/SQL/mssql.initial.sql b/db_version/SQL/mssql.initial.sql new file mode 100644 index 0000000..80261cf --- /dev/null +++ b/db_version/SQL/mssql.initial.sql @@ -0,0 +1,5 @@ +CREATE TABLE [dbo].[system] ( + [name] [varchar] (64) COLLATE Latin1_General_CI_AI NOT NULL , + [value] [text] COLLATE Latin1_General_CI_AI NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO diff --git a/db_version/SQL/mysql.initial.sql b/db_version/SQL/mysql.initial.sql new file mode 100644 index 0000000..bb10b47 --- /dev/null +++ b/db_version/SQL/mysql.initial.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS `myrc` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +ALTER TABLE `myrc` + ADD CONSTRAINT `myrc_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE; + +CREATE INDEX myrc_idx ON myrc (`user_id`); + +DROP TABLE `myrc`; \ No newline at end of file diff --git a/db_version/SQL/pgsql.initial.sql b/db_version/SQL/pgsql.initial.sql new file mode 100644 index 0000000..d7b974e --- /dev/null +++ b/db_version/SQL/pgsql.initial.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS myrc ( + id serial NOT NULL, + user_id integer NOT NULL, + PRIMARY KEY (id) +); + +ALTER TABLE myrc + ADD CONSTRAINT myrc_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE; + +CREATE INDEX myrc_idx ON myrc (user_id); + +DROP TABLE myrc; \ No newline at end of file diff --git a/db_version/SQL/sqlite.initial.sql b/db_version/SQL/sqlite.initial.sql new file mode 100644 index 0000000..776c0e4 --- /dev/null +++ b/db_version/SQL/sqlite.initial.sql @@ -0,0 +1,12 @@ +PRAGMA foreign_keys = ON; + +CREATE TABLE IF NOT EXISTS myrc ( + id serial NOT NULL, + user_id integer NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY (user_id) REFERENCES users (user_id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX myrc_idx ON myrc (user_id); + +DROP TABLE myrc; \ No newline at end of file diff --git a/db_version/db_version.php b/db_version/db_version.php new file mode 100644 index 0000000..6b43e98 --- /dev/null +++ b/db_version/db_version.php @@ -0,0 +1,474 @@ + 'MySQL', 'pgsql' => 'PostGreSQL', 'sqlite' => 'Sqlite v.3', 'mssql' => 'MSSQL'); + + /* unified plugin properties */ + static private $plugin = 'db_version'; + static private $author = 'myroundcube@mail4us.net'; + static private $authors_comments = 'Documentation'; + static private $download = 'http://myroundcube.googlecode.com'; + static private $version = '3.1.10'; + static private $date = '21-01-2015'; + static private $licence = 'All Rights reserved'; + static private $requirements = array( + 'Roundcube' => '1.0', + 'PHP' => '5.3', + 'required_plugins' => array( + 'codemirror_ui' => 'require_plugin', + ), + ); + static private $prefs = array( + ); + static private $config_dist = null; + static private $db_map = array( + 'sqlite' => 'sqlite', + 'sqlite2' => 'sqlite', + 'sqlite3' => 'sqlite', + 'sybase' => 'mssql', + 'dblib' => 'mssql', + 'sqlsrv' => 'mssql', + 'mssql' => 'mssql', + 'mysql' => 'mysql', + 'mysqli' => 'mysql', + 'pgsql' => 'pgsql', + 'postgresql' => 'pgsql', + ); + static private $default_tables = array( + 'users', + 'attachments', + 'cache', + 'cache_index', + 'cache_thread', + 'cache_tables', + 'cache_messages', + 'cache_shared', + 'contactgroupmembers', + 'contactgroups', + 'contacts', + 'dictionary', + 'identities', + 'searches', + 'system' + ); + static private $f; + + function init(){ + self::$f = $this; + } + + static public function about($keys = false){ + $requirements = self::$requirements; + foreach(array('required_', 'recommended_') as $prefix){ + if(is_array($requirements[$prefix.'plugins'])){ + foreach($requirements[$prefix.'plugins'] as $plugin => $method){ + if(class_exists($plugin) && method_exists($plugin, 'about')){ + /* PHP 5.2.x workaround for $plugin::about() */ + $class = new $plugin(false); + $requirements[$prefix.'plugins'][$plugin] = array( + 'method' => $method, + 'plugin' => $class->about($keys), + ); + } + else{ + $requirements[$prefix.'plugins'][$plugin] = array( + 'method' => $method, + 'plugin' => $plugin, + ); + } + } + } + } + return array( + 'plugin' => self::$plugin, + 'version' => self::$version, + 'date' => self::$date, + 'author' => self::$author, + 'comments' => self::$authors_comments, + 'licence' => self::$licence, + 'requirements' => $requirements, + ); + } + + function form($p){ + return self::$out; + } + + static public function exec($plugin, $tables, $dbversion){ + $rcmail = rcmail::get_instance(); + /* + if($rcmail->action == 'plugin.plugin_manager_update' || $rcmail->action == 'about' || $rcmail->action == 'alive' || $rcmail->action == 'refresh'){ + return true; + } + */ + if($rcmail->action == 'about'){ // Do not force database adjustments on about request + return true; + } + if(get_input_value('_load_pm_settings', RCUBE_INPUT_GET)){ + if($plugin = get_input_value('_plugin', RCUBE_INPUT_GET)){ + $append = '&_plugin=' . $plugin; + } + else{ + $append = ''; + } + if(!self::$done){ + self::$done = true; + if($rcmail->config->get('skin', 'classic') == 'classic'){ + $frame = 'prefs-frame'; + } + else{ + $frame = 'preferences-frame'; + } + $rcmail->output->add_script('$("#'. $frame . '").attr("src", "./?_task=settings&_action=edit-prefs&_section=plugin_manager_settings&_framed=1' . $append . '");', 'docready'); + } + return false; + } + $return = false; + $dbversion = implode('|', $dbversion); + $query = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quoteIdentifier('name') . '=?'; + $res = $rcmail->db->limitquery($query, 0, 1, 'myrc_' . $plugin); + $version = $rcmail->db->fetch_assoc($res); + if($error = $rcmail->db->is_error()){ + write_log('db_version', $error); + return false; + } + if($version['value'] == $dbversion){ + $return = true; + } + else if($plugin == 'plugin_manager' || $rcmail->config->get('plugin_manager_hash')){ + $hash = $rcmail->config->get('plugin_manager_hash'); + if(($plugin == 'plugin_manager' && !is_array($version)) || ($rcmail->task != 'logout' && file_exists(INSTALL_PATH . $hash . '.myrc'))){ + if(get_input_value('_framed', RCUBE_INPUT_GPC)){ + return false; + } + $type = current(explode(':', $rcmail->config->get('db_dsnw'), 2)); + $type = self::$db_map[$type]; + if(!$type){ + if(!file_exists(slashify($rcmail->config->get('log_dir', 'logs/')) . 'dbtypefailure')){ + write_log('dbtypefailure', 'MyRoundcube Fatal Error'); + write_log('dbtypefailure', '-----------------------'); + write_log('dbtypefailure', 'Failed to detect database type.'); + write_log('dbtypefailure', 'Please contact MyRoundcube Dev Team (dev-team@myroundcube.com) and mail the following string (don\'t miss to mask password and to clear your Browser cache):'); + write_log('dbtypefailure', ' '); + write_log('dbtypefailure', $rcmail->config->get('db_dsnw')); + } + $content = file_get_contents(slashify($rcmail->config->get('log_dir', 'logs/')) . 'dbtypefailure'); + $content = explode("\n", $content); + $out = ''; + foreach($content as $nb => $line){ + $line = explode("]: ", $line); + $out .= $line[1] . "\n"; + } + $rcmail->output->nocacheing_headers(); + die('MyRoundcube Fatal Error
' . $out . '
'); + } + if(get_input_value('_remote', RCUBE_INPUT_GPC) && get_input_value('_action', RCUBE_INPUT_GPC) != 'plugin.plugin_manager_update_notifier' && !$_SESSION['db_version_lock']){ + $db_version = explode('|', $dbversion); + $redirect = true; + $reward = false; + $missing = ''; + foreach($db_version as $script){ + if(!file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql') && !file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){ + $rcmail->output->show_message('Plugin "' . $plugin . '": Can\'t load plugin. ' . self::$map[strtolower($type)] . ' database scripts are incomplete.', 'error'); + $redirect = false; + $missing .= $plugin . ': plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql does not exist!'; + //$reward = '--> REWARD MyRC$ 5: Create missing scripts and mail it to dev-team@myroundcube.com (include your customer ID)!'; + } + } + if($reward && !$_SESSION['db_version_missing_logged_' . $plugin]){ + $_SESSION['db_version_missing_logged_' . $plugin] = true; + write_log('errors', $missing); + //write_log('errors', $reward); + } + if($redirect){ + echo json_encode(array('exec' => 'document.location.href="./"')); + exit; + } + } + $return = db_version::db_versioning($plugin, array_merge(array('system'), $tables)); + } + } + else if($plugin == 'db_config'){ + $return = true; + } + return $return; + } + + static public function test_permissions($type, $db){ + if($type == 'sqlite'){ + return true; + } + $sql = @file_get_contents(INSTALL_PATH . 'plugins/db_version/SQL/' . $type . '.initial.sql'); + if(!$sql){ + $sql = @file_get_contents(INSTALL_PATH . 'plugins/db_version/sql/' . $type . '.initial.sql'); + } + if($sql){ + $sql = trim($sql) . "\r\n"; + $sql = self::fix_table_names($sql, array('myrc')); + $sql = explode(';', $sql); + foreach($sql as $line){ + if(trim($line)){ + if(!$db->query($line)){ + $command = explode(' ', $line); + return $command[0]; + } + } + } + return true; + } + else{ + return $type; + } + } + + static public function db_versioning($plugin, $tables){ + $rcmail = rcmail::get_instance(); + /* PHP 5.2.x workaround for $plugin::about() */ + $class = new $plugin(false); + $db_version = $class->about(array('db_version')); + $db_version = $db_version['db_version']; + if(is_array($db_version)){ + $database = parse_url($rcmail->config->get('db_dsnw')); + if(!$database){ + $database = parse_url(end(explode(':', $rcmail->config->get('db_dsnw'), 2))); + $database['scheme'] = current(explode(':', $rcmail->config->get('db_dsnw'), 2)); + } + $type = self::$db_map[$database['scheme']]; + $sql = 'SELECT * FROM ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quote_identifier('name') . '=?'; + $res = $rcmail->db->limitquery($sql, 0, 1, 'myrc_' . $plugin); + $system = $rcmail->db->fetch_assoc($res); + if($system){ + $versions = explode('|', $system['value']); + } + if(implode('|', $db_version) == $system['value']){ + return true; + } + if(count($_POST) == 0){ + $sql = ''; + foreach($db_version as $script){ + if(!is_array($versions) || !in_array($script, $versions)){ + if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){ + $sql .= trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n"; + } + else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){ + $sql .= trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n"; + } + else{ + return false; + } + } + } + if($sql){ + $disable = ''; + if($plugin != 'plugin_manager'){ + $res = $rcmail->db->limitquery('SELECT * FROM ' . get_table_name('plugin_manager') . ' WHERE ' . $rcmail->db->quote_identifier('conf') . '=?', 0, 1, '_plugin_manager_file_based_config'); + $fb = $rcmail->db->fetch_assoc($res); + if($fb['value'] == 0){ + $disable = ' ' . html::tag('input', array('onclick' => 'document.location.href="./?_task=settings&_load_pm_settings=1&_plugin=' . $plugin . '"', 'type' => 'button', 'class' => 'button', 'value' => 'Disable Plugin')); + } + } + if($database['user']){ + $dsnw = $database['scheme'] . '://' . $database['user'] . ':***masked***@' . $database['host'] . $database['path']; + } + else{ + $dsnw = $rcmail->config->get('db_dsnw'); + } + $v = explode('-', RCMAIL_VERSION); + $v = trim($v[0]); + if(version_compare($v, '0.9', '>=')){ + $out = + html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'), + html::tag('h3', null, 'Plugin Manager database versioning: Plugin "' . $plugin . '"') . + 'Plugin Manager has detected required missing adjustments in your database. The following commands will be executed against your database ' . + html::tag('b', null, $dsnw . ':') . html::tag('br') . html::tag('br') . + html::tag('textarea', array('readonly' => true, 'rows' => '18', 'cols' => '95', 'id' => 'code'), self::fix_table_names($sql, $tables)) . + html::tag('table', null, + html::tag('tr', null, html::tag('td', null, html::tag('input', array('type' => 'radio', 'name' => '_dbadjust_agreed', 'checked' => true, 'value' => 1, 'onclick' => '$("#submitbutton").show();$("#donebox").hide()')) . + html::tag('td', null, 'I have a recent database backup. I understand the code and I agree to execute it. '))) . + html::tag('tr', null, html::tag('td', null, html::tag('input', array('type' => 'radio', 'name' => '_dbadjust_agreed', 'value' => 0, 'onclick' => '$("#submitbutton").hide();$("#donebox").show()')) . + html::tag('td', null, 'I will take care of the necessary ' . + html::tag('a', array('href' => 'http://myroundcube.com/myroundcube-plugins/faqs/myroundcube-plugins-database-versioning-support', 'target' => '_new'), 'database adjustments') . ' by myself. ' . + 'I\'m aware that MyRoundcube "' . $plugin . '" plugin does not work without these database adjustments. '))) + ) . + html::tag('center', null, html::tag('input', array('id' => 'submitbutton', 'type' => 'submit', 'value' => 'Submit')) . $disable) . html::tag('br') . + html::tag('center', array('style' => 'display: none;', 'id' => 'donebox'), html::tag('input', array('type' => 'checkbox', 'onclick' => '$("#submitbutton").show();$("#donebox").hide();$(this).prop("checked", false)')) . html::tag('span', null, ' ' . + html::tag('b', null, 'I have unregistered this plugin or I have already applied database adjustments manually.'))) + ); + $hidden = new html_hiddenfield(array('name' => '_token', 'value' => $rcmail->get_request_token())); + $out .= "\n" . $hidden->show(); + $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();'); + $section = ''; + if($section = get_input_value('_plugin_manager_settings_section', RCUBE_INPUT_GET)){ + $section = '&_plugin_manager_settings_section=' . $section . '&_expand=' . $plugin; + } + $form = html::tag('form', array('method' => 'post', 'action' => './?_task=' . $rcmail->task . $section), $out); + } + else{ + $out = + html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'), + html::tag('h3', null, 'Plugin Manager database versioning: Plugin "' . $plugin . '"') . + 'Plugin Manager has detected required missing adjustments in your database. Please execute the following commands against your database ' . + html::tag('b', null, $database['scheme'] . '://' . $database['user'] . ':***masked***@' . $database['host'] . $database['path'] . ':') . html::tag('br') . html::tag('br') . + html::tag('textarea', array('readonly' => true, 'rows' => '18', 'cols' => '95', 'id' => 'code'), self::fix_table_names($sql, $tables)) . + html::tag('table', null, + html::tag('tr', null, html::tag('td', null, + html::tag('td', null, 'Please backup your database. ' . + 'Please note, that MyRoundcube "' . $plugin . '" plugin does not work without these database adjustments.'))) + ) . + html::tag('center', null, html::tag('input', array('id' => 'submitbutton', 'type' => 'submit', 'value' => 'Database has been backed up and commands have been executed.'))) + ); + $hidden = new html_hiddenfield(array('name' => '_token', 'value' => $rcmail->get_request_token())); + $out .= "\n" . $hidden->show(); + $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();'); + $section = ''; + if($section = get_input_value('_plugin_manager_settings_section', RCUBE_INPUT_GET)){ + $section = '&_plugin_manager_settings_section=' . $section . '&_expand=' . $plugin; + } + $form = html::tag('form', array('method' => 'post', 'action' => './?_task=' . $rcmail->task . $section), $out); + } + $out = str_replace('##FORM##', $form, @file_get_contents(INSTALL_PATH . 'plugins/db_version/skins/' . $rcmail->config->get('skin', 'classic') . '/sql.html')); + if(method_exists($rcmail->output, 'just_parse')){ + send_nocacheing_headers(); + header('Content-Type: text/html; charset=' . RCMAIL_CHARSET); + echo $rcmail->output->just_parse($out); + exit; + } + } + } + else{ + if(get_input_value('_dbadjust_agreed', RCUBE_INPUT_POST)){ + unset($_POST); + $rcmail->session->remove('db_version_lock'); + if($dsn = $rcmail->config->get('db_dsnw_superadmin')){ + $rcmail->db = rcube_db::factory($dsn . '?new_link=true', '', false); + $rcmail->db = $rcmail->db->factory($dsn . '?new_link=true'); + $rcmail->db->set_debug((bool)$rcmail->config->get('sql_debug')); + $rcmail->db->db_connect('r'); + } + $ret = self::test_permissions($type, $rcmail->db); + $sversions = is_array($system) ? $system['value'] : ''; + $sversions = explode('|', $sversions); + if($ret !== true){ + $sql = ''; + foreach($db_version as $script){ + if(!in_array($script, $sversions)){ + if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){ + $sql .= self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n", $tables); + } + else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){ + $sql .= self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n", $tables); + } + } + } + if($ret === $type){ + $rcmail->output->show_message('Plugin "db_version": ' . self::$map[strtolower($type)] . ' database is not supported!', 'error'); + return false; + } + self::html_output($sql, $ret); + } + foreach($db_version as $script){ + if(!in_array($script, $sversions)){ + if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')){ + $sql = self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/SQL/' . $type . '.' . $script . '.sql')) . "\r\n", $tables); + $lines = explode(';', $sql); + foreach($lines as $line){ + if(trim($line)){ + $rcmail->db->query(trim($line)); + } + } + } + else if(file_exists(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')){ + $sql = self::fix_table_names(trim(file_get_contents(INSTALL_PATH . 'plugins/' . $plugin . '/sql/' . $type . '.' . $script . '.sql')) . "\r\n", $tables); + $lines = explode(';', $sql); + foreach($lines as $line){ + if(trim($line)){ + $rcmail->db->query(trim($line)); + } + } + } + } + } + $sql = 'DELETE from ' . get_table_name('system') . ' WHERE ' . $rcmail->db->quoteIdentifier('name') . '=?'; + $rcmail->db->query($sql, 'myrc_' . $plugin); + $sql = 'INSERT INTO ' . get_table_name('system') . ' (' . $rcmail->db->quote_identifier('name') . ', ' . $rcmail->db->quote_identifier('value') . ') VALUES(?, ?)'; + $res = $rcmail->db->query($sql, 'myrc_' . $plugin, implode('|', $db_version)); + if($rcmail->db->affected_rows($res)){ + return true; + } + else{ + return false; + } + } + } + } + } + + static public function html_output($script, $command = false){ + $rcmail = rcmail::get_instance(); + $config_var = '$config'; + $config_file = 'config.inc.php'; + $v = current(explode('-', RCMAIL_VERSION)); + if(version_compare($v, '1.0', '<')){ + $config_var = '$rcmail_config'; + $config_file = 'db.inc.php'; + } + $dbconfig = parse_url($rcmail->config->get('db_dsnw')); + $out = html::tag('div', array('style' => 'font-size: 12px; text-align: justify; position: absolute; margin-left: auto; left: 50%; margin-left: -400px; width: 800px;'), + html::tag('h3', null, sprintf('Database adjustment failed (Command: %s)', $command)) . + html::tag('span', null, 'The user ' . + html::tag('b', null, '"' . ($dbconfig['user'] ? $dbconfig['user'] : get_current_user()) . '"') .' does not seem to have sufficient permissions on the database ' . + html::tag('b', null, '"' . ($dbconfig['path'] ? substr($dbconfig['path'], 1) : $rcmail->config->get('db_dsnw')) . '"') . ':' . html::tag('br') . html::tag('br') . + ' ' . html::tag('center', null, html::tag('i', null, 'Required permissions: SELECT / INSERT / UPDATE / DELETE / CREATE / ALTER / INDEX / DROP')) . + html::tag('br') . + 'Please, grant the user sufficient permissions on the database or execute the following database script manually:') . html::tag('br') . html::tag('br') . + html::tag('textarea', array('readonly' => true, 'rows' => '10', 'cols' => '95', 'id' => 'code'), self::fix_table_names($script, array('plugin_manager'))) . + html::tag('br') . html::tag('br') . + html::tag('div', array('style' => $display_superadmin ? 'block' : 'none'), + $dbconfig['user'] ? + ( + html::tag('left', null, html::tag('b', null, 'Alternatively') . ' add a different database user with sufficient permissions to your configuration in ' . + html::tag('b', null, '"./config/' . $config_file . '"') . ':' . html::tag('br') . html::tag('br') . + html::tag('textarea', array('readonly' => true, 'cols' => '95', 'rows' => '2'), + $config_var . '[\'db_dsnw_superadmin\'] = \'' . $dbconfig['scheme'] . '://root:password@' . $dbconfig['host'] . $dbconfig['path'] . '\';')) . + html::tag('br') . html::tag('br') + ) : '' + ) . + html::tag('div', array('style' => 'display: inline; float: left'), + html::tag('a', array('href' => 'javascript:void(0)', 'onclick' => 'document.location.href=\'./\''), 'Done') + ) + ); + $out .= html::tag('script', array('type' => 'text/javascript'), '$("#taskbar.topright").hide();'); + $out = str_replace('##FORM##', $out, @file_get_contents(INSTALL_PATH . 'plugins/db_version/skins/' . $rcmail->config->get('skin', 'classic') . '/sql.html')); + send_nocacheing_headers(); + header('Content-Type: text/html; charset=' . RCMAIL_CHARSET); + echo $rcmail->output->just_parse($out); + exit; + } + + static public function fix_table_names($sql, $tables){ + $tables = array_merge(self::$default_tables, $tables); + $DB = rcmail::get_instance()->db; + if(is_array($tables)){ + foreach($tables as $table){ + $real_table = $DB->table_name($table); + if($real_table != $table){ + $sql = preg_replace("/([^a-z0-9_'])$table([^a-z0-9_'])/i", "\\1$real_table\\2", $sql); + } + } + } + return $sql; + } +} +?> \ No newline at end of file diff --git a/db_version/package.xml b/db_version/package.xml new file mode 100644 index 0000000..3710a27 --- /dev/null +++ b/db_version/package.xml @@ -0,0 +1,22 @@ + + + db_version + + Myroundcube Dev Team + rosali + dev-team@myroundcube.com + yes + 2014-07-05 + + 3.1.4 + 3.1.4 + + + stable + stable + + All Rights reserved + diff --git a/db_version/skins/classic/sql.html b/db_version/skins/classic/sql.html new file mode 100644 index 0000000..36a73e4 --- /dev/null +++ b/db_version/skins/classic/sql.html @@ -0,0 +1,31 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + + + + + + + +
+##FORM## +
+ + + diff --git a/db_version/skins/larry/sql.html b/db_version/skins/larry/sql.html new file mode 100644 index 0000000..99cd78a --- /dev/null +++ b/db_version/skins/larry/sql.html @@ -0,0 +1,48 @@ + + + +<roundcube:object name="pagetitle" /> + + + + + + + + + + + + + + + +
+ + + + + +
+##FORM## + +
+
+ + + + -- cgit v1.2.3