lib/kolab_sync_data_email.php lib/kolab_sync_message.php tests/message.php tests/src
Aleksander Machniak
machniak at kolabsys.com
Wed Jan 22 14:48:28 CET 2014
lib/kolab_sync_data_email.php | 2
lib/kolab_sync_message.php | 99 ++++++++++++++++++++++++++++++++++--------
tests/message.php | 39 ++++++++++++++++
tests/src/mail.recode1 | 16 ++++++
tests/src/mail.recode1.out | 13 +++++
tests/src/mail.recode2 | 46 +++++++++++++++++++
tests/src/mail.recode2.out | 42 +++++++++++++++++
tests/src/mail.recode3 | 11 ++++
tests/src/mail.recode3.out | 11 ++++
9 files changed, 261 insertions(+), 18 deletions(-)
New commits:
commit 122c53ee6a51047e7a4d31037535278a15fa5795
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Jan 22 14:45:32 2014 +0100
Fix issue where mime message source wasn't encoded when sending to the device (Bug #2715, #2757)
This caused removing some characters in messages that use 8bit transfer-encoding
and character set other than UTF-8.
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index cea12da..cc3e19a 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -270,6 +270,8 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
}
else if ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) {
$messageBody = $this->storage->get_raw_body($message->uid);
+ // make the source safe (Bug #2715, #2757)
+ $messageBody = kolab_sync_message::recode_message($messageBody);
// strip out any non utf-8 characters
$messageBody = rcube_charset::clean($messageBody);
$real_length = $body_length = strlen($messageBody);
diff --git a/lib/kolab_sync_message.php b/lib/kolab_sync_message.php
index 8c5c44f..355b4f7 100644
--- a/lib/kolab_sync_message.php
+++ b/lib/kolab_sync_message.php
@@ -140,7 +140,7 @@ class kolab_sync_message
*/
public function set_header($name, $value)
{
- $name = $this->normalize_header_name($name);
+ $name = self::normalize_header_name($name);
if ($name != 'Content-Type') {
$this->headers[$name] = $value;
@@ -277,6 +277,58 @@ class kolab_sync_message
}
/**
+ * Parses the message source and fixes 8bit data for ActiveSync.
+ * This way any not UTF8 characters will be encoded before
+ * sending to the device.
+ *
+ * @param string $message Message source
+ *
+ * @return string Fixed message source
+ */
+ public static function recode_message($message)
+ {
+ // @TODO: work with stream, to workaround memory issues with big messages
+ if (is_resource($message)) {
+ $message = stream_get_contents($message);
+ }
+
+ list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY);
+
+ $hdrs = self::parse_headers($headers);
+
+ // multipart message
+ if (preg_match('/boundary="?([a-z0-9-_]+)"?/i', $hdrs['Content-Type'], $matches)) {
+ $boundary = '--' . $matches[1];
+ $message = explode($boundary, $message);
+
+ for ($x=1, $parts = count($message) - 1; $x<$parts; $x++) {
+ $message[$x] = "\r\n" . self::recode_message($message[$x]);
+ }
+
+ return $headers . "\r\n\r\n" . implode($boundary, $message);
+ }
+
+ // single part
+ $enc = strtolower($hdrs['Content-Transfer-Encoding']);
+
+ // do nothing if already encoded
+ if ($enc != 'quoted-printable' && $enc != 'base64') {
+ // recode body if any non-printable-ascii characters found
+ if (preg_match('/[^\x20-\x7E\x0A\x0D\x09]/', $message)) {
+ $hdrs['Content-Transfer-Encoding'] = 'base64';
+ foreach ($hdrs as $header => $header_value) {
+ $hdrs[$header] = $header . ': ' . $header_value;
+ }
+
+ $headers = trim(implode("\r\n", $hdrs));
+ $message = rtrim(chunk_split(base64_encode(rtrim($message)), 76, "\r\n")) . "\r\n";
+ }
+ }
+
+ return $headers . "\r\n\r\n" . $message;
+ }
+
+ /**
* MIME message parser
*
* @param string|resource $message MIME message source
@@ -293,6 +345,30 @@ class kolab_sync_message
list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY);
+ $headers = self::parse_headers($headers);
+
+ // parse Content-Type header
+ $ctype_parts = preg_split('/[; ]+/', $headers['Content-Type']);
+ $this->ctype = strtolower(array_shift($ctype_parts));
+ foreach ($ctype_parts as $part) {
+ if (preg_match('/^([a-z-_]+)\s*=\s*(.+)$/i', trim($part), $m)) {
+ $this->ctype_params[strtolower($m[1])] = trim($m[2], '"');
+ }
+ }
+
+ if (!empty($headers['Content-Transfer-Encoding'])) {
+ $headers['Content-Transfer-Encoding'] = strtolower($headers['Content-Transfer-Encoding']);
+ }
+
+ $this->headers = $headers;
+ $this->body = $message;
+ }
+
+ /**
+ * Parse message source with headers
+ */
+ protected static function parse_headers($headers)
+ {
// Parse headers
$headers = str_replace("\r\n", "\n", $headers);
$headers = explode("\n", trim($headers));
@@ -313,31 +389,18 @@ class kolab_sync_message
$headers = array();
foreach ($lines as $line) {
list($field, $string) = explode(':', $line, 2);
- $field = $this->normalize_header_name($field);
- $headers[$field] = trim($string);
- }
-
- // parse Content-Type header
- $ctype_parts = preg_split('/[; ]+/', $headers['Content-Type']);
- $this->ctype = strtolower(array_shift($ctype_parts));
- foreach ($ctype_parts as $part) {
- if (preg_match('/^([a-z-_]+)\s*=\s*(.+)$/i', trim($part), $m)) {
- $this->ctype_params[strtolower($m[1])] = trim($m[2], '"');
+ if ($field = self::normalize_header_name($field)) {
+ $headers[$field] = trim($string);
}
}
- if (!empty($headers['Content-Transfer-Encoding'])) {
- $headers['Content-Transfer-Encoding'] = strtolower($headers['Content-Transfer-Encoding']);
- }
-
- $this->headers = $headers;
- $this->body = $message;
+ return $headers;
}
/**
* Normalize (fix) header names
*/
- protected function normalize_header_name($name)
+ protected static function normalize_header_name($name)
{
$headers_map = array(
'subject' => 'Subject',
diff --git a/tests/message.php b/tests/message.php
index 1cafa5f..19e1901 100644
--- a/tests/message.php
+++ b/tests/message.php
@@ -96,4 +96,43 @@ class message extends PHPUnit_Framework_TestCase
$result = str_replace("\r\n", "\n", $result);
$this->assertEquals($append, $result);
}
+
+ /**
+ * Test recoding the message
+ */
+ function test_recode_message_1()
+ {
+ $source = file_get_contents(TESTS_DIR . '/src/mail.recode1');
+ $result = file_get_contents(TESTS_DIR . '/src/mail.recode1.out');
+
+ $message = kolab_sync_message::recode_message($source);
+
+ $this->assertEquals($result, $message);
+ }
+
+ /**
+ * Test recoding the message
+ */
+ function test_recode_message_2()
+ {
+ $source = file_get_contents(TESTS_DIR . '/src/mail.recode2');
+ $result = file_get_contents(TESTS_DIR . '/src/mail.recode2.out');
+
+ $message = kolab_sync_message::recode_message($source);
+
+ $this->assertEquals($result, $message);
+ }
+
+ /**
+ * Test recoding the message
+ */
+ function test_recode_message_3()
+ {
+ $source = file_get_contents(TESTS_DIR . '/src/mail.recode3');
+ $result = file_get_contents(TESTS_DIR . '/src/mail.recode3.out');
+
+ $message = kolab_sync_message::recode_message($source);
+
+ $this->assertEquals($result, $message);
+ }
}
diff --git a/tests/src/mail.recode1 b/tests/src/mail.recode1
new file mode 100644
index 0000000..72767c5
--- /dev/null
+++ b/tests/src/mail.recode1
@@ -0,0 +1,16 @@
+X-Sieve: CMU Sieve 2.4
+X-Virus-Scanned: amavisd-new at mx.domain.de
+Message-ID: <52CDD362.2020009 at domain.de>
+Date: Wed, 08 Jan 2014 23:38:26 +0100
+From: Daniel <daniel at domain.de>
+MIME-Version: 1.0
+To: <alec at domain.de>
+Subject: Bitte um =?ISO-8859-15?Q?R=FCckruf?=
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+Content-Transfer-Encoding: 8bit
+
+Hallo Björn,
+bitte rufe mich doch mal ganz dringend zurück. 0178-5217029
+
+Liebe Grüße
+Daniel
diff --git a/tests/src/mail.recode1.out b/tests/src/mail.recode1.out
new file mode 100644
index 0000000..09cefc0
--- /dev/null
+++ b/tests/src/mail.recode1.out
@@ -0,0 +1,13 @@
+X-Sieve: CMU Sieve 2.4
+X-Virus-Scanned: amavisd-new at mx.domain.de
+Message-ID: <52CDD362.2020009 at domain.de>
+Date: Wed, 08 Jan 2014 23:38:26 +0100
+From: Daniel <daniel at domain.de>
+MIME-Version: 1.0
+To: <alec at domain.de>
+Subject: Bitte um =?ISO-8859-15?Q?R=FCckruf?=
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+Content-Transfer-Encoding: base64
+
+SGFsbG8gQmr2cm4sDQpiaXR0ZSBydWZlIG1pY2ggZG9jaCBtYWwgZ2FueiBkcmluZ2VuZCB6dXL8
+Y2suIDAxNzgtNTIxNzAyOQ0KDQpMaWViZSBHcvzfZQ0KRGFuaWVs
diff --git a/tests/src/mail.recode2 b/tests/src/mail.recode2
new file mode 100644
index 0000000..2ac9a2d
--- /dev/null
+++ b/tests/src/mail.recode2
@@ -0,0 +1,46 @@
+Message-ID: <52B02B8F.9010500 at domain.de>
+Date: Tue, 17 Dec 2013 11:46:39 +0100
+From: Sender <sender at domain.de>
+User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7
+To: Verborgene_Empfaenger:;
+Subject: Weihnachtsbrief
+Content-Type: multipart/mixed;
+ boundary="------------000801030509090203070207"
+
+This is a multi-part message in MIME format.
+--------------000801030509090203070207
+Content-Type: multipart/alternative;
+ boundary="------------060305070900000101080707"
+
+
+--------------060305070900000101080707
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+Content-Transfer-Encoding: 8bit
+
+Herzliche Adventsgrüße
+
+--------------060305070900000101080707
+Content-Type: text/html; charset=ISO-8859-15
+Content-Transfer-Encoding: 8bit
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-15">
+ </head>
+ <body bgcolor="#ffffff" text="#000000">
+ Herzliche Adventsgrüße<br>
+ </body>
+</html>
+
+--------------060305070900000101080707--
+
+--------------000801030509090203070207
+Content-Type: application/pdf;
+ name="Weihnachtsbrief13.pdf"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="Weihnachtsbrief13.pdf"
+
+JVBERi0 [...shortened...] DYKJSVFT0YK
+--------------000801030509090203070207--
\ No newline at end of file
diff --git a/tests/src/mail.recode2.out b/tests/src/mail.recode2.out
new file mode 100644
index 0000000..ff4c323
--- /dev/null
+++ b/tests/src/mail.recode2.out
@@ -0,0 +1,42 @@
+Message-ID: <52B02B8F.9010500 at domain.de>
+Date: Tue, 17 Dec 2013 11:46:39 +0100
+From: Sender <sender at domain.de>
+User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7
+To: Verborgene_Empfaenger:;
+Subject: Weihnachtsbrief
+Content-Type: multipart/mixed;
+ boundary="------------000801030509090203070207"
+
+This is a multi-part message in MIME format.
+--------------000801030509090203070207
+
+Content-Type: multipart/alternative;
+ boundary="------------060305070900000101080707"
+
+
+--------------060305070900000101080707
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+Content-Transfer-Encoding: base64
+
+SGVyemxpY2hlIEFkdmVudHNncvzfZQ==
+--------------060305070900000101080707
+Content-Type: text/html; charset=ISO-8859-15
+Content-Transfer-Encoding: base64
+
+PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEgVHJhbnNpdGlvbmFs
+Ly9FTiI+DQo8aHRtbD4NCiAgPGhlYWQ+DQogICAgPG1ldGEgaHR0cC1lcXVpdj0iY29udGVudC10
+eXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9SVNPLTg4NTktMTUiPg0KICA8L2hlYWQ+
+DQogIDxib2R5IGJnY29sb3I9IiNmZmZmZmYiIHRleHQ9IiMwMDAwMDAiPg0KICAgIEhlcnpsaWNo
+ZSBBZHZlbnRzZ3L832U8YnI+DQogIDwvYm9keT4NCjwvaHRtbD4=
+--------------060305070900000101080707--
+
+--------------000801030509090203070207
+
+Content-Type: application/pdf;
+ name="Weihnachtsbrief13.pdf"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="Weihnachtsbrief13.pdf"
+
+JVBERi0 [...shortened...] DYKJSVFT0YK
+--------------000801030509090203070207--
\ No newline at end of file
diff --git a/tests/src/mail.recode3 b/tests/src/mail.recode3
new file mode 100644
index 0000000..5ca5d19
--- /dev/null
+++ b/tests/src/mail.recode3
@@ -0,0 +1,11 @@
+X-Sieve: CMU Sieve 2.4
+X-Virus-Scanned: amavisd-new at mx.domain.de
+Message-ID: <52CDD362.2020009 at domain.de>
+Date: Wed, 08 Jan 2014 23:38:26 +0100
+From: Daniel <daniel at domain.de>
+MIME-Version: 1.0
+To: <alec at domain.de>
+Subject: Hello
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+
+Hello
diff --git a/tests/src/mail.recode3.out b/tests/src/mail.recode3.out
new file mode 100644
index 0000000..5ca5d19
--- /dev/null
+++ b/tests/src/mail.recode3.out
@@ -0,0 +1,11 @@
+X-Sieve: CMU Sieve 2.4
+X-Virus-Scanned: amavisd-new at mx.domain.de
+Message-ID: <52CDD362.2020009 at domain.de>
+Date: Wed, 08 Jan 2014 23:38:26 +0100
+From: Daniel <daniel at domain.de>
+MIME-Version: 1.0
+To: <alec at domain.de>
+Subject: Hello
+Content-Type: text/plain; charset=ISO-8859-15; format=flowed
+
+Hello
More information about the commits
mailing list