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 + 1 file changed, 1 insertion(+) (limited to 'CHANGELOG') 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) -- 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(-) (limited to 'CHANGELOG') 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(-) (limited to 'CHANGELOG') 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(-) (limited to 'CHANGELOG') 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(+) (limited to 'CHANGELOG') 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 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(-) (limited to 'CHANGELOG') 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(-) (limited to 'CHANGELOG') 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 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(-) (limited to 'CHANGELOG') 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(-) (limited to 'CHANGELOG') 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 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 (limited to 'CHANGELOG') 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('/