From 413df054ad3235c59c24e897b616c569adc4f67b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 12 Aug 2012 11:47:45 +0200 Subject: CS fixes (mostly tab -> spaces) --- program/include/clisetup.php | 49 +++++++++++++++++++----------------- program/include/html.php | 26 +++++++++++-------- program/include/rcube_cache.php | 4 +-- program/include/rcube_config.php | 4 +-- program/include/rcube_imap.php | 22 ++++++++-------- program/include/rcube_ldap.php | 8 +++--- program/include/rcube_plugin_api.php | 4 +-- program/include/rcube_session.php | 11 ++++---- program/include/rcube_smtp.php | 2 +- program/include/rcube_user.php | 2 +- program/include/rcube_utils.php | 10 ++++---- 11 files changed, 75 insertions(+), 67 deletions(-) diff --git a/program/include/clisetup.php b/program/include/clisetup.php index 039020bdc..a9af90a6f 100644 --- a/program/include/clisetup.php +++ b/program/include/clisetup.php @@ -33,33 +33,36 @@ require_once INSTALL_PATH . 'program/include/iniset.php'; */ function get_opt($aliases = array()) { - $args = array(); - for ($i=1; $i < count($_SERVER['argv']); $i++) { - $arg = $_SERVER['argv'][$i]; - $value = true; - $key = null; + $args = array(); - if ($arg[0] == '-') { - $key = preg_replace('/^-+/', '', $arg); - $sp = strpos($arg, '='); - if ($sp > 0) { - $key = substr($key, 0, $sp - 2); - $value = substr($arg, $sp+1); - } - else if (strlen($_SERVER['argv'][$i+1]) && $_SERVER['argv'][$i+1][0] != '-') { - $value = $_SERVER['argv'][++$i]; - } + for ($i=1; $i < count($_SERVER['argv']); $i++) { + $arg = $_SERVER['argv'][$i]; + $value = true; + $key = null; - $args[$key] = is_string($value) ? preg_replace(array('/^["\']/', '/["\']$/'), '', $value) : $value; - } - else - $args[] = $arg; + if ($arg[0] == '-') { + $key = preg_replace('/^-+/', '', $arg); + $sp = strpos($arg, '='); + if ($sp > 0) { + $key = substr($key, 0, $sp - 2); + $value = substr($arg, $sp+1); + } + else if (strlen($_SERVER['argv'][$i+1]) && $_SERVER['argv'][$i+1][0] != '-') { + $value = $_SERVER['argv'][++$i]; + } - if ($alias = $aliases[$key]) - $args[$alias] = $args[$key]; - } + $args[$key] = is_string($value) ? preg_replace(array('/^["\']/', '/["\']$/'), '', $value) : $value; + } + else { + $args[] = $arg; + } - return $args; + if ($alias = $aliases[$key]) { + $args[$alias] = $args[$key]; + } + } + + return $args; } diff --git a/program/include/html.php b/program/include/html.php index b42da1d7f..880c90463 100644 --- a/program/include/html.php +++ b/program/include/html.php @@ -171,7 +171,7 @@ class html $attr = array('href' => $attr); } return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, - array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); + array('href','target','name','rel','onclick','onmouseover','onmouseout','onmousedown','onmouseup'))); } /** @@ -532,7 +532,7 @@ class html_textarea extends html { protected $tagname = 'textarea'; protected $allowed = array('name','rows','cols','wrap','tabindex', - 'onchange','disabled','readonly','spellcheck'); + 'onchange','disabled','readonly','spellcheck'); /** * Get HTML code for this object @@ -563,7 +563,7 @@ class html_textarea extends html } return self::tag($this->tagname, $this->attrib, $value, - array_merge(self::$common_attrib, $this->allowed)); + array_merge(self::$common_attrib, $this->allowed)); } } @@ -591,7 +591,7 @@ class html_select extends html protected $tagname = 'select'; protected $options = array(); protected $allowed = array('name','size','tabindex','autocomplete', - 'multiple','onchange','disabled','rel'); + 'multiple','onchange','disabled','rel'); /** * Add a new option to this drop-down @@ -655,7 +655,7 @@ class html_table extends html { protected $tagname = 'table'; protected $allowed = array('id','class','style','width','summary', - 'cellpadding','cellspacing','border'); + 'cellpadding','cellspacing','border'); private $header = array(); private $rows = array(); @@ -705,8 +705,9 @@ class html_table extends html */ public function add_header($attr, $cont) { - if (is_string($attr)) - $attr = array('class' => $attr); + if (is_string($attr)) { + $attr = array('class' => $attr); + } $cell = new stdClass; $cell->attrib = $attr; @@ -763,11 +764,13 @@ class html_table extends html */ public function set_row_attribs($attr = array(), $index = null) { - if (is_string($attr)) - $attr = array('class' => $attr); + if (is_string($attr)) { + $attr = array('class' => $attr); + } - if ($index === null) + if ($index === null) { $index = $this->rowindex; + } $this->rows[$index]->attrib = $attr; } @@ -781,8 +784,9 @@ class html_table extends html */ public function get_row_attribs($index = null) { - if ($index === null) + if ($index === null) { $index = $this->rowindex; + } return $this->rows[$index] ? $this->rows[$index]->attrib : null; } diff --git a/program/include/rcube_cache.php b/program/include/rcube_cache.php index cdb1dd52f..4e60deaff 100644 --- a/program/include/rcube_cache.php +++ b/program/include/rcube_cache.php @@ -254,7 +254,7 @@ class rcube_cache } else if ($this->type == 'apc') { $data = apc_fetch($this->ckey($key)); - } + } if ($data) { $md5sum = md5($data); @@ -294,7 +294,7 @@ class rcube_cache } $this->cache[$key] = $data; - $this->cache_sums[$key] = $md5sum; + $this->cache_sums[$key] = $md5sum; } else { $this->cache[$key] = null; diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php index 2fe0d9745..e2997906c 100644 --- a/program/include/rcube_config.php +++ b/program/include/rcube_config.php @@ -324,7 +324,7 @@ class rcube_config if (strlen($key) != 24) { rcube::raise_error(array( 'code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, + 'file' => __FILE__, 'line' => __LINE__, 'message' => "Configured crypto key '$key' is not exactly 24 bytes long" ), true, true); } @@ -348,7 +348,7 @@ class rcube_config else rcube::raise_error(array( 'code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, + 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid mail_header_delimiter setting" ), true, false); } diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 4ab06cf60..461ecb0d2 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -359,11 +359,11 @@ class rcube_imap extends rcube_storage return array( $this->search_string, - $this->search_set, - $this->search_charset, - $this->search_sort_field, - $this->search_sorted, - ); + $this->search_set, + $this->search_charset, + $this->search_sort_field, + $this->search_sorted, + ); } @@ -3847,12 +3847,12 @@ class rcube_imap extends rcube_storage protected function rsort($folder, $delimiter, &$list, &$out) { while (list($key, $name) = each($list)) { - if (strpos($name, $folder.$delimiter) === 0) { - // set the type of folder name variable (#1485527) - $out[] = (string) $name; - unset($list[$key]); - $this->rsort($name, $delimiter, $list, $out); - } + if (strpos($name, $folder.$delimiter) === 0) { + // set the type of folder name variable (#1485527) + $out[] = (string) $name; + unset($list[$key]); + $this->rsort($name, $delimiter, $list, $out); + } } reset($list); } diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 3a7fc1805..7f51b8fa7 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -2027,12 +2027,12 @@ class rcube_ldap extends rcube_addressbook # a0 = type context-specific/constructed with a length of 06 (6) bytes following # 02 = type integer with 2 bytes following (offset): 01 01 (ie 1) # 02 = type integer with 2 bytes following (contentCount): 01 00 - + # whith a search string present: # 81 = type context-specific/constructed with a length of 04 (4) bytes following (the length will change here) # 81 indicates a user string is present where as a a0 indicates just a offset search # 81 = type context-specific/constructed with a length of 06 (6) bytes following - + # the following info was taken from the ISO/IEC 8825-1:2003 x.690 standard re: the # encoding of integer values (note: these values are in # two-complement form so since offset will never be negative bit 8 of the @@ -2042,7 +2042,7 @@ class rcube_ldap extends rcube_addressbook # of the second (to the left of first octet) octet: # a) shall not all be ones; and # b) shall not all be zero - + if ($search) { $search = preg_replace('/[^-[:alpha:] ,.()0-9]+/', '', $search); @@ -2062,7 +2062,7 @@ class rcube_ldap extends rcube_addressbook // now compute length over $str $str = self::_ber_addseq($str, 'a0'); } - + // now tack on records per page $str = "020100" . self::_ber_addseq(self::_ber_encode_int($rpp-1), '02') . $str; diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php index 8c1e125ce..9ef68cab9 100644 --- a/program/include/rcube_plugin_api.php +++ b/program/include/rcube_plugin_api.php @@ -32,12 +32,12 @@ if (!defined('RCMAIL_PLUGINS_DIR')) class rcube_plugin_api { static private $instance; - + public $dir; public $url = 'plugins/'; public $task = ''; public $output; - + public $handlers = array(); private $plugins = array(); private $tasks = array(); diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php index b6a0ccf62..6192466cd 100644 --- a/program/include/rcube_session.php +++ b/program/include/rcube_session.php @@ -531,7 +531,7 @@ class rcube_session public function set_keep_alive($keep_alive) { $this->keep_alive = $keep_alive; - + if ($this->lifetime < $keep_alive) $this->set_lifetime($keep_alive + 30); } @@ -551,7 +551,7 @@ class rcube_session { return $this->ip; } - + /** * Setter for cookie encryption secret */ @@ -568,7 +568,8 @@ class rcube_session { $this->ip_check = $check; } - + + /** * Setter for the cookie name used for session cookie */ @@ -605,7 +606,7 @@ class rcube_session $result = true; } } - } + } if (!$result) $this->log("Session authentication failed for " . $this->key . "; invalid auth cookie sent; timeslot = " . date('Y-m-d H:i:s', $prev)); @@ -637,7 +638,7 @@ class rcube_session } /** - * + * Writes debug information to the log */ function log($line) { diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php index e5748248c..b28be5206 100644 --- a/program/include/rcube_smtp.php +++ b/program/include/rcube_smtp.php @@ -423,7 +423,7 @@ class rcube_smtp $lines[] = $key . ': ' . $value; } } - + return array($from, join(SMTP_MIME_CRLF, $lines) . SMTP_MIME_CRLF); } diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php index 644d24bd9..29eb0f26e 100644 --- a/program/include/rcube_user.php +++ b/program/include/rcube_user.php @@ -443,7 +443,7 @@ class rcube_user } $data = $rcube->plugins->exec_hook('user_create', - array('user'=>$user, 'user_name'=>$user_name, 'user_email'=>$user_email, 'host'=>$host)); + array('user'=>$user, 'user_name'=>$user_name, 'user_email'=>$user_email, 'host'=>$host)); // plugin aborted this operation if ($data['abort']) diff --git a/program/include/rcube_utils.php b/program/include/rcube_utils.php index 9344a929b..d1a8315ec 100644 --- a/program/include/rcube_utils.php +++ b/program/include/rcube_utils.php @@ -84,9 +84,9 @@ class rcube_utils // from PEAR::Validate $regexp = '&^(?: - ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name - ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322) - $&xi'; + ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name + ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322) + $&xi'; if (!preg_match($regexp, $local_part)) { return false; @@ -617,8 +617,8 @@ class rcube_utils // %n - host $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); // %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld - $t = preg_replace('/^[^\.]+\./', '', $n); - // %d - domain name without first part + $t = preg_replace('/^[^\.]+\./', '', $n); + // %d - domain name without first part $d = preg_replace('/^[^\.]+\./', '', $_SERVER['HTTP_HOST']); // %h - IMAP host $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host; -- cgit v1.2.3 From e1cfb0bc01395bc71162cdd986234f3fe009edb4 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 14 Aug 2012 14:09:39 +0200 Subject: s/rcmail/rcube/ --- program/include/rcube_ldap.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 3a7fc1805..5561613db 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -767,9 +767,9 @@ class rcube_ldap extends rcube_addressbook } // use VLV pseudo-search for autocompletion - $rcmail = rcmail::get_instance(); + $rcube = rcube::get_instance(); - if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == join(',', $rcmail->config->get('contactlist_fields'))) + if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == join(',', $rcube->config->get('contactlist_fields'))) { // add general filter to query if (!empty($this->prop['filter']) && empty($this->filter)) -- cgit v1.2.3 From b8dc3e0e61311fe03f21761fd7de1ca80d10c990 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 14 Aug 2012 15:10:05 +0200 Subject: Disable autocapitalization in login form on iPad/iPhone (#1488609) --- CHANGELOG | 1 + program/include/html.php | 2 +- program/include/rcube_output_html.php | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3441f1e03..827bb5c0c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/include/html.php b/program/include/html.php index b42da1d7f..6d177e16d 100644 --- a/program/include/html.php +++ b/program/include/html.php @@ -358,7 +358,7 @@ class html_inputfield extends html protected $tagname = 'input'; protected $type = 'text'; protected $allowed = array( - 'type','name','value','size','tabindex', + 'type','name','value','size','tabindex','autocapitalize', 'autocomplete','checked','onchange','onclick','disabled','readonly', 'spellcheck','results','maxlength','src','multiple','placeholder', ); diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php index 30512d227..0a8f0e364 100644 --- a/program/include/rcube_output_html.php +++ b/program/include/rcube_output_html.php @@ -1378,6 +1378,9 @@ class rcube_output_html extends rcube_output if (empty($url) && !preg_match('/_(task|action)=logout/', $_SERVER['QUERY_STRING'])) $url = $_SERVER['QUERY_STRING']; + // Disable autocapitalization on iPad/iPhone (#1488609) + $attrib['autocapitalize'] = 'off'; + // set atocomplete attribute $user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off'); $host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off'); -- cgit v1.2.3 From b28a38c7575dd6068d9e1b7f95e391e214a52a78 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 14 Aug 2012 15:22:16 +0200 Subject: - Fix Remove from group option is active for contact search result (#1488608) --- CHANGELOG | 1 + program/js/app.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 827bb5c0c..8e585822b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/js/app.js b/program/js/app.js index 214a5cb80..de61b21f1 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4031,8 +4031,7 @@ function rcube_webmail() // if a group is currently selected, and there is at least one contact selected // thend we can enable the group-remove-selected command - this.enable_command('group-remove-selected', typeof this.env.group != 'undefined' && list.selection.length > 0); - + this.enable_command('group-remove-selected', this.env.group && list.selection.length > 0); this.enable_command('compose', this.env.group || list.selection.length > 0); this.enable_command('edit', id && writable); this.enable_command('delete', list.selection.length && writable); -- cgit v1.2.3 From 56689b31ae3746600b12a9c5c9ec1438e704a6e7 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 14 Aug 2012 15:40:14 +0200 Subject: Fix inactive Save search option after advanced search (#1488607) --- CHANGELOG | 1 + program/steps/addressbook/search.inc | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8e585822b..c2d7c40f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/steps/addressbook/search.inc b/program/steps/addressbook/search.inc index d31e54b1a..851325070 100644 --- a/program/steps/addressbook/search.inc +++ b/program/steps/addressbook/search.inc @@ -237,9 +237,12 @@ function rcmail_contact_search() $OUTPUT->command('set_env', 'source', ''); $OUTPUT->command('set_env', 'group', ''); - // unselect currently selected directory/group - if (!$sid) + if (!$sid) { + // unselect currently selected directory/group $OUTPUT->command('unselect_directory'); + // enable "Save search" command + $OUTPUT->command('enable_command', 'search-create', true); + } $OUTPUT->command('update_group_commands'); // send response -- cgit v1.2.3 From 21d463babac32ced33dd93850ca7d29efd43cde6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 09:05:44 +0200 Subject: Fix stripped apostrophes when replying in plain text to HTML message (#1488606) --- CHANGELOG | 1 + program/lib/html2text.php | 30 +++++++++++++++--------------- program/steps/mail/sendmail.inc | 15 +++------------ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c2d7c40f4..893b7ab52 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/lib/html2text.php b/program/lib/html2text.php index 9de2e961e..28c5ae059 100644 --- a/program/lib/html2text.php +++ b/program/lib/html2text.php @@ -89,7 +89,7 @@ * out that extra spaces should be compressed--a problem addressed with * Marcus Bointon's fixes but that I had not yet incorporated. * - * Thanks to Daniel Schledermann (http://www.typoconsult.dk/) for + * Thanks to Daniel Schledermann (http://www.typoconsult.dk/) for * suggesting a valuable fix with tag handling. * * Thanks to Wojciech Bajon (again!) for suggesting fixes and additions, @@ -200,7 +200,7 @@ class html2text var $ent_search = array( '/&(nbsp|#160);/i', // Non-breaking space '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i', - // Double quotes + // Double quotes '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes '/>/i', // Greater-than '/</i', // Less-than @@ -437,11 +437,11 @@ class html2text function set_base_url( $url = '' ) { if ( empty($url) ) { - if ( !empty($_SERVER['HTTP_HOST']) ) { - $this->url = 'http://' . $_SERVER['HTTP_HOST']; - } else { - $this->url = ''; - } + if ( !empty($_SERVER['HTTP_HOST']) ) { + $this->url = 'http://' . $_SERVER['HTTP_HOST']; + } else { + $this->url = ''; + } } else { // Strip any trailing slashes for consistency (relative // URLs may already start with a slash like "/file.html") @@ -515,7 +515,7 @@ class html2text $text = preg_replace($this->ent_search, $this->ent_replace, $text); // Replace known html entities - $text = html_entity_decode($text, ENT_COMPAT, 'UTF-8'); + $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8'); // 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); @@ -535,7 +535,7 @@ class html2text // for PHP versions >= 4.0.2. Default width is 75 // If width is 0 or less, don't wrap the text. if ( $this->width > 0 ) { - $text = wordwrap($text, $this->width); + $text = wordwrap($text, $this->width); } } @@ -554,16 +554,16 @@ class html2text */ function _build_link_list( $link, $display ) { - if (!$this->_do_links || empty($link)) { - return $display; - } + if (!$this->_do_links || empty($link)) { + return $display; + } // Ignored link types - if (preg_match('!^(javascript:|mailto:|#)!i', $link)) { - return $display; + if (preg_match('!^(javascript:|mailto:|#)!i', $link)) { + return $display; } - if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) { + if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) { $url = $link; } else { diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index 70f1af714..577751742 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -511,14 +511,9 @@ if ($isHtml) { $h2t = new html2text($plugin['body'], false, true, 0); $plainTextPart = rc_wordwrap($h2t->get_text(), $LINE_LENGTH, "\r\n"); $plainTextPart = wordwrap($plainTextPart, 998, "\r\n", true); - if (!$plainTextPart) { - // empty message body breaks attachment handling in drafts - $plainTextPart = "\r\n"; - } - else { - // make sure all line endings are CRLF (#1486712) - $plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart); - } + + // make sure all line endings are CRLF (#1486712) + $plainTextPart = preg_replace('/\r?\n/', "\r\n", $plainTextPart); $plugin = $RCMAIL->plugins->exec_hook('message_outgoing_body', array('body' => $plainTextPart, 'type' => 'alternative', 'message' => $MAIL_MIME)); @@ -542,10 +537,6 @@ else { $message_body = rc_wordwrap($message_body, $LINE_LENGTH, "\r\n"); $message_body = wordwrap($message_body, 998, "\r\n", true); - if (!strlen($message_body)) { - // empty message body breaks attachment handling in drafts - $message_body = "\r\n"; - } $MAIL_MIME->setTXTBody($message_body, false, true); } -- cgit v1.2.3 From b6d731b7da23870c8282296534eccf087e9de047 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 09:08:13 +0200 Subject: Add changelog entry for fix in last commit --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 893b7ab52..4e2b22a4a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) -- cgit v1.2.3 From f326e956e5223e4d097463e6d2a0436a1a997092 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 10:09:09 +0200 Subject: Remove redundant label tag --- skins/larry/templates/compose.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html index ff0c833c6..d29c1bd2a 100644 --- a/skins/larry/templates/compose.html +++ b/skins/larry/templates/compose.html @@ -131,7 +131,7 @@ - -- cgit v1.2.3 From 5ef8e4ad9d3ee8689d2b83750aa65395b7cd59ee Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 10:12:18 +0200 Subject: Fix XSS issue with href="javascript:" not being removed (#1488613) --- CHANGELOG | 1 + program/lib/washtml.php | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4e2b22a4a..932680645 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Fix XSS issue with href="javascript:" not being removed (#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) diff --git a/program/lib/washtml.php b/program/lib/washtml.php index c12315fec..98ae5ed5a 100644 --- a/program/lib/washtml.php +++ b/program/lib/washtml.php @@ -214,8 +214,11 @@ class washtml $key = strtolower($key); $value = $node->getAttribute($key); if (isset($this->_html_attribs[$key]) || - ($key == 'href' && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value))) + ($key == 'href' && !preg_match('!^javascript!i', $value) + && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value)) + ) { $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; + } else if ($key == 'style' && ($style = $this->wash_style($value))) { $quot = strpos($style, '"') !== false ? "'" : '"'; $t .= ' style=' . $quot . $style . $quot; @@ -237,7 +240,8 @@ class washtml else if (preg_match('/^data:.+/i', $value)) { // RFC2397 $t .= ' ' . $key . '="' . htmlspecialchars($value, ENT_QUOTES) . '"'; } - } else + } + else $washed .= ($washed?' ':'') . $key; } return $t . ($washed && $this->config['show_washed']?' x-washed="'.$washed.'"':''); -- cgit v1.2.3 From c086978f6a91eacb339fd2976202fca9dad2ef32 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 11:20:40 +0200 Subject: Fix XSS issue where plain signatures wasn't secured in HTML mode (#1488613) --- CHANGELOG | 3 ++- program/js/app.js | 31 +++++-------------------------- program/steps/mail/compose.inc | 30 +++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 932680645..37170fc65 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ CHANGELOG Roundcube Webmail =========================== -- Fix XSS issue with href="javascript:" not being removed (#1488613) +- 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) diff --git a/program/js/app.js b/program/js/app.js index de61b21f1..e8bb6c1a7 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -3298,8 +3298,7 @@ function rcube_webmail() input_message = $("[name='_message']"), message = input_message.val(), is_html = ($("input[name='_is_html']").val() == '1'), - sig = this.env.identity, - sig_separator = this.env.sig_above && (this.env.compose_mode == 'reply' || this.env.compose_mode == 'forward') ? '---' : '-- '; + sig = this.env.identity; // enable manual signature insert if (this.env.signatures && this.env.signatures[id]) { @@ -3312,25 +3311,18 @@ function rcube_webmail() if (!is_html) { // remove the 'old' signature if (show_sig && sig && this.env.signatures && this.env.signatures[sig]) { - - sig = this.env.signatures[sig].is_html ? this.env.signatures[sig].plain_text : this.env.signatures[sig].text; + sig = this.env.signatures[sig].text; sig = sig.replace(/\r\n/g, '\n'); - if (!sig.match(/^--[ -]\n/m)) - sig = sig_separator + '\n' + sig; - p = this.env.sig_above ? message.indexOf(sig) : message.lastIndexOf(sig); if (p >= 0) message = message.substring(0, p) + message.substring(p+sig.length, message.length); } // add the new signature string if (show_sig && this.env.signatures && this.env.signatures[id]) { - sig = this.env.signatures[id]['is_html'] ? this.env.signatures[id]['plain_text'] : this.env.signatures[id]['text']; + sig = this.env.signatures[id].text; sig = sig.replace(/\r\n/g, '\n'); - if (!sig.match(/^--[ -]\n/m)) - sig = sig_separator + '\n' + sig; - if (this.env.sig_above) { if (p >= 0) { // in place of removed signature message = message.substring(0, p) + sig + message.substring(p, message.length); @@ -3394,21 +3386,8 @@ function rcube_webmail() } } - if (this.env.signatures[id]) { - if (this.env.signatures[id].is_html) { - sig = this.env.signatures[id].text; - if (!this.env.signatures[id].plain_text.match(/^--[ -]\r?\n/m)) - sig = sig_separator + '
' + sig; - } - else { - sig = this.env.signatures[id].text; - if (!sig.match(/^--[ -]\r?\n/m)) - sig = sig_separator + '\n' + sig; - sig = '
' + sig + '
'; - } - - sigElem.innerHTML = sig; - } + if (this.env.signatures[id]) + sigElem.innerHTML = this.env.signatures[id].html; } this.env.identity = id; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 71a1c0f21..1a1d244e1 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -529,7 +529,7 @@ function rcmail_compose_headers($attrib) function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT; + global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -540,6 +540,8 @@ function rcmail_compose_header_from($attrib) if (count($MESSAGE->identities)) { $a_signatures = array(); + $separator = $RCMAIL->config->get('sig_above') + && ($compose_mode == RCUBE_COMPOSE_REPLY || $compose_mode == RCUBE_COMPOSE_FORWARD) ? '---' : '-- '; $field_attrib['onchange'] = JS_OBJECT_NAME.".change_identity(this)"; $select_from = new html_select($field_attrib); @@ -553,13 +555,27 @@ function rcmail_compose_header_from($attrib) // add signature to array if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) { - $a_signatures[$identity_id]['text'] = $sql_arr['signature']; - $a_signatures[$identity_id]['is_html'] = ($sql_arr['html_signature'] == 1) ? true : false; - if ($a_signatures[$identity_id]['is_html']) - { - $h2t = new html2text($a_signatures[$identity_id]['text'], false, false); - $a_signatures[$identity_id]['plain_text'] = trim($h2t->get_text()); + $text = $html = $sql_arr['signature']; + + if ($sql_arr['html_signature']) { + $h2t = new html2text($sql_arr['signature'], false, false); + $text = trim($h2t->get_text()); + } + else { + $html = htmlentities($html, ENT_NOQUOTES, RCMAIL_CHARSET); + } + + if (!preg_match('/^--[ -]\r?\n/m', $text)) { + $text = $separator . "\n" . $text; + $html = $separator . "
" . $html; + } + + if (!$sql_arr['html_signature']) { + $html = "
" . $html . "
"; } + + $a_signatures[$identity_id]['text'] = $text; + $a_signatures[$identity_id]['html'] = $html; } } -- cgit v1.2.3 From 0db8d00d298f8f67d6843f016a5a6259edff9f96 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 15 Aug 2012 15:15:54 +0200 Subject: PDO: quote null values as NULL instad of an empty string --- program/include/rcube_db.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/program/include/rcube_db.php b/program/include/rcube_db.php index 042ca15e4..f97d70ab3 100644 --- a/program/include/rcube_db.php +++ b/program/include/rcube_db.php @@ -576,6 +576,10 @@ class rcube_db return intval($input); } + if (is_null($input)) { + return 'NULL'; + } + // create DB handle if not available if (!$this->dbh) { $this->db_connect('r'); -- cgit v1.2.3 From fb2f825cd95677a2ede38e0a2ea99b6823841d74 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 15:32:02 +0200 Subject: Fix line separator in exported messages (#1488603) --- CHANGELOG | 1 + program/include/rcube_imap.php | 7 +++++-- program/include/rcube_imap_generic.php | 4 ++-- program/include/rcube_storage.php | 5 ++++- program/steps/mail/viewsource.inc | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 37170fc65..4cbaa6ece 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index 461ecb0d2..5dd9c1250 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -2138,14 +2138,17 @@ class rcube_imap extends rcube_storage /** * Sends the whole message source to stdout + * + * @param int $uid Message UID + * @param bool $formatted Enables line-ending formatting */ - public function print_raw_body($uid) + public function print_raw_body($uid, $formatted = true) { if (!$this->check_connection()) { return; } - $this->conn->handlePartBody($this->folder, $uid, true, NULL, NULL, true); + $this->conn->handlePartBody($this->folder, $uid, true, null, null, true, null, $formatted); } diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 8d956f2b9..915a11aad 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -2377,7 +2377,7 @@ class rcube_imap_generic return $this->handlePartBody($mailbox, $id, $is_uid, $part); } - function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL) + function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=true) { if (!$this->select($mailbox)) { return false; @@ -2494,7 +2494,7 @@ class rcube_imap_generic continue; $line = convert_uudecode($line); // default - } else { + } else if ($formatted) { $line = rtrim($line, "\t\r\n\0\x0B") . "\n"; } diff --git a/program/include/rcube_storage.php b/program/include/rcube_storage.php index 1075b0f43..768a26d73 100644 --- a/program/include/rcube_storage.php +++ b/program/include/rcube_storage.php @@ -502,8 +502,11 @@ abstract class rcube_storage /** * Sends the whole message source to stdout + * + * @param int $uid Message UID + * @param bool $formatted Enables line-ending formatting */ - abstract function print_raw_body($uid); + abstract function print_raw_body($uid, $formatted = true); /** diff --git a/program/steps/mail/viewsource.inc b/program/steps/mail/viewsource.inc index 59ccb386e..c560d7d41 100644 --- a/program/steps/mail/viewsource.inc +++ b/program/steps/mail/viewsource.inc @@ -44,7 +44,7 @@ if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) header("Content-Disposition: attachment; filename=\"$filename\""); } - $RCMAIL->storage->print_raw_body($uid); + $RCMAIL->storage->print_raw_body($uid, empty($_GET['_save'])); } else { -- cgit v1.2.3 From 6ab9369eb194e4dde0cc830a84466dd240e95b23 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Wed, 15 Aug 2012 16:21:34 +0200 Subject: Fix lower-casing email address on replies (#1488598) --- CHANGELOG | 1 + program/include/rcube_shared.inc | 23 +++++++++++++++++++++++ program/steps/mail/compose.inc | 9 +++++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4cbaa6ece..192ecce91 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 85f278432..5b839d8d2 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -305,6 +305,29 @@ function format_email_recipient($email, $name = '') } +/** + * Format e-mail address + * + * @param string $email E-mail address + * + * @return string Formatted e-mail address + */ +function format_email($email) +{ + $email = trim($email); + $parts = explode('@', $email); + $count = count($parts); + + if ($count > 1) { + $parts[$count-1] = mb_strtolower($parts[$count-1]); + + $email = implode('@', $parts); + } + + return $email; +} + + /** * mbstring replacement functions */ diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 1a1d244e1..56f4a052b 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -252,7 +252,8 @@ $MESSAGE->identities = $RCMAIL->user->list_identities(); if (count($MESSAGE->identities)) { foreach ($MESSAGE->identities as $idx => $ident) { - $email = mb_strtolower(rcube_idn_to_utf8($ident['email'])); + $ident['email'] = format_email($ident['email']); + $email = format_email(rcube_idn_to_utf8($ident['email'])); $MESSAGE->identities[$idx]['email_ascii'] = $ident['email']; $MESSAGE->identities[$idx]['ident'] = format_email_recipient($ident['email'], $ident['name']); @@ -277,7 +278,7 @@ else if (count($MESSAGE->identities)) { $a_to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, true, $MESSAGE->headers->charset); foreach ($a_to as $addr) { if (!empty($addr['mailto'])) { - $a_recipients[] = strtolower($addr['mailto']); + $a_recipients[] = format_email($addr['mailto']); $a_names[] = $addr['name']; } } @@ -286,7 +287,7 @@ else if (count($MESSAGE->identities)) { $a_cc = rcube_mime::decode_address_list($MESSAGE->headers->cc, null, true, $MESSAGE->headers->charset); foreach ($a_cc as $addr) { if (!empty($addr['mailto'])) { - $a_recipients[] = strtolower($addr['mailto']); + $a_recipients[] = format_email($addr['mailto']); $a_names[] = $addr['name']; } } @@ -433,7 +434,7 @@ foreach ($parts as $header) { if (empty($addr_part['mailto'])) continue; - $mailto = mb_strtolower(rcube_idn_to_utf8($addr_part['mailto'])); + $mailto = format_email(rcube_idn_to_utf8($addr_part['mailto'])); if (!in_array($mailto, $a_recipients) && ($header == 'to' || empty($MESSAGE->compose['from_email']) || $mailto != $MESSAGE->compose['from_email']) -- cgit v1.2.3 From 287eff030a7c6437495dc15badb125640cc4c3d3 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 16 Aug 2012 09:36:49 +0200 Subject: Make $inline_parts property publicly available --- program/include/rcube_message.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 9d36acf38..f550b574e 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -50,13 +50,13 @@ class rcube_message */ private $mime; private $opt = array(); - private $inline_parts = array(); private $parse_alternative = false; public $uid = null; public $headers; public $parts = array(); public $mime_parts = array(); + public $inline_parts = array(); public $attachments = array(); public $subject = ''; public $sender = null; -- cgit v1.2.3 From fb001f851f60e99b4ba9d2f837a76a46dfd3fd5f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 16 Aug 2012 12:00:35 +0200 Subject: Force at least one subtype of address to be specified. Fixes issue where contact address wasn't displayed at all. --- program/include/rcube_ldap.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index dbab0fd06..ad2ccddeb 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -139,6 +139,11 @@ class rcube_ldap extends rcube_addressbook unset($this->coltypes[$childcol]); // remove address child col from global coltypes list } } + + // at least one address type must be specified + if (empty($this->coltypes['address']['subtypes'])) { + $this->coltypes['address']['subtypes'] = array('home'); + } } else if ($this->coltypes['address']) { $this->coltypes['address'] += array('type' => 'textarea', 'childs' => null, 'size' => 40); -- cgit v1.2.3 From e824925290a0fdf3852f4562dc459a4cbd4e5768 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 16 Aug 2012 19:44:28 +0200 Subject: Rewritten test scripts for PHPUnit --- CHANGELOG | 1 + tests/HtmlToText.php | 59 +++++++++++++++++ tests/MailDecode.php | 123 +++++++++++++++++++++++++++++++++++ tests/MailFunc.php | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/ModCss.php | 39 +++++++++++ tests/VCards.php | 59 +++++++++++++++++ tests/bootstrap.php | 33 ++++++++++ tests/html_to_text.php | 61 ----------------- tests/maildecode.php | 130 ------------------------------------- tests/mailfunc.php | 173 ------------------------------------------------- tests/modcss.php | 45 ------------- tests/phpunit.xml | 13 ++++ tests/runtests.sh | 54 --------------- tests/vcards.php | 65 ------------------- 14 files changed, 499 insertions(+), 528 deletions(-) create mode 100644 tests/HtmlToText.php create mode 100644 tests/MailDecode.php create mode 100644 tests/MailFunc.php create mode 100644 tests/ModCss.php create mode 100644 tests/VCards.php create mode 100644 tests/bootstrap.php delete mode 100644 tests/html_to_text.php delete mode 100644 tests/maildecode.php delete mode 100644 tests/mailfunc.php delete mode 100644 tests/modcss.php create mode 100644 tests/phpunit.xml delete mode 100755 tests/runtests.sh delete mode 100644 tests/vcards.php diff --git a/CHANGELOG b/CHANGELOG index 192ecce91..3edbdd494 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- 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) diff --git a/tests/HtmlToText.php b/tests/HtmlToText.php new file mode 100644 index 000000000..34e2d1a63 --- /dev/null +++ b/tests/HtmlToText.php @@ -0,0 +1,59 @@ + array( + 'title' => 'Test entry', + 'in' => '', + 'out' => '', + ), + 1 => array( + 'title' => 'Basic HTML entities', + 'in' => '"&', + 'out' => '"&', + ), + 2 => array( + 'title' => 'HTML entity string', + 'in' => '&quot;', + 'out' => '"', + ), + 3 => array( + 'title' => 'HTML entity in STRONG tag', + 'in' => 'ś', // ś + 'out' => 'Ś', // upper ś + ), + 4 => array( + 'title' => 'STRONG tag to upper-case conversion', + 'in' => 'ś', + 'out' => 'Ś', + ), + 5 => array( + 'title' => 'STRONG inside B tag', + 'in' => 'ś', + 'out' => 'Ś', + ), + ); + } + + /** + * @dataProvider data + */ + function test_html2text($title, $in, $out) + { + $ht = new html2text(null, false, false); + + $ht->set_html($in); + $res = $ht->get_text(); + + $this->assertEquals($out, $res, $title); + } +} diff --git a/tests/MailDecode.php b/tests/MailDecode.php new file mode 100644 index 000000000..7969603dd --- /dev/null +++ b/tests/MailDecode.php @@ -0,0 +1,123 @@ + 'test@domain.tld', + 1 => '', + 2 => 'Test ', + 3 => 'Test Test ', + 4 => 'Test Test', + 5 => '"Test Test" ', + 6 => '"Test Test"', + 7 => '"Test \\" Test" ', + 8 => '"Test', + 9 => '=?ISO-8859-1?B?VGVzdAo=?= ', + 10 => '=?ISO-8859-1?B?VGVzdAo=?=', // #1487068 + // comments in address (#1487673) + 11 => 'Test (comment) ', + 12 => '"Test" (comment) ', + 13 => '"Test (comment)" (comment) ', + 14 => '(comment) ', + 15 => 'Test ', + 16 => 'Test Test ((comment)) ', + 17 => 'test@domain.tld (comment)', + 18 => '"Test,Test" ', + // 1487939 + 19 => 'Test <"test test"@domain.tld>', + 20 => '<"test test"@domain.tld>', + 21 => '"test test"@domain.tld', + ); + + $results = array( + 0 => array(1, '', 'test@domain.tld'), + 1 => array(1, '', 'test@domain.tld'), + 2 => array(1, 'Test', 'test@domain.tld'), + 3 => array(1, 'Test Test', 'test@domain.tld'), + 4 => array(1, 'Test Test', 'test@domain.tld'), + 5 => array(1, 'Test Test', 'test@domain.tld'), + 6 => array(1, 'Test Test', 'test@domain.tld'), + 7 => array(1, 'Test " Test', 'test@domain.tld'), + 8 => array(1, 'Test array(1, 'Test', 'test@domain.tld'), + 10 => array(1, 'Test', 'test@domain.tld'), + 11 => array(1, 'Test', 'test@domain.tld'), + 12 => array(1, 'Test', 'test@domain.tld'), + 13 => array(1, 'Test (comment)', 'test@domain.tld'), + 14 => array(1, '', 'test@domain.tld'), + 15 => array(1, 'Test', 'test@domain.tld'), + 16 => array(1, 'Test Test', 'test@domain.tld'), + 17 => array(1, '', 'test@domain.tld'), + 18 => array(1, 'Test,Test', 'test@domain.tld'), + 19 => array(1, 'Test', '"test test"@domain.tld'), + 20 => array(1, '', '"test test"@domain.tld'), + 21 => array(1, '', '"test test"@domain.tld'), + ); + + foreach ($headers as $idx => $header) { + $res = rcube_mime::decode_address_list($header); + + $this->assertEquals($results[$idx][0], count($res), "Rows number in result for header: " . $header); + $this->assertEquals($results[$idx][1], $res[1]['name'], "Name part decoding for header: " . $header); + $this->assertEquals($results[$idx][2], $res[1]['mailto'], "Email part decoding for header: " . $header); + } + } + + /** + * Test decoding of header values + * Uses rcube_mime::decode_mime_string() + */ + function test_header_decode_qp() + { + $test = array( + // #1488232: invalid character "?" + 'quoted-printable (1)' => array( + 'in' => '=?utf-8?Q?Certifica=C3=A7=C3=A3??=', + 'out' => 'Certifica=C3=A7=C3=A3?', + ), + 'quoted-printable (2)' => array( + 'in' => '=?utf-8?Q?Certifica=?= =?utf-8?Q?C3=A7=C3=A3?=', + 'out' => 'Certifica=C3=A7=C3=A3', + ), + 'quoted-printable (3)' => array( + 'in' => '=?utf-8?Q??= =?utf-8?Q??=', + 'out' => '', + ), + 'quoted-printable (4)' => array( + 'in' => '=?utf-8?Q??= a =?utf-8?Q??=', + 'out' => ' a ', + ), + 'quoted-printable (5)' => array( + 'in' => '=?utf-8?Q?a?= =?utf-8?Q?b?=', + 'out' => 'ab', + ), + 'quoted-printable (6)' => array( + 'in' => '=?utf-8?Q? ?= =?utf-8?Q?a?=', + 'out' => ' a', + ), + 'quoted-printable (7)' => array( + 'in' => '=?utf-8?Q?___?= =?utf-8?Q?a?=', + 'out' => ' a', + ), + ); + + foreach ($test as $idx => $item) { + $res = rcube_mime::decode_mime_string($item['in'], 'UTF-8'); + $res = quoted_printable_encode($res); + + $this->assertEquals($item['out'], $res, "Header decoding for: " . $idx); + } + } +} diff --git a/tests/MailFunc.php b/tests/MailFunc.php new file mode 100644 index 000000000..57a6b9d10 --- /dev/null +++ b/tests/MailFunc.php @@ -0,0 +1,172 @@ +load_gui(); + $RCMAIL->action = 'autocomplete'; + $RCMAIL->storage_init(false); + + require_once INSTALL_PATH . 'program/steps/mail/func.inc'; + + $GLOBALS['EMAIL_ADDRESS_PATTERN'] = $EMAIL_ADDRESS_PATTERN; + } + + /** + * Helper method to create a HTML message part object + */ + function get_html_part($body) + { + $part = new rcube_message_part; + $part->ctype_primary = 'text'; + $part->ctype_secondary = 'html'; + $part->body = file_get_contents(TESTS_DIR . $body); + $part->replaces = array(); + return $part; + } + + + /** + * Test sanitization of a "normal" html message + */ + function test_html() + { + $part = $this->get_html_part('src/htmlbody.txt'); + $part->replaces = array('ex1.jpg' => 'part_1.2.jpg', 'ex2.jpg' => 'part_1.2.jpg'); + + // render HTML in normal mode + $html = rcmail_html4inline(rcmail_print_body($part, array('safe' => false)), 'foo'); + + $this->assertRegExp('/src="'.$part->replaces['ex1.jpg'].'"/', $html, "Replace reference to inline image"); + $this->assertRegExp('#background="./program/resources/blocked.gif"#', $html, "Replace external background image"); + $this->assertNotRegExp('/ex3.jpg/', $html, "No references to external images"); + $this->assertNotRegExp('/]+>/', $html, "No meta tags allowed"); + //$this->assertNoPattern('/