Change GMime dependency from 2.6.17 to 3.2.4

This commit squashes several non-compiling commits:

66dd6500 Change required GMime version to 3.2.4 or higher
4b9c8a38 Fix some compilations errors in test code
98aa5a2e Fix some (hopefully) last compilation errors
558360c6 Fix parser format when getting message headers
cc248ffc Fix name of stream-buffer mode
b293c66b Fix another iteration over a header-list
52fa183f Fix parsing of Gmime parameters
e078ee62 Use Unix2Dos-, Dos2Unix- and/or SmtpData-filters instead of 'FilterCRLF'
ff31b8e5 Fix setting of email headers
eb676482 Fix compilation errros due to string-uint8-char conversion problems
8558769f Fix datetime conversion
d44a28cd Remove some obsolete arguments
1ce81662 Pass charset where it's required
6013806f Pass GMime.ParserOptions to header-decode methods
986d05a0 Pass GMime.FormatOptions where it's required
e9b93187 Pass GMime.ParserOptions where it's required
640ce667 Fix compilation errors in GMime initialization
312f80bf Remove use of GMime.HeaderIter
acc73d14 Change GMime dependency from 2.6 to 3.0
54fc250a Adapt names to 'offical' gmime-2.6 bindings

The commits are part of the branch 'letorbi/gmime-3-spread', which can be
found at: https://gitlab.gnome.org/letorbi/geary/tree/letorbi/gmime-3-spread
This commit is contained in:
Torben 2019-11-30 20:09:28 +01:00
parent fced79bfd2
commit 1aac6f2284
17 changed files with 236 additions and 203 deletions

View file

@ -57,7 +57,7 @@ target_webkit = '2.24'
# Primary deps
glib = dependency('glib-2.0', version: '>=' + target_glib)
gmime = dependency('gmime-2.6', version: '>= 2.6.17')
gmime = dependency('gmime-3.0', version: '>= 3.2.4')
gtk = dependency('gtk+-3.0', version: '>=' + target_gtk)
sqlite = dependency('sqlite3', version: '>= 3.24')
webkit2gtk = dependency('webkit2gtk-4.0', version: '>=' + target_webkit)

View file

@ -180,7 +180,7 @@ private class Geary.ImapDB.Attachment : Geary.Attachment {
target_stream
);
stream = new GMime.StreamBuffer(
stream, GMime.StreamBufferMode.BLOCK_WRITE
stream, GMime.StreamBufferMode.WRITE
);
part.write_to_stream(stream, RFC822.Part.EncodingConversion.NONE);

View file

@ -102,7 +102,7 @@ public class Geary.Mime.ContentDisposition : Geary.BaseObject {
out is_unknown);
is_unknown_disposition_type = is_unknown;
original_disposition_type_string = content_disposition.get_disposition();
params = new ContentParameters.from_gmime(content_disposition.get_params());
params = new ContentParameters.from_gmime(content_disposition.get_parameters());
}
}

View file

@ -51,11 +51,13 @@ public class Geary.Mime.ContentParameters : BaseObject {
}
}
internal ContentParameters.from_gmime(GMime.Param? gmime_param) {
internal ContentParameters.from_gmime(GMime.ParamList? gmime_params) {
Gee.Map<string,string> params = new Gee.HashMap<string,string>();
while (gmime_param != null) {
params.set(gmime_param.get_name(), gmime_param.get_value());
gmime_param = gmime_param.get_next();
if (gmime_params != null) {
for (int i=0; i < gmime_params.length(); i++) {
GMime.Param gmime_param = gmime_params.get_parameter_at(i);
params.set(gmime_param.get_name(), gmime_param.get_value());
}
}
this(params);
}

View file

@ -74,7 +74,10 @@ public class Geary.Mime.ContentType : Geary.BaseObject {
if (!str.contains("/"))
throw new MimeError.PARSE("Invalid MIME Content-Type: %s", str);
return new ContentType.from_gmime(new GMime.ContentType.from_string(str));
return new ContentType.from_gmime(GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
str
));
}
/**
@ -158,7 +161,7 @@ public class Geary.Mime.ContentType : Geary.BaseObject {
internal ContentType.from_gmime(GMime.ContentType content_type) {
media_type = content_type.get_media_type().strip();
media_subtype = content_type.get_media_subtype().strip();
params = new ContentParameters.from_gmime(content_type.get_params());
params = new ContentParameters.from_gmime(content_type.get_parameters());
}
/**

View file

@ -49,7 +49,7 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
return new_filter;
}
private void do_filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
private void do_filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace, bool flush) {
// This may not be strictly necessary.
@ -64,7 +64,7 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
}
for (uint i = 0; i < inbuf.length; i++) {
char c = inbuf[i];
uint8 c = inbuf[i];
if (in_prefix && !in_tag) {
if (c == Geary.RFC822.Utils.QUOTE_MARKER) {
@ -122,12 +122,12 @@ private class Geary.RFC822.FilterBlockquotes : GMime.Filter {
outprespace = this.outpre;
}
public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
do_filter(inbuf, prespace, out processed_buffer, out outprespace, false);
}
public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
do_filter(inbuf, prespace, out processed_buffer, out outprespace, true);
}

View file

@ -57,7 +57,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
return new_filter;
}
public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
// Worst-case scenario: We are about to leave the prefix,
@ -67,7 +67,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
uint out_index = 0;
for (uint i = 0; i < inbuf.length; i++) {
char c = inbuf[i];
uint8 c = inbuf[i];
if (this.in_prefix) {
if (c == '>') {
@ -147,7 +147,7 @@ private class Geary.RFC822.FilterFlowed : GMime.Filter {
outprespace = this.outpre;
}
public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
filter(inbuf, prespace, out processed_buffer, out outprespace);
}

View file

@ -26,7 +26,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
return new_filter;
}
public override void filter(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void filter(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
// This may not be strictly necessary.
@ -34,7 +34,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
uint out_index = 0;
for (uint i = 0; i < inbuf.length; i++) {
char c = inbuf[i];
uint8 c = inbuf[i];
if (in_prefix) {
if (c == '>') {
@ -56,7 +56,7 @@ private class Geary.RFC822.FilterPlain : GMime.Filter {
outprespace = this.outpre;
}
public override void complete(char[] inbuf, size_t prespace, out unowned char[] processed_buffer,
public override void complete(uint8[] inbuf, size_t prespace, out unowned uint8[] processed_buffer,
out size_t outprespace) {
filter(inbuf, prespace, out processed_buffer, out outprespace);
}

View file

@ -42,11 +42,17 @@ public class Geary.RFC822.MailboxAddress :
}
private static string decode_name(string name) {
return GMime.utils_header_decode_phrase(prepare_header_text_part(name));
return GMime.utils_header_decode_phrase(
Geary.RFC822.get_parser_options(),
prepare_header_text_part(name)
);
}
private static string decode_address_part(string mailbox) {
return GMime.utils_header_decode_text(prepare_header_text_part(mailbox));
return GMime.utils_header_decode_text(
Geary.RFC822.get_parser_options(),
prepare_header_text_part(mailbox)
);
}
private static bool display_name_needs_quoting(string name) {
@ -118,8 +124,9 @@ public class Geary.RFC822.MailboxAddress :
// _internet_address_decode_name() function.
// see if a broken mailer has sent raw 8-bit information
string text = GMime.utils_text_is_8bit(part, part.length)
? part : GMime.utils_decode_8bit(part, part.length);
string text = GMime.utils_text_is_8bit(part.data)
? part : GMime.utils_decode_8bit(Geary.RFC822.get_parser_options(),
part.data);
// unquote the string then decode the text
GMime.utils_unquote_string(text);
@ -222,16 +229,19 @@ public class Geary.RFC822.MailboxAddress :
}
public MailboxAddress.from_rfc822_string(string rfc822) throws RFC822Error {
InternetAddressList addrlist = InternetAddressList.parse_string(rfc822);
GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse(
Geary.RFC822.get_parser_options(),
rfc822
);
if (addrlist == null)
return;
int length = addrlist.length();
for (int ctr = 0; ctr < length; ctr++) {
InternetAddress? addr = addrlist.get_address(ctr);
GMime.InternetAddress? addr = addrlist.get_address(ctr);
// TODO: Handle group lists
InternetAddressMailbox? mbox_addr = addr as InternetAddressMailbox;
GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox;
if (mbox_addr != null) {
this.gmime(mbox_addr);
return;
@ -240,7 +250,7 @@ public class Geary.RFC822.MailboxAddress :
throw new RFC822Error.INVALID("Could not parse RFC822 address: %s", rfc822);
}
public MailboxAddress.gmime(InternetAddressMailbox mailbox) {
public MailboxAddress.gmime(GMime.InternetAddressMailbox mailbox) {
// GMime strips source route for us, so the address part
// should only ever contain a single '@'
string? name = mailbox.get_name();
@ -456,7 +466,11 @@ public class Geary.RFC822.MailboxAddress :
public string to_rfc822_string() {
return has_distinct_name()
? "%s <%s>".printf(
GMime.utils_header_encode_phrase(this.name),
GMime.utils_header_encode_phrase(
Geary.RFC822.get_format_options(),
this.name,
Geary.RFC822.get_charset()
),
to_rfc822_address()
)
: to_rfc822_address();

View file

@ -74,27 +74,30 @@ public class Geary.RFC822.MailboxAddresses :
}
public MailboxAddresses.from_rfc822_string(string rfc822) {
InternetAddressList addrlist = InternetAddressList.parse_string(rfc822);
GMime.InternetAddressList addrlist = GMime.InternetAddressList.parse(
Geary.RFC822.get_parser_options(),
rfc822
);
if (addrlist == null)
return;
int length = addrlist.length();
for (int ctr = 0; ctr < length; ctr++) {
InternetAddress? addr = addrlist.get_address(ctr);
GMime.InternetAddress? addr = addrlist.get_address(ctr);
InternetAddressMailbox? mbox_addr = addr as InternetAddressMailbox;
GMime.InternetAddressMailbox? mbox_addr = addr as GMime.InternetAddressMailbox;
if (mbox_addr != null) {
this.addrs.add(new MailboxAddress.gmime(mbox_addr));
} else {
// XXX this is pretty bad - we just flatten the
// group's addresses into this list, merging lists and
// losing the group names.
InternetAddressGroup? mbox_group = addr as InternetAddressGroup;
GMime.InternetAddressGroup? mbox_group = addr as GMime.InternetAddressGroup;
if (mbox_group != null) {
InternetAddressList group_list = mbox_group.get_members();
GMime.InternetAddressList group_list = mbox_group.get_members();
for (int i = 0; i < group_list.length(); i++) {
InternetAddressMailbox? group_addr =
addrlist.get_address(i) as InternetAddressMailbox;
GMime.InternetAddressMailbox? group_addr =
addrlist.get_address(i) as GMime.InternetAddressMailbox;
if (group_addr != null) {
this.addrs.add(new MailboxAddress.gmime(group_addr));
}

View file

@ -173,27 +173,13 @@ public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.Abs
public DateTime value { get; private set; }
public Date(string rfc822) throws ImapError {
int offset = 0;
int64 time_t_utc = GMime.utils_header_decode_date(rfc822, out offset);
if (time_t_utc == 0)
throw new ImapError.PARSE_ERROR(
"Unable to parse \"%s\": Not ISO-8601 date", rfc822
);
DateTime? value = new DateTime.from_unix_utc(time_t_utc);
DateTime? value = GMime.utils_header_decode_date(rfc822);
if (value == null) {
throw new ImapError.PARSE_ERROR(
"Unable to parse \"%s\": Outside supported range", rfc822
);
}
this.value = value;
if (offset != 0) {
this.value = value.to_timezone(
new GLib.TimeZone("%+05d".printf(offset))
);
}
this.original = rfc822;
}
@ -206,18 +192,7 @@ public class Geary.RFC822.Date : Geary.RFC822.MessageData, Geary.MessageData.Abs
* Returns the {@link Date} in RFC 822 format.
*/
public string to_rfc822_string() {
// Although GMime documents its conversion methods as
// requiring the tz offset in hours, it appears the number is
// handed directly to the string (i.e. an offset of -7:30 becomes
// "-0007", whereas we want "-0730").
int hours = (int) GLib.Math.floor(value.get_utc_offset() / TimeSpan.HOUR);
int minutes = (int) (
(value.get_utc_offset() % TimeSpan.HOUR) / (double) TimeSpan.HOUR * 60
);
return GMime.utils_header_format_date(
(time_t) this.value.to_utc().to_unix(),
(hours * 100) + minutes
);
return GMime.utils_header_format_date(this.value);
}
/**
@ -261,7 +236,7 @@ public class Geary.RFC822.Subject : Geary.MessageData.StringMessageData,
}
public Subject.decode(string value) {
base (GMime.utils_header_decode_text(value));
base (GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value));
original = value;
}
@ -337,9 +312,10 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(buffer));
parser.set_respect_content_length(false);
parser.set_scan_from(false);
// TODO Could this be omitted?
parser.set_format(GMime.Format.MESSAGE);
message = parser.construct_message();
message = parser.construct_message(Geary.RFC822.get_parser_options());
if (message == null)
throw new RFC822Error.INVALID("Unable to parse RFC 822 headers");
@ -347,17 +323,15 @@ public class Geary.RFC822.Header : Geary.MessageData.BlockMessageData, Geary.RFC
}
public string? get_header(string name) throws RFC822Error {
return get_headers().get(name);
return get_headers().get_header(name).get_value();
}
public string[] get_header_names() throws RFC822Error {
if (this.names == null) {
this.names = new string[0];
GMime.HeaderIter iter = new GMime.HeaderIter();
if (get_headers().get_iter(iter) && iter.first()) {
do {
names += iter.get_name();
} while (iter.next());
GMime.HeaderList headers = get_headers();
for (int i = 0; i < headers.get_count(); i++) {
names += headers.get_header_at(i).get_name();
}
}
return this.names;
@ -388,7 +362,7 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
// Parse the header.
GMime.Stream header_stream = Utils.create_stream_mem(preview_header);
GMime.Parser parser = new GMime.Parser.with_stream(header_stream);
GMime.Part? gpart = parser.construct_part() as GMime.Part;
GMime.Part? gpart = parser.construct_part(Geary.RFC822.get_parser_options()) as GMime.Part;
if (gpart != null) {
Part part = new Part(gpart);
@ -402,7 +376,7 @@ public class Geary.RFC822.PreviewText : Geary.RFC822.Text {
new GMime.StreamMem.with_buffer(preview.get_uint8_array()),
gpart.get_content_encoding()
);
gpart.set_content_object(body);
gpart.set_content(body);
try {
Memory.Buffer preview_buffer = part.write_to_buffer(

View file

@ -29,6 +29,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
*/
public delegate string? InlinePartReplacer(Part part);
private const string HEADER_DATE = "Date";
private const string HEADER_SENDER = "Sender";
private const string HEADER_IN_REPLY_TO = "In-Reply-To";
private const string HEADER_REFERENCES = "References";
@ -89,7 +90,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
public Message(Full full) throws RFC822Error {
GMime.Parser parser = new GMime.Parser.with_stream(Utils.create_stream_mem(full.buffer));
message = parser.construct_message();
message = parser.construct_message(Geary.RFC822.get_parser_options());
if (message == null)
throw new RFC822Error.INVALID("Unable to parse RFC 822 message");
@ -115,7 +116,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
stream_cat.add_source(new GMime.StreamMem.with_buffer(body.buffer.get_bytes().get_data()));
GMime.Parser parser = new GMime.Parser.with_stream(stream_cat);
message = parser.construct_message();
message = parser.construct_message(Geary.RFC822.get_parser_options());
if (message == null)
throw new RFC822Error.INVALID("Unable to parse RFC 822 message");
@ -136,67 +137,71 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
this.from = email.from;
this.date = email.date;
// GMimeMessage.set_sender actually sets the From header - and
// although the API docs make it sound otherwise, it also
// supports a list of addresses
message.set_sender(this.from.to_rfc822_string());
message.set_date_as_string(this.date.serialize());
if (message_id != null) {
this.message_id = new MessageID(message_id);
message.set_message_id(message_id);
//message.set_date_as_string(this.date.serialize());
this.message.set_header(HEADER_DATE,
this.date.serialize(),
Geary.RFC822.get_charset());
if (email.from != null) {
foreach (RFC822.MailboxAddress mailbox in email.from)
this.message.add_mailbox(GMime.AddressType.FROM, mailbox.name, mailbox.address);
}
if (email.sender != null) {
this.message.add_mailbox(GMime.AddressType.SENDER, this.sender.name, this.sender.address);
// TODO Is setting the header still required?
this.message.set_header(HEADER_SENDER,
this.sender.to_rfc822_string(),
Geary.RFC822.get_charset());
}
// Optional headers
if (email.to != null) {
this.to = email.to;
foreach (RFC822.MailboxAddress mailbox in email.to)
this.message.add_recipient(GMime.RecipientType.TO, mailbox.name, mailbox.address);
this.message.add_mailbox(GMime.AddressType.TO, mailbox.name, mailbox.address);
}
if (email.cc != null) {
this.cc = email.cc;
foreach (RFC822.MailboxAddress mailbox in email.cc)
this.message.add_recipient(GMime.RecipientType.CC, mailbox.name, mailbox.address);
this.message.add_mailbox(GMime.AddressType.CC, mailbox.name, mailbox.address);
}
if (email.bcc != null) {
this.bcc = email.bcc;
foreach (RFC822.MailboxAddress mailbox in email.bcc)
this.message.add_recipient(GMime.RecipientType.BCC, mailbox.name, mailbox.address);
}
if (email.sender != null) {
this.sender = email.sender;
this.message.set_header(HEADER_SENDER,
email.sender.to_rfc822_string());
}
if (email.reply_to != null) {
this.reply_to = email.reply_to;
this.message.set_reply_to(email.reply_to.to_rfc822_string());
this.message.add_mailbox(GMime.AddressType.BCC, mailbox.name, mailbox.address);
}
if (email.in_reply_to != null) {
this.in_reply_to = email.in_reply_to;
foreach (RFC822.MailboxAddress mailbox in email.reply_to)
this.message.add_mailbox(GMime.AddressType.BCC, mailbox.name, mailbox.address);
// TODO Is setting the header still required?
this.message.set_header(HEADER_IN_REPLY_TO,
email.in_reply_to.to_rfc822_string());
email.in_reply_to.to_rfc822_string(),
Geary.RFC822.get_charset());
}
if (email.references != null) {
this.references = email.references;
this.message.set_header(HEADER_REFERENCES,
email.references.to_rfc822_string());
email.references.to_rfc822_string(),
Geary.RFC822.get_charset());
}
if (email.subject != null) {
this.subject = email.subject;
this.message.set_subject(email.subject.value);
this.message.set_subject(email.subject.value,
Geary.RFC822.get_charset());
}
// User-Agent
if (!Geary.String.is_empty(email.mailer)) {
this.mailer = email.mailer;
this.message.set_header(HEADER_MAILER, email.mailer);
this.message.set_header(HEADER_MAILER, email.mailer,
Geary.RFC822.get_charset());
}
// Build the message's body mime parts
@ -406,7 +411,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
string type) {
GMime.Object? part = coalesce_parts(parts, "related");
if (parts.size > 1) {
part.set_header("Type", type);
part.set_header("Type", type, Geary.RFC822.get_charset());
}
return part;
}
@ -437,7 +442,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
part.set_disposition(disposition.serialize());
part.set_filename(file.get_basename());
GMime.ContentType content_type = new GMime.ContentType.from_string(
GMime.ContentType content_type = GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
file_info.get_content_type()
);
part.set_content_type(content_type);
@ -468,7 +474,10 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
);
}
GMime.ContentType? content_type = new GMime.ContentType.from_string(mime_type.get_mime_type());
GMime.ContentType? content_type = GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
mime_type.get_mime_type()
);
if (content_type == null) {
throw new RFC822Error.INVALID(
@ -515,7 +524,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
}
part.set_content_encoding(encoding);
part.set_content_object(
part.set_content(
new GMime.DataWrapper.with_stream(
stream, GMime.ContentEncoding.BINARY
)
@ -536,7 +545,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
Geary.Email email = new Geary.Email(id);
email.set_message_header(new Geary.RFC822.Header(new Geary.Memory.StringBuffer(
message.get_headers())));
message.get_headers(Geary.RFC822.get_format_options()))));
email.set_send_date(date);
email.set_originators(from, sender, reply_to);
email.set_receivers(to, cc, bcc);
@ -884,68 +893,72 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
}
private void stock_from_gmime() {
this.message.get_header_list().foreach((name, value) => {
switch (name.down()) {
case "from":
this.from = append_address(this.from, value);
break;
GMime.HeaderList headers = this.message.get_header_list();
for (int i=0; i < headers.get_count(); i++) {
GMime.Header header = headers.get_header_at(i);
string name = header.get_name();
string value = header.get_value();
switch (name.down()) {
case "from":
this.from = append_address(this.from, value);
break;
case "sender":
try {
this.sender = new RFC822.MailboxAddress.from_rfc822_string(value);
} catch (Error err) {
debug("Could parse subject: %s", err.message);
}
break;
case "reply-to":
this.reply_to = append_address(this.reply_to, value);
break;
case "to":
this.to = append_address(this.to, value);
break;
case "cc":
this.cc = append_address(this.cc, value);
break;
case "bcc":
this.bcc = append_address(this.bcc, value);
break;
case "subject":
this.subject = new RFC822.Subject.decode(value);
break;
case "date":
try {
this.date = new Geary.RFC822.Date(value);
} catch (Error err) {
debug("Could not parse date: %s", err.message);
}
break;
case "message-id":
this.message_id = new MessageID(value);
break;
case "in-reply-to":
this.in_reply_to = append_message_id(this.in_reply_to, value);
break;
case "references":
this.references = append_message_id(this.references, value);
break;
case "x-mailer":
this.mailer = GMime.utils_header_decode_text(value);
break;
default:
break;
case "sender":
try {
this.sender = new RFC822.MailboxAddress.from_rfc822_string(value);
} catch (Error err) {
debug("Could parse subject: %s", err.message);
}
});
break;
case "reply-to":
this.reply_to = append_address(this.reply_to, value);
break;
case "to":
this.to = append_address(this.to, value);
break;
case "cc":
this.cc = append_address(this.cc, value);
break;
case "bcc":
this.bcc = append_address(this.bcc, value);
break;
case "subject":
this.subject = new RFC822.Subject.decode(value);
break;
case "date":
try {
this.date = new Geary.RFC822.Date(value);
} catch (Error err) {
debug("Could not parse date: %s", err.message);
}
break;
case "message-id":
this.message_id = new MessageID(value);
break;
case "in-reply-to":
this.in_reply_to = append_message_id(this.in_reply_to, value);
break;
case "references":
this.references = append_message_id(this.references, value);
break;
case "x-mailer":
this.mailer = GMime.utils_header_decode_text(Geary.RFC822.get_parser_options(), value);
break;
default:
break;
}
};
}
private MailboxAddresses append_address(MailboxAddresses? existing,
@ -990,11 +1003,11 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
if (requested_disposition == Mime.DispositionType.UNSPECIFIED || disposition == requested_disposition) {
GMime.Stream stream = new GMime.StreamMem();
message.write_to_stream(stream);
message.write_to_stream(Geary.RFC822.get_format_options(), stream);
GMime.DataWrapper data = new GMime.DataWrapper.with_stream(stream,
GMime.ContentEncoding.BINARY); // Equivalent to no encoding
GMime.Part part = new GMime.Part.with_type("message", "rfc822");
part.set_content_object(data);
part.set_content(data);
part.set_filename((message.get_subject() ?? _("(no subject)")) + ".eml");
attachments.add(new Part(part));
}
@ -1017,7 +1030,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
#if WITH_TNEF_SUPPORT
if (content_type.is_type("application", "vnd.ms-tnef")) {
GMime.StreamMem stream = new GMime.StreamMem();
((GMime.Part) root).get_content_object().write_to_stream(stream);
((GMime.Part) root).get_content().write_to_stream(stream);
ByteArray tnef_data = stream.get_byte_array();
Ytnef.TNEFStruct tn;
if (Ytnef.ParseMemory(tnef_data.data, out tn) == 0) {
@ -1052,8 +1065,8 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
GMime.Part part = new GMime.Part();
part.set_filename(filename);
part.set_content_type(new GMime.ContentType.from_string(GLib.ContentType.guess(filename, data, null)));
part.set_content_object(new GMime.DataWrapper.with_stream(new GMime.StreamMem.with_buffer(data), GMime.ContentEncoding.BINARY));
part.set_content_type(GMime.ContentType.parse(Geary.RFC822.get_parser_options(), GLib.ContentType.guess(filename, data, null)));
part.set_content(new GMime.DataWrapper.with_stream(new GMime.StreamMem.with_buffer(data), GMime.ContentEncoding.BINARY));
return part;
}
#endif
@ -1092,9 +1105,17 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
stream.set_owner(false);
GMime.StreamFilter stream_filter = new GMime.StreamFilter(stream);
stream_filter.add(new GMime.FilterCRLF(encoded, dotstuffed));
if (encoded) {
stream_filter.add(new GMime.FilterUnix2Dos(false));
}
else {
stream_filter.add(new GMime.FilterDos2Unix(false));
}
if (dotstuffed) {
stream_filter.add(new GMime.FilterSmtpData());
}
if (message.write_to_stream(stream_filter) < 0)
if (message.write_to_stream(Geary.RFC822.get_format_options(), stream_filter) < 0)
throw new RFC822Error.FAILED("Unable to write RFC822 message to memory buffer");
if (stream_filter.flush() != 0)
@ -1104,7 +1125,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
}
public string to_string() {
return message.to_string();
return message.to_string(Geary.RFC822.get_format_options());
}
/**
@ -1152,11 +1173,13 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
// Base64-encoded text needs to have CR's added after LF's
// before encoding, otherwise it breaks format=flowed. See
// Bug 753528.
filter_stream.add(new GMime.FilterCRLF(true, false));
filter_stream.add(new GMime.FilterUnix2Dos(false));
}
GMime.ContentType complete_type =
new GMime.ContentType.from_string(content_type);
GMime.ContentType complete_type = GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
content_type
);
complete_type.set_parameter("charset", charset);
if (is_flowed) {
complete_type.set_parameter("format", "flowed");
@ -1168,7 +1191,7 @@ public class Geary.RFC822.Message : BaseObject, EmailHeaderSet {
GMime.Part body_part = new GMime.Part();
body_part.set_content_type(complete_type);
body_part.set_content_object(body);
body_part.set_content(body);
body_part.set_content_encoding(encoding);
return body_part;
}

View file

@ -160,7 +160,7 @@ public class Geary.RFC822.Part : Object {
BodyFormatting format = BodyFormatting.NONE)
throws RFC822Error {
GMime.DataWrapper? wrapper = (this.source_part != null)
? this.source_part.get_content_object() : null;
? this.source_part.get_content() : null;
if (wrapper == null) {
throw new RFC822Error.INVALID(
"Could not get the content wrapper for content-type %s",
@ -201,7 +201,7 @@ public class Geary.RFC822.Part : Object {
if ((this.source_part == null ||
this.source_part.encoding != BASE64) &&
!(content_type.media_subtype in CR_PRESERVING_TEXT_TYPES)) {
filter.add(new GMime.FilterCRLF(false, false));
filter.add(new GMime.FilterDos2Unix(false));
}
if (flowed) {

View file

@ -186,7 +186,7 @@ public string email_addresses_for_reply(Geary.RFC822.MailboxAddresses? addresses
}
public bool comp_char_arr_slice(char[] array, uint start, string comp) {
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;
@ -277,7 +277,7 @@ public async string get_best_charset(GMime.Stream in_stream,
},
cancellable
);
return filter.charset();
return filter.get_charset();
}
/**

View file

@ -32,18 +32,7 @@ public void init() {
if (init_count++ != 0)
return;
GMime.init(GMime.ENABLE_RFC2047_WORKAROUNDS);
// This has the effect of ensuring all non US-ASCII and non-ISO-8859-1
// headers are always encoded as UTF-8. This should be fine because
// message bodies are also always sent as UTF-8.
const string?[] USER_CHARSETS = {
UTF8_CHARSET,
// GMime.set_user_charsets calls g_strdupv under the hood, so
// the array needs to be null-terminated
null
};
GMime.set_user_charsets(USER_CHARSETS);
GMime.init();
try {
invalid_filename_character_re = new Regex("[/\\0]");
@ -52,6 +41,17 @@ public void init() {
}
}
public GMime.FormatOptions get_format_options() {
return new GMime.FormatOptions();
}
public GMime.ParserOptions get_parser_options() {
return new GMime.ParserOptions();
}
public string? get_charset() {
return null;
}
internal bool is_utf_8(string charset) {
string up = charset.up();

View file

@ -21,7 +21,7 @@ class Geary.ImapDB.AttachmentTest : TestCase {
public void new_from_minimal_mime_part() throws Error {
GMime.Part part = new_part(null, ATTACHMENT_BODY.data);
part.set_header("Content-Type", "");
part.set_header("Content-Type", "", Geary.RFC822.get_charset());
Attachment test = new Attachment.from_part(
1, new Geary.RFC822.Part(part)
@ -51,7 +51,8 @@ class Geary.ImapDB.AttachmentTest : TestCase {
part.set_content_id(ID);
part.set_content_description(DESC);
part.set_content_disposition(
new GMime.ContentDisposition.from_string(
GMime.ContentDisposition.parse(
Geary.RFC822.get_parser_options(),
"attachment; filename=%s".printf(NAME)
)
);
@ -74,7 +75,10 @@ class Geary.ImapDB.AttachmentTest : TestCase {
public void new_from_inline_mime_part() throws Error {
GMime.Part part = new_part(null, ATTACHMENT_BODY.data);
part.set_content_disposition(
new GMime.ContentDisposition.from_string("inline")
GMime.ContentDisposition.parse(
Geary.RFC822.get_parser_options(),
"inline"
)
);
Attachment test = new Attachment.from_part(
@ -205,7 +209,8 @@ CREATE TABLE MessageAttachmentTable (
part.set_content_id(ID);
part.set_content_description(DESCRIPTION);
part.set_content_disposition(
new GMime.ContentDisposition.from_string(
GMime.ContentDisposition.parse(
Geary.RFC822.get_parser_options(),
"inline; filename=%s;".printf(FILENAME)
));
@ -352,12 +357,15 @@ private GMime.Part new_part(string? mime_type,
GMime.ContentEncoding encoding = GMime.ContentEncoding.DEFAULT) {
GMime.Part part = new GMime.Part();
if (mime_type != null) {
part.set_content_type(new GMime.ContentType.from_string(mime_type));
part.set_content_type(GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
mime_type
));
}
GMime.DataWrapper body_wrapper = new GMime.DataWrapper.with_stream(
new GMime.StreamMem.with_buffer(body),
encoding
);
part.set_content_object(body_wrapper);
part.set_content(body_wrapper);
return part;
}

View file

@ -40,7 +40,10 @@ class Geary.RFC822.PartTest : TestCase {
part.set_content_id(ID);
part.set_content_description(DESC);
part.set_content_disposition(
new GMime.ContentDisposition.from_string("inline")
GMime.ContentDisposition.parse(
Geary.RFC822.get_parser_options(),
"inline"
)
);
Part test = new Part(part);
@ -93,13 +96,16 @@ class Geary.RFC822.PartTest : TestCase {
uint8[] body) {
GMime.Part part = new GMime.Part();
if (mime_type != null) {
part.set_content_type(new GMime.ContentType.from_string(mime_type));
part.set_content_type(GMime.ContentType.parse(
Geary.RFC822.get_parser_options(),
mime_type
));
}
GMime.DataWrapper body_wrapper = new GMime.DataWrapper.with_stream(
new GMime.StreamMem.with_buffer(body),
GMime.ContentEncoding.BINARY
);
part.set_content_object(body_wrapper);
part.set_content(body_wrapper);
part.encode(GMime.EncodingConstraint.7BIT);
return part;
}