diff options
| author | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
|---|---|---|
| committer | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
| commit | b62676ca5d3d6f6ba3f019ea3f99722e165a98d8 (patch) | |
| tree | 86722cb80f07d4569f90088eeaea2fc2f6e2ef94 /webmail/bin | |
Diffstat (limited to '')
| -rwxr-xr-x | webmail/bin/cleandb.sh | 78 | ||||
| -rwxr-xr-x | webmail/bin/decrypt.sh | 67 | ||||
| -rwxr-xr-x | webmail/bin/exportgettext.sh | 236 | ||||
| -rwxr-xr-x | webmail/bin/importgettext.sh | 199 | ||||
| -rwxr-xr-x | webmail/bin/indexcontacts.sh | 54 | ||||
| -rwxr-xr-x | webmail/bin/installto.sh | 81 | ||||
| -rwxr-xr-x | webmail/bin/jsshrink.sh | 67 | ||||
| -rwxr-xr-x | webmail/bin/jsunshrink.sh | 14 | ||||
| -rwxr-xr-x | webmail/bin/moduserprefs.sh | 82 | ||||
| -rwxr-xr-x | webmail/bin/msgexport.sh | 143 | ||||
| -rwxr-xr-x | webmail/bin/msgimport.sh | 113 | ||||
| -rwxr-xr-x | webmail/bin/update.sh | 170 | ||||
| -rwxr-xr-x | webmail/bin/updatecss.sh | 122 | ||||
| -rwxr-xr-x | webmail/bin/updatedb.sh | 202 |
14 files changed, 1628 insertions, 0 deletions
diff --git a/webmail/bin/cleandb.sh b/webmail/bin/cleandb.sh new file mode 100755 index 0000000..ea905c8 --- /dev/null +++ b/webmail/bin/cleandb.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/cleandb.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2010, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Finally remove all db records marked as deleted some time ago | + | | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require INSTALL_PATH.'program/include/clisetup.php'; + +// mapping for table name => primary key +$primary_keys = array( + 'contacts' => "contact_id", + 'contactgroups' => "contactgroup_id", +); + +// connect to DB +$RCMAIL = rcmail::get_instance(); +$db = $RCMAIL->get_dbh(); +$db->db_connect('w'); + +if (!$db->is_connected() || $db->is_error()) { + rcube::raise_error("No DB connection", false, true); +} + +if (!empty($_SERVER['argv'][1])) + $days = intval($_SERVER['argv'][1]); +else + $days = 7; + +// remove all deleted records older than two days +$threshold = date('Y-m-d 00:00:00', time() - $days * 86400); + +foreach (array('contacts','contactgroups','identities') as $table) { + + $sqltable = get_table_name($table); + + // also delete linked records + // could be skipped for databases which respect foreign key constraints + if ($db->db_provider == 'sqlite' + && ($table == 'contacts' || $table == 'contactgroups') + ) { + $pk = $primary_keys[$table]; + $memberstable = get_table_name('contactgroupmembers'); + + $db->query( + "DELETE FROM $memberstable". + " WHERE $pk IN (". + "SELECT $pk FROM $sqltable". + " WHERE del=1 AND changed < ?". + ")", + $threshold); + + echo $db->affected_rows() . " records deleted from '$memberstable'\n"; + } + + // delete outdated records + $db->query("DELETE FROM $sqltable WHERE del=1 AND changed < ?", $threshold); + + echo $db->affected_rows() . " records deleted from '$table'\n"; +} + +?> diff --git a/webmail/bin/decrypt.sh b/webmail/bin/decrypt.sh new file mode 100755 index 0000000..ff7c430 --- /dev/null +++ b/webmail/bin/decrypt.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/decrypt.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2005-2009, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Decrypt the encrypted parts of the HTTP Received: headers | + | | + +-----------------------------------------------------------------------+ + | Author: Tomas Tevesz <ice@extreme.hu> | + +-----------------------------------------------------------------------+ +*/ + +/** + * If http_received_header_encrypt is configured, the IP address and the + * host name of the added Received: header is encrypted with 3DES, to + * protect information that some could consider sensitve, yet their + * availability is a must in some circumstances. + * + * Such an encrypted Received: header might look like: + * + * Received: from DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ== + * [my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4] + * with HTTP/1.1 (POST); Thu, 14 May 2009 19:17:28 +0200 + * + * In this example, the two encrypted components are the sender host name + * (DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ==) and the IP + * address (my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4). + * + * Using this tool, they can be decrypted into plain text: + * + * $ bin/decrypt.sh 'my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4' \ + * > 'DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ==' + * 84.3.187.208 + * 5403BBD0.catv.pool.telekom.hu + * $ + * + * Thus it is known that this particular message was sent by 84.3.187.208, + * having, at the time of sending, the name of 5403BBD0.catv.pool.telekom.hu. + * + * If (most likely binary) junk is shown, then + * - either the encryption password has, between the time the mail was sent + * and 'now', changed, or + * - you are dealing with counterfeit header data. + */ + +define('INSTALL_PATH', realpath(dirname(__FILE__).'/..') . '/'); + +require INSTALL_PATH . 'program/include/clisetup.php'; + +if ($argc < 2) { + die("Usage: " . basename($argv[0]) . " encrypted-hdr-part [encrypted-hdr-part ...]\n"); +} + +$RCMAIL = rcmail::get_instance(); + +for ($i = 1; $i < $argc; $i++) { + printf("%s\n", $RCMAIL->decrypt($argv[$i])); +}; diff --git a/webmail/bin/exportgettext.sh b/webmail/bin/exportgettext.sh new file mode 100755 index 0000000..c1e6302 --- /dev/null +++ b/webmail/bin/exportgettext.sh @@ -0,0 +1,236 @@ +#!/usr/bin/env php +<?php +/* + + +-----------------------------------------------------------------------+ + | bin/exportgettext.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2011, The Roundcube Dev Team | + | Licensed under the GNU General Public License | + | | + | PURPOSE: | + | Export PHP-based localization files to PO files for gettext | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); +require INSTALL_PATH.'program/include/clisetup.php'; + +if ($argc < 2) { + die("Usage: " . basename($argv[0]) . " SRCDIR DESTDIR\n"); +} + +$srcdir = unslashify(realpath($argv[1])); +$destdir = unslashify($argv[2]); +$layout = 'launchpad'; # or 'narro'; +$langcode_map = array( + 'hy_AM' => 'hy', + 'ar_SA' => 'ar', + 'az_AZ' => 'az', + 'bg_BG' => 'bg', + 'bs_BA' => 'bs', + 'ca_ES' => 'ca', + 'cs_CZ' => 'cs', + 'cy_GB' => 'cy', + 'da_DK' => 'da', + 'et_EE' => 'et', + 'el_GR' => 'el', + 'eu_ES' => 'eu', + 'fa_IR' => 'fa', + 'ga_IE' => 'ga', + 'ka_GE' => 'ka', + 'gl_ES' => 'gl', + 'he_IL' => 'he', + 'hi_IN' => 'hi', + 'hr_HR' => 'hr', + 'ja_JP' => 'ja', + 'ko_KR' => 'ko', + 'km_KH' => 'km', + 'ms_MY' => 'ms', + 'mr_IN' => 'mr', + 'pl_PL' => 'pl', + 'si_LK' => 'si', + 'sl_SI' => 'sl', + 'sq_AL' => 'sq', + 'sr_CS' => 'sr', + 'sv_SE' => 'sv', + 'uk_UA' => 'uk', + 'vi_VN' => 'vi', +); + + +// converting roundcube localization dir +if (is_dir($srcdir.'/en_US')) { + load_en_US($srcdir.'/en_US'); + + foreach (glob($srcdir.'/*') as $locdir) { + if (is_dir($locdir)) { + $lang = basename($locdir); + //echo "$locdir => $destdir$lang\n"; + convert_dir($locdir, $destdir . ($layout != 'launchpad' ? $lang : '')); + } + } +} +// converting single localization directory +else if (is_dir($srcdir)) { + if (is_file($srcdir.'/en_US.inc')) // plugin localization + load_en_US($srcdir.'/en_US.inc'); + else + load_en_US(realpath($srcdir.'/../en_US')); // single language + convert_dir($srcdir, $destdir); +} +// converting a single file +else if (is_file($srcdir)) { + //load_en_US(); + convert_file($srcdir, $destdir); +} + + +/** + * Load en_US localization which is used to build msgids + */ +function load_en_US($fn) +{ + $texts = array(); + + if (is_dir($fn)) { + foreach (glob($fn.'/*.inc') as $ifn) { + include($ifn); + $texts = array_merge($texts, (array)$labels, (array)$messages); + } + } + else if (is_file($fn)) { + include($fn); + $texts = array_merge($texts, (array)$labels, (array)$messages); + } + + $GLOBALS['en_US'] = $texts; +} + +/** + * Convert all .inc files in the given src directory + */ +function convert_dir($indir, $outdir) +{ + global $layout; + + if (!is_dir($outdir)) // attempt to create destination dir + mkdir($outdir, 0777, true); + + foreach (glob($indir.'/*.inc') as $fn) { + $filename = basename($fn); + + // create subdir for each template (launchpad rules) + if ($layout == 'launchpad' && preg_match('/^(labels|messages)/', $filename, $m)) { + $lang = end(explode('/', $indir)); + $destdir = $outdir . '/' . $m[1]; + if (!is_dir($destdir)) + mkdir($destdir, 0777, true); + $outfn = $destdir . '/' . $lang . '.po'; + } + else { + $outfn = $outdir . '/' . preg_replace('/\.[a-z0-9]+$/i', '', basename($fn)) . '.po'; + } + + convert_file($fn, $outfn); + } +} + +/** + * Convert the given Roundcube localization file into a gettext .po file + */ +function convert_file($fn, $outfn) +{ + global $layout, $langcode_map; + + $basename = basename($fn); + $srcname = str_replace(INSTALL_PATH, '', $fn); + $product = preg_match('!plugins/(\w+)!', $srcname, $m) ? 'roundcube-plugin-' . $m[1] : 'roundcubemail'; + $lang = preg_match('!/([a-z]{2}(_[A-Z]{2})?)[./]!', $outfn, $m) ? $m[1] : ''; + $labels = $messages = $seen = array(); + + if (is_dir($outfn)) + $outfn .= '/' . $basename . '.po'; + + // launchpad requires the template file to have the same name as the directory + if (strstr($outfn, '/en_US') && $layout == 'launchpad') { + $a = explode('/', $outfn); + array_pop($a); + $templ = end($a); + $a[] = $templ . '.pot'; + $outfn = join('/', $a); + $is_pot = true; + } + // launchpad is very picky about file names + else if ($layout == 'launchpad' && preg_match($regex = '!/([a-z]{2})_([A-Z]{2})!', $outfn, $m)) { + if ($shortlang = $langcode_map[$lang]) + $outfn = preg_replace($regex, '/'.$shortlang, $outfn); + else if ($m[1] == strtolower($m[2])) + $outfn = preg_replace($regex, '/\1', $outfn); + } + + include($fn); + $texts = array_merge($labels, $messages); + + // write header + $header = <<<EOF +# Converted from Roundcube PHP localization files +# Copyright (C) 2011 The Roundcube Dev Team +# This file is distributed under the same license as the Roundcube package. +# +#: %s +msgid "" +msgstr "" +"Project-Id-Version: %s\\n" +"Report-Msgid-Bugs-To: \\n" +"%s: %s\\n" +"Last-Translator: \\n" +"Language-Team: Translations <hello@roundcube.net>\\n" +"Language: %s\\n" +"Content-Type: text/plain; charset=UTF-8\\n" +"Content-Transfer-Encoding: 8bit\\n" +EOF; + + $out = sprintf($header, $srcname, $product, $is_pot ? "POT-Creation-Date" : "PO-Revision-Date", date('c'), $shortlang ? $shortlang : $lang); + $out .= "\n"; + + $messages = array(); + foreach ((array)$texts as $label => $msgstr) { + $msgid = $is_pot ? $msgstr : ($GLOBALS['en_US'][$label] ?: $label); + $messages[$msgid][] = $label; + } + + foreach ($messages as $msgid => $labels) { + $out .= "\n"; + foreach ($labels as $label) + $out .= "#: $srcname:$label\n"; + $msgstr = $texts[$label]; + $out .= 'msgid ' . gettext_quote($msgid) . "\n"; + $out .= 'msgstr ' . gettext_quote(!$is_pot ? $msgstr : '') . "\n"; + } + + if ($outfn == '-') + echo $out; + else { + echo "$fn\t=>\t$outfn\n"; + file_put_contents($outfn, $out); + } +} + +function gettext_quote($str) +{ + $out = ""; + $lines = explode("\n", wordwrap(stripslashes($str))); + $last = count($lines) - 1; + foreach ($lines as $i => $line) + $out .= '"' . addcslashes($line, '"') . ($i < $last ? ' ' : '') . "\"\n"; + return rtrim($out); +} + +?> diff --git a/webmail/bin/importgettext.sh b/webmail/bin/importgettext.sh new file mode 100755 index 0000000..cda1f6e --- /dev/null +++ b/webmail/bin/importgettext.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env php +<?php +/* + + +-----------------------------------------------------------------------+ + | bin/importgettext.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2011, The Roundcube Dev Team | + | Licensed under the GNU General Public License | + | | + | PURPOSE: | + | Import localizations from gettext PO format | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ + + $Id$ + +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); +require INSTALL_PATH.'program/include/clisetup.php'; + +if ($argc < 2) { + die("Usage: " . basename($argv[0]) . " SRCDIR\n"); +} + +$srcdir = unslashify(realpath($argv[1])); + +if (is_dir($srcdir)) { + $out = import_dir($srcdir); +} +else if (is_file($srcdir)) { + $out = import_file($srcdir); +} + +// write output files +foreach ($out as $outfn => $texts) { + $lang = preg_match('!/([a-z]{2}(_[A-Z]{2})?)[./]!', $outfn, $m) ? $m[1] : ''; + $varname = strpos($outfn, 'messages.inc') !== false ? 'messages' : 'labels'; + + $header = <<<EOF +<?php + +/* + +-----------------------------------------------------------------------+ + | localization/%s/%-51s| + | | + | Language file of the Roundcube Webmail client | + | Copyright (C) %s, The Roundcube Dev Team | + | Licensed under the GNU General Public License | + | | + +-----------------------------------------------------------------------+ + | Author: %-62s| + +-----------------------------------------------------------------------+ +*/ + +$%s = array(); + +EOF; + + $author = preg_replace('/\s*<Unknown>/i', '', $texts['_translator']); + $output = sprintf($header, $lang, $varname.'.inc', date('Y'), $author, $varname); + + foreach ($texts as $label => $value) { + if (is_array($value)) { var_dump($outfn, $label, $value); exit; } + if ($label[0] != '_' && strlen($value)) + $output .= sprintf("\$%s['%s'] = '%s';\n", $varname, $label, strtr(addcslashes($value, "'"), array("\r" => '', "\n" => '\n'))); + } + + $output .= "\n"; + $dir = dirname($outfn); + @mkdir($dir, 664, true); + if (file_put_contents($outfn, $output)) + echo "-> $outfn\n"; +} + + +/** + * Convert all .po files in the given src directory + */ +function import_dir($indir) +{ + $out = array(); + foreach (glob($indir.'/*.po') as $fn) { + $out = array_merge_recursive($out, import_file($fn)); + } + return $out; +} + +/** + * Convert the given .po file into a Roundcube localization array + */ +function import_file($fn) +{ + $out = array(); + $lines = file($fn); + $language = ''; + $translator = ''; + + // get language code from file name + if (preg_match('/-([a-z_]+).po$/i', $fn, $m)) + $language = expand_langcode($m[1]); + + $is_header = true; + $msgid = null; + $msgstr = ''; + $dests = array(); + foreach ($lines as $i => $line) { + $line = trim($line); + + // parse header + if ($is_header && $line[0] == '"') { + list($key, $val) = explode(": ", preg_replace('/\\\n$/', '', trim($line, '"')), 2); + switch (strtolower($key)) { + case 'language': + $language = expand_langcode($val); + break; + case 'last-translator': + $translator = $val; + break; + } + } + + // empty line + if ($line == '') { + if ($msgid && $dests) { + foreach ($dests as $dest) { + list($file, $label) = explode(':', $dest); + $out[$file][$label] = $msgstr; + } + } + + $msgid = null; + $msgstr = ''; + $dests = array(); + } + + // meta line + if ($line[0] == '#') { + $value = trim(substr($line, 2)); + if ($line[1] == ':') + $dests[] = str_replace('en_US', $language, $value); + } + else if (strpos($line, 'msgid') === 0) { + $msgid = gettext_decode(substr($line, 6)); + + if (!empty($msgid)) + $is_header = false; + } + else if (strpos($line, 'msgstr') === 0) { + $msgstr = gettext_decode(substr($line, 7)); + } + else if ($msgid && $line[0] == '"') { + $msgstr .= gettext_decode($line); + } + else if ($msgid !== null && $line[0] == '"') { + $msgid .= gettext_decode($line); + } + } + + if ($msgid && $dests) { + foreach ($dests as $dest) { + list($file, $label) = explode(':', $dest); + $out[$file][$label] = $msgstr; + $out[$file]['_translator'] = $translator; + } + } + + return $language ? $out : array(); +} + + +function gettext_decode($str) +{ + return stripslashes(trim($str, '"')); +} + +/** + * Translate two-chars language codes to our internally used language identifiers + */ +function expand_langcode($lang) +{ + static $rcube_language_aliases, $rcube_languages; + + if (!$rcube_language_aliases) + include(INSTALL_PATH . 'program/localization/index.inc'); + + if ($rcube_language_aliases[$lang]) + return $rcube_language_aliases[$lang]; + else if (strlen($lang) == 2 && !isset($rcube_languages[$lang])) + return strtolower($lang) . '_' . strtoupper($lang); + else + return $lang; +} + + +?> diff --git a/webmail/bin/indexcontacts.sh b/webmail/bin/indexcontacts.sh new file mode 100755 index 0000000..413dc4b --- /dev/null +++ b/webmail/bin/indexcontacts.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/indexcontacts.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2011, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Update the fulltext index for all contacts of the internal | + | address book. | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH.'program/include/clisetup.php'; +ini_set('memory_limit', -1); + +// connect to DB +$RCMAIL = rcmail::get_instance(); + +$db = $RCMAIL->get_dbh(); +$db->db_connect('w'); + +if (!$db->is_connected() || $db->is_error()) { + rcube::raise_error("No DB connection", false, true); +} + +// iterate over all users +$sql_result = $db->query("SELECT user_id FROM " . $RCMAIL->config->get('db_table_users', 'users')." WHERE 1=1"); +while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) { + echo "Indexing contacts for user " . $sql_arr['user_id'] . "..."; + + $contacts = new rcube_contacts($db, $sql_arr['user_id']); + $contacts->set_pagesize(9999); + + $result = $contacts->list_records(); + while ($result->count && ($row = $result->next())) { + unset($row['words']); + $contacts->update($row['ID'], $row); + } + + echo "done.\n"; +} + +?> diff --git a/webmail/bin/installto.sh b/webmail/bin/installto.sh new file mode 100755 index 0000000..8e1ab1f --- /dev/null +++ b/webmail/bin/installto.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/installto.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2012, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Update an existing Roundcube installation with files from | + | this version | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; + +$target_dir = unslashify($_SERVER['argv'][1]); + +if (empty($target_dir) || !is_dir(realpath($target_dir))) + rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh <TARGET>", false, true); + +// 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)) + rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true); + +$oldversion = $m[1]; + +if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>=')) + rcube::raise_error("Installation at target location is up-to-date!", false, true); + +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') as $dir) { + if (!system("rsync -avC " . 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.md','UPGRADING','LICENSE') as $file) { + if (!system("rsync -av " . INSTALL_PATH . "$file $target_dir/$file")) { + $err = true; + break; + } + } + echo "done.\n\n"; + + if (is_dir("$target_dir/skins/default")) { + echo "Removing old default skin..."; + system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default"); + foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) { + $plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir); + if (is_dir("$target_dir/$plugin_skin_dir/classic")) + system("rm -rf $target_dir/$plugin_skin_dir/default"); + } + 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/webmail/bin/jsshrink.sh b/webmail/bin/jsshrink.sh new file mode 100755 index 0000000..1d77ff3 --- /dev/null +++ b/webmail/bin/jsshrink.sh @@ -0,0 +1,67 @@ +#!/bin/sh +JS_DIR=`dirname "$0"`/../program/js +JAR_DIR='/tmp' +LANG_IN='ECMASCRIPT3' +CLOSURE_COMPILER_URL='http://closure-compiler.googlecode.com/files/compiler-latest.zip' + +do_shrink() { + rm -f "$2" + java -jar $JAR_DIR/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js="$1" --js_output_file="$2" --language_in="$3" +} + +if [ ! -d "$JS_DIR" ]; then + echo "Directory $JS_DIR not found." + exit 1 +fi + +if [ ! -w "$JAR_DIR" ]; then + JAR_DIR=`dirname "$0"` +fi + +if java -version >/dev/null 2>&1; then + : +else + echo "Java not found. Please ensure that the 'java' program is in your PATH." + exit 1 +fi + +if [ ! -r "$JAR_DIR/compiler.jar" ]; then + if which wget >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then + wget "$CLOSURE_COMPILER_URL" -O "/tmp/$$.zip" + elif which curl >/dev/null 2>&1 && which unzip >/dev/null 2>&1; then + curl "$CLOSURE_COMPILER_URL" -o "/tmp/$$.zip" + else + echo "Please download $CLOSURE_COMPILER_URL and extract compiler.jar to $JAR_DIR/." + exit 1 + fi + (cd $JAR_DIR && unzip "/tmp/$$.zip" "compiler.jar") + rm -f "/tmp/$$.zip" +fi + +# compress single file from argument +if [ $# -gt 0 ]; then + JS_DIR=`dirname "$1"` + JS_FILE="$1" + + if [ $# -gt 1 ]; then + LANG_IN="$2" + fi + + if [ ! -r "${JS_FILE}.src" ]; then + mv "$JS_FILE" "${JS_FILE}.src" + fi + echo "Shrinking $JS_FILE" + do_shrink "${JS_FILE}.src" "$JS_FILE" "$LANG_IN" + exit +fi + +# default: compress application scripts +for fn in app common googiespell list; do + if [ -r "$JS_DIR/${fn}.js.src" ]; then + echo "$JS_DIR/${fn}.js.src already exists, not overwriting" + else + mv "$JS_DIR/${fn}.js" "$JS_DIR/${fn}.js.src" + fi + echo "Shrinking $JS_DIR/${fn}.js" + do_shrink "$JS_DIR/${fn}.js.src" "$JS_DIR/${fn}.js" "$LANG_IN" +done diff --git a/webmail/bin/jsunshrink.sh b/webmail/bin/jsunshrink.sh new file mode 100755 index 0000000..9d77550 --- /dev/null +++ b/webmail/bin/jsunshrink.sh @@ -0,0 +1,14 @@ +#!/bin/sh +JS_DIR=`dirname "$0"`/../program/js + +if [ ! -d "$JS_DIR" ]; then + echo "Directory $JS_DIR not found." + exit 1 +fi + +for fn in app common googiespell list; do + if [ -r "$JS_DIR/${fn}.js.src" ]; then + mv "$JS_DIR/${fn}.js.src" "$JS_DIR/${fn}.js" + echo "Reverted $JS_DIR/${fn}.js" + fi +done diff --git a/webmail/bin/moduserprefs.sh b/webmail/bin/moduserprefs.sh new file mode 100755 index 0000000..049372c --- /dev/null +++ b/webmail/bin/moduserprefs.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/moduserprefs.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2012, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Bulk-change settings stored in user preferences | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH.'program/include/clisetup.php'; + +function print_usage() +{ + print "Usage: moduserprefs.sh [--user=user-id] pref-name [pref-value|--delete]\n"; + print "--user User ID in local database\n"; + print "--delete Unset the given preference\n"; +} + + +// get arguments +$args = rcube_utils::get_opt(array('u' => 'user', 'd' => 'delete')); + +if ($_SERVER['argv'][1] == 'help') { + print_usage(); + exit; +} +else if (empty($args[0]) || (!isset($args[1]) && !$args['delete'])) { + print "Missing required parameters.\n"; + print_usage(); + exit; +} + +$pref_name = trim($args[0]); +$pref_value = $args['delete'] ? null : trim($args[1]); + +// connect to DB +$rcmail = rcmail::get_instance(); + +$db = $rcmail->get_dbh(); +$db->db_connect('w'); + +if (!$db->is_connected() || $db->is_error()) + die("No DB connection\n" . $db->is_error()); + +$query = '1=1'; + +if ($args['user']) + $query = 'user_id=' . intval($args['user']); + +// iterate over all users +$sql_result = $db->query("SELECT * FROM " . $rcmail->config->get('db_table_users', 'users')." WHERE $query"); +while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) { + echo "Updating prefs for user " . $sql_arr['user_id'] . "..."; + + $user = new rcube_user($sql_arr['user_id'], $sql_arr); + $prefs = $old_prefs = $user->get_prefs(); + + $prefs[$pref_name] = $pref_value; + + if ($prefs != $old_prefs) { + $user->save_prefs($prefs); + echo "saved.\n"; + } + else { + echo "nothing changed.\n"; + } +} + +?> diff --git a/webmail/bin/msgexport.sh b/webmail/bin/msgexport.sh new file mode 100755 index 0000000..e98e5fe --- /dev/null +++ b/webmail/bin/msgexport.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env php +<?php + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); +ini_set('memory_limit', -1); + +require_once INSTALL_PATH.'program/include/clisetup.php'; + +function print_usage() +{ + print "Usage: msgexport -h imap-host -u user-name -m mailbox name\n"; + print "--host IMAP host\n"; + print "--user IMAP user name\n"; + print "--mbox Folder name, set to '*' for all\n"; + print "--file Output file\n"; +} + +function vputs($str) +{ + $out = $GLOBALS['args']['file'] ? STDOUT : STDERR; + fwrite($out, $str); +} + +function progress_update($pos, $max) +{ + $percent = round(100 * $pos / $max); + vputs(sprintf("%3d%% [%-51s] %d/%d\033[K\r", $percent, @str_repeat('=', $percent / 2) . '>', $pos, $max)); +} + +function export_mailbox($mbox, $filename) +{ + global $IMAP; + + $IMAP->set_folder($mbox); + + $index = $IMAP->index($mbox, null, 'ASC'); + $count = $index->count(); + $index = $index->get(); + + vputs("Getting message list of {$mbox}..."); + vputs("$count messages\n"); + + if ($filename) + { + if (!($out = fopen($filename, 'w'))) + { + vputs("Cannot write to output file\n"); + return; + } + vputs("Writing to $filename\n"); + } + else + $out = STDOUT; + + for ($i = 0; $i < $count; $i++) + { + $headers = $IMAP->get_message_headers($index[$i]); + $from = current(rcube_mime::decode_address_list($headers->from, 1, false)); + + fwrite($out, sprintf("From %s %s UID %d\n", $from['mailto'], $headers->date, $headers->uid)); + fwrite($out, $IMAP->print_raw_body($headers->uid)); + fwrite($out, "\n\n\n"); + + progress_update($i+1, $count); + } + vputs("\ncomplete.\n"); + + if ($filename) + fclose($out); +} + + +// get arguments +$opts = array('h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file'); +$args = rcube_utils::get_opt($opts) + array('host' => 'localhost', 'mbox' => 'INBOX'); + +if ($_SERVER['argv'][1] == 'help') +{ + print_usage(); + exit; +} +else if (!$args['host']) +{ + vputs("Missing required parameters.\n"); + print_usage(); + exit; +} + +// prompt for username if not set +if (empty($args['user'])) +{ + vputs("IMAP user: "); + $args['user'] = trim(fgets(STDIN)); +} + +// prompt for password +$args['pass'] = rcube_utils::prompt_silent("Password: "); + + +// parse $host URL +$a_host = parse_url($args['host']); +if ($a_host['host']) +{ + $host = $a_host['host']; + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE; + $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); +} +else +{ + $host = $args['host']; + $imap_port = 143; +} + +// instantiate IMAP class +$IMAP = new rcube_imap(null); + +// try to connect to IMAP server +if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) +{ + vputs("IMAP login successful.\n"); + + $filename = null; + $mailboxes = $args['mbox'] == '*' ? $IMAP->list_folders(null) : array($args['mbox']); + + foreach ($mailboxes as $mbox) + { + if ($args['file']) + $filename = preg_replace('/\.[a-z0-9]{3,4}$/i', '', $args['file']) . asciiwords($mbox) . '.mbox'; + else if ($args['mbox'] == '*') + $filename = asciiwords($mbox) . '.mbox'; + + if ($args['mbox'] == '*' && in_array(strtolower($mbox), array('junk','spam','trash'))) + continue; + + export_mailbox($mbox, $filename); + } +} +else +{ + vputs("IMAP login failed.\n"); +} + +?> diff --git a/webmail/bin/msgimport.sh b/webmail/bin/msgimport.sh new file mode 100755 index 0000000..1fcc346 --- /dev/null +++ b/webmail/bin/msgimport.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env php +<?php + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); +ini_set('memory_limit', -1); + +require_once INSTALL_PATH.'program/include/clisetup.php'; + +function print_usage() +{ + print "Usage: msgimport -h imap-host -u user-name -m mailbox -f message-file\n"; + print "--host IMAP host\n"; + print "--user IMAP user name\n"; + print "--mbox Target mailbox\n"; + print "--file Message file to upload\n"; +} + + +// get arguments +$opts = array('h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file'); +$args = rcube_utils::get_opt($opts) + array('host' => 'localhost', 'mbox' => 'INBOX'); + +if ($_SERVER['argv'][1] == 'help') +{ + print_usage(); + exit; +} +else if (!($args['host'] && $args['file'])) +{ + print "Missing required parameters.\n"; + print_usage(); + exit; +} +else if (!is_file($args['file'])) +{ + rcube::raise_error("Cannot read message file.", false, true); +} + +// prompt for username if not set +if (empty($args['user'])) +{ + //fwrite(STDOUT, "Please enter your name\n"); + echo "IMAP user: "; + $args['user'] = trim(fgets(STDIN)); +} + +// prompt for password +if (empty($args['pass'])) +{ + $args['pass'] = rcube_utils::prompt_silent("Password: "); +} + +// parse $host URL +$a_host = parse_url($args['host']); +if ($a_host['host']) +{ + $host = $a_host['host']; + $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE; + $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143); +} +else +{ + $host = $args['host']; + $imap_port = 143; +} + +// instantiate IMAP class +$IMAP = new rcube_imap(null); + +// try to connect to IMAP server +if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) +{ + print "IMAP login successful.\n"; + print "Uploading messages...\n"; + + $count = 0; + $message = $lastline = ''; + + $fp = fopen($args['file'], 'r'); + while (($line = fgets($fp)) !== false) + { + if (preg_match('/^From\s+-/', $line) && $lastline == '') + { + if (!empty($message)) + { + if ($IMAP->save_message($args['mbox'], rtrim($message))) + $count++; + else + rcube::raise_error("Failed to save message to {$args['mbox']}", false, true); + $message = ''; + } + continue; + } + + $message .= $line; + $lastline = rtrim($line); + } + + if (!empty($message) && $IMAP->save_message($args['mbox'], rtrim($message))) + $count++; + + // upload message from file + if ($count) + print "$count messages successfully added to {$args['mbox']}.\n"; + else + print "Adding messages failed!\n"; +} +else +{ + rcube::raise_error("IMAP login failed.", false, true); +} + +?> diff --git a/webmail/bin/update.sh b/webmail/bin/update.sh new file mode 100755 index 0000000..05956b9 --- /dev/null +++ b/webmail/bin/update.sh @@ -0,0 +1,170 @@ +#!/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 General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Check local configuration and database schema after upgrading | + | to a new version | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli <roundcube@gmail.com> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; +require_once INSTALL_PATH . 'installer/rcube_install.php'; + +// get arguments +$opts = rcube_utils::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; + else + $opts['version'] = RCMAIL_VERSION; +} + +if ($opts['version'] && version_compare(version_parse($opts['version']), version_parse(RCMAIL_VERSION), '>=')) + die("Nothing to be done here. Bye!\n"); + + +$RCI = rcube_install::get_instance(); +$RCI->load_config(); + +if ($RCI->configured) { + $success = true; + + if ($messages = $RCI->check_config()) { + $success = false; + $err = 0; + + // list missing config options + if (is_array($messages['missing'])) { + echo "WARNING: Missing config options:\n"; + echo "(These config options should be present in the current configuration)\n"; + + foreach ($messages['missing'] as $msg) { + echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; + $err++; + } + echo "\n"; + } + + // list old/replaced config options + if (is_array($messages['replaced'])) { + echo "WARNING: Replaced config options:\n"; + echo "(These config options have been replaced or renamed)\n"; + + foreach ($messages['replaced'] as $msg) { + echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n"; + $err++; + } + echo "\n"; + } + + // list obsolete config options (just a notice) + if (is_array($messages['obsolete'])) { + echo "NOTICE: Obsolete config options:\n"; + echo "(You still have some obsolete or inexistent properties set. This isn't a problem but should be noticed)\n"; + + foreach ($messages['obsolete'] as $msg) { + echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; + $err++; + } + echo "\n"; + } + + // ask user to update config files + if ($err) { + echo "Do you want me to fix your local configuration? (y/N)\n"; + $input = trim(fgets(STDIN)); + + // positive: let's merge the local config with the defaults + if (strtolower($input) == 'y') { + $copy1 = $copy2 = $write1 = $write2 = false; + + // backup current config + echo ". backing up the current config files...\n"; + $copy1 = copy(RCMAIL_CONFIG_DIR . '/main.inc.php', RCMAIL_CONFIG_DIR . '/main.old.php'); + $copy2 = copy(RCMAIL_CONFIG_DIR . '/db.inc.php', RCMAIL_CONFIG_DIR . '/db.old.php'); + + if ($copy1 && $copy2) { + $RCI->merge_config(); + + echo ". writing " . RCMAIL_CONFIG_DIR . "/main.inc.php...\n"; + $write1 = file_put_contents(RCMAIL_CONFIG_DIR . '/main.inc.php', $RCI->create_config('main', true)); + echo ". writing " . RCMAIL_CONFIG_DIR . "/main.db.php...\n"; + $write2 = file_put_contents(RCMAIL_CONFIG_DIR . '/db.inc.php', $RCI->create_config('db', true)); + } + + // Success! + if ($write1 && $write2) { + echo "Done.\n"; + echo "Your configuration files are now up-to-date!\n"; + + if ($messages['missing']) { + echo "But you still need to add the following missing options:\n"; + foreach ($messages['missing'] as $msg) + echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; + } + } + else { + echo "Failed to write config files!\n"; + echo "Grant write privileges to the current user or update the files manually according to the above messages.\n"; + } + } + else { + echo "Please update your config files manually according to the above messages.\n"; + } + } + + // check dependencies based on the current configuration + if (is_array($messages['dependencies'])) { + echo "WARNING: Dependency check failed!\n"; + echo "(Some of your configuration settings require other options to be configured or additional PHP modules to be installed)\n"; + + foreach ($messages['dependencies'] as $msg) { + echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n"; + } + echo "Please fix your config files and run this script again!\n"; + echo "See ya.\n"; + } + } + + // check database schema + if ($RCI->config['db_dsnw']) { + echo "Executing database schema update.\n"; + system(INSTALL_PATH . "bin/updatedb.sh --package=roundcube --version=" . $opts['version'] + . " --dir=" . INSTALL_PATH . DIRECTORY_SEPARATOR . "SQL", $res); + + $success = !$res; + } + + // index contacts for fulltext searching + if (version_compare(version_parse($opts['version']), '0.6.0', '<')) { + system(INSTALL_PATH . 'bin/indexcontacts.sh'); + } + + if ($success) { + echo "This instance of Roundcube is up-to-date.\n"; + echo "Have fun!\n"; + } +} +else { + echo "This instance of Roundcube is not yet configured!\n"; + echo "Open http://url-to-roundcube/installer/ in your browser and follow the instuctions.\n"; +} + +?> diff --git a/webmail/bin/updatecss.sh b/webmail/bin/updatecss.sh new file mode 100755 index 0000000..53d237c --- /dev/null +++ b/webmail/bin/updatecss.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/updatecss.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2010-2013, The Roundcube Dev Team | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Update cache-baster marks for css background images | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; + +// get arguments +$opts = rcube_utils::get_opt(array( + 'd' => 'dir', +)); + +if (empty($opts['dir'])) { + print "Skin directory not specified (--dir). Using skins/ and plugins/*/skins/.\n"; + + $dir = INSTALL_PATH . 'skins'; + $dir_p = INSTALL_PATH . 'plugins'; + $skins = glob("$dir/*", GLOB_ONLYDIR); + $skins_p = glob("$dir_p/*/skins/*", GLOB_ONLYDIR); + + $dirs = array_merge($skins, $skins_p); +} +// Check if directory exists +else if (!file_exists($opts['dir'])) { + rcube::raise_error("Specified directory doesn't exist.", false, true); +} +else { + $dirs = array($opts['dir']); +} + +foreach ($dirs as $dir) { + $img_dir = $dir . '/images'; + if (!file_exists($img_dir)) { + continue; + } + + $files = get_files($dir); + $images = get_images($img_dir); + $find = array(); + $replace = array(); + + // build regexps array + foreach ($images as $path => $sum) { + $path_ex = str_replace('.', '\\.', $path); + $find[] = "#url\(['\"]?images/$path_ex(\?v=[a-f0-9-\.]+)?['\"]?\)#"; + $replace[] = "url(images/$path?v=$sum)"; + } + + foreach ($files as $file) { + $file = $dir . '/' . $file; + print "File: $file\n"; + $content = file_get_contents($file); + $content = preg_replace($find, $replace, $content, -1, $count); + if ($count) { + file_put_contents($file, $content); + } + } +} + + +function get_images($dir) +{ + $images = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(gif|ico|png|jpg|jpeg)$/', $file, $m)) { + $filepath = "$dir/$file"; + $images[$file] = substr(md5_file($filepath), 0, 4) . '.' . filesize($filepath); + print "Image: $filepath ({$images[$file]})\n"; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_images($dir . '/' . $file) as $img => $sum) { + $images[$file . '/' . $img] = $sum; + } + } + } + + closedir($dh); + + return $images; +} + +function get_files($dir) +{ + $files = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(css|html)$/', $file, $m)) { + $files[] = $file; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_files($dir . '/' . $file) as $f) { + $files[] = $file . '/' . $f; + } + } + } + + closedir($dh); + + return $files; +} + +?> diff --git a/webmail/bin/updatedb.sh b/webmail/bin/updatedb.sh new file mode 100755 index 0000000..e344cf3 --- /dev/null +++ b/webmail/bin/updatedb.sh @@ -0,0 +1,202 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/updatedb.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2010-2012, The Roundcube Dev Team | + | Copyright (C) 2010-2012, Kolab Systems AG | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Update database schema | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; + +// get arguments +$opts = rcube_utils::get_opt(array( + 'v' => 'version', + 'd' => 'dir', + 'p' => 'package', +)); + +if (empty($opts['dir'])) { + rcube::raise_error("Database schema directory not specified (--dir).", false, true); +} +if (empty($opts['package'])) { + rcube::raise_error("Database schema package name not specified (--package).", false, true); +} + +// Check if directory exists +if (!file_exists($opts['dir'])) { + rcube::raise_error("Specified database schema directory doesn't exist.", false, true); +} + +$RC = rcube::get_instance(); +$DB = rcube_db::factory($RC->config->get('db_dsnw')); + +// Connect to database +$DB->db_connect('w'); +if (!$DB->is_connected()) { + rcube::raise_error("Error connecting to database: " . $DB->is_error(), false, true); +} + +// Read DB schema version from database (if 'system' table exists) +if (in_array($DB->table_name('system'), (array)$DB->list_tables())) { + $DB->query("SELECT " . $DB->quote_identifier('value') + ." FROM " . $DB->quote_identifier($DB->table_name('system')) + ." WHERE " . $DB->quote_identifier('name') ." = ?", + $opts['package'] . '-version'); + + $row = $DB->fetch_array(); + $version = preg_replace('/[^0-9]/', '', $row[0]); +} + +// DB version not found, but release version is specified +if (!$version && $opts['version']) { + // Map old release version string to DB schema version + // Note: This is for backward compat. only, do not need to be updated + $map = array( + '0.1-stable' => 1, + '0.1.1' => 2008030300, + '0.2-alpha' => 2008040500, + '0.2-beta' => 2008060900, + '0.2-stable' => 2008092100, + '0.2.1' => 2008092100, + '0.2.2' => 2008092100, + '0.3-stable' => 2008092100, + '0.3.1' => 2009090400, + '0.4-beta' => 2009103100, + '0.4' => 2010042300, + '0.4.1' => 2010042300, + '0.4.2' => 2010042300, + '0.5-beta' => 2010100600, + '0.5' => 2010100600, + '0.5.1' => 2010100600, + '0.5.2' => 2010100600, + '0.5.3' => 2010100600, + '0.5.4' => 2010100600, + '0.6-beta' => 2011011200, + '0.6' => 2011011200, + '0.7-beta' => 2011092800, + '0.7' => 2011111600, + '0.7.1' => 2011111600, + '0.7.2' => 2011111600, + '0.7.3' => 2011111600, + '0.7.4' => 2011111600, + '0.8-beta' => 2011121400, + '0.8-rc' => 2011121400, + '0.8.0' => 2011121400, + '0.8.1' => 2011121400, + '0.8.2' => 2011121400, + '0.8.3' => 2011121400, + '0.8.4' => 2011121400, + '0.8.5' => 2011121400, + '0.8.6' => 2011121400, + '0.9-beta' => 2012080700, + ); + + $version = $map[$opts['version']]; +} + +// Assume last version before the 'system' table was added +if (empty($version)) { + $version = 2012080700; +} + +$dir = $opts['dir'] . DIRECTORY_SEPARATOR . $DB->db_provider; +if (!file_exists($dir)) { + rcube::raise_error("DDL Upgrade files for " . $DB->db_provider . " driver not found.", false, true); +} + +$dh = opendir($dir); +$result = array(); + +while ($file = readdir($dh)) { + if (preg_match('/^([0-9]+)\.sql$/', $file, $m) && $m[1] > $version) { + $result[] = $m[1]; + } +} +sort($result, SORT_NUMERIC); + +foreach ($result as $v) { + echo "Updating database schema ($v)... "; + $error = update_db_schema($opts['package'], $v, $dir . DIRECTORY_SEPARATOR . "$v.sql"); + + if ($error) { + echo "[FAILED]\n"; + rcube::raise_error("Error in DDL upgrade $v: $error", false, true); + } + echo "[OK]\n"; +} + + +function update_db_schema($package, $version, $file) +{ + global $DB; + + // read DDL file + if ($lines = file($file)) { + $sql = ''; + foreach ($lines as $line) { + if (preg_match('/^--/', $line) || trim($line) == '') + continue; + + $sql .= $line . "\n"; + if (preg_match('/(;|^GO)$/', trim($line))) { + @$DB->query(fix_table_names($sql)); + $sql = ''; + if ($error = $DB->is_error()) { + return $error; + } + } + } + } + + // escape if 'system' table does not exist + if ($version < 2013011000) { + return; + } + + $system_table = $DB->quote_identifier($DB->table_name('system')); + + $DB->query("UPDATE " . $system_table + ." SET " . $DB->quote_identifier('value') . " = ?" + ." WHERE " . $DB->quote_identifier('name') . " = ?", + $version, $package . '-version'); + + if (!$DB->is_error() && !$DB->affected_rows()) { + $DB->query("INSERT INTO " . $system_table + ." (" . $DB->quote_identifier('name') . ", " . $DB->quote_identifier('value') . ")" + ." VALUES (?, ?)", + $package . '-version', $version); + } + + return $DB->is_error(); +} + +function fix_table_names($sql) +{ + global $DB; + + foreach (array('users','identities','contacts','contactgroups','contactgroupmembers','session','cache','cache_index','cache_index','cache_messages','dictionary','searches','system') 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; +} + +?> |
