Don't quote an RFC 822 mailbox local part if it has a '.' in the middle.

This breaks sending mail via Yahoo since it doesn't like it if the SMTP
return path local part is quoted.

We can't use GMime.utils_quote_string since it's currently broken, so
implement our own quoter.
This commit is contained in:
Michael James Gratton 2018-07-28 17:57:48 +10:00
parent a682e17aa1
commit 183a9f3e7a
2 changed files with 88 additions and 12 deletions

View file

@ -21,6 +21,11 @@ public class Geary.RFC822.MailboxAddress :
Gee.Hashable<MailboxAddress>,
BaseObject {
private static char[] ATEXT = {
'!', '#', '$', '%', '&', '\'', '*', '+', '-',
'/', '=', '?', '^', '_', '`', '{', '|', '}', '~'
};
/** Determines if a string contains a valid RFC822 mailbox address. */
public static bool is_valid_address(string address) {
try {
@ -44,6 +49,54 @@ public class Geary.RFC822.MailboxAddress :
return GMime.utils_header_decode_text(prepare_header_text_part(mailbox));
}
private static bool local_part_needs_quoting(string local_part) {
bool needs_quote = false;
bool is_dot = false;
if (!String.is_empty(local_part)) {
int index = 0;
for (;;) {
char ch = local_part[index++];
if (ch == String.EOS)
break;
is_dot = (ch == '.');
print("\nchecking: %c (is ATEXT? %s)\n", ch, (ch in ATEXT).to_string());
if (!(ch >= 0x41 && ch <= 0x5A) && // A-Z
!(ch >= 0x61 && ch <= 0x7A) && // a-z
!(ch >= 0x30 && ch <= 0x39) && // 0-9
!(ch in ATEXT) &&
!(is_dot && index > 1)) { // no leading dots
needs_quote = true;
break;
}
}
}
return needs_quote || is_dot; // no trailing dots
}
private static string quote_local_part(string local_part) {
StringBuilder builder = new StringBuilder();
if (!String.is_empty(local_part)) {
builder.append_c('"');
int index = 0;
for (;;) {
char ch = local_part[index++];
if (ch == String.EOS)
break;
if (ch == '"' || ch == '\\') {
builder.append_c('\\');
}
builder.append_c(ch);
}
builder.append_c('"');
}
return builder.str;
}
private static string prepare_header_text_part(string part) {
// Borrowed liberally from GMime's internal
// _internet_address_decode_name() function.
@ -372,10 +425,17 @@ public class Geary.RFC822.MailboxAddress :
* brackets.
*/
public string to_rfc822_address() {
// XXX GMime.utils_header_encode_text won't quote if spaces or
// quotes present, and GMime.utils_quote_string will
// erroneously quote if a '.' is present (which at least
// Yahoo doesn't like in SMTP return paths), so need to quote
// manually.
string local_part = GMime.utils_header_encode_text(this.mailbox);
if (local_part_needs_quoting(local_part)) {
local_part = quote_local_part(local_part);
}
return "%s@%s".printf(
// XXX utils_quote_string won't quote if spaces or quotes
// present, so need to do that manually
GMime.utils_quote_string(GMime.utils_header_encode_text(this.mailbox)),
local_part,
// XXX Need to punycode international domains.
this.domain
);

View file

@ -206,21 +206,37 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
"example@example@example.com");
}
public void to_rfc822_address() throws Error {
assert(new MailboxAddress(null, "example@example.com").to_rfc822_address() ==
"example@example.com");
public void to_rfc822_address() throws GLib.Error {
assert_string(
"example@example.com",
new MailboxAddress(null, "example@example.com").to_rfc822_address()
);
assert_string(
"test.account@example.com",
new MailboxAddress(null, "test.account@example.com").to_rfc822_address()
);
//assert(new MailboxAddress(null, "test test@example.com").to_rfc822_address() ==
// "\"test test\"@example.com");
//assert(new MailboxAddress(null, "test\" test@example.com").to_rfc822_address() ==
// "\"test\" test\"@example.com");
//assert(new MailboxAddress(null, "test\"test@example.com").to_rfc822_address() ==
// "\"test\"test\"@example.com");
assert(new MailboxAddress(null, "test@test@example.com").to_rfc822_address() ==
"\"test@test\"@example.com");
assert(new MailboxAddress(null, "©@example.com").to_rfc822_address() ==
"\"=?iso-8859-1?b?qQ==?=\"@example.com");
assert(new MailboxAddress(null, "😸@example.com").to_rfc822_address() ==
"\"=?UTF-8?b?8J+YuA==?=\"@example.com");
assert_string(
"$test@example.com",
new MailboxAddress(null, "$test@example.com").to_rfc822_address()
);
assert_string(
"\"test@test\"@example.com",
new MailboxAddress(null, "test@test@example.com").to_rfc822_address()
);
assert_string(
"=?iso-8859-1?b?qQ==?=@example.com",
new MailboxAddress(null, "©@example.com").to_rfc822_address()
);
assert_string(
"=?UTF-8?b?8J+YuA==?=@example.com",
new MailboxAddress(null, "😸@example.com").to_rfc822_address()
);
}
public void to_rfc822_string() throws Error {