summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG7
-rw-r--r--config/main.inc.php.dist4
-rw-r--r--installer/rcube_install.php43
-rw-r--r--program/include/main.inc43
-rw-r--r--program/include/rcube_browser.php24
-rw-r--r--program/include/rcube_config.php7
-rw-r--r--program/include/rcube_smtp.php2
-rw-r--r--program/js/app.js7
-rw-r--r--program/lib/html2text.php96
-rw-r--r--program/steps/addressbook/func.inc2
-rw-r--r--program/steps/mail/search.inc20
-rw-r--r--skins/default/functions.js164
-rw-r--r--tests/mailfunc.php2
13 files changed, 252 insertions, 169 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 71be8a90f..bec2a6147 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,13 @@
CHANGELOG Roundcube Webmail
===========================
+- Use strpos() instead of strstr() when possible (#1488211)
+- Fix handling HTML entities when converting HTML to text (#1488212)
+- Fix fit_string_to_size() renders browser and ui unresponsive (#1488207)
+- Fix handling of invalid characters in request (#1488124)
+- Fix merging some configuration options in update.sh script (#1485864)
+- Fix so TEXT key will remove all HEADER keys in IMAP SEARCH (#1488208)
+- Fix handling contact photo url with https:// prefix (#1488202)
- Fix possible infinite redirect on attachment preview (#1488199)
- Improved clickjacking protection for browsers which don't support X-Frame-Options headers
- Fixed bug where similiar folder names were highlighted wrong (#1487860)
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index d07a3b3c2..e355b2df6 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -653,8 +653,8 @@ $rcmail_config['pagesize'] = 40;
// use this timezone to display date/time
$rcmail_config['timezone'] = 'auto';
-// is daylight saving On?
-$rcmail_config['dst_active'] = (bool)date('I');
+// is daylight saving On? Default: (bool)date('I');
+$rcmail_config['dst_active'] = null;
// prefer displaying HTML messages
$rcmail_config['prefer_html'] = true;
diff --git a/installer/rcube_install.php b/installer/rcube_install.php
index ff3f7a4c3..dbe662acf 100644
--- a/installer/rcube_install.php
+++ b/installer/rcube_install.php
@@ -142,20 +142,22 @@ class rcube_install
foreach ($this->config as $prop => $default) {
- $value = (isset($_POST["_$prop"]) || $this->bool_config_props[$prop]) ? $_POST["_$prop"] : $default;
+ $is_default = !isset($_POST["_$prop"]);
+ $value = !$is_default || $this->bool_config_props[$prop] ? $_POST["_$prop"] : $default;
// convert some form data
- if ($prop == 'debug_level') {
- $val = 0;
- if (is_array($value))
+ if ($prop == 'debug_level' && !$is_default) {
+ if (is_array($value)) {
+ $val = 0;
foreach ($value as $dbgval)
$val += intval($dbgval);
- $value = $val;
+ $value = $val;
+ }
}
else if ($which == 'db' && $prop == 'db_dsnw' && !empty($_POST['_dbtype'])) {
if ($_POST['_dbtype'] == 'sqlite')
$value = sprintf('%s://%s?mode=0646', $_POST['_dbtype'], $_POST['_dbname']{0} == '/' ? '/' . $_POST['_dbname'] : $_POST['_dbname']);
- else
+ else if ($_POST['_dbtype'])
$value = sprintf('%s://%s:%s@%s/%s', $_POST['_dbtype'],
rawurlencode($_POST['_dbuser']), rawurlencode($_POST['_dbpass']), $_POST['_dbhost'], $_POST['_dbname']);
}
@@ -177,9 +179,9 @@ class rcube_install
$value = '%p';
}
else if ($prop == 'default_imap_folders') {
- $value = Array();
+ $value = array();
foreach ($this->config['default_imap_folders'] as $_folder) {
- switch($_folder) {
+ switch ($_folder) {
case 'Drafts': $_folder = $this->config['drafts_mbox']; break;
case 'Sent': $_folder = $this->config['sent_mbox']; break;
case 'Junk': $_folder = $this->config['junk_mbox']; break;
@@ -206,7 +208,7 @@ class rcube_install
// replace the matching line in config file
$out = preg_replace(
'/(\$rcmail_config\[\''.preg_quote($prop).'\'\])\s+=\s+(.+);/Uie',
- "'\\1 = ' . rcube_install::_dump_var(\$value) . ';'",
+ "'\\1 = ' . rcube_install::_dump_var(\$value, \$prop) . ';'",
$out);
}
@@ -299,7 +301,7 @@ class rcube_install
$current = $this->config;
$this->config = array();
$this->load_defaults();
-
+
foreach ($this->replaced_config as $prop => $replacement) {
if (isset($current[$prop])) {
if ($prop == 'skin_path')
@@ -328,9 +330,9 @@ class rcube_install
if ($current['keep_alive'] && $current['session_lifetime'] < $current['keep_alive'])
$current['session_lifetime'] = max(10, ceil($current['keep_alive'] / 60) * 2);
-
+
$this->config = array_merge($this->config, $current);
-
+
foreach ((array)$current['ldap_public'] as $key => $values) {
$this->config['ldap_public'][$key] = $current['ldap_public'][$key];
}
@@ -614,7 +616,22 @@ class rcube_install
}
- static function _dump_var($var) {
+ static function _dump_var($var, $name=null) {
+ // special values
+ switch ($name) {
+ case 'syslog_facility':
+ $list = array(32 => 'LOG_AUTH', 80 => 'LOG_AUTHPRIV', 72 => ' LOG_CRON',
+ 24 => 'LOG_DAEMON', 0 => 'LOG_KERN', 128 => 'LOG_LOCAL0',
+ 136 => 'LOG_LOCAL1', 144 => 'LOG_LOCAL2', 152 => 'LOG_LOCAL3',
+ 160 => 'LOG_LOCAL4', 168 => 'LOG_LOCAL5', 176 => 'LOG_LOCAL6',
+ 184 => 'LOG_LOCAL7', 48 => 'LOG_LPR', 16 => 'LOG_MAIL',
+ 56 => 'LOG_NEWS', 40 => 'LOG_SYSLOG', 8 => 'LOG_USER', 64 => 'LOG_UUCP');
+ if ($val = $list[$var])
+ return $val;
+ break;
+ }
+
+
if (is_array($var)) {
if (empty($var)) {
return 'array()';
diff --git a/program/include/main.inc b/program/include/main.inc
index 25940bd67..714764959 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -640,20 +640,23 @@ function JQ($str)
function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
{
$value = NULL;
-
- if ($source==RCUBE_INPUT_GET && isset($_GET[$fname]))
- $value = $_GET[$fname];
- else if ($source==RCUBE_INPUT_POST && isset($_POST[$fname]))
- $value = $_POST[$fname];
- else if ($source==RCUBE_INPUT_GPC)
- {
+
+ if ($source == RCUBE_INPUT_GET) {
+ if (isset($_GET[$fname]))
+ $value = $_GET[$fname];
+ }
+ else if ($source == RCUBE_INPUT_POST) {
+ if (isset($_POST[$fname]))
+ $value = $_POST[$fname];
+ }
+ else if ($source == RCUBE_INPUT_GPC) {
if (isset($_POST[$fname]))
$value = $_POST[$fname];
else if (isset($_GET[$fname]))
$value = $_GET[$fname];
else if (isset($_COOKIE[$fname]))
$value = $_COOKIE[$fname];
- }
+ }
return parse_input_value($value, $allow_html, $charset);
}
@@ -661,7 +664,7 @@ function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
/**
* Parse/validate input value. See get_input_value()
* Performs stripslashes() and charset conversion if necessary
- *
+ *
* @param string Input value
* @param boolean Allow HTML tags in field value
* @param string Charset to convert into
@@ -687,15 +690,21 @@ function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
else if (get_magic_quotes_gpc() || get_magic_quotes_runtime())
$value = stripslashes($value);
- // remove HTML tags if not allowed
+ // remove HTML tags if not allowed
if (!$allow_html)
$value = strip_tags($value);
-
+
+ $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null;
+
+ // remove invalid characters (#1488124)
+ if ($output_charset == 'UTF-8')
+ $value = rc_utf8_clean($value);
+
// convert to internal charset
- if (is_object($OUTPUT) && $charset)
- return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset);
- else
- return $value;
+ if ($charset && $output_charset)
+ $value = rcube_charset_convert($value, $output_charset, $charset);
+
+ return $value;
}
/**
@@ -711,10 +720,10 @@ function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action')
$src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST);
foreach ($src as $key => $value) {
$fname = $key[0] == '_' ? substr($key, 1) : $key;
- if ($ignore && !preg_match("/($ignore)/", $fname))
+ if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname))
$out[$fname] = get_input_value($key, $mode);
}
-
+
return $out;
}
diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php
index c89c3897f..859f36795 100644
--- a/program/include/rcube_browser.php
+++ b/program/include/rcube_browser.php
@@ -33,19 +33,19 @@ class rcube_browser
$HTTP_USER_AGENT = strtolower($_SERVER['HTTP_USER_AGENT']);
$this->ver = 0;
- $this->win = strstr($HTTP_USER_AGENT, 'win');
- $this->mac = strstr($HTTP_USER_AGENT, 'mac');
- $this->linux = strstr($HTTP_USER_AGENT, 'linux');
- $this->unix = strstr($HTTP_USER_AGENT, 'unix');
+ $this->win = strpos($HTTP_USER_AGENT, 'win') != false;
+ $this->mac = strpos($HTTP_USER_AGENT, 'mac') != false;
+ $this->linux = strpos($HTTP_USER_AGENT, 'linux') != false;
+ $this->unix = strpos($HTTP_USER_AGENT, 'unix') != false;
- $this->opera = strstr($HTTP_USER_AGENT, 'opera');
- $this->ns4 = strstr($HTTP_USER_AGENT, 'mozilla/4') && !stristr($HTTP_USER_AGENT, 'msie');
- $this->ns = ($this->ns4 || strstr($HTTP_USER_AGENT, 'netscape'));
- $this->ie = !$this->opera && stristr($HTTP_USER_AGENT, 'compatible; msie');
- $this->mz = !$this->ie && strstr($HTTP_USER_AGENT, 'mozilla/5');
- $this->chrome = strstr($HTTP_USER_AGENT, 'chrome');
- $this->khtml = strstr($HTTP_USER_AGENT, 'khtml');
- $this->safari = !$this->chrome && ($this->khtml || strstr($HTTP_USER_AGENT, 'safari'));
+ $this->opera = strpos($HTTP_USER_AGENT, 'opera') !== false;
+ $this->ns4 = strpos($HTTP_USER_AGENT, 'mozilla/4') !== false && strpos($HTTP_USER_AGENT, 'msie') === false;
+ $this->ns = ($this->ns4 || strpos($HTTP_USER_AGENT, 'netscape') !== false);
+ $this->ie = !$this->opera && strpos($HTTP_USER_AGENT, 'compatible; msie') !== false;
+ $this->mz = !$this->ie && strpos($HTTP_USER_AGENT, 'mozilla/5') !== false;
+ $this->chrome = strpos($HTTP_USER_AGENT, 'chrome') !== false;
+ $this->khtml = strpos($HTTP_USER_AGENT, 'khtml') !== false;
+ $this->safari = !$this->chrome && ($this->khtml || strpos($HTTP_USER_AGENT, 'safari') !== false);
if ($this->ns || $this->chrome) {
$test = preg_match('/(mozilla|chrome)\/([0-9.]+)/', $HTTP_USER_AGENT, $regs);
diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php
index 01e678150..f80f92c91 100644
--- a/program/include/rcube_config.php
+++ b/program/include/rcube_config.php
@@ -90,11 +90,14 @@ class rcube_config
// enable display_errors in 'show' level, but not for ajax requests
ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4)));
-
+
// set timezone auto settings values
if ($this->prop['timezone'] == 'auto') {
$this->prop['dst_active'] = intval(date('I'));
- $this->prop['_timezone_value'] = date('Z') / 3600 - $this->prop['dst_active'];
+ $this->prop['_timezone_value'] = date('Z') / 3600 - $this->prop['dst_active'];
+ }
+ else if ($this->prop['dst_active'] === null) {
+ $this->prop['dst_active'] = intval(date('I'));
}
// export config data
diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php
index 5c2dd92d2..56b601290 100644
--- a/program/include/rcube_smtp.php
+++ b/program/include/rcube_smtp.php
@@ -381,7 +381,7 @@ class rcube_smtp
$from = $addresses[0];
// Reject envelope From: addresses with spaces.
- if (strstr($from, ' '))
+ if (strpos($from, ' ') !== false)
return false;
$lines[] = $key . ': ' . $value;
diff --git a/program/js/app.js b/program/js/app.js
index 6c0d2cd8d..8ffcf93af 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -5743,10 +5743,13 @@ function rcube_webmail()
});
};
- this.plain2html = function(plainText, id)
+ this.plain2html = function(plain, id)
{
var lock = this.set_busy(true, 'converting');
- $('#'+id).val(plainText ? '<pre>'+plainText+'</pre>' : '');
+
+ plain = plain.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ $('#'+id).val(plain ? '<pre>'+plain+'</pre>' : '');
+
this.set_busy(false, null, lock);
};
diff --git a/program/lib/html2text.php b/program/lib/html2text.php
index 1ab16055b..9fc96eac7 100644
--- a/program/lib/html2text.php
+++ b/program/lib/html2text.php
@@ -145,7 +145,6 @@ class html2text
var $search = array(
"/\r/", // Non-legal carriage return
"/[\n\t]+/", // Newlines and tabs
- '/[ ]{2,}/', // Runs of spaces, pre-handling
'/<script[^>]*>.*?<\/script>/i', // <script>s -- which strip_tags supposedly has problems with
'/<style[^>]*>.*?<\/style>/i', // <style>s -- which strip_tags supposedly has problems with
'/<p[^>]*>/i', // <P>
@@ -161,22 +160,6 @@ class html2text
'/(<table[^>]*>|<\/table>)/i', // <table> and </table>
'/(<tr[^>]*>|<\/tr>)/i', // <tr> and </tr>
'/<td[^>]*>(.*?)<\/td>/i', // <td> and </td>
- '/&(nbsp|#160);/i', // Non-breaking space
- '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
- // Double quotes
- '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes
- '/&gt;/i', // Greater-than
- '/&lt;/i', // Less-than
- '/&(copy|#169);/i', // Copyright
- '/&(trade|#8482|#153);/i', // Trademark
- '/&(reg|#174);/i', // Registered
- '/&(mdash|#151|#8212);/i', // mdash
- '/&(ndash|minus|#8211|#8722);/i', // ndash
- '/&(bull|#149|#8226);/i', // Bullet
- '/&(pound|#163);/i', // Pound sign
- '/&(euro|#8364);/i', // Euro sign
- '/&(amp|#38);/i', // Ampersand: see _converter()
- '/[ ]{2,}/' // Runs of spaces, post-handling
);
/**
@@ -189,7 +172,6 @@ class html2text
var $replace = array(
'', // Non-legal carriage return
' ', // Newlines and tabs
- ' ', // Runs of spaces, pre-handling
'', // <script>s -- which strip_tags supposedly has problems with
'', // <style>s -- which strip_tags supposedly has problems with
"\n\n", // <P>
@@ -205,6 +187,43 @@ class html2text
"\n\n", // <table> and </table>
"\n", // <tr> and </tr>
"\t\t\\1\n", // <td> and </td>
+ );
+
+ /**
+ * List of preg* regular expression patterns to search for,
+ * used in conjunction with $ent_replace.
+ *
+ * @var array $ent_search
+ * @access public
+ * @see $ent_replace
+ */
+ var $ent_search = array(
+ '/&(nbsp|#160);/i', // Non-breaking space
+ '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
+ // Double quotes
+ '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes
+ '/&gt;/i', // Greater-than
+ '/&lt;/i', // Less-than
+ '/&(copy|#169);/i', // Copyright
+ '/&(trade|#8482|#153);/i', // Trademark
+ '/&(reg|#174);/i', // Registered
+ '/&(mdash|#151|#8212);/i', // mdash
+ '/&(ndash|minus|#8211|#8722);/i', // ndash
+ '/&(bull|#149|#8226);/i', // Bullet
+ '/&(pound|#163);/i', // Pound sign
+ '/&(euro|#8364);/i', // Euro sign
+ '/&(amp|#38);/i', // Ampersand: see _converter()
+ '/[ ]{2,}/', // Runs of spaces, post-handling
+ );
+
+ /**
+ * List of pattern replacements corresponding to patterns searched.
+ *
+ * @var array $ent_replace
+ * @access public
+ * @see $ent_search
+ */
+ var $ent_replace = array(
' ', // Non-breaking space
'"', // Double quotes
"'", // Single quotes
@@ -219,7 +238,7 @@ class html2text
'£',
'EUR', // Euro sign. ?
'|+|amp|+|', // Ampersand: see _converter()
- ' ' // Runs of spaces, post-handling
+ ' ', // Runs of spaces, post-handling
);
/**
@@ -303,7 +322,7 @@ class html2text
* @see _build_link_list()
*/
var $_link_list = '';
-
+
/**
* Number of valid links detected in the text, used for plain text
* display (rendered similar to footnotes).
@@ -314,15 +333,15 @@ class html2text
*/
var $_link_count = 0;
- /**
- * Boolean flag, true if a table of link URLs should be listed after the text.
- *
- * @var boolean $_do_links
- * @access private
- * @see html2text()
+ /**
+ * Boolean flag, true if a table of link URLs should be listed after the text.
+ *
+ * @var boolean $_do_links
+ * @access private
+ * @see html2text()
*/
var $_do_links = true;
-
+
/**
* Constructor.
*
@@ -492,15 +511,21 @@ class html2text
// Convert <PRE>
$this->_convert_pre($text);
- // Run our defined search-and-replace
+ // Run our defined tags search-and-replace
$text = preg_replace($this->search, $this->replace, $text);
+ // Run our defined tags search-and-replace with callback
+ $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text);
+
+ // Strip any other HTML tags
+ $text = strip_tags($text, $this->allowed_tags);
+
+ // Run our defined entities/characters search-and-replace
+ $text = preg_replace($this->ent_search, $this->ent_replace, $text);
+
// Replace known html entities
$text = html_entity_decode($text, ENT_COMPAT, 'UTF-8');
- // Run our defined search-and-replace with callback
- $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text);
-
// Remove unknown/unhandled entities (this cannot be done in search-and-replace block)
$text = preg_replace('/&([a-zA-Z0-9]{2,6}|#[0-9]{2,4});/', '', $text);
@@ -508,15 +533,12 @@ class html2text
// This properly handles situation of "&amp;quot;" in input string
$text = str_replace('|+|amp|+|', '&', $text);
- // Strip any other HTML tags
- $text = strip_tags($text, $this->allowed_tags);
-
// Bring down number of empty lines to 2 max
$text = preg_replace("/\n\s+\n/", "\n\n", $text);
$text = preg_replace("/[\n]{3,}/", "\n\n", $text);
// remove leading empty lines (can be produced by eg. P tag on the beginning)
- $text = preg_replace('/^\n+/', '', $text);
+ $text = ltrim($text, "\n");
// Wrap the text to a readable format
// for PHP versions >= 4.0.2. Default width is 75
@@ -544,9 +566,7 @@ class html2text
if ( !$this->_do_links )
return $display;
- if ( substr($link, 0, 7) == 'http://' || substr($link, 0, 8) == 'https://' ||
- substr($link, 0, 7) == 'mailto:'
- ) {
+ if ( preg_match('!^(https?://|mailto:)!', $link) ) {
$this->_link_count++;
$this->_link_list .= '[' . $this->_link_count . "] $link\n";
$additional = ' [' . $this->_link_count . ']';
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 2f1fbb70f..cb5cc63dc 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -705,7 +705,7 @@ function rcmail_contact_photo($attrib)
$RCMAIL->output->set_env('photo_placeholder', $photo_img);
unset($attrib['placeholder']);
- if (strpos($record['photo'], 'http:') === 0)
+ if (preg_match('!^https?://!i', $record['photo']))
$photo_img = $record['photo'];
else if ($record['photo'])
$photo_img = $RCMAIL->url(array('_action' => 'photo', '_cid' => $record['ID'], '_source' => $SOURCE_ID));
diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc
index 2e7fd130c..593eac427 100644
--- a/program/steps/mail/search.inc
+++ b/program/steps/mail/search.inc
@@ -31,6 +31,7 @@ $str = get_input_value('_q', RCUBE_INPUT_GET, true);
$mbox = get_input_value('_mbox', RCUBE_INPUT_GET, true);
$filter = get_input_value('_filter', RCUBE_INPUT_GET);
$headers = get_input_value('_headers', RCUBE_INPUT_GET);
+$subject = array();
$search_request = md5($mbox.$filter.$str);
@@ -70,14 +71,19 @@ else if (preg_match("/^body:.*/i", $str))
list(,$srch) = explode(":", $str);
$subject['text'] = "TEXT";
}
-else if(trim($str))
+else if (strlen(trim($str)))
{
if ($headers) {
- foreach(explode(',', $headers) as $header)
- switch ($header) {
- case 'text': $subject['text'] = 'TEXT'; break;
- default: $subject[$header] = 'HEADER '.strtoupper($header);
+ foreach (explode(',', $headers) as $header) {
+ if ($header == 'text') {
+ // #1488208: get rid of other headers when searching by "TEXT"
+ $subject = array('text' => 'TEXT');
+ break;
}
+ else {
+ $subject[$header] = 'HEADER '.strtoupper($header);
+ }
+ }
// save search modifiers for the current folder to user prefs
$search_mods = $RCMAIL->config->get('search_mods', $SEARCH_MODS_DEFAULT);
@@ -89,9 +95,9 @@ else if(trim($str))
}
}
-$search = $srch ? trim($srch) : trim($str);
+$search = isset($srch) ? trim($srch) : trim($str);
-if ($subject) {
+if (!empty($subject)) {
$search_str .= str_repeat(' OR', count($subject)-1);
foreach ($subject as $sub)
$search_str .= sprintf(" %s {%d}\r\n%s", $sub, strlen($search), $search);
diff --git a/skins/default/functions.js b/skins/default/functions.js
index 6f22bb6c2..8482e375a 100644
--- a/skins/default/functions.js
+++ b/skins/default/functions.js
@@ -192,29 +192,32 @@ searchmenu: function(show)
if (show && ref) {
var pos = $(ref).offset();
- obj.css({ left:pos.left, top:(pos.top + ref.offsetHeight + 2)})
- .find(':checked').prop('checked', false);
+ obj.css({left:pos.left, top:(pos.top + ref.offsetHeight + 2)});
if (rcmail.env.search_mods) {
- var n, mbox = rcmail.env.mailbox, mods = rcmail.env.search_mods;
+ var n, all,
+ list = $('input:checkbox[name="s_mods[]"]', obj),
+ mbox = rcmail.env.mailbox,
+ mods = rcmail.env.search_mods;
- if (rcmail.env.task != 'addressbook') {
+ if (rcmail.env.task == 'mail') {
mods = mods[mbox] ? mods[mbox] : mods['*'];
+ all = 'text';
+ }
+ else {
+ all = '*';
+ }
+ if (mods[all])
+ list.map(function() {
+ this.checked = true;
+ this.disabled = this.value != all;
+ });
+ else {
+ list.prop('disabled', false).prop('checked', false);
for (n in mods)
$('#s_mod_' + n).prop('checked', true);
}
- else {
- if (mods['*'])
- $('input:checkbox[name="s_mods[]"]').map(function() {
- this.checked = true;
- this.disabled = this.value != '*';
- });
- else {
- for (n in mods)
- $('#s_mod_' + n).prop('checked', true);
- }
- }
}
}
obj[show?'show':'hide']();
@@ -222,7 +225,7 @@ searchmenu: function(show)
set_searchmod: function(elem)
{
- var task = rcmail.env.task,
+ var all, m, task = rcmail.env.task,
mods = rcmail.env.search_mods,
mbox = rcmail.env.mailbox;
@@ -232,36 +235,37 @@ set_searchmod: function(elem)
if (task == 'mail') {
if (!mods[mbox])
mods[mbox] = rcube_clone_object(mods['*']);
- if (!elem.checked)
- delete(mods[mbox][elem.value]);
- else
- mods[mbox][elem.value] = 1;
+ m = mods[mbox];
+ all = 'text';
}
else { //addressbook
- if (!elem.checked)
- delete(mods[elem.value]);
- else
- mods[elem.value] = 1;
+ m = mods;
+ all = '*';
+ }
- // mark all fields
- if (elem.value == '*') {
- $('input:checkbox[name="s_mods[]"]').map(function() {
- if (this == elem)
- return;
+ if (!elem.checked)
+ delete(m[elem.value]);
+ else
+ m[elem.value] = 1;
- if (elem.checked) {
- mods[this.value] = 1;
- this.checked = true;
- this.disabled = true;
- }
- else {
- this.disabled = false;
- }
- });
- }
- }
+ // mark all fields
+ if (elem.value != all)
+ return;
- rcmail.env.search_mods = mods;
+ $('input:checkbox[name="s_mods[]"]').map(function() {
+ if (this == elem)
+ return;
+
+ this.checked = true;
+ if (elem.checked) {
+ this.disabled = true;
+ delete m[this.value];
+ }
+ else {
+ this.disabled = false;
+ m[this.value] = 1;
+ }
+ });
},
listmenu: function(show)
@@ -566,7 +570,6 @@ function rcube_init_mail_ui()
rcmail.addEventListener('responseaftergetunread', rcube_render_mailboxlist);
rcmail.addEventListener('responseaftercheck-recent', rcube_render_mailboxlist);
rcmail.addEventListener('aftercollapse-folder', rcube_render_mailboxlist);
- rcube_render_mailboxlist();
}
if (rcmail.env.action == 'compose')
@@ -588,12 +591,16 @@ function iframe_events()
// Abbreviate mailbox names to fit width of the container
function rcube_render_mailboxlist()
{
- if (bw.ie6) // doesn't work well on IE6
+ var list = $('#mailboxlist > li a, #mailboxlist ul:visible > li a');
+
+ // it's too slow with really big number of folders, especially on IE
+ if (list.length > 500 * (bw.ie ? 0.2 : 1))
return;
- $('#mailboxlist > li a, #mailboxlist ul:visible > li a').each(function(){
- var elem = $(this);
- var text = elem.data('text');
+ list.each(function(){
+ var elem = $(this),
+ text = elem.data('text');
+
if (!text) {
text = elem.text().replace(/\s+\(.+$/, '');
elem.data('text', text);
@@ -611,34 +618,45 @@ function rcube_render_mailboxlist()
// inspired by https://gist.github.com/24261/7fdb113f1e26111bd78c0c6fe515f6c0bf418af5
function fit_string_to_size(str, elem, len)
{
- var result = str;
- var ellip = '...';
- var span = $('<b>').css({ visibility:'hidden', padding:'0px' }).appendTo(elem).get(0);
-
- // on first run, check if string fits into the length already.
- span.innerHTML = result;
- if (span.offsetWidth > len) {
- var cut = Math.max(1, Math.floor(str.length * ((span.offsetWidth - len) / span.offsetWidth) / 2)),
- mid = Math.floor(str.length / 2);
- var offLeft = mid, offRight = mid;
- while (true) {
- offLeft = mid - cut;
- offRight = mid + cut;
- span.innerHTML = str.substring(0,offLeft) + ellip + str.substring(offRight);
-
- // break loop if string fits size
- if (span.offsetWidth <= len || offLeft < 3)
- break;
-
- cut++;
- }
-
- // build resulting string
- result = str.substring(0,offLeft) + ellip + str.substring(offRight);
+ var w, span, result = str, ellip = '...';
+
+ if (!rcmail.env.tmp_span) {
+ // it should be appended to elem to use the same css style
+ // but for performance reasons we'll append it to body (once)
+ span = $('<b>').css({visibility: 'hidden', padding: '0px'})
+ .appendTo($('body', document)).get(0);
+ rcmail.env.tmp_span = span;
+ }
+ else {
+ span = rcmail.env.tmp_span;
+ }
+ span.innerHTML = result;
+
+ // on first run, check if string fits into the length already.
+ w = span.offsetWidth;
+ if (w > len) {
+ var cut = Math.max(1, Math.floor(str.length * ((w - len) / w) / 2)),
+ mid = Math.floor(str.length / 2),
+ offLeft = mid,
+ offRight = mid;
+
+ while (true) {
+ offLeft = mid - cut;
+ offRight = mid + cut;
+ span.innerHTML = str.substring(0,offLeft) + ellip + str.substring(offRight);
+
+ // break loop if string fits size
+ if (offLeft < 3 || span.offsetWidth)
+ break;
+
+ cut++;
}
-
- span.parentNode.removeChild(span);
- return result;
+
+ // build resulting string
+ result = str.substring(0,offLeft) + ellip + str.substring(offRight);
+ }
+
+ return result;
}
// Optional parameters used by TinyMCE
diff --git a/tests/mailfunc.php b/tests/mailfunc.php
index 92234efc6..d8111c7df 100644
--- a/tests/mailfunc.php
+++ b/tests/mailfunc.php
@@ -106,7 +106,7 @@ class rcube_test_mailfunc extends UnitTestCase
$part = $this->get_html_part('src/invalidchars.html');
$washed = rcmail_print_body($part);
- $this->assertPattern('/<p>сОЌвПл<\/p>/', $washed, "Remove non-unicode characters from HTML message body");
+ $this->assertPattern('/<p>символ<\/p>/', $washed, "Remove non-unicode characters from HTML message body");
}
/**