diff --git a/bindings/vapi/gmime-2.6.vapi b/bindings/vapi/gmime-2.6.vapi index 4b7967d1..5694a1aa 100644 --- a/bindings/vapi/gmime-2.6.vapi +++ b/bindings/vapi/gmime-2.6.vapi @@ -966,7 +966,7 @@ namespace GMime { [CCode (cname = "g_mime_stream_printf")] public ssize_t printf (string fmt); [CCode (cname = "g_mime_stream_read")] - public virtual ssize_t read (string buf, size_t len); + public virtual ssize_t read (uint8[] buf); [CCode (cname = "g_mime_stream_reset")] public virtual int reset (); [CCode (cname = "g_mime_stream_seek")] diff --git a/bindings/vapi/gmime-2.6/gmime-2.6.metadata b/bindings/vapi/gmime-2.6/gmime-2.6.metadata index b6986a8f..f56d5243 100644 --- a/bindings/vapi/gmime-2.6/gmime-2.6.metadata +++ b/bindings/vapi/gmime-2.6/gmime-2.6.metadata @@ -15,6 +15,8 @@ g_mime_part_get_content_part nullable="1" g_mime_signer_next name="get_next" g_mime_stream_mem_new_with_buffer.buffer is_array="1" array_length_pos="1.0" type_name="uint8[]" g_mime_stream_mem_new_with_buffer.len hidden="1" +g_mime_stream_read.buf is_array="1" type_name="uint8[]" +g_mime_stream_read.len hidden="1" g_mime_utils_decode_8bit transfer_ownership="1" g_mime_utils_header_decode_date type_name="time_t" g_mime_utils_header_decode_date.tz_offset is_out="1" nullable="1" diff --git a/src/engine/rfc822/rfc822-message.vala b/src/engine/rfc822/rfc822-message.vala index 42120de6..4b387191 100644 --- a/src/engine/rfc822/rfc822-message.vala +++ b/src/engine/rfc822/rfc822-message.vala @@ -112,28 +112,28 @@ public class Geary.RFC822.Message : BaseObject { // Body: text format (optional) GMime.Part? body_text = null; if (email.body_text != null) { - GMime.DataWrapper content = new GMime.DataWrapper.with_stream( - new GMime.StreamMem.with_buffer(email.body_text.data), + GMime.StreamMem stream = new GMime.StreamMem.with_buffer(email.body_text.data); + GMime.DataWrapper content = new GMime.DataWrapper.with_stream(stream, GMime.ContentEncoding.DEFAULT); body_text = new GMime.Part(); body_text.set_content_type(new GMime.ContentType.from_string("text/plain; charset=utf-8; format=flowed")); body_text.set_content_object(content); - body_text.set_content_encoding(body_text.get_best_content_encoding( + body_text.set_content_encoding(Geary.RFC822.Utils.get_best_content_encoding(stream, GMime.EncodingConstraint.7BIT)); } // Body: HTML format (also optional) GMime.Part? body_html = null; if (email.body_html != null) { - GMime.DataWrapper content = new GMime.DataWrapper.with_stream( - new GMime.StreamMem.with_buffer(email.body_html.data), + GMime.StreamMem stream = new GMime.StreamMem.with_buffer(email.body_html.data); + GMime.DataWrapper content = new GMime.DataWrapper.with_stream(stream, GMime.ContentEncoding.DEFAULT); body_html = new GMime.Part(); body_html.set_content_type(new GMime.ContentType.from_string("text/html; charset=utf-8")); body_html.set_content_object(content); - body_html.set_content_encoding(body_html.get_best_content_encoding( + body_html.set_content_encoding(Geary.RFC822.Utils.get_best_content_encoding(stream, GMime.EncodingConstraint.7BIT)); } @@ -249,7 +249,8 @@ public class Geary.RFC822.Message : BaseObject { part.set_content_object(new GMime.DataWrapper.with_stream(stream, GMime.ContentEncoding.BINARY)); // This encoding is the "Content-Transfer-Encoding", which GMime automatically converts to. - part.set_content_encoding(part.get_best_content_encoding(GMime.EncodingConstraint.7BIT)); + part.set_content_encoding(Geary.RFC822.Utils.get_best_content_encoding(stream, + GMime.EncodingConstraint.7BIT)); return part; } diff --git a/src/engine/rfc822/rfc822-utils.vala b/src/engine/rfc822/rfc822-utils.vala index 429387d0..b13803f8 100644 --- a/src/engine/rfc822/rfc822-utils.vala +++ b/src/engine/rfc822/rfc822-utils.vala @@ -1,4 +1,5 @@ /* Copyright 2011-2013 Yorba Foundation + * Portions copyright (C) 2000-2013 Jeffrey Stedfast * * This software is licensed under the GNU Lesser General Public License * (version 2.1 or later). See the COPYING file in this distribution. @@ -227,5 +228,64 @@ public bool comp_char_arr_slice(char[] array, uint start, string comp) { return true; } +/* + * This function is adapted from the GMimeFilterBest source in the GMime + * library (gmime-filter-best.c) by Jeffrey Stedfast, LGPL 2.1. + */ +public GMime.ContentEncoding get_best_content_encoding(GMime.Stream stream, + GMime.EncodingConstraint constraint) { + int count0 = 0, count8 = 0, linelen = 0, maxline = 0; + size_t total = 0, readlen; + uint8[] buffer = new uint8[1024]; + + while ((readlen = stream.read(buffer)) > 0) { + total += readlen; + for(int i = 0; i < readlen; i++) { + char c = (char) buffer[i]; + if (c == '\n') { + maxline = maxline > linelen ? maxline : linelen; + linelen = 0; + } else { + linelen++; + if (c == 0) + count0++; + else if ((c & 0x80) != 0) + count8++; + } + } + } + maxline = maxline > linelen ? maxline : linelen; + + GMime.ContentEncoding encoding = GMime.ContentEncoding.DEFAULT; + switch (constraint) { + case GMime.EncodingConstraint.7BIT: + if (count0 > 0) { + encoding = GMime.ContentEncoding.BASE64; + } else if (count8 > 0) { + if (count8 > (int) (total * 0.17)) + encoding = GMime.ContentEncoding.BASE64; + else + encoding = GMime.ContentEncoding.QUOTEDPRINTABLE; + } else if (maxline > 998) { + encoding = GMime.ContentEncoding.QUOTEDPRINTABLE; + } + break; + + case GMime.EncodingConstraint.8BIT: + if (count0 > 0) + encoding = GMime.ContentEncoding.BASE64; + else if (maxline > 998) + encoding = GMime.ContentEncoding.QUOTEDPRINTABLE; + break; + + case GMime.EncodingConstraint.BINARY: + if (count0 + count8 > 0) + encoding = GMime.ContentEncoding.BINARY; + break; + } + + return encoding; +} + }