Resolves issue with non-UTF8 body and preview encoding. Closes #4408
This commit is contained in:
parent
43b0f0a16e
commit
ce510e14a9
5 changed files with 88 additions and 7 deletions
|
|
@ -116,7 +116,7 @@ public class Geary.Email : Object {
|
|||
public Geary.EmailProperties? properties { get; private set; default = null; }
|
||||
|
||||
// PREVIEW
|
||||
public RFC822.Text? preview { get; private set; default = null; }
|
||||
public RFC822.PreviewText? preview { get; private set; default = null; }
|
||||
|
||||
public Geary.Email.Field fields { get; private set; default = Field.NONE; }
|
||||
|
||||
|
|
@ -198,7 +198,7 @@ public class Geary.Email : Object {
|
|||
fields |= Field.PROPERTIES;
|
||||
}
|
||||
|
||||
public void set_message_preview(Geary.RFC822.Text preview) {
|
||||
public void set_message_preview(Geary.RFC822.PreviewText preview) {
|
||||
this.preview = preview;
|
||||
|
||||
fields |= Field.PREVIEW;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@ public class Geary.Imap.Mailbox : Geary.SmartReference {
|
|||
int plain_id = batch.add(new MailboxOperation(context, fetch_cmd));
|
||||
|
||||
int preview_id = NonblockingBatch.INVALID_ID;
|
||||
int preview_charset_id = NonblockingBatch.INVALID_ID;
|
||||
if (fields.require(Geary.Email.Field.PREVIEW)) {
|
||||
// Preview text.
|
||||
FetchBodyDataType fetch_preview = new FetchBodyDataType.peek(FetchBodyDataType.SectionPart.NONE,
|
||||
{ 1 }, 0, Geary.Email.MAX_PREVIEW_BYTES, null);
|
||||
Gee.List<FetchBodyDataType> list = new Gee.ArrayList<FetchBodyDataType>();
|
||||
|
|
@ -99,6 +101,17 @@ public class Geary.Imap.Mailbox : Geary.SmartReference {
|
|||
FetchCommand preview_cmd = new FetchCommand(msg_set, null, list);
|
||||
|
||||
preview_id = batch.add(new MailboxOperation(context, preview_cmd));
|
||||
|
||||
// Preview character set.
|
||||
FetchBodyDataType fetch_preview_charset = new FetchBodyDataType.peek(
|
||||
FetchBodyDataType.SectionPart.MIME,
|
||||
{ 1 }, -1, -1, null);
|
||||
Gee.List<FetchBodyDataType> list_charset = new Gee.ArrayList<FetchBodyDataType>();
|
||||
list_charset.add(fetch_preview_charset);
|
||||
|
||||
FetchCommand preview_charset_cmd = new FetchCommand(msg_set, null, list_charset);
|
||||
|
||||
preview_charset_id = batch.add(new MailboxOperation(context, preview_charset_cmd));
|
||||
}
|
||||
|
||||
yield batch.execute_all_async(cancellable);
|
||||
|
|
@ -129,20 +142,38 @@ public class Geary.Imap.Mailbox : Geary.SmartReference {
|
|||
|
||||
// process preview FETCH results
|
||||
|
||||
if (preview_id != NonblockingBatch.INVALID_ID) {
|
||||
if (preview_id != NonblockingBatch.INVALID_ID &&
|
||||
preview_charset_id != NonblockingBatch.INVALID_ID) {
|
||||
|
||||
MailboxOperation preview_op = (MailboxOperation) batch.get_operation(preview_id);
|
||||
CommandResponse preview_resp = (CommandResponse) batch.get_result(preview_id);
|
||||
|
||||
MailboxOperation preview_charset_op = (MailboxOperation)
|
||||
batch.get_operation(preview_charset_id);
|
||||
CommandResponse preview_charset_resp = (CommandResponse)
|
||||
batch.get_result(preview_charset_id);
|
||||
|
||||
if (preview_resp.status_response.status != Status.OK) {
|
||||
throw new ImapError.SERVER_ERROR("Server error for %s: %s", preview_op.cmd.to_string(),
|
||||
preview_resp.to_string());
|
||||
}
|
||||
|
||||
if (preview_charset_resp.status_response.status != Status.OK) {
|
||||
throw new ImapError.SERVER_ERROR("Server error for %s: %s",
|
||||
preview_charset_op.cmd.to_string(), preview_charset_resp.to_string());
|
||||
}
|
||||
|
||||
FetchResults[] preview_results = FetchResults.decode(preview_resp);
|
||||
FetchResults[] preview_header_results = FetchResults.decode(preview_charset_resp);
|
||||
int i = 0;
|
||||
foreach (FetchResults preview_res in preview_results) {
|
||||
Geary.Email? preview_email = map.get(preview_res.msg_num);
|
||||
if (preview_email != null)
|
||||
preview_email.set_message_preview(new RFC822.Text(preview_res.get_body_data()[0]));
|
||||
if (preview_email == null)
|
||||
continue;
|
||||
|
||||
preview_email.set_message_preview(new RFC822.PreviewText(
|
||||
preview_res.get_body_data()[0], preview_header_results[i].get_body_data()[0]));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -149,3 +149,48 @@ public class Geary.RFC822.Full : Geary.Common.BlockMessageData, Geary.RFC822.Mes
|
|||
}
|
||||
}
|
||||
|
||||
// Used for decoding preview text.
|
||||
public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
|
||||
public PreviewText(Geary.Memory.AbstractBuffer _buffer, Geary.Memory.AbstractBuffer?
|
||||
preview_header = null) {
|
||||
|
||||
Geary.Memory.AbstractBuffer buffer = _buffer;
|
||||
|
||||
if (preview_header != null) {
|
||||
string? charset = null;
|
||||
string? encoding = null;
|
||||
|
||||
// Parse the header.
|
||||
GMime.Stream header_stream = new GMime.StreamMem.with_buffer(
|
||||
preview_header.get_array());
|
||||
GMime.Parser parser = new GMime.Parser.with_stream(header_stream);
|
||||
GMime.Part? part = parser.construct_part() as GMime.Part;
|
||||
if (part != null) {
|
||||
charset = part.get_content_type_parameter("charset");
|
||||
encoding = part.get_header("Content-Transfer-Encoding");
|
||||
}
|
||||
|
||||
GMime.StreamMem input_stream = new GMime.StreamMem.with_buffer(buffer.get_array());
|
||||
|
||||
ByteArray output = new ByteArray();
|
||||
GMime.StreamMem output_stream = new GMime.StreamMem.with_byte_array(output);
|
||||
output_stream.set_owner(false);
|
||||
|
||||
// Convert the encoding and character set.
|
||||
GMime.StreamFilter filter = new GMime.StreamFilter(output_stream);
|
||||
if (encoding != null)
|
||||
filter.add(new GMime.FilterBasic(GMime.content_encoding_from_string(encoding), false));
|
||||
|
||||
if (charset != null)
|
||||
filter.add(new GMime.FilterCharset(charset, "UTF8"));
|
||||
|
||||
input_stream.write_to_stream(filter);
|
||||
uint8[] data = output.data;
|
||||
data += (uint8) '\0';
|
||||
buffer = new Geary.Memory.StringBuffer((string) data);
|
||||
}
|
||||
|
||||
base (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,12 @@ public class Geary.RFC822.Message : Object {
|
|||
GMime.StreamMem stream = new GMime.StreamMem.with_byte_array(byte_array);
|
||||
stream.set_owner(false);
|
||||
|
||||
wrapper.write_to_stream(stream);
|
||||
// Convert encoding to UTF-8.
|
||||
GMime.StreamFilter stream_filter = new GMime.StreamFilter(stream);
|
||||
stream_filter.add(new GMime.FilterCharset(part.get_content_type_parameter("charset"),
|
||||
"UTF8"));
|
||||
|
||||
wrapper.write_to_stream(stream_filter);
|
||||
|
||||
return new Geary.Memory.Buffer(byte_array.data, byte_array.len);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ public class Geary.Sqlite.MessageRow : Geary.Sqlite.Row {
|
|||
email.set_message_body(new RFC822.Text(new Geary.Memory.StringBuffer(body)));
|
||||
|
||||
if (((fields & Geary.Email.Field.PREVIEW) != 0) && (preview != null))
|
||||
email.set_message_preview(new RFC822.Text(new Geary.Memory.StringBuffer(preview)));
|
||||
email.set_message_preview(new RFC822.PreviewText(new Geary.Memory.StringBuffer(preview)));
|
||||
|
||||
return email;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue