Geary.Imap: Add Quirks object to collect all IMAP service quirk config

This commit is contained in:
Michael Gratton 2020-05-01 15:40:18 +10:00 committed by Michael James Gratton
parent 865765a24f
commit ddb3a899fb
12 changed files with 73 additions and 24 deletions

View file

@ -315,7 +315,8 @@ class ImapConsole : Gtk.Window {
new GLib.NetworkAddress(args[0], Geary.Imap.IMAP_TLS_PORT),
method,
IMAP_TIMEOUT_SEC
)
),
new Geary.Imap.Quirks()
);
cx.sent_command.connect(on_sent_command);

View file

@ -284,7 +284,10 @@ public class Geary.Engine : BaseObject {
(security, cx) => account.untrusted_host(service, security, cx)
);
var client = new Imap.ClientSession(endpoint);
var client = new Imap.ClientSession(
endpoint,
Imap.ClientService.new_quirks_for_provider(account.service_provider)
);
GLib.Error? imap_err = null;
try {
yield client.connect_async(

View file

@ -39,6 +39,12 @@ 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();
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.)
@ -101,6 +107,8 @@ public class Geary.Imap.ClientService : Geary.ClientService {
get { return LOGGING_DOMAIN; }
}
private Quirks quirks;
private Nonblocking.Mutex sessions_mutex = new Nonblocking.Mutex();
private Gee.Set<ClientSession> all_sessions =
new Gee.HashSet<ClientSession>();
@ -112,9 +120,10 @@ public class Geary.Imap.ClientService : Geary.ClientService {
public ClientService(AccountInformation account,
ServiceInformation service,
ServiceInformation configuration,
Endpoint remote) {
base(account, service, remote);
base(account, configuration, remote);
this.quirks = new_quirks_for_provider(account.service_provider);
}
/**
@ -445,7 +454,7 @@ public class Geary.Imap.ClientService : Geary.ClientService {
throw new ImapError.UNAUTHENTICATED("Token not loaded");
}
ClientSession new_session = new ClientSession(remote);
ClientSession new_session = new ClientSession(remote, this.quirks);
new_session.set_logging_parent(this);
yield new_session.connect_async(
ClientSession.DEFAULT_GREETING_TIMEOUT_SEC, cancellable

View file

@ -0,0 +1,18 @@
/*
* Copyright © 2019-2020 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.
*/
/**
* A set of quirks for a specific IMAP service.
*/
public class Geary.Imap.Quirks : BaseObject {
/** The set of additional characters allowed in an IMAP flag. */
public string? flag_atom_exceptions { get; set; }
}

View file

@ -65,6 +65,7 @@ public class Geary.Imap.ClientConnection : BaseObject, Logging.Source {
private Geary.Endpoint endpoint;
private int cx_id;
private Quirks quirks;
private IOStream? cx = null;
private Deserializer? deserializer = null;
private Serializer? serializer = null;
@ -111,9 +112,11 @@ public class Geary.Imap.ClientConnection : BaseObject, Logging.Source {
public ClientConnection(
Geary.Endpoint endpoint,
Quirks quirks,
uint command_timeout = Command.DEFAULT_RESPONSE_TIMEOUT_SEC,
uint idle_timeout_sec = DEFAULT_IDLE_TIMEOUT_SEC) {
this.endpoint = endpoint;
this.quirks = quirks;
this.cx_id = next_cx_id++;
this.command_timeout = command_timeout;
this.idle_timer = new TimeoutManager.seconds(
@ -323,7 +326,9 @@ public class Geary.Imap.ClientConnection : BaseObject, Logging.Source {
// Not buffering the Deserializer because it uses a
// DataInputStream, which is already buffered
this.deserializer = new Deserializer(id, this.cx.input_stream);
this.deserializer = new Deserializer(
id, this.cx.input_stream, this.quirks
);
this.deserializer.bytes_received.connect(on_bytes_received);
this.deserializer.deserialize_failure.connect(on_deserialize_failure);
this.deserializer.end_of_stream.connect(on_eos);

View file

@ -296,6 +296,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
private Gee.List<Namespace> shared_namespaces = new Gee.ArrayList<Namespace>();
private Endpoint imap_endpoint;
private Quirks quirks;
private Geary.State.Machine fsm;
private ClientConnection? cx = null;
@ -344,8 +345,9 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
public signal void status(StatusData status_data);
public ClientSession(Endpoint imap_endpoint) {
public ClientSession(Endpoint imap_endpoint, Quirks quirks) {
this.imap_endpoint = imap_endpoint;
this.quirks = quirks;
Geary.State.Mapping[] mappings = {
new Geary.State.Mapping(State.NOT_CONNECTED, Event.CONNECT, on_connect),
@ -774,7 +776,7 @@ public class Geary.Imap.ClientSession : BaseObject, Logging.Source {
MachineParams params = (MachineParams) object;
assert(cx == null);
cx = new ClientConnection(imap_endpoint);
cx = new ClientConnection(imap_endpoint, this.quirks);
cx.set_logging_parent(this);
cx.sent_command.connect(on_network_sent_command);
cx.send_failure.connect(on_network_send_error);

View file

@ -85,6 +85,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
private weak Logging.Source? _logging_parent = null;
private string identifier;
private Quirks quirks;
private DataInputStream input;
private Geary.State.Machine fsm;
@ -153,13 +154,17 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
public signal void end_of_stream();
public Deserializer(string identifier, GLib.InputStream input) {
public Deserializer(string identifier,
GLib.InputStream input,
Quirks quirks) {
this.identifier = identifier;
this.input = new GLib.DataInputStream(input);
this.input.set_close_base_stream(false);
this.input.set_newline_type(CR_LF);
this.quirks = quirks;
Geary.State.Mapping[] mappings = {
new Geary.State.Mapping(State.TAG, Event.CHAR, on_tag_char),
new Geary.State.Mapping(State.TAG, Event.EOS, on_eos),

View file

@ -93,6 +93,7 @@ geary_engine_vala_sources = files(
'imap/api/imap-folder-properties.vala',
'imap/api/imap-folder-root.vala',
'imap/api/imap-folder-session.vala',
'imap/api/imap-quirks.vala',
'imap/api/imap-session-object.vala',
'imap/command/imap-append-command.vala',
'imap/command/imap-authenticate-command.vala',

View file

@ -38,7 +38,7 @@ class Geary.Imap.ClientConnectionTest : TestCase {
}
public void connect_disconnect() throws GLib.Error {
var test_article = new ClientConnection(new_endpoint());
var test_article = new ClientConnection(new_endpoint(), new Quirks());
test_article.connect_async.begin(null, this.async_completion);
test_article.connect_async.end(async_result());
@ -69,7 +69,7 @@ class Geary.Imap.ClientConnectionTest : TestCase {
const int IDLE_TIMEOUT = 1;
var test_article = new ClientConnection(
new_endpoint(), COMMAND_TIMEOUT, IDLE_TIMEOUT
new_endpoint(), new Quirks(), COMMAND_TIMEOUT, IDLE_TIMEOUT
);
test_article.connect_async.begin(null, this.async_completion);
test_article.connect_async.end(async_result());
@ -123,7 +123,9 @@ class Geary.Imap.ClientConnectionTest : TestCase {
bool recv_fail = false;
bool timed_out = false;
var test_article = new ClientConnection(new_endpoint(), TIMEOUT);
var test_article = new ClientConnection(
new_endpoint(), new Quirks(), TIMEOUT
);
test_article.sent_command.connect(() => { sent = true; });
test_article.receive_failure.connect(() => { recv_fail = true; });
test_article.connect_async.begin(null, this.async_completion);

View file

@ -43,7 +43,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
);
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -69,7 +69,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
);
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
test_article.connect_async.begin(
CONNECT_TIMEOUT, null, this.async_completion
);
@ -87,7 +87,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
public void connect_timeout() throws GLib.Error {
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
GLib.Timer timer = new GLib.Timer();
timer.start();
@ -115,7 +115,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
);
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
test_article.connect_async.begin(
CONNECT_TIMEOUT, null, this.async_completion
);
@ -147,7 +147,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a001 OK ohhai");
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -184,7 +184,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a001 OK laters");
this.server.add_script_line(DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -215,7 +215,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a002 OK laters");
this.server.add_script_line(DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -260,7 +260,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a004 OK there");
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -304,7 +304,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a002 OK there");
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(
@ -367,7 +367,7 @@ class Geary.Imap.ClientSessionTest : TestCase {
this.server.add_script_line(SEND_LINE, "a003 OK there");
this.server.add_script_line(WAIT_FOR_DISCONNECT, "");
var test_article = new ClientSession(new_endpoint());
var test_article = new ClientSession(new_endpoint(), new Quirks());
assert_true(test_article.get_protocol_state() == NOT_CONNECTED);
test_article.connect_async.begin(

View file

@ -47,7 +47,7 @@ class Geary.Imap.DeserializerTest : TestCase {
public override void set_up() {
this.stream = new MemoryInputStream();
this.deser = new Deserializer(ID, this.stream);
this.deser = new Deserializer(ID, this.stream, new Quirks());
}
public override void tear_down() {

View file

@ -28,7 +28,10 @@ class Integration.Imap.ClientSession : TestCase {
public override void set_up() {
this.session = new Geary.Imap.ClientSession(
this.config.target
this.config.target,
Geary.Imap.ClientService.new_quirks_for_provider(
this.config.provider
)
);
}