Merge branch 'mjog/dovecot-envelope-mailbox-quirk' into 'mainline'
Dovecot envelope mailbox quirk See merge request GNOME/geary!546
This commit is contained in:
commit
67a2d32a6c
21 changed files with 490 additions and 205 deletions
|
|
@ -284,10 +284,7 @@ public class Geary.Engine : BaseObject {
|
|||
(security, cx) => account.untrusted_host(service, security, cx)
|
||||
);
|
||||
|
||||
var client = new Imap.ClientSession(
|
||||
endpoint,
|
||||
Imap.ClientService.new_quirks_for_provider(account.service_provider)
|
||||
);
|
||||
var client = new Imap.ClientSession(endpoint, new Imap.Quirks());
|
||||
GLib.Error? imap_err = null;
|
||||
try {
|
||||
yield client.connect_async(
|
||||
|
|
|
|||
|
|
@ -39,36 +39,6 @@ public class Geary.Imap.ClientService : Geary.ClientService {
|
|||
private const int CHECK_NOOP_THRESHOLD_SEC = 5;
|
||||
|
||||
|
||||
public static Quirks new_quirks_for_provider(ServiceProvider provider) {
|
||||
var quirks = new Quirks();
|
||||
switch (provider) {
|
||||
case GMAIL:
|
||||
// As of 2020-05-02, GMail doesn't seem to quote flag
|
||||
// atoms containing reserved characters, and at least one
|
||||
// use of both `]` and ` ` have been found. This works
|
||||
// around the former. See #746
|
||||
quirks.flag_atom_exceptions = "]";
|
||||
break;
|
||||
|
||||
case ServiceProvider.OUTLOOK:
|
||||
// As of June 2016, outlook.com's IMAP servers have a bug
|
||||
// where a large number (~50) of pipelined STATUS commands
|
||||
// on mailboxes with many messages will eventually cause
|
||||
// it to break command parsing and return a BAD response,
|
||||
// causing us to drop the connection. Limit the number of
|
||||
// pipelined commands per batch to work around this. See
|
||||
// b.g.o Bug 766552
|
||||
quirks.max_pipeline_batch_size = 25;
|
||||
break;
|
||||
|
||||
default:
|
||||
// noop
|
||||
break;
|
||||
}
|
||||
return quirks;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set to zero or negative value if keepalives should be disabled when a connection has not
|
||||
* selected a mailbox. (This is not recommended.)
|
||||
|
|
@ -131,7 +101,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
|
|||
get { return LOGGING_DOMAIN; }
|
||||
}
|
||||
|
||||
private Quirks quirks;
|
||||
private Quirks quirks = new Quirks();
|
||||
|
||||
private Nonblocking.Mutex sessions_mutex = new Nonblocking.Mutex();
|
||||
private Gee.Set<ClientSession> all_sessions =
|
||||
|
|
@ -147,7 +117,6 @@ public class Geary.Imap.ClientService : Geary.ClientService {
|
|||
ServiceInformation configuration,
|
||||
Endpoint remote) {
|
||||
base(account, configuration, remote);
|
||||
this.quirks = new_quirks_for_provider(account.service_provider);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -403,6 +372,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
|
|||
// An error was thrown, so close the pool
|
||||
this.close_pool.begin(true);
|
||||
} else {
|
||||
this.quirks.update_for_server(new_session);
|
||||
try {
|
||||
yield this.sessions_mutex.execute_locked(() => {
|
||||
this.all_sessions.add(new_session);
|
||||
|
|
|
|||
|
|
@ -38,5 +38,83 @@ public class Geary.Imap.Quirks : BaseObject {
|
|||
*/
|
||||
public uint max_pipeline_batch_size { get; set; default = 0; }
|
||||
|
||||
/**
|
||||
* The value sent by the server for missing envelope mailbox local parts.
|
||||
*
|
||||
* IMAP FETCH ENVELOPE structures use NIL for the "mailbox name"
|
||||
* part (in addition to a NIL "host name" part) as an end-of-list
|
||||
* marker for RFC822 group syntax. To indicate a missing
|
||||
* local-part in a non-group mailbox some mail servers use a
|
||||
* string such as "MISSING_MAILBOX" rather than the empty string.
|
||||
*/
|
||||
public string empty_envelope_mailbox_name { get; set; default = ""; }
|
||||
|
||||
/**
|
||||
* The value sent by the server for missing envelope mailbox domains.
|
||||
*
|
||||
* IMAP FETCH ENVELOPE structures use NIL for the "host name"
|
||||
* argument to indicate RFC822 group syntax. To indicate a missing
|
||||
* some mail servers use a string such as "MISSING_DOMAIN" rather
|
||||
* than the empty string.
|
||||
*/
|
||||
public string empty_envelope_host_name { get; set; default = ""; }
|
||||
|
||||
|
||||
public void update_for_server(ClientSession session) {
|
||||
if (session.server_greeting != null) {
|
||||
var greeting = session.server_greeting.get_text() ?? "";
|
||||
if (greeting.has_prefix("Gimap")) {
|
||||
update_for_gmail();
|
||||
} else if (greeting.has_prefix("The Microsoft Exchange")) {
|
||||
update_for_outlook();
|
||||
} else if (greeting.has_prefix("Dovecot")) {
|
||||
update_for_dovecot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this quirks object with known quirks for GMail.
|
||||
*
|
||||
* As of 2020-05-02, GMail doesn't seem to quote flag
|
||||
* atoms containing reserved characters, and at least one
|
||||
* use of both `]` and ` ` have been found. This works
|
||||
* around the former.
|
||||
*
|
||||
* See [[https://gitlab.gnome.org/GNOME/geary/-/issues/746]]
|
||||
*/
|
||||
public void update_for_gmail() {
|
||||
this.flag_atom_exceptions = "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this quirks object with known quirks for Outlook.com.
|
||||
*
|
||||
* As of June 2016, outlook.com's IMAP servers have a bug where a
|
||||
* large number (~50) of pipelined STATUS commands on mailboxes
|
||||
* with many messages will eventually cause it to break command
|
||||
* parsing and return a BAD response, causing us to drop the
|
||||
* connection. Limit the number of pipelined commands per batch to
|
||||
* work around this.
|
||||
*
|
||||
* See [[https://bugzilla.gnome.org/show_bug.cgi?id=766552]]
|
||||
*/
|
||||
public void update_for_outlook() {
|
||||
this.max_pipeline_batch_size = 25;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this quirks object with known quirks for Dovecot
|
||||
*
|
||||
* Dovecot 2.3.4.1 and earlier uses "MISSING_MAILBOX" and
|
||||
* "MISSING_DOMAIN" in the address structures of FETCH ENVELOPE
|
||||
* replies when the mailbox or domain is missing.
|
||||
*
|
||||
* See [[https://dovecot.org/pipermail/dovecot/2020-August/119658.html]]
|
||||
*/
|
||||
public void update_for_dovecot() {
|
||||
this.empty_envelope_mailbox_name = "MISSING_MAILBOX";
|
||||
this.empty_envelope_host_name = "MISSING_DOMAIN";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public enum Geary.Imap.FetchDataSpecifier {
|
|||
*
|
||||
* @return null if no FetchDataDecoder is associated with this value, or an invalid value.
|
||||
*/
|
||||
public FetchDataDecoder? get_decoder() {
|
||||
public FetchDataDecoder? get_decoder(Quirks quirks) {
|
||||
switch (this) {
|
||||
case UID:
|
||||
return new UIDDecoder();
|
||||
|
|
@ -151,7 +151,7 @@ public enum Geary.Imap.FetchDataSpecifier {
|
|||
return new MessageFlagsDecoder();
|
||||
|
||||
case ENVELOPE:
|
||||
return new EnvelopeDecoder();
|
||||
return new EnvelopeDecoder(quirks);
|
||||
|
||||
case INTERNALDATE:
|
||||
return new InternalDateDecoder();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ public class Geary.Imap.ListParameter : Geary.Imap.Parameter {
|
|||
private Gee.List<Parameter> list = new Gee.ArrayList<Parameter>();
|
||||
|
||||
|
||||
/** Constructs a new, empty list. */
|
||||
public ListParameter() {
|
||||
// noop
|
||||
}
|
||||
|
||||
/** Constructs a new list wit a single parameter. */
|
||||
public ListParameter.single(Parameter param) {
|
||||
base();
|
||||
add(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a parameter to the end of this list.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
|
||||
public class Geary.Imap.ContinuationResponse : ServerResponse {
|
||||
private ContinuationResponse() {
|
||||
base (Tag.get_continuation());
|
||||
|
||||
|
||||
private ContinuationResponse(Quirks quirks) {
|
||||
base(Tag.get_continuation(), quirks);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -25,9 +27,9 @@ public class Geary.Imap.ContinuationResponse : ServerResponse {
|
|||
* The supplied root is "stripped" of its children. This may happen even if an exception is
|
||||
* thrown. It's recommended to use {@link is_continuation_response} prior to this call.
|
||||
*/
|
||||
public ContinuationResponse.migrate(RootParameters root) throws ImapError {
|
||||
base.migrate(root);
|
||||
|
||||
public ContinuationResponse.migrate(RootParameters root, Quirks quirks)
|
||||
throws ImapError {
|
||||
base.migrate(root, quirks);
|
||||
if (!tag.is_continuation())
|
||||
throw new ImapError.INVALID("Tag %s is not a continuation", tag.to_string());
|
||||
}
|
||||
|
|
@ -37,8 +39,6 @@ public class Geary.Imap.ContinuationResponse : ServerResponse {
|
|||
*/
|
||||
public static bool is_continuation_response(RootParameters root) {
|
||||
Tag? tag = root.get_tag();
|
||||
|
||||
return tag != null ? tag.is_continuation() : false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,8 +124,14 @@ public class Geary.Imap.RFC822SizeDecoder : Geary.Imap.FetchDataDecoder {
|
|||
}
|
||||
|
||||
public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
|
||||
public EnvelopeDecoder() {
|
||||
base (FetchDataSpecifier.ENVELOPE);
|
||||
|
||||
|
||||
private Quirks quirks;
|
||||
|
||||
|
||||
public EnvelopeDecoder(Quirks quirks) {
|
||||
base(FetchDataSpecifier.ENVELOPE);
|
||||
this.quirks = quirks;
|
||||
}
|
||||
|
||||
protected override MessageData decode_list(ListParameter listp) throws ImapError {
|
||||
|
|
@ -150,7 +156,7 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
|
|||
try {
|
||||
sent_date = new RFC822.Date.from_rfc822_string(sent.ascii);
|
||||
} catch (GLib.Error err) {
|
||||
debug(
|
||||
warning(
|
||||
"Error parsing sent date from FETCH envelope: %s",
|
||||
err.message
|
||||
);
|
||||
|
|
@ -179,14 +185,22 @@ public class Geary.Imap.EnvelopeDecoder : Geary.Imap.FetchDataDecoder {
|
|||
ListParameter fields = listp.get_as_empty_list(ctr);
|
||||
StringParameter? name = fields.get_as_nullable_string(0);
|
||||
StringParameter? source_route = fields.get_as_nullable_string(1);
|
||||
StringParameter mailbox = fields.get_as_empty_string(2);
|
||||
StringParameter domain = fields.get_as_empty_string(3);
|
||||
StringParameter? mailbox = fields.get_as_empty_string(2);
|
||||
StringParameter? domain = fields.get_as_empty_string(3);
|
||||
|
||||
if (mailbox.ascii == this.quirks.empty_envelope_mailbox_name) {
|
||||
mailbox = null;
|
||||
}
|
||||
if (domain.ascii == this.quirks.empty_envelope_host_name) {
|
||||
domain = null;
|
||||
}
|
||||
|
||||
Geary.RFC822.MailboxAddress addr = new Geary.RFC822.MailboxAddress.imap(
|
||||
(name != null) ? name.nullable_ascii : null,
|
||||
(source_route != null) ? source_route.nullable_ascii : null,
|
||||
mailbox.ascii,
|
||||
domain.ascii);
|
||||
mailbox != null ? mailbox.ascii : "",
|
||||
domain != null ? domain.ascii : ""
|
||||
);
|
||||
list.add(addr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ public class Geary.Imap.FetchedData : Object {
|
|||
fetched_data.body_data_map.set(specifier, Memory.EmptyBuffer.instance);
|
||||
} else {
|
||||
FetchDataSpecifier data_item = FetchDataSpecifier.from_parameter(data_item_param);
|
||||
FetchDataDecoder? decoder = data_item.get_decoder();
|
||||
FetchDataDecoder? decoder = data_item.get_decoder(server_data.quirks);
|
||||
if (decoder == null) {
|
||||
debug("Unable to decode fetch response for \"%s\": No decoder available",
|
||||
data_item.to_string());
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
public class Geary.Imap.ServerData : ServerResponse {
|
||||
public ServerDataType server_data_type { get; private set; }
|
||||
|
||||
private ServerData(Tag tag, ServerDataType server_data_type) {
|
||||
base (tag);
|
||||
private ServerData(Tag tag, ServerDataType server_data_type, Quirks quirks) {
|
||||
base(tag, quirks);
|
||||
|
||||
this.server_data_type = server_data_type;
|
||||
}
|
||||
|
|
@ -25,8 +25,9 @@ public class Geary.Imap.ServerData : ServerResponse {
|
|||
* The supplied root is "stripped" of its children. This may happen even if an exception is
|
||||
* thrown. It's recommended to use {@link is_server_data} prior to this call.
|
||||
*/
|
||||
public ServerData.migrate(RootParameters root) throws ImapError {
|
||||
base.migrate(root);
|
||||
public ServerData.migrate(RootParameters root, Quirks quirks)
|
||||
throws ImapError {
|
||||
base.migrate(root, quirks);
|
||||
|
||||
server_data_type = ServerDataType.from_response(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,15 @@
|
|||
*/
|
||||
|
||||
public abstract class Geary.Imap.ServerResponse : RootParameters {
|
||||
public Tag tag { get; private set; }
|
||||
|
||||
protected ServerResponse(Tag tag) {
|
||||
|
||||
public Tag tag { get; private set; }
|
||||
public Quirks quirks { get; private set; }
|
||||
|
||||
|
||||
protected ServerResponse(Tag tag, Quirks quirks) {
|
||||
this.tag = tag;
|
||||
this.quirks = quirks;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -25,36 +30,16 @@ public abstract class Geary.Imap.ServerResponse : RootParameters {
|
|||
*
|
||||
* The supplied root is "stripped" of its children.
|
||||
*/
|
||||
protected ServerResponse.migrate(RootParameters root) throws ImapError {
|
||||
protected ServerResponse.migrate(RootParameters root,
|
||||
Quirks quirks)
|
||||
throws ImapError {
|
||||
base.migrate(root);
|
||||
this.quirks = quirks;
|
||||
|
||||
if (!has_tag())
|
||||
if (!has_tag()) {
|
||||
throw new ImapError.INVALID("Server response does not have a tag token: %s", to_string());
|
||||
|
||||
tag = get_tag();
|
||||
}
|
||||
this.tag = get_tag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the contents of RootParameters into a new, properly-typed ServerResponse.
|
||||
*
|
||||
* The returned ServerResponse may be a {@link ContinuationResponse}, {@link ServerData},
|
||||
* or a generic {@link StatusResponse}.
|
||||
*
|
||||
* The RootParameters will be migrated and stripped clean upon exit.
|
||||
*
|
||||
* @throws ImapError.PARSE_ERROR if not a known form of ServerResponse.
|
||||
*/
|
||||
public static ServerResponse migrate_from_server(RootParameters root) throws ImapError {
|
||||
if (ContinuationResponse.is_continuation_response(root))
|
||||
return new ContinuationResponse.migrate(root);
|
||||
|
||||
if (StatusResponse.is_status_response(root))
|
||||
return new StatusResponse.migrate(root);
|
||||
|
||||
if (ServerData.is_server_data(root))
|
||||
return new ServerData.migrate(root);
|
||||
|
||||
throw new ImapError.PARSE_ERROR("Unknown server response: %s", root.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
* StatusResponses may be tagged or untagged, depending on their nature.
|
||||
*
|
||||
* See [[http://tools.ietf.org/html/rfc3501#section-7.1]] for more information.
|
||||
*
|
||||
* @see ServerResponse.migrate_from_server
|
||||
*/
|
||||
|
||||
public class Geary.Imap.StatusResponse : ServerResponse {
|
||||
|
|
@ -34,8 +32,11 @@ public class Geary.Imap.StatusResponse : ServerResponse {
|
|||
*/
|
||||
public ResponseCode? response_code { get; private set; }
|
||||
|
||||
private StatusResponse(Tag tag, Status status, ResponseCode? response_code) {
|
||||
base (tag);
|
||||
private StatusResponse(Tag tag,
|
||||
Status status,
|
||||
ResponseCode? response_code,
|
||||
Quirks quirks) {
|
||||
base(tag, quirks);
|
||||
|
||||
this.status = status;
|
||||
this.response_code = response_code;
|
||||
|
|
@ -48,8 +49,9 @@ public class Geary.Imap.StatusResponse : ServerResponse {
|
|||
* The supplied root is "stripped" of its children. This may happen even if an exception is
|
||||
* thrown. It's recommended to use {@link is_status_response} prior to this call.
|
||||
*/
|
||||
public StatusResponse.migrate(RootParameters root) throws ImapError {
|
||||
base.migrate(root);
|
||||
public StatusResponse.migrate(RootParameters root, Quirks quirks)
|
||||
throws ImapError {
|
||||
base.migrate(root, quirks);
|
||||
|
||||
status = Status.from_parameter(get_as_string(1));
|
||||
response_code = get_if_list(2) as ResponseCode;
|
||||
|
|
|
|||
|
|
@ -467,26 +467,24 @@ public class Geary.Imap.ClientConnection : BaseObject, Logging.Source {
|
|||
|
||||
private void on_parameters_ready(RootParameters root) {
|
||||
try {
|
||||
ServerResponse response = ServerResponse.migrate_from_server(root);
|
||||
GLib.Type type = response.get_type();
|
||||
if (type == typeof(StatusResponse)) {
|
||||
on_status_response((StatusResponse) response);
|
||||
} else if (type == typeof(ServerData)) {
|
||||
on_server_data((ServerData) response);
|
||||
} else if (type == typeof(ContinuationResponse)) {
|
||||
on_continuation_response((ContinuationResponse) response);
|
||||
// Important! The order of these tests matters.
|
||||
if (ContinuationResponse.is_continuation_response(root)) {
|
||||
on_continuation_response(
|
||||
new ContinuationResponse.migrate(root, this.quirks)
|
||||
);
|
||||
} else if (StatusResponse.is_status_response(root)) {
|
||||
on_status_response(new StatusResponse.migrate(root, this.quirks));
|
||||
} else if (ServerData.is_server_data(root)) {
|
||||
on_server_data(new ServerData.migrate(root, this.quirks));
|
||||
} else {
|
||||
warning(
|
||||
"Unknown ServerResponse of type %s received: %s:",
|
||||
response.get_type().name(),
|
||||
response.to_string()
|
||||
throw new ImapError.PARSE_ERROR(
|
||||
"Unknown server response: %s", root.to_string()
|
||||
);
|
||||
}
|
||||
} catch (ImapError err) {
|
||||
received_bad_response(root, err);
|
||||
}
|
||||
|
||||
|
||||
if (this.pending_queue.is_empty && this.sent_queue.is_empty) {
|
||||
// There's nothing remaining to send, and every sent
|
||||
// command has been dealt with, so ready an IDLE command.
|
||||
|
|
|
|||
|
|
@ -245,6 +245,14 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
|
|||
get { return this.capabilities.has_capability(Capabilities.IDLE); }
|
||||
}
|
||||
|
||||
/**
|
||||
* The server's greeting, if any.
|
||||
*
|
||||
* This will be null up until the session has successfully
|
||||
* connected and the server has responded with a greeting.
|
||||
*/
|
||||
public StatusResponse? server_greeting { get; private set; default = null; }
|
||||
|
||||
/** The currently selected mailbox, if any. */
|
||||
public MailboxSpecifier? selected_mailbox = null;
|
||||
|
||||
|
|
@ -846,9 +854,12 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
|
|||
new_state = State.LOGOUT;
|
||||
}
|
||||
|
||||
this.server_greeting = status_response;
|
||||
debug("Server greeting: %s", status_response.get_text());
|
||||
|
||||
try {
|
||||
connect_waiter.notify();
|
||||
} catch (Error err) {
|
||||
this.connect_waiter.notify();
|
||||
} catch (GLib.Error err) {
|
||||
warning(
|
||||
"Unable to notify connect_waiter of connection: %s",
|
||||
err.message
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ public class Geary.RFC822.MailboxAddress :
|
|||
Gee.Hashable<MailboxAddress>,
|
||||
DecodedMessageData {
|
||||
|
||||
private static Regex? email_regex = null;
|
||||
|
||||
private static unichar[] ATEXT = {
|
||||
'!', '#', '$', '%', '&', '\'', '*', '+', '-',
|
||||
'/', '=', '?', '^', '_', '`', '{', '|', '}', '~'
|
||||
|
|
@ -29,17 +31,20 @@ public class Geary.RFC822.MailboxAddress :
|
|||
|
||||
/** Determines if a string contains a valid RFC822 mailbox address. */
|
||||
public static bool is_valid_address(string address) {
|
||||
try {
|
||||
// http://www.regular-expressions.info/email.html
|
||||
// matches john@dep.aol.museum not john@aol...com
|
||||
Regex email_regex =
|
||||
new Regex("[A-Z0-9._%+-]+@((?:[A-Z0-9-]+\\.)+[A-Z]{2}|localhost)",
|
||||
RegexCompileFlags.CASELESS);
|
||||
return email_regex.match(address);
|
||||
} catch (RegexError e) {
|
||||
debug("Regex error validating email address: %s", e.message);
|
||||
return false;
|
||||
if (MailboxAddress.email_regex == null) {
|
||||
try {
|
||||
// http://www.regular-expressions.info/email.html
|
||||
// matches john@dep.aol.museum not john@aol...com
|
||||
MailboxAddress.email_regex = new Regex(
|
||||
"[A-Z0-9._%+-]+@((?:[A-Z0-9-]+\\.)+[A-Z]{2}|localhost)",
|
||||
RegexCompileFlags.CASELESS
|
||||
);
|
||||
} catch (RegexError e) {
|
||||
warning("Regex error validating email address: %s", e.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return MailboxAddress.email_regex.match(address);
|
||||
}
|
||||
|
||||
private static string decode_name(string name) {
|
||||
|
|
@ -206,7 +211,7 @@ public class Geary.RFC822.MailboxAddress :
|
|||
*
|
||||
* The given name (if any) and address parts will be used
|
||||
* verbatim, and quoted or encoded if needed when serialising to
|
||||
* an RFC 833 mailbox address string.
|
||||
* an RFC 822 mailbox address string.
|
||||
*/
|
||||
public MailboxAddress(string? name, string address) {
|
||||
this.name = name;
|
||||
|
|
@ -228,7 +233,18 @@ public class Geary.RFC822.MailboxAddress :
|
|||
this.source_route = source_route;
|
||||
this.mailbox = decode_address_part(mailbox);
|
||||
this.domain = domain;
|
||||
this.address = "%s@%s".printf(mailbox, domain);
|
||||
|
||||
bool empty_mailbox = String.is_empty_or_whitespace(mailbox);
|
||||
bool empty_domain = String.is_empty_or_whitespace(domain);
|
||||
if (!empty_mailbox && !empty_domain) {
|
||||
this.address = "%s@%s".printf(mailbox, domain);
|
||||
} else if (empty_mailbox) {
|
||||
this.address = domain;
|
||||
} else if (empty_domain) {
|
||||
this.address = mailbox;
|
||||
} else {
|
||||
this.address = "";
|
||||
}
|
||||
}
|
||||
|
||||
public MailboxAddress.from_rfc822_string(string rfc822) throws Error {
|
||||
|
|
@ -261,9 +277,11 @@ public class Geary.RFC822.MailboxAddress :
|
|||
// GMime strips source route for us, so the address part
|
||||
// should only ever contain a single '@'
|
||||
string? name = mailbox.get_name();
|
||||
if (name != "") {
|
||||
this.name = decode_name(name);
|
||||
}
|
||||
this.name = (
|
||||
!String.is_empty_or_whitespace(name)
|
||||
? decode_name(name)
|
||||
: null
|
||||
);
|
||||
|
||||
string address = mailbox.get_addr();
|
||||
int atsign = Ascii.last_index_of(address, '@');
|
||||
|
|
@ -281,7 +299,7 @@ public class Geary.RFC822.MailboxAddress :
|
|||
} else {
|
||||
this.mailbox = "";
|
||||
this.domain = "";
|
||||
this.address = address;
|
||||
this.address = decode_address_part(address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,15 +515,33 @@ public class Geary.RFC822.MailboxAddress :
|
|||
// GMime.utils_header_encode_text will use MIME encoding,
|
||||
// which is disallowed in mailboxes by RFC 2074 §5. So quote
|
||||
// manually.
|
||||
string local_part = this.mailbox;
|
||||
if (local_part_needs_quoting(local_part)) {
|
||||
local_part = quote_string(local_part);
|
||||
var address = "";
|
||||
if (this.mailbox != "") {
|
||||
address = this.mailbox;
|
||||
if (local_part_needs_quoting(address)) {
|
||||
address = quote_string(address);
|
||||
}
|
||||
}
|
||||
return "%s@%s".printf(
|
||||
local_part,
|
||||
// XXX Need to punycode international domains.
|
||||
this.domain
|
||||
);
|
||||
if (this.domain != "") {
|
||||
address = "%s@%s".printf(
|
||||
address,
|
||||
// XXX Need to punycode international domains.
|
||||
this.domain
|
||||
);
|
||||
}
|
||||
if (address == "") {
|
||||
// Both mailbox and domain are empty, i.e. there was no
|
||||
// '@' symbol in the address, so just assume the address
|
||||
// is a mailbox since this is not uncommon practice on
|
||||
// UNIX systems where mail is sent from a local account,
|
||||
// and it supports a greater range of characters than the
|
||||
// domain component
|
||||
address = this.address;
|
||||
if (local_part_needs_quoting(address)) {
|
||||
address = quote_string(address);
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
135
test/engine/imap/response/imap-fetch-data-decoder-test.vala
Normal file
135
test/engine/imap/response/imap-fetch-data-decoder-test.vala
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright 2019 Michael Gratton <mike@vee.net>
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
class Geary.Imap.FetchDataDecoderTest : TestCase {
|
||||
|
||||
|
||||
public FetchDataDecoderTest() {
|
||||
base("Geary.Imap.FetchDataDecoderTest");
|
||||
add_test("envelope_basic", envelope_basic);
|
||||
add_test(
|
||||
"envelope_mailbox_missing_mailbox_name_quirk",
|
||||
envelope_mailbox_missing_mailbox_name_quirk
|
||||
);
|
||||
add_test(
|
||||
"envelope_mailbox_missing_host_name_quirk",
|
||||
envelope_mailbox_missing_host_name_quirk
|
||||
);
|
||||
}
|
||||
|
||||
public void envelope_basic() throws GLib.Error {
|
||||
ListParameter env = new ListParameter();
|
||||
env.add(new QuotedStringParameter("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"));
|
||||
env.add(new QuotedStringParameter("Test subject"));
|
||||
|
||||
// From
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
|
||||
// Sender
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
|
||||
// Reply-To
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
|
||||
env.add(new ListParameter.single(new_mailbox_structure("To", "to", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("Cc", "cc", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("Bcc", "bcc", "example.com")));
|
||||
|
||||
// In-Reply-To
|
||||
env.add(new QuotedStringParameter("<1234@example.com>"));
|
||||
|
||||
// Message-Id
|
||||
env.add(new QuotedStringParameter("<5678@example.com>"));
|
||||
|
||||
var test_article = new EnvelopeDecoder(new Quirks());
|
||||
var decoded_generic = test_article.decode(env);
|
||||
var decoded = decoded_generic as Envelope;
|
||||
|
||||
assert_non_null(decoded, "decoded type");
|
||||
assert_non_null(decoded.sent, "decoded sent");
|
||||
assert_equal(decoded.subject.value, "Test subject");
|
||||
assert_equal(decoded.from.to_rfc822_string(), "From <from@example.com>");
|
||||
assert_equal(decoded.sender.to_rfc822_string(), "From <from@example.com>");
|
||||
assert_equal(decoded.reply_to.to_rfc822_string(), "From <from@example.com>");
|
||||
|
||||
assert_non_null(decoded.to, "to");
|
||||
assert_equal(decoded.to.to_rfc822_string(), "To <to@example.com>");
|
||||
|
||||
assert_non_null(decoded.cc, "cc");
|
||||
assert_equal(decoded.cc.to_rfc822_string(), "Cc <cc@example.com>");
|
||||
|
||||
assert_non_null(decoded.bcc, "bcc");
|
||||
assert_equal(decoded.bcc.to_rfc822_string(), "Bcc <bcc@example.com>");
|
||||
|
||||
assert_non_null(decoded.in_reply_to, "in_reply_to");
|
||||
assert_equal(decoded.in_reply_to.to_rfc822_string(), "<1234@example.com>");
|
||||
|
||||
assert_non_null(decoded.message_id, "message_id");
|
||||
assert_equal(decoded.message_id.to_rfc822_string(), "<5678@example.com>");
|
||||
}
|
||||
|
||||
public void envelope_mailbox_missing_mailbox_name_quirk() throws GLib.Error {
|
||||
ListParameter env = new ListParameter();
|
||||
env.add(new QuotedStringParameter("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"));
|
||||
env.add(new QuotedStringParameter("Test subject"));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
|
||||
env.add(new ListParameter.single(new_mailbox_structure("To", "BOGUS", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("Cc", "cc", "example.com")));
|
||||
env.add(NilParameter.instance);
|
||||
env.add(NilParameter.instance);
|
||||
env.add(NilParameter.instance);
|
||||
|
||||
var quirks = new Quirks();
|
||||
quirks.empty_envelope_mailbox_name = "BOGUS";
|
||||
|
||||
var test_article = new EnvelopeDecoder(quirks);
|
||||
var decoded = test_article.decode(env) as Envelope;
|
||||
|
||||
assert_non_null(decoded.to, "to");
|
||||
assert_equal(decoded.to.to_rfc822_string(), "To <@example.com>");
|
||||
assert_non_null(decoded.cc, "cc");
|
||||
assert_equal(decoded.cc.to_rfc822_string(), "Cc <cc@example.com>");
|
||||
}
|
||||
|
||||
public void envelope_mailbox_missing_host_name_quirk() throws GLib.Error {
|
||||
ListParameter env = new ListParameter();
|
||||
env.add(new QuotedStringParameter("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"));
|
||||
env.add(new QuotedStringParameter("Test subject"));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("From", "from", "example.com")));
|
||||
|
||||
env.add(new ListParameter.single(new_mailbox_structure("To name", "to", "BOGUS")));
|
||||
env.add(new ListParameter.single(new_mailbox_structure("Cc", "cc", "example.com")));
|
||||
env.add(NilParameter.instance);
|
||||
env.add(NilParameter.instance);
|
||||
env.add(NilParameter.instance);
|
||||
|
||||
var quirks = new Quirks();
|
||||
quirks.empty_envelope_host_name = "BOGUS";
|
||||
|
||||
var test_article = new EnvelopeDecoder(quirks);
|
||||
var decoded = test_article.decode(env) as Envelope;
|
||||
|
||||
assert_non_null(decoded.to, "to");
|
||||
assert_equal(decoded.to.to_rfc822_string(), "To name <to>");
|
||||
assert_non_null(decoded.cc, "cc");
|
||||
assert_equal(decoded.cc.to_rfc822_string(), "Cc <cc@example.com>");
|
||||
}
|
||||
|
||||
private ListParameter new_mailbox_structure(string name, string local, string domain) {
|
||||
ListParameter mailbox = new ListParameter();
|
||||
mailbox.add(new QuotedStringParameter(name));
|
||||
mailbox.add(NilParameter.instance);
|
||||
mailbox.add(new QuotedStringParameter(local));
|
||||
mailbox.add(new QuotedStringParameter(domain));
|
||||
return mailbox;
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ class Geary.Imap.NamespaceResponseTest : TestCase {
|
|||
else
|
||||
root.add(shared);
|
||||
|
||||
return new ServerData.migrate(root);
|
||||
return new ServerData.migrate(root, new Quirks());
|
||||
}
|
||||
|
||||
private ListParameter newNamespace(string prefix, string? delim) {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ class Geary.Imap.DeserializerTest : TestCase {
|
|||
string greeting = "* OK Gimap ready for requests from 115.187.245.46 c194mb399904375ivc";
|
||||
this.stream.add_data(greeting.data);
|
||||
this.stream.add_data(EOL.data);
|
||||
this.deser.quirks = ClientService.new_quirks_for_provider(GMAIL);
|
||||
|
||||
this.process.begin(Expect.MESSAGE, this.async_completion);
|
||||
RootParameters? message = this.process.end(async_result());
|
||||
|
|
@ -249,7 +248,8 @@ class Geary.Imap.DeserializerTest : TestCase {
|
|||
string flags = """* FLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing)""";
|
||||
this.stream.add_data(flags.data);
|
||||
this.stream.add_data(EOL.data);
|
||||
this.deser.quirks = ClientService.new_quirks_for_provider(GMAIL);
|
||||
this.deser.quirks = new Imap.Quirks();
|
||||
this.deser.quirks.update_for_gmail();
|
||||
|
||||
this.process.begin(Expect.MESSAGE, this.async_completion);
|
||||
RootParameters? message = this.process.end(async_result());
|
||||
|
|
@ -261,7 +261,8 @@ class Geary.Imap.DeserializerTest : TestCase {
|
|||
string flags = """* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing \*)] Flags permitted.""";
|
||||
this.stream.add_data(flags.data);
|
||||
this.stream.add_data(EOL.data);
|
||||
this.deser.quirks = ClientService.new_quirks_for_provider(GMAIL);
|
||||
this.deser.quirks = new Imap.Quirks();
|
||||
this.deser.quirks.update_for_gmail();
|
||||
|
||||
this.process.begin(Expect.MESSAGE, this.async_completion);
|
||||
RootParameters? message = this.process.end(async_result());
|
||||
|
|
@ -275,7 +276,8 @@ class Geary.Imap.DeserializerTest : TestCase {
|
|||
string flags = """* FLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded $MDNSent $NotPhishing $Phishing Junk LoadRemoteImages NonJunk OIB-Seen-INBOX OIB-Seen-Unsubscribe OIB-Seen-[Gmail]/Important OIB-Seen-[Gmail]/Spam OIB-Seen-[Gmail]/Tous les messages)""";
|
||||
this.stream.add_data(flags.data);
|
||||
this.stream.add_data(EOL.data);
|
||||
this.deser.quirks = ClientService.new_quirks_for_provider(GMAIL);
|
||||
this.deser.quirks = new Imap.Quirks();
|
||||
this.deser.quirks.update_for_gmail();
|
||||
|
||||
this.process.begin(Expect.MESSAGE, this.async_completion);
|
||||
RootParameters? message = this.process.end(async_result());
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
|
|||
|
||||
public MailboxAddressTest() {
|
||||
base("Geary.RFC822.MailboxAddressTest");
|
||||
add_test("imap_address", imap_address);
|
||||
add_test("is_valid_address", is_valid_address);
|
||||
add_test("unescaped_constructor", unescaped_constructor);
|
||||
add_test("from_rfc822_string_encoded", from_rfc822_string_encoded);
|
||||
|
|
@ -24,6 +25,25 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
|
|||
add_test("equal_to", equal_to);
|
||||
}
|
||||
|
||||
public void imap_address() throws GLib.Error {
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "test", "example.com").address,
|
||||
"test@example.com"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "test", "").address,
|
||||
"test"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "", "example.com").address,
|
||||
"example.com"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "", "").address,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
public void is_valid_address() throws GLib.Error {
|
||||
assert(Geary.RFC822.MailboxAddress.is_valid_address("john@dep.aol.museum") == true);
|
||||
assert(Geary.RFC822.MailboxAddress.is_valid_address("test@example.com") == true);
|
||||
|
|
@ -73,84 +93,93 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
|
|||
}
|
||||
|
||||
public void from_rfc822_string_encoded() throws GLib.Error {
|
||||
try {
|
||||
MailboxAddress addr = new MailboxAddress.from_rfc822_string("test@example.com");
|
||||
assert(addr.name == null);
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
var encoded = "test@example.com";
|
||||
var addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("\"test\"@example.com");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "test@example.com");
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "\"test\"@example.com";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("=?UTF-8?b?dGVzdA==?=@example.com");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "test@example.com");
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "=?UTF-8?b?dGVzdA==?=@example.com";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("\"=?UTF-8?b?dGVzdA==?=\"@example.com");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "test@example.com");
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "\"=?UTF-8?b?dGVzdA==?=\"@example.com";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("<test@example.com>");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "test@example.com");
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "<test@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test");
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("<\"test\"@example.com>");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "test@example.com");
|
||||
assert(addr.mailbox == "test");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "<\"test\"@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_null(addr.name, encoded);
|
||||
assert_equal(addr.mailbox, "test", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("Test 1 <test2@example.com>");
|
||||
assert(addr.name == "Test 1");
|
||||
assert(addr.address == "test2@example.com");
|
||||
assert(addr.mailbox == "test2");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "Test 1 <test2@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "Test 1", encoded);
|
||||
assert_equal(addr.mailbox, "test2", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test2@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("\"Test 1\" <test2@example.com>");
|
||||
assert(addr.name == "Test 1");
|
||||
assert(addr.address == "test2@example.com");
|
||||
assert(addr.mailbox == "test2");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "\"Test 1\" <test2@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "Test 1", encoded);
|
||||
assert_equal(addr.mailbox, "test2", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test2@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("Test 1 <\"test2\"@example.com>");
|
||||
assert(addr.name == "Test 1");
|
||||
assert(addr.address == "test2@example.com");
|
||||
assert(addr.mailbox == "test2");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "Test 1 <\"test2\"@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "Test 1", encoded);
|
||||
assert_equal(addr.mailbox, "test2", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test2@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("=?UTF-8?b?VGVzdCAx?= <test2@example.com>");
|
||||
assert(addr.name == "Test 1");
|
||||
assert(addr.address == "test2@example.com");
|
||||
assert(addr.mailbox == "test2");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "=?UTF-8?b?VGVzdCAx?= <test2@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "Test 1", encoded);
|
||||
assert_equal(addr.mailbox, "test2", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test2@example.com", encoded);
|
||||
|
||||
addr = new MailboxAddress.from_rfc822_string("\"=?UTF-8?b?VGVzdCAx?=\" <test2@example.com>");
|
||||
assert(addr.name == "Test 1");
|
||||
assert(addr.address == "test2@example.com");
|
||||
assert(addr.mailbox == "test2");
|
||||
assert(addr.domain == "example.com");
|
||||
encoded = "\"=?UTF-8?b?VGVzdCAx?=\" <test2@example.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "Test 1", encoded);
|
||||
assert_equal(addr.mailbox, "test2", encoded);
|
||||
assert_equal(addr.domain, "example.com", encoded);
|
||||
assert_equal(addr.address, "test2@example.com", encoded);
|
||||
|
||||
// Courtesy Mailsploit https://www.mailsploit.com
|
||||
addr = new MailboxAddress.from_rfc822_string("\"=?utf-8?b?dGVzdCIgPHBvdHVzQHdoaXRlaG91c2UuZ292Pg==?==?utf-8?Q?=00=0A?=\" <demo@mailsploit.com>");
|
||||
assert(addr.name == "test <potus@whitehouse.gov>?");
|
||||
assert(addr.address == "demo@mailsploit.com");
|
||||
// Courtesy Mailsploit https://www.mailsploit.com
|
||||
encoded = "\"=?utf-8?b?dGVzdCIgPHBvdHVzQHdoaXRlaG91c2UuZ292Pg==?==?utf-8?Q?=00=0A?=\" <demo@mailsploit.com>";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, "test <potus@whitehouse.gov>?", encoded);
|
||||
assert_equal(addr.address, "demo@mailsploit.com", encoded);
|
||||
|
||||
// Courtesy Mailsploit https://www.mailsploit.com
|
||||
addr = new MailboxAddress.from_rfc822_string("\"=?utf-8?Q?=42=45=47=49=4E=20=2F=20=28=7C=29=7C=3C=7C=3E=7C=40=7C=2C=7C=3B=7C=3A=7C=5C=7C=22=7C=2F=7C=5B=7C=5D=7C=3F=7C=2E=7C=3D=20=2F=20=00=20=50=41=53=53=45=44=20=4E=55=4C=4C=20=42=59=54=45=20=2F=20=0D=0A=20=50=41=53=53=45=44=20=43=52=4C=46=20=2F=20?==?utf-8?b?RU5E=?=\"");
|
||||
assert(addr.name == null);
|
||||
assert(addr.address == "BEGIN / (|)|<|>|@|,|;|:|\\|\"|/|[|]|?|.|= / ? PASSED NULL BYTE / \r\n PASSED CRLF / END");
|
||||
} catch (Error err) {
|
||||
assert_not_reached();
|
||||
}
|
||||
// Courtesy Mailsploit https://www.mailsploit.com
|
||||
encoded = "\"=?utf-8?Q?=42=45=47=49=4E=20=2F=20=28=7C=29=7C=3C=7C=3E=7C=40=7C=2C=7C=3B=7C=3A=7C=5C=7C=22=7C=2F=7C=5B=7C=5D=7C=3F=7C=2E=7C=3D=20=2F=20=00=20=50=41=53=53=45=44=20=4E=55=4C=4C=20=42=59=54=45=20=2F=20=0D=0A=20=50=41=53=53=45=44=20=43=52=4C=46=20=2F=20?==?utf-8?b?RU5E=?=\"";
|
||||
addr = new MailboxAddress.from_rfc822_string(encoded);
|
||||
assert_equal(addr.name, null, encoded);
|
||||
assert_equal(addr.address, "BEGIN / (|)|<|>|@|,|;|:|\\|\"|/|[|]|?|.|= / ? PASSED NULL BYTE / \r\n PASSED CRLF / END", encoded);
|
||||
}
|
||||
|
||||
public void prepare_header_text_part() throws GLib.Error {
|
||||
|
|
@ -286,6 +315,22 @@ class Geary.RFC822.MailboxAddressTest : TestCase {
|
|||
"😸@example.com"
|
||||
);
|
||||
|
||||
assert_equal(
|
||||
new MailboxAddress(null, "example1").to_rfc822_address(),
|
||||
"example1"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "example2", "").to_rfc822_address(),
|
||||
"example2"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "", "example3").to_rfc822_address(),
|
||||
"@example3"
|
||||
);
|
||||
assert_equal(
|
||||
new MailboxAddress.imap(null, null, "", "").to_rfc822_address(),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
public void to_rfc822_string() throws GLib.Error {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@ class Integration.Imap.ClientSession : TestCase {
|
|||
public override void set_up() {
|
||||
this.session = new Geary.Imap.ClientSession(
|
||||
this.config.target,
|
||||
Geary.Imap.ClientService.new_quirks_for_provider(
|
||||
this.config.provider
|
||||
)
|
||||
new Geary.Imap.Quirks()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ test_engine_sources = [
|
|||
'engine/imap/message/imap-data-format-test.vala',
|
||||
'engine/imap/message/imap-mailbox-specifier-test.vala',
|
||||
'engine/imap/parameter/imap-list-parameter-test.vala',
|
||||
'engine/imap/response/imap-fetch-data-decoder-test.vala',
|
||||
'engine/imap/response/imap-namespace-response-test.vala',
|
||||
'engine/imap/transport/imap-client-connection-test.vala',
|
||||
'engine/imap/transport/imap-client-session-test.vala',
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ int main(string[] args) {
|
|||
|
||||
engine.add_suite(new Geary.Imap.CreateCommandTest().suite);
|
||||
engine.add_suite(new Geary.Imap.FetchCommandTest().suite);
|
||||
engine.add_suite(new Geary.Imap.FetchDataDecoderTest().suite);
|
||||
engine.add_suite(new Geary.Imap.ListParameterTest().suite);
|
||||
engine.add_suite(new Geary.Imap.MailboxSpecifierTest().suite);
|
||||
engine.add_suite(new Geary.Imap.NamespaceResponseTest().suite);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue