Merge branch 'master' of github.com:roundcube/roundcubemail

pull/10/merge
Aleksander Machniak 12 years ago
commit a696e86c80

@ -1,22 +1,7 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- Fix bug where domain name was converted to lower-case even with login_lc=false (#1488593)
- Rewritten test scripts for PHPUnit - Rewritten test scripts for PHPUnit
- Fix lower-casing email address on replies (#1488598)
- Fix line separator in exported messages (#1488603)
- Fix XSS issue where plain signatures wasn't secured in HTML mode (#1488613)
- Fix XSS issue where href="javascript:" wasn't secured (#1488613)
- Fix impossible to create message with empty plain text part (#1488610)
- Fix stripped apostrophes when replying in plain text to HTML message (#1488606)
- Fix inactive Save search option after advanced search (#1488607)
- Fix Remove from group option is active for contact search result (#1488608)
- Disable autocapitalization in login form on iPad/iPhone (#1488609)
- Fix focus on the list when list row is clicked (#1488600)
- Added separate From and To columns apart from smart From/To column (#1486891)
- Fix fallback to Larry skin when configured skin isn't available (#1488591)
- Fix (workaround) delete operations with some versions of memcache (#1488592)
- Fix (disable) request validation for spell and spell_html actions
- Add new DB abstraction layer based on PHP PDO, supporting SQLite3 (#1488332) - Add new DB abstraction layer based on PHP PDO, supporting SQLite3 (#1488332)
- Removed PEAR::MDB2 package - Removed PEAR::MDB2 package
- Removed users.alias column, added option ('user_aliases') - Removed users.alias column, added option ('user_aliases')
@ -42,6 +27,24 @@ CHANGELOG Roundcube Webmail
Move global functions from main.inc and rcube_shared.inc into classes Move global functions from main.inc and rcube_shared.inc into classes
Better classes separation Better classes separation
RELEASE 0.8.1
-------------
- Fix bug where domain name was converted to lower-case even with login_lc=false (#1488593)
- Fix lower-casing email address on replies (#1488598)
- Fix line separator in exported messages (#1488603)
- Fix XSS issue where plain signatures wasn't secured in HTML mode (#1488613)
- Fix XSS issue where href="javascript:" wasn't secured (#1488613)
- Fix impossible to create message with empty plain text part (#1488610)
- Fix stripped apostrophes when replying in plain text to HTML message (#1488606)
- Fix inactive Save search option after advanced search (#1488607)
- Fix Remove from group option is active for contact search result (#1488608)
- Disable autocapitalization in login form on iPad/iPhone (#1488609)
- Fix focus on the list when list row is clicked (#1488600)
- Added separate From and To columns apart from smart From/To column (#1486891)
- Fix fallback to Larry skin when configured skin isn't available (#1488591)
- Fix (workaround) delete operations with some versions of memcache (#1488592)
- Fix (disable) request validation for spell and spell_html actions
RELEASE 0.8.0 RELEASE 0.8.0
------------- -------------
- Don't show product version on login screen (can be enabled by config) - Don't show product version on login screen (can be enabled by config)

@ -27,11 +27,7 @@ class hide_blockquote extends rcube_plugin
&& ($limit = $rcmail->config->get('hide_blockquote_limit')) && ($limit = $rcmail->config->get('hide_blockquote_limit'))
) { ) {
// include styles // include styles
$skin = $rcmail->config->get('skin'); $this->include_stylesheet($this->local_skin_path() . "/style.css");
if (!file_exists($this->home."/skins/$skin/style.css")) {
$skin = 'default';
}
$this->include_stylesheet("skins/$skin/style.css");
// Script and localization // Script and localization
$this->include_script('hide_blockquote.js'); $this->include_script('hide_blockquote.js');

@ -25,7 +25,8 @@
* Base class of the Roundcube Framework * Base class of the Roundcube Framework
* implemented as singleton * implemented as singleton
* *
* @package Core * @package Framework
* @subpackage Core
*/ */
class rcube class rcube
{ {
@ -49,7 +50,7 @@ class rcube
/** /**
* Instace of database class. * Instace of database class.
* *
* @var rcube_pdo * @var rcube_db
*/ */
public $db; public $db;
@ -107,6 +108,7 @@ class rcube
* This implements the 'singleton' design pattern * This implements the 'singleton' design pattern
* *
* @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants * @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants
*
* @return rcube The one and only instance * @return rcube The one and only instance
*/ */
static function get_instance($mode = 0) static function get_instance($mode = 0)
@ -126,7 +128,7 @@ class rcube
protected function __construct() protected function __construct()
{ {
// load configuration // load configuration
$this->config = new rcube_config(); $this->config = new rcube_config;
$this->plugins = new rcube_dummy_plugin_api; $this->plugins = new rcube_dummy_plugin_api;
register_shutdown_function(array($this, 'shutdown')); register_shutdown_function(array($this, 'shutdown'));
@ -160,7 +162,7 @@ class rcube
/** /**
* Get the current database connection * Get the current database connection
* *
* @return rcube_pdo Database connection object * @return rcube_db Database object
*/ */
public function get_dbh() public function get_dbh()
{ {
@ -202,15 +204,17 @@ class rcube
$port = 0; $port = 0;
} }
$this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); $this->mc_available += intval($this->memcache->addServer(
$host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure')));
} }
// test connection and failover (will result in $this->mc_available == 0 on complete failure) // test connection and failover (will result in $this->mc_available == 0 on complete failure)
$this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist
if (!$this->mc_available) if (!$this->mc_available) {
$this->memcache = false; $this->memcache = false;
} }
}
return $this->memcache; return $this->memcache;
} }
@ -226,7 +230,8 @@ class rcube
// only report once // only report once
if (!$seen["$host:$port"]++) { if (!$seen["$host:$port"]++) {
$this->mc_available--; $this->mc_available--;
self::raise_error(array('code' => 604, 'type' => 'db', self::raise_error(array(
'code' => 604, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__, 'line' => __LINE__, 'file' => __FILE__,
'message' => "Memcache failure on host $host:$port"), 'message' => "Memcache failure on host $host:$port"),
true, false); true, false);
@ -263,9 +268,10 @@ class rcube
{ {
$this->smtp = new rcube_smtp(); $this->smtp = new rcube_smtp();
if ($connect) if ($connect) {
$this->smtp->connect(); $this->smtp->connect();
} }
}
/** /**
@ -320,10 +326,12 @@ class rcube
$messages_cache = true; $messages_cache = true;
} }
if ($storage_cache) if ($storage_cache) {
$this->storage->set_caching($storage_cache); $this->storage->set_caching($storage_cache);
if ($messages_cache) }
if ($messages_cache) {
$this->storage->set_messages_caching(true); $this->storage->set_messages_caching(true);
}
// set pagesize from config // set pagesize from config
$pagesize = $this->config->get('mail_pagesize'); $pagesize = $this->config->get('mail_pagesize');
@ -503,22 +511,25 @@ class rcube
public function gettext($attrib, $domain=null) public function gettext($attrib, $domain=null)
{ {
// load localization files if not done yet // load localization files if not done yet
if (empty($this->texts)) if (empty($this->texts)) {
$this->load_language(); $this->load_language();
}
// extract attributes // extract attributes
if (is_string($attrib)) if (is_string($attrib)) {
$attrib = array('name' => $attrib); $attrib = array('name' => $attrib);
}
$name = $attrib['name'] ? $attrib['name'] : ''; $name = $attrib['name'] ? $attrib['name'] : '';
// attrib contain text values: use them from now // attrib contain text values: use them from now
if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) {
$this->texts[$name] = $setval; $this->texts[$name] = $setval;
}
// check for text with domain // check for text with domain
if ($domain && ($text = $this->texts[$domain.'.'.$name])) if ($domain && ($text = $this->texts[$domain.'.'.$name])) {
; }
// text does not exist // text does not exist
else if (!($text = $this->texts[$name])) { else if (!($text = $this->texts[$name])) {
return "[$name]"; return "[$name]";
@ -526,17 +537,21 @@ class rcube
// replace vars in text // replace vars in text
if (is_array($attrib['vars'])) { if (is_array($attrib['vars'])) {
foreach ($attrib['vars'] as $var_key => $var_value) foreach ($attrib['vars'] as $var_key => $var_value) {
$text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text); $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text);
} }
}
// format output // format output
if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst']) if (($attrib['uppercase'] && strtolower($attrib['uppercase'] == 'first')) || $attrib['ucfirst']) {
return ucfirst($text); return ucfirst($text);
else if ($attrib['uppercase']) }
else if ($attrib['uppercase']) {
return mb_strtoupper($text); return mb_strtoupper($text);
else if ($attrib['lowercase']) }
else if ($attrib['lowercase']) {
return mb_strtolower($text); return mb_strtolower($text);
}
return strtr($text, array('\n' => "\n")); return strtr($text, array('\n' => "\n"));
} }
@ -554,8 +569,9 @@ class rcube
public function text_exists($name, $domain = null, &$ref_domain = null) public function text_exists($name, $domain = null, &$ref_domain = null)
{ {
// load localization files if not done yet // load localization files if not done yet
if (empty($this->texts)) if (empty($this->texts)) {
$this->load_language(); $this->load_language();
}
if (isset($this->texts[$name])) { if (isset($this->texts[$name])) {
$ref_domain = ''; $ref_domain = '';
@ -564,12 +580,13 @@ class rcube
// any of loaded domains (plugins) // any of loaded domains (plugins)
if ($domain == '*') { if ($domain == '*') {
foreach ($this->plugins->loaded_plugins() as $domain) foreach ($this->plugins->loaded_plugins() as $domain) {
if (isset($this->texts[$domain.'.'.$name])) { if (isset($this->texts[$domain.'.'.$name])) {
$ref_domain = $domain; $ref_domain = $domain;
return true; return true;
} }
} }
}
// specified domain // specified domain
else if ($domain) { else if ($domain) {
$ref_domain = $domain; $ref_domain = $domain;
@ -579,10 +596,12 @@ class rcube
return false; return false;
} }
/** /**
* Load a localization package * Load a localization package
* *
* @param string Language ID * @param string Language ID
* @param array Additional text labels/messages
*/ */
public function load_language($lang = null, $add = array()) public function load_language($lang = null, $add = array())
{ {
@ -621,15 +640,17 @@ class rcube
} }
// append additional texts (from plugin) // append additional texts (from plugin)
if (is_array($add) && !empty($add)) if (is_array($add) && !empty($add)) {
$this->texts += $add; $this->texts += $add;
} }
}
/** /**
* Check the given string and return a valid language code * Check the given string and return a valid language code
* *
* @param string Language code * @param string Language code
*
* @return string Valid language code * @return string Valid language code
*/ */
protected function language_prop($lang) protected function language_prop($lang)
@ -686,12 +707,14 @@ class rcube
if ($dh = @opendir(INSTALL_PATH . 'program/localization')) { if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {
while (($name = readdir($dh)) !== false) { while (($name = readdir($dh)) !== false) {
if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) {
continue; continue;
}
if ($label = $rcube_languages[$name]) if ($label = $rcube_languages[$name]) {
$sa_languages[$name] = $label; $sa_languages[$name] = $label;
} }
}
closedir($dh); closedir($dh);
} }
} }
@ -711,8 +734,9 @@ class rcube
*/ */
public function encrypt($clear, $key = 'des_key', $base64 = true) public function encrypt($clear, $key = 'des_key', $base64 = true)
{ {
if (!$clear) if (!$clear) {
return ''; return '';
}
/*- /*-
* Add a single canary byte to the end of the clear text, which * Add a single canary byte to the end of the clear text, which
@ -722,7 +746,8 @@ class rcube
$clear = pack("a*H2", $clear, "80"); $clear = pack("a*H2", $clear, "80");
if (function_exists('mcrypt_module_open') && if (function_exists('mcrypt_module_open') &&
($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) { ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))
) {
$iv = $this->create_iv(mcrypt_enc_get_iv_size($td)); $iv = $this->create_iv(mcrypt_enc_get_iv_size($td));
mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
$cipher = $iv . mcrypt_generic($td, $clear); $cipher = $iv . mcrypt_generic($td, $clear);
@ -749,6 +774,7 @@ class rcube
return $base64 ? base64_encode($cipher) : $cipher; return $base64 ? base64_encode($cipher) : $cipher;
} }
/** /**
* Decrypt 3DES-encrypted string * Decrypt 3DES-encrypted string
* *
@ -760,19 +786,22 @@ class rcube
*/ */
public function decrypt($cipher, $key = 'des_key', $base64 = true) public function decrypt($cipher, $key = 'des_key', $base64 = true)
{ {
if (!$cipher) if (!$cipher) {
return ''; return '';
}
$cipher = $base64 ? base64_decode($cipher) : $cipher; $cipher = $base64 ? base64_decode($cipher) : $cipher;
if (function_exists('mcrypt_module_open') && if (function_exists('mcrypt_module_open') &&
($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) { ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))
) {
$iv_size = mcrypt_enc_get_iv_size($td); $iv_size = mcrypt_enc_get_iv_size($td);
$iv = substr($cipher, 0, $iv_size); $iv = substr($cipher, 0, $iv_size);
// session corruption? (#1485970) // session corruption? (#1485970)
if (strlen($iv) < $iv_size) if (strlen($iv) < $iv_size) {
return ''; return '';
}
$cipher = substr($cipher, $iv_size); $cipher = substr($cipher, $iv_size);
mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv); mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
@ -807,10 +836,12 @@ class rcube
return $clear; return $clear;
} }
/** /**
* Generates encryption initialization vector (IV) * Generates encryption initialization vector (IV)
* *
* @param int Vector size * @param int Vector size
*
* @return string Vector string * @return string Vector string
*/ */
private function create_iv($size) private function create_iv($size)
@ -818,8 +849,10 @@ class rcube
// mcrypt_create_iv() can be slow when system lacks entrophy // mcrypt_create_iv() can be slow when system lacks entrophy
// we'll generate IV vector manually // we'll generate IV vector manually
$iv = ''; $iv = '';
for ($i = 0; $i < $size; $i++) for ($i = 0; $i < $size; $i++) {
$iv .= chr(mt_rand(0, 255)); $iv .= chr(mt_rand(0, 255));
}
return $iv; return $iv;
} }
@ -843,20 +876,24 @@ class rcube
*/ */
public function shutdown() public function shutdown()
{ {
foreach ($this->shutdown_functions as $function) foreach ($this->shutdown_functions as $function) {
call_user_func($function); call_user_func($function);
}
if (is_object($this->smtp)) if (is_object($this->smtp)) {
$this->smtp->disconnect(); $this->smtp->disconnect();
}
foreach ($this->caches as $cache) { foreach ($this->caches as $cache) {
if (is_object($cache)) if (is_object($cache)) {
$cache->close(); $cache->close();
} }
}
if (is_object($this->storage)) { if (is_object($this->storage)) {
if ($this->expunge_cache) if ($this->expunge_cache) {
$this->storage->expunge_cache(); $this->storage->expunge_cache();
}
$this->storage->close(); $this->storage->close();
} }
} }
@ -881,6 +918,7 @@ class rcube
* *
* @param $cmd Format string with {keywords} to be replaced * @param $cmd Format string with {keywords} to be replaced
* @param $values (zero, one or more arrays can be passed) * @param $values (zero, one or more arrays can be passed)
*
* @return output of command. shell errors not detectable * @return output of command. shell errors not detectable
*/ */
public static function exec(/* $cmd, $values1 = array(), ... */) public static function exec(/* $cmd, $values1 = array(), ... */)
@ -890,8 +928,9 @@ class rcube
$values = $replacements = array(); $values = $replacements = array();
// merge values into one array // merge values into one array
foreach ($args as $arg) foreach ($args as $arg) {
$values += (array)$arg; $values += (array)$arg;
}
preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER); preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER);
foreach ($matches as $tags) { foreach ($matches as $tags) {
@ -900,16 +939,21 @@ class rcube
if ($option) { if ($option) {
foreach ((array)$values["-$key"] as $key => $value) { foreach ((array)$values["-$key"] as $key => $value) {
if ($value === true || $value === false || $value === null) if ($value === true || $value === false || $value === null) {
$parts[] = $value ? $key : ""; $parts[] = $value ? $key : "";
else foreach ((array)$value as $val) }
else {
foreach ((array)$value as $val) {
$parts[] = "$key " . escapeshellarg($val); $parts[] = "$key " . escapeshellarg($val);
} }
} }
}
}
else { else {
foreach ((array)$values[$key] as $value) foreach ((array)$values[$key] as $value) {
$parts[] = escapeshellarg($value); $parts[] = escapeshellarg($value);
} }
}
$replacements[$tag] = join(" ", $parts); $replacements[$tag] = join(" ", $parts);
} }

@ -20,8 +20,6 @@
*/ */
/** /**
* rcube_browser
*
* Provide details about the client's browser based on the User-Agent header * Provide details about the client's browser based on the User-Agent header
* *
* @package Core * @package Core

@ -336,7 +336,7 @@ abstract class rcube_plugin
public function local_skin_path() public function local_skin_path()
{ {
$rcmail = rcube::get_instance(); $rcmail = rcube::get_instance();
foreach (array($rcmail->config->get('skin'),'default') as $skin) { foreach (array($rcmail->config->get('skin'), 'larry') as $skin) {
$skin_path = 'skins/' . $skin; $skin_path = 'skins/' . $skin;
if (is_dir(realpath(slashify($this->home) . $skin_path))) if (is_dir(realpath(slashify($this->home) . $skin_path)))
break; break;

Loading…
Cancel
Save