From 243084601ad83486601f7cf1a756ee6e37e74571 Mon Sep 17 00:00:00 2001 From: alecpl Date: Sat, 5 Mar 2011 08:10:52 +0000 Subject: - Applied some fixes from trunk --- CHANGELOG | 3 + program/include/rcube_imap.php | 125 ++++++++++++++++++--------------- program/include/rcube_imap_generic.php | 2 +- program/lib/html2text.php | 6 +- program/localization/fr_FR/labels.inc | 2 +- program/steps/mail/func.inc | 3 + 6 files changed, 82 insertions(+), 59 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f02c50ac3..4882f4eb7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ CHANGELOG Roundcube Webmail =========================== +- Fix some emails are not shown using Cyrus IMAP (#1487820) +- Fix handling of mime-encoded words with non-integral number of octets in a word (#1487801) +- Fix parsing links with non-printable characters inside (#1487805) - Fixed de_CH Localization bugs (#1487773) - Add variable for 'Today' label in date_today option (#1486120) - Applied plugin changes since 0.5-stable release diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index dd821bf37..adca4e3d4 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -4344,80 +4344,95 @@ class rcube_imap */ public static function decode_mime_string($input, $fallback=null) { - // Initialize variable - $out = ''; + if (!empty($fallback)) { + $default_charset = $fallback; + } + else { + $default_charset = rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1'); + } - // Iterate instead of recursing, this way if there are too many values we don't have stack overflows // rfc: all line breaks or other characters not found // in the Base64 Alphabet must be ignored by decoding software // delete all blanks between MIME-lines, differently we can // receive unnecessary blanks and broken utf-8 symbols $input = preg_replace("/\?=\s+=\?/", '?==?', $input); - // Check if there is stuff to decode - if (strpos($input, '=?') !== false) { - // Loop through the string to decode all occurences of =? ?= into the variable $out - while(($pos = strpos($input, '=?')) !== false) { - // Append everything that is before the text to be decoded - $out .= substr($input, 0, $pos); - - // Get the location of the text to decode - $end_cs_pos = strpos($input, "?", $pos+2); - $end_en_pos = strpos($input, "?", $end_cs_pos+1); - $end_pos = strpos($input, "?=", $end_en_pos+1); + // encoded-word regexp + $re = '/=\?([^?]+)\?([BbQq])\?([^?\n]*)\?=/'; - // Extract the encoded string - $encstr = substr($input, $pos+2, ($end_pos-$pos-2)); - // Extract the remaining string - $input = substr($input, $end_pos+2); + // Find all RFC2047's encoded words + if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { + // Initialize variables + $tmp = array(); + $out = ''; + $start = 0; - // Decode the string fragement - $out .= rcube_imap::_decode_mime_string_part($encstr); - } + foreach ($matches as $idx => $m) { + $pos = $m[0][1]; + $charset = $m[1][0]; + $encoding = $m[2][0]; + $text = $m[3][0]; + $length = strlen($m[0][0]); - // Deocde the rest (if any) - if (strlen($input) != 0) - $out .= rcube_imap::decode_mime_string($input, $fallback); + // Append everything that is before the text to be decoded + if ($start != $pos) { + $substr = substr($input, $start, $pos-$start); + $out .= rcube_charset_convert($substr, $default_charset); + $start = $pos; + } + $start += $length; + + // Per RFC2047, each string part "MUST represent an integral number + // of characters . A multi-octet character may not be split across + // adjacent encoded-words." However, some mailers break this, so we + // try to handle characters spanned across parts anyway by iterating + // through and aggregating sequential encoded parts with the same + // character set and encoding, then perform the decoding on the + // aggregation as a whole. + + $tmp[] = $text; + if ($next_match = $matches[$idx+1]) { + if ($next_match[0][1] == $start + && $next_match[1][0] == $charset + && $next_match[2][0] == $encoding + ) { + continue; + } + } - // return the results - return $out; - } - - // no encoding information, use fallback - return rcube_charset_convert($input, - !empty($fallback) ? $fallback : rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1')); - } + $count = count($tmp); + $text = ''; + // Decode and join encoded-word's chunks + if ($encoding == 'B' || $encoding == 'b') { + // base64 must be decoded a segment at a time + for ($i=0; $i<$count; $i++) + $text .= base64_decode($tmp[$i]); + } + else { //if ($encoding == 'Q' || $encoding == 'q') { + // quoted printable can be combined and processed at once + for ($i=0; $i<$count; $i++) + $text .= $tmp[$i]; - /** - * Decode a part of a mime-encoded string - * - * @param string $str String to decode - * @return string Decoded string - * @access private - */ - private function _decode_mime_string_part($str) - { - $a = explode('?', $str); - $count = count($a); + $text = str_replace('_', ' ', $text); + $text = quoted_printable_decode($text); + } - // should be in format "charset?encoding?base64_string" - if ($count >= 3) { - for ($i=2; $i<$count; $i++) - $rest .= $a[$i]; + $out .= rcube_charset_convert($text, $charset); + $tmp = array(); + } - if (($a[1]=='B') || ($a[1]=='b')) - $rest = base64_decode($rest); - else if (($a[1]=='Q') || ($a[1]=='q')) { - $rest = str_replace('_', ' ', $rest); - $rest = quoted_printable_decode($rest); + // add the last part of the input string + if ($start != strlen($input)) { + $out .= rcube_charset_convert(substr($input, $start), $default_charset); } - return rcube_charset_convert($rest, $a[0]); + // return the results + return $out; } - // we dont' know what to do with this - return $str; + // no encoding information, use fallback + return rcube_charset_convert($input, $default_charset); } diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index f1b3dfda8..f3855892a 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -1351,7 +1351,7 @@ class rcube_imap_generic $result[$id] = ''; } } else if ($mode == 2) { - if (preg_match('/\((UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) { + if (preg_match('/(UID|RFC822\.SIZE) ([0-9]+)/', $line, $matches)) { $result[$id] = trim($matches[2]); } else { $result[$id] = 0; diff --git a/program/lib/html2text.php b/program/lib/html2text.php index 3b98e8df7..325a1c941 100644 --- a/program/lib/html2text.php +++ b/program/lib/html2text.php @@ -652,10 +652,12 @@ class html2text case 'h': return $this->_strtoupper("\n\n". $matches[2] ."\n\n"); case 'a': - return $this->_build_link_list($matches[3], $matches[4]); + // Remove spaces in URL (#1487805) + $url = str_replace(' ', '', $matches[3]); + return $this->_build_link_list($url, $matches[4]); } } - + /** * Strtoupper multibyte wrapper function * diff --git a/program/localization/fr_FR/labels.inc b/program/localization/fr_FR/labels.inc index 4430de619..96c78cc56 100644 --- a/program/localization/fr_FR/labels.inc +++ b/program/localization/fr_FR/labels.inc @@ -103,7 +103,7 @@ $labels['replytoallmessage'] = 'Répondre à tous'; $labels['replyall'] = 'Répondre à tous'; $labels['replylist'] = 'Répondre à la liste'; $labels['forwardmessage'] = 'Transmettre le message'; -$labels['deletemessage'] = 'Déplacer le message dans la corbeille'; +$labels['deletemessage'] = 'Supprimer le message'; $labels['movemessagetotrash'] = 'Déplacer le message dans la corbeille'; $labels['printmessage'] = 'Imprimer ce message'; $labels['previousmessage'] = 'Voir le message précédent'; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index a4eb13175..f700a6cdb 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1200,6 +1200,9 @@ function rcmail_alter_html_link($matches) $attrib = parse_attrib_string($matches[2]); $end = '>'; + // Remove non-printable characters in URL (#1487805) + $attrib['href'] = preg_replace('/[\x00-\x1F]/', '', $attrib['href']); + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) { $tempurl = 'tmp-' . md5($attrib['href']) . '.css'; $_SESSION['modcssurls'][$tempurl] = $attrib['href']; -- cgit v1.2.3