src/engine/rfc822/rfc822-utils.vala: Updated to better match code style
This commit is contained in:
parent
d7e128ae72
commit
f77bb50b5c
1 changed files with 271 additions and 262 deletions
|
|
@ -1,179 +1,138 @@
|
|||
/* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
/*
|
||||
* Copyright 2016 Software Freedom Conservancy Inc.
|
||||
* 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.
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
namespace Geary.RFC822.Utils {
|
||||
|
||||
// We use DEL to mark quote levels, since it's unlikely to be in email bodies, is a single byte
|
||||
// in UTF-8, and is unmolested by GMime.FilterHTML.
|
||||
public const char QUOTE_MARKER = '\x7f';
|
||||
// We use DEL to mark quote levels, since it's unlikely to be in
|
||||
// email bodies, is a single byte in UTF-8, and is unmolested by
|
||||
// GMime.FilterHTML.
|
||||
public const char QUOTE_MARKER = '\x7f';
|
||||
|
||||
|
||||
/**
|
||||
* Uses the best-possible transfer of bytes from the Memory.Buffer to the GMime.StreamMem object.
|
||||
* The StreamMem object should be destroyed *before* the Memory.Buffer object, since this method
|
||||
* will use unowned variants whenever possible.
|
||||
*/
|
||||
public GMime.StreamMem create_stream_mem(Memory.Buffer buffer) {
|
||||
Memory.UnownedByteArrayBuffer? unowned_bytes_array_buffer = buffer as Memory.UnownedByteArrayBuffer;
|
||||
if (unowned_bytes_array_buffer != null) {
|
||||
// set_byte_array doesn't do any copying and doesn't take ownership -- perfect, this is
|
||||
// the best of all possible worlds, assuming the Memory.Buffer is not destroyed first
|
||||
GMime.StreamMem stream = new GMime.StreamMem();
|
||||
stream.set_byte_array(unowned_bytes_array_buffer.to_unowned_byte_array());
|
||||
|
||||
return stream;
|
||||
public string create_subject_for_reply(Email email) {
|
||||
return (email.subject ?? new Subject("")).create_reply().value;
|
||||
}
|
||||
|
||||
Memory.UnownedBytesBuffer? unowned_bytes_buffer = buffer as Memory.UnownedBytesBuffer;
|
||||
if (unowned_bytes_buffer != null) {
|
||||
// StreamMem.with_buffer does do a buffer copy (there's not set_buffer() call like
|
||||
// set_byte_array() for some reason), but don't do a buffer copy when it comes out of the
|
||||
// Memory.Buffer
|
||||
return new GMime.StreamMem.with_buffer(unowned_bytes_buffer.to_unowned_uint8_array());
|
||||
public string create_subject_for_forward(Email email) {
|
||||
return (email.subject ?? new Subject("")).create_forward().value;
|
||||
}
|
||||
|
||||
// do plain-old buffer copy
|
||||
return new GMime.StreamMem.with_buffer(buffer.get_uint8_array());
|
||||
}
|
||||
public MailboxAddresses create_to_addresses_for_reply(Email email,
|
||||
Gee.List<MailboxAddress>? sender_addresses = null) {
|
||||
var new_to = new Gee.ArrayList<MailboxAddress>();
|
||||
|
||||
public string create_subject_for_reply(Geary.Email email) {
|
||||
return (email.subject ?? new Geary.RFC822.Subject("")).create_reply().value;
|
||||
}
|
||||
// If we're replying to something we sent, send it to the same people we originally did.
|
||||
// Otherwise, we'll send to the reply-to address or the from address.
|
||||
if (email.to != null && email_is_from_sender(email, sender_addresses))
|
||||
new_to.add_all(email.to.get_all());
|
||||
else if (email.reply_to != null)
|
||||
new_to.add_all(email.reply_to.get_all());
|
||||
else if (email.from != null)
|
||||
new_to.add_all(email.from.get_all());
|
||||
|
||||
public string create_subject_for_forward(Geary.Email email) {
|
||||
return (email.subject ?? new Geary.RFC822.Subject("")).create_forward().value;
|
||||
}
|
||||
|
||||
// Removes address from the list of addresses. If the list contains only the given address, the
|
||||
// behavior depends on empty_ok: if true the list will be emptied, otherwise it will leave the
|
||||
// address in the list once. Used to remove the sender's address from a list of addresses being
|
||||
// created for the "reply to" recipients.
|
||||
private void remove_address(Gee.List<Geary.RFC822.MailboxAddress> addresses,
|
||||
RFC822.MailboxAddress address, bool empty_ok = false) {
|
||||
for (int i = 0; i < addresses.size; ++i) {
|
||||
if (addresses[i].equal_to(address) && (empty_ok || addresses.size > 1))
|
||||
addresses.remove_at(i--);
|
||||
}
|
||||
}
|
||||
|
||||
private bool email_is_from_sender(Geary.Email email, Gee.List<RFC822.MailboxAddress>? sender_addresses) {
|
||||
if (sender_addresses == null || email.from == null)
|
||||
return false;
|
||||
|
||||
return Geary.traverse<RFC822.MailboxAddress>(sender_addresses)
|
||||
.any(a => email.from.get_all().contains(a));
|
||||
}
|
||||
|
||||
public Geary.RFC822.MailboxAddresses create_to_addresses_for_reply(Geary.Email email,
|
||||
Gee.List< Geary.RFC822.MailboxAddress>? sender_addresses = null) {
|
||||
Gee.List<Geary.RFC822.MailboxAddress> new_to =
|
||||
new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
|
||||
|
||||
// If we're replying to something we sent, send it to the same people we originally did.
|
||||
// Otherwise, we'll send to the reply-to address or the from address.
|
||||
if (email.to != null && email_is_from_sender(email, sender_addresses))
|
||||
new_to.add_all(email.to.get_all());
|
||||
else if (email.reply_to != null)
|
||||
new_to.add_all(email.reply_to.get_all());
|
||||
else if (email.from != null)
|
||||
new_to.add_all(email.from.get_all());
|
||||
|
||||
// Exclude the current sender. No need to receive the mail they're sending.
|
||||
if (sender_addresses != null) {
|
||||
foreach (RFC822.MailboxAddress address in sender_addresses)
|
||||
remove_address(new_to, address);
|
||||
}
|
||||
|
||||
return new Geary.RFC822.MailboxAddresses(new_to);
|
||||
}
|
||||
|
||||
public Geary.RFC822.MailboxAddresses create_cc_addresses_for_reply_all(Geary.Email email,
|
||||
Gee.List<Geary.RFC822.MailboxAddress>? sender_addresses = null) {
|
||||
Gee.List<Geary.RFC822.MailboxAddress> new_cc = new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
|
||||
|
||||
// If we're replying to something we received, also add other recipients. Don't do this for
|
||||
// emails we sent, since everyone we sent it to is already covered in
|
||||
// create_to_addresses_for_reply().
|
||||
if (email.to != null && !email_is_from_sender(email, sender_addresses))
|
||||
new_cc.add_all(email.to.get_all());
|
||||
|
||||
if (email.cc != null)
|
||||
new_cc.add_all(email.cc.get_all());
|
||||
|
||||
// Again, exclude the current sender.
|
||||
if (sender_addresses != null) {
|
||||
foreach (RFC822.MailboxAddress address in sender_addresses)
|
||||
remove_address(new_cc, address, true);
|
||||
}
|
||||
|
||||
return new Geary.RFC822.MailboxAddresses(new_cc);
|
||||
}
|
||||
|
||||
public Geary.RFC822.MailboxAddresses merge_addresses(Geary.RFC822.MailboxAddresses? first,
|
||||
Geary.RFC822.MailboxAddresses? second) {
|
||||
Gee.List<Geary.RFC822.MailboxAddress> result = new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
|
||||
if (first != null) {
|
||||
result.add_all(first.get_all());
|
||||
// Add addresses from second that aren't in first.
|
||||
if (second != null)
|
||||
foreach (Geary.RFC822.MailboxAddress address in second)
|
||||
if (!first.contains_normalized(address.address))
|
||||
result.add(address);
|
||||
} else if (second != null) {
|
||||
result.add_all(second.get_all());
|
||||
}
|
||||
|
||||
return new Geary.RFC822.MailboxAddresses(result);
|
||||
}
|
||||
|
||||
public Geary.RFC822.MailboxAddresses remove_addresses(Geary.RFC822.MailboxAddresses? from_addresses,
|
||||
Geary.RFC822.MailboxAddresses? remove_addresses) {
|
||||
Gee.List<Geary.RFC822.MailboxAddress> result = new Gee.ArrayList<Geary.RFC822.MailboxAddress>();
|
||||
if (from_addresses != null) {
|
||||
result.add_all(from_addresses.get_all());
|
||||
if (remove_addresses != null)
|
||||
foreach (Geary.RFC822.MailboxAddress address in remove_addresses)
|
||||
remove_address(result, address, true);
|
||||
}
|
||||
return new Geary.RFC822.MailboxAddresses(result);
|
||||
}
|
||||
|
||||
public string reply_references(Geary.Email source) {
|
||||
// generate list for References
|
||||
Gee.ArrayList<RFC822.MessageID> list = new Gee.ArrayList<RFC822.MessageID>();
|
||||
|
||||
// 1. Start with the source's References list
|
||||
if (source.references != null && source.references.list.size > 0)
|
||||
list.add_all(source.references.list);
|
||||
|
||||
// 2. If there are In-Reply-To Message-IDs and they're not in the References list, append them
|
||||
if (source.in_reply_to != null) {
|
||||
foreach (RFC822.MessageID reply_id in source.in_reply_to.list) {
|
||||
if (!list.contains(reply_id))
|
||||
list.add(reply_id);
|
||||
// Exclude the current sender. No need to receive the mail they're sending.
|
||||
if (sender_addresses != null) {
|
||||
foreach (var address in sender_addresses) {
|
||||
remove_address(new_to, address);
|
||||
}
|
||||
}
|
||||
|
||||
return new MailboxAddresses(new_to);
|
||||
}
|
||||
|
||||
// 3. Append the source's Message-ID, if available.
|
||||
if (source.message_id != null)
|
||||
list.add(source.message_id);
|
||||
public MailboxAddresses create_cc_addresses_for_reply_all(Email email,
|
||||
Gee.List<MailboxAddress>? sender_addresses = null) {
|
||||
var new_cc = new Gee.ArrayList<MailboxAddress>();
|
||||
|
||||
string[] strings = new string[list.size];
|
||||
for(int i = 0; i < list.size; ++i)
|
||||
strings[i] = list[i].value;
|
||||
// If we're replying to something we received, also add other recipients. Don't do this for
|
||||
// emails we sent, since everyone we sent it to is already covered in
|
||||
// create_to_addresses_for_reply().
|
||||
if (email.to != null && !email_is_from_sender(email, sender_addresses))
|
||||
new_cc.add_all(email.to.get_all());
|
||||
|
||||
return (list.size > 0) ? string.joinv(" ", strings) : "";
|
||||
}
|
||||
if (email.cc != null)
|
||||
new_cc.add_all(email.cc.get_all());
|
||||
|
||||
public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses, TextFormat format) {
|
||||
if (addresses == null)
|
||||
return "";
|
||||
// Again, exclude the current sender.
|
||||
if (sender_addresses != null) {
|
||||
foreach (var address in sender_addresses) {
|
||||
remove_address(new_cc, address, true);
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
return new MailboxAddresses(new_cc);
|
||||
}
|
||||
|
||||
public MailboxAddresses merge_addresses(MailboxAddresses? first,
|
||||
MailboxAddresses? second) {
|
||||
var result = new Gee.ArrayList<MailboxAddress>();
|
||||
if (first != null) {
|
||||
result.add_all(first.get_all());
|
||||
// Add addresses from second that aren't in first.
|
||||
if (second != null)
|
||||
foreach (MailboxAddress address in second)
|
||||
if (!first.contains_normalized(address.address))
|
||||
result.add(address);
|
||||
} else if (second != null) {
|
||||
result.add_all(second.get_all());
|
||||
}
|
||||
return new MailboxAddresses(result);
|
||||
}
|
||||
|
||||
public MailboxAddresses remove_addresses(MailboxAddresses? from_addresses,
|
||||
MailboxAddresses? remove_addresses) {
|
||||
Gee.List<MailboxAddress> result = new Gee.ArrayList<MailboxAddress>();
|
||||
if (from_addresses != null) {
|
||||
result.add_all(from_addresses.get_all());
|
||||
if (remove_addresses != null)
|
||||
foreach (MailboxAddress address in remove_addresses)
|
||||
remove_address(result, address, true);
|
||||
}
|
||||
return new MailboxAddresses(result);
|
||||
}
|
||||
|
||||
public string reply_references(Email source) {
|
||||
// generate list for References
|
||||
var list = new Gee.ArrayList<MessageID>();
|
||||
|
||||
// 1. Start with the source's References list
|
||||
if (source.references != null && source.references.list.size > 0) {
|
||||
list.add_all(source.references.list);
|
||||
}
|
||||
|
||||
// 2. If there are In-Reply-To Message-IDs and they're not in the References list, append them
|
||||
if (source.in_reply_to != null) {
|
||||
foreach (var reply_id in source.in_reply_to.list) {
|
||||
if (!list.contains(reply_id)) {
|
||||
list.add(reply_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Append the source's Message-ID, if available.
|
||||
if (source.message_id != null) {
|
||||
list.add(source.message_id);
|
||||
}
|
||||
|
||||
string[] strings = new string[list.size];
|
||||
for(int i = 0; i < list.size; ++i) {
|
||||
strings[i] = list[i].value;
|
||||
}
|
||||
|
||||
return (list.size > 0) ? string.joinv(" ", strings) : "";
|
||||
}
|
||||
|
||||
public string email_addresses_for_reply(MailboxAddresses? addresses,
|
||||
TextFormat format) {
|
||||
if (addresses == null)
|
||||
return "";
|
||||
|
||||
switch (format) {
|
||||
case TextFormat.HTML:
|
||||
return HTML.escape_markup(addresses.to_full_display());
|
||||
|
||||
|
|
@ -182,127 +141,177 @@ public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses
|
|||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool comp_char_arr_slice(uint8[] array, uint start, string comp) {
|
||||
for (int i = 0; i < comp.length; i++) {
|
||||
if (array[start + i] != comp[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Obtains the best preview text from a plain or HTML string.
|
||||
*
|
||||
* The given string `text` should have UNIX encoded line endings (LF),
|
||||
* rather than RFC822 (CRLF). The string returned will will have had
|
||||
* its whitespace squashed.
|
||||
*/
|
||||
public string to_preview_text(string? text, TextFormat format) {
|
||||
string preview = "";
|
||||
|
||||
/**
|
||||
* Obtains the best preview text from a plain or HTML string.
|
||||
*
|
||||
* The given string `text` should have UNIX encoded line endings (LF),
|
||||
* rather than RFC822 (CRLF). The string returned will will have had
|
||||
* its whitespace squashed.
|
||||
*/
|
||||
public string to_preview_text(string? text, TextFormat format) {
|
||||
string preview = "";
|
||||
|
||||
if (format == TextFormat.PLAIN) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
string[] all_lines = text.split("\n");
|
||||
bool in_inline_pgp_header = false;
|
||||
foreach (string line in all_lines) {
|
||||
if (in_inline_pgp_header) {
|
||||
if (Geary.String.is_empty(line)) {
|
||||
in_inline_pgp_header = false;
|
||||
if (format == TextFormat.PLAIN) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
string[] all_lines = text.split("\n");
|
||||
bool in_inline_pgp_header = false;
|
||||
foreach (string line in all_lines) {
|
||||
if (in_inline_pgp_header) {
|
||||
if (Geary.String.is_empty(line)) {
|
||||
in_inline_pgp_header = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("-----BEGIN PGP SIGNED MESSAGE-----")) {
|
||||
in_inline_pgp_header = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.has_prefix(">"))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("--"))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("===="))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("~~~~"))
|
||||
continue;
|
||||
|
||||
if (Geary.String.is_empty_or_whitespace(line)) {
|
||||
buf.append("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.append(" ");
|
||||
buf.append(line);
|
||||
}
|
||||
|
||||
if (line.has_prefix("-----BEGIN PGP SIGNED MESSAGE-----")) {
|
||||
in_inline_pgp_header = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.has_prefix(">"))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("--"))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("===="))
|
||||
continue;
|
||||
|
||||
if (line.has_prefix("~~~~"))
|
||||
continue;
|
||||
|
||||
if (Geary.String.is_empty_or_whitespace(line)) {
|
||||
buf.append("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.append(" ");
|
||||
buf.append(line);
|
||||
preview = buf.str;
|
||||
} else if (format == TextFormat.HTML) {
|
||||
preview = Geary.HTML.html_to_text(text, false);
|
||||
}
|
||||
|
||||
preview = buf.str;
|
||||
} else if (format == TextFormat.HTML) {
|
||||
preview = Geary.HTML.html_to_text(text, false);
|
||||
// XXX really shouldn't have to call make_valid here but do so to
|
||||
// avoid segfaults in the regex engine on invalid char data. See
|
||||
// issue #186 for the proper fix.
|
||||
return Geary.String.reduce_whitespace(preview.make_valid());
|
||||
}
|
||||
|
||||
// XXX really shouldn't have to call make_valid here but do so to
|
||||
// avoid segfaults in the regex engine on invalid char data. See
|
||||
// issue #186 for the proper fix.
|
||||
return Geary.String.reduce_whitespace(preview.make_valid());
|
||||
}
|
||||
/**
|
||||
* Uses a GMime.FilterBest to determine the best charset.
|
||||
*
|
||||
* This may require processing the entire stream, so occurs in a
|
||||
* background thread.
|
||||
*/
|
||||
internal async string get_best_charset(GMime.Stream in_stream,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
GMime.FilterBest filter = new GMime.FilterBest(CHARSET);
|
||||
GMime.StreamFilter out_stream = new GMime.StreamFilter(
|
||||
new GMime.StreamNull()
|
||||
);
|
||||
out_stream.add(filter);
|
||||
|
||||
/**
|
||||
* Uses a GMime.FilterBest to determine the best charset.
|
||||
*
|
||||
* This may require processing the entire stream, so occurs in a
|
||||
* background thread.
|
||||
*/
|
||||
public async string get_best_charset(GMime.Stream in_stream,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
GMime.FilterBest filter = new GMime.FilterBest(CHARSET);
|
||||
GMime.StreamFilter out_stream = new GMime.StreamFilter(
|
||||
new GMime.StreamNull()
|
||||
);
|
||||
out_stream.add(filter);
|
||||
yield Nonblocking.Concurrent.global.schedule_async(() => {
|
||||
in_stream.write_to_stream(out_stream);
|
||||
in_stream.reset();
|
||||
out_stream.close();
|
||||
},
|
||||
cancellable
|
||||
);
|
||||
return filter.get_charset();
|
||||
}
|
||||
|
||||
yield Nonblocking.Concurrent.global.schedule_async(() => {
|
||||
in_stream.write_to_stream(out_stream);
|
||||
in_stream.reset();
|
||||
out_stream.close();
|
||||
},
|
||||
cancellable
|
||||
);
|
||||
return filter.get_charset();
|
||||
}
|
||||
/**
|
||||
* Uses a GMime.FilterBest to determine the best encoding.
|
||||
*
|
||||
* This may require processing the entire stream, so occurs in a
|
||||
* background thread.
|
||||
*/
|
||||
internal async GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream,
|
||||
GMime.EncodingConstraint constraint,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
GMime.FilterBest filter = new GMime.FilterBest(ENCODING);
|
||||
GMime.StreamFilter out_stream = new GMime.StreamFilter(
|
||||
new GMime.StreamNull()
|
||||
);
|
||||
out_stream.add(filter);
|
||||
|
||||
/**
|
||||
* Uses a GMime.FilterBest to determine the best encoding.
|
||||
*
|
||||
* This may require processing the entire stream, so occurs in a
|
||||
* background thread.
|
||||
*/
|
||||
public async GMime.ContentEncoding get_best_encoding(GMime.Stream in_stream,
|
||||
GMime.EncodingConstraint constraint,
|
||||
GLib.Cancellable? cancellable)
|
||||
throws GLib.Error {
|
||||
GMime.FilterBest filter = new GMime.FilterBest(ENCODING);
|
||||
GMime.StreamFilter out_stream = new GMime.StreamFilter(
|
||||
new GMime.StreamNull()
|
||||
);
|
||||
out_stream.add(filter);
|
||||
yield Nonblocking.Concurrent.global.schedule_async(() => {
|
||||
in_stream.write_to_stream(out_stream);
|
||||
in_stream.reset();
|
||||
out_stream.close();
|
||||
},
|
||||
cancellable
|
||||
);
|
||||
return filter.encoding(constraint);
|
||||
}
|
||||
|
||||
yield Nonblocking.Concurrent.global.schedule_async(() => {
|
||||
in_stream.write_to_stream(out_stream);
|
||||
in_stream.reset();
|
||||
out_stream.close();
|
||||
},
|
||||
cancellable
|
||||
);
|
||||
return filter.encoding(constraint);
|
||||
}
|
||||
/**
|
||||
* Uses the best-possible transfer of bytes from the Memory.Buffer to the GMime.StreamMem object.
|
||||
* The StreamMem object should be destroyed *before* the Memory.Buffer object, since this method
|
||||
* will use unowned variants whenever possible.
|
||||
*/
|
||||
internal GMime.StreamMem create_stream_mem(Memory.Buffer buffer) {
|
||||
Memory.UnownedByteArrayBuffer? unowned_bytes_array_buffer = buffer as Memory.UnownedByteArrayBuffer;
|
||||
if (unowned_bytes_array_buffer != null) {
|
||||
// set_byte_array doesn't do any copying and doesn't take ownership -- perfect, this is
|
||||
// the best of all possible worlds, assuming the Memory.Buffer is not destroyed first
|
||||
GMime.StreamMem stream = new GMime.StreamMem();
|
||||
stream.set_byte_array(unowned_bytes_array_buffer.to_unowned_byte_array());
|
||||
return stream;
|
||||
}
|
||||
|
||||
Memory.UnownedBytesBuffer? unowned_bytes_buffer = buffer as Memory.UnownedBytesBuffer;
|
||||
if (unowned_bytes_buffer != null) {
|
||||
// StreamMem.with_buffer does do a buffer copy (there's not set_buffer() call like
|
||||
// set_byte_array() for some reason), but don't do a buffer copy when it comes out of the
|
||||
// Memory.Buffer
|
||||
return new GMime.StreamMem.with_buffer(unowned_bytes_buffer.to_unowned_uint8_array());
|
||||
}
|
||||
|
||||
// do plain-old buffer copy
|
||||
return new GMime.StreamMem.with_buffer(buffer.get_uint8_array());
|
||||
}
|
||||
|
||||
internal bool comp_char_arr_slice(uint8[] array, uint start, string comp) {
|
||||
for (int i = 0; i < comp.length; i++) {
|
||||
if (array[start + i] != comp[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes address from the list of addresses. If the list contains only the given address, the
|
||||
// behavior depends on empty_ok: if true the list will be emptied, otherwise it will leave the
|
||||
// address in the list once. Used to remove the sender's address from a list of addresses being
|
||||
// created for the "reply to" recipients.
|
||||
private void remove_address(Gee.List<MailboxAddress> addresses,
|
||||
MailboxAddress address,
|
||||
bool empty_ok = false) {
|
||||
for (int i = 0; i < addresses.size; ++i) {
|
||||
if (addresses[i].equal_to(address) &&
|
||||
(empty_ok || addresses.size > 1)) {
|
||||
addresses.remove_at(i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool email_is_from_sender(Email email, Gee.List<RFC822.MailboxAddress>? sender_addresses) {
|
||||
var ret = false;
|
||||
if (sender_addresses != null && email.from != null) {
|
||||
ret = traverse<MailboxAddress>(sender_addresses)
|
||||
.any(a => email.from.get_all().contains(a));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue