This commit is contained in:
Jim Nelson 2013-04-25 14:47:20 -07:00
parent 2d7c14cc0d
commit 0ab03c0a28
18 changed files with 160 additions and 132 deletions

View file

@ -216,7 +216,7 @@ public class Geary.Engine : BaseObject {
return error_code;
// validate IMAP, which requires logging in and establishing an AUTHORIZED cx state
Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(account.get_imap_endpoint(), true);
Geary.Imap.ClientSession? imap_session = new Imap.ClientSession(account.get_imap_endpoint());
try {
yield imap_session.connect_async(cancellable);
} catch (Error err) {

View file

@ -96,12 +96,12 @@ private class Geary.ImapDB.Account : BaseObject {
throws Error {
check_open();
Geary.Imap.FolderProperties? properties = imap_folder.get_properties();
Geary.Imap.FolderProperties? properties = imap_folder.properties;
// properties *must* be available to perform a clone
assert(properties != null);
Geary.FolderPath path = imap_folder.get_path();
Geary.FolderPath path = imap_folder.path;
yield db.exec_transaction_async(Db.TransactionType.RW, (cx) => {
// get the parent of this folder, creating parents if necessary ... ok if this fails,
@ -137,8 +137,8 @@ private class Geary.ImapDB.Account : BaseObject {
throws Error {
check_open();
Geary.Imap.FolderProperties properties = imap_folder.get_properties();
Geary.FolderPath path = imap_folder.get_path();
Geary.Imap.FolderProperties properties = imap_folder.properties;
Geary.FolderPath path = imap_folder.path;
yield db.exec_transaction_async(Db.TransactionType.RW, (cx) => {
int64 parent_id;

View file

@ -309,7 +309,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
Gee.Collection<Geary.Folder> engine_folders, Cancellable? cancellable) {
Gee.Collection<Geary.Imap.Folder> remote_folders;
try {
remote_folders = yield remote.list_folders_async(parent, cancellable);
remote_folders = yield remote.list_mailboxes_async(parent, cancellable);
} catch (Error remote_error) {
debug("Unable to retrieve folder list from server: %s", remote_error.message);
@ -321,20 +321,20 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
Hashable.hash_func, Equalable.equal_func);
foreach (Imap.Folder remote_folder in remote_folders) {
// only worry about alterations if the remote is openable
if (remote_folder.get_properties().is_openable.is_possible()) {
if (remote_folder.properties.is_openable.is_possible()) {
ImapDB.Folder? local_folder = null;
try {
local_folder = yield local.fetch_folder_async(remote_folder.get_path(), cancellable);
local_folder = yield local.fetch_folder_async(remote_folder.path, cancellable);
} catch (Error err) {
if (!(err is EngineError.NOT_FOUND)) {
debug("Unable to fetch local folder for remote %s: %s", remote_folder.get_path().to_string(),
debug("Unable to fetch local folder for remote %s: %s", remote_folder.path.to_string(),
err.message);
}
}
if (local_folder != null) {
if (remote_folder.get_properties().have_contents_changed(local_folder.get_properties()).is_possible())
altered_paths.add(remote_folder.get_path());
if (remote_folder.properties.have_contents_changed(local_folder.get_properties()).is_possible())
altered_paths.add(remote_folder.path);
}
}
@ -356,23 +356,23 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
Gee.Set<Geary.FolderPath> remote_paths = new Gee.HashSet<Geary.FolderPath>(
Geary.Hashable.hash_func, Geary.Equalable.equal_func);
foreach (Geary.Imap.Folder remote_folder in remote_folders) {
remote_paths.add(remote_folder.get_path());
remote_paths.add(remote_folder.path);
// use this iteration to add discovered properties to map
properties_map.set(remote_folder.get_path(), remote_folder.get_properties());
properties_map.set(remote_folder.path, remote_folder.properties);
// also use this iteration to set the local folder's special type
// (but only promote, not demote, since getting the special folder type via its
// properties relies on the optional XLIST extension)
GenericFolder? local_folder = existing_folders.get(remote_folder.get_path());
GenericFolder? local_folder = existing_folders.get(remote_folder.path);
if (local_folder != null && local_folder.get_special_folder_type() == SpecialFolderType.NONE)
local_folder.set_special_folder_type(remote_folder.get_properties().attrs.get_special_folder_type());
local_folder.set_special_folder_type(remote_folder.properties.attrs.get_special_folder_type());
}
// If path in remote but not local, need to add it
Gee.List<Geary.Imap.Folder> to_add = new Gee.ArrayList<Geary.Imap.Folder>();
foreach (Geary.Imap.Folder folder in remote_folders) {
if (!local_paths.contains(folder.get_path()))
if (!local_paths.contains(folder.path))
to_add.add(folder);
}
@ -396,7 +396,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
try {
yield local.clone_folder_async(folder, cancellable);
} catch (Error err) {
debug("Unable to add/remove folder %s: %s", folder.get_path().to_string(),
debug("Unable to add/remove folder %s: %s", folder.path.to_string(),
err.message);
}
}
@ -411,7 +411,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
foreach (Geary.Imap.Folder remote_folder in to_add) {
try {
folders_to_build.add((ImapDB.Folder) yield local.fetch_folder_async(
remote_folder.get_path(), cancellable));
remote_folder.path, cancellable));
} catch (Error convert_err) {
// This isn't fatal, but irksome ... in the future, when local folders are
// removed, it's possible for one to disappear between cloning it and fetching
@ -449,11 +449,11 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.AbstractAccount {
// enumerate children of each remote folder
foreach (Imap.Folder remote_folder in remote_folders) {
if (remote_folder.get_properties().has_children.is_possible()) {
if (remote_folder.properties.has_children.is_possible()) {
try {
yield enumerate_folders_async(remote_folder.get_path(), cancellable);
yield enumerate_folders_async(remote_folder.path, cancellable);
} catch (Error err) {
debug("Unable to enumerate children of %s: %s", remote_folder.get_path().to_string(),
debug("Unable to enumerate children of %s: %s", remote_folder.path.to_string(),
err.message);
}
}

View file

@ -56,7 +56,7 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
// - From open remote folder
// - Fetch from local store
if (remote_folder != null && get_open_state() == OpenState.BOTH)
return remote_folder.get_properties();
return remote_folder.properties;
return local_folder.get_properties();
}
@ -106,7 +106,7 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
debug("normalize_folders %s", to_string());
Geary.Imap.FolderProperties local_properties = local_folder.get_properties();
Geary.Imap.FolderProperties remote_properties = remote_folder.get_properties();
Geary.Imap.FolderProperties remote_properties = remote_folder.properties;
// and both must have their next UID's (it's possible they don't if it's a non-selectable
// folder)
@ -454,12 +454,14 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
yield local.update_folder_async(folder, cancellable);
// signals
/*
folder.messages_appended.connect(on_remote_messages_appended);
folder.message_at_removed.connect(on_remote_message_at_removed);
folder.disconnected.connect(on_remote_disconnected);
*/
// state
remote_count = folder.get_email_count();
remote_count = folder.properties.email_total;
// all set; bless the remote folder as opened
remote_folder = folder;
@ -547,9 +549,11 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
}
if (closing_remote_folder != null) {
/*
closing_remote_folder.messages_appended.disconnect(on_remote_messages_appended);
closing_remote_folder.message_at_removed.disconnect(on_remote_message_at_removed);
closing_remote_folder.disconnected.disconnect(on_remote_disconnected);
*/
// to avoid keeping the caller waiting while the remote end closes, close it in the
// background

View file

@ -10,6 +10,13 @@ private class Geary.Imap.Account : BaseObject {
public const string INBOX_NAME = "INBOX";
public const string ASSUMED_SEPARATOR = "/";
private static MailboxParameter? _GLOB_PARAMETER = null;
private static MailboxParameter GLOB_PARAMETER {
get {
return (_GLOB_PARAMETER != null) ? _GLOB_PARAMETER : _GLOB_PARAMETER = new MailboxParameter("%");
}
}
public bool is_open { get; private set; default = false; }
private string name;
@ -18,7 +25,7 @@ private class Geary.Imap.Account : BaseObject {
private Gee.HashMap<string, string?> delims = new Gee.HashMap<string, string?>();
private ClientSession? account_session = null;
private NonblockingMutex cmd_mutex = new NonblockingMutex();
private Gee.ArrayList<MailboxInformation> mailbox_collector = new Gee.ArrayList<MailboxInformation>();
private Gee.ArrayList<MailboxInformation> list_collector = new Gee.ArrayList<MailboxInformation>();
private Gee.ArrayList<StatusData> status_collector = new Gee.ArrayList<StatusData>();
public signal void email_sent(Geary.RFC822.Message rfc822);
@ -33,6 +40,11 @@ private class Geary.Imap.Account : BaseObject {
session_mgr.login_failed.connect(on_login_failed);
}
private void check_open() throws Error {
if (!is_open)
throw new EngineError.OPEN_REQUIRED("Imap.Account not open");
}
public async void open_async(Cancellable? cancellable = null) throws Error {
if (is_open)
throw new EngineError.ALREADY_OPEN("Imap.Account already open");
@ -71,13 +83,14 @@ private class Geary.Imap.Account : BaseObject {
Geary.FolderPath? processed = process_path(path, null, path.get_root().default_separator);
if (processed == null)
throw new ImapError.INVALID_PATH("Invalid path %s", path.to_string());
throw new ImapError.INVALID("Invalid path %s", path.to_string());
bool can_xlist = account_session.capabilities.has_capability(Capabilities.XLIST);
Gee.List<MailboxInformation> list_results = new Gee.ArrayList<MailboxInformation>();
CompletionStatusResponse response = yield send_command_async(
new ListCommand(processed.get_fullpath(), can_xlist), list_results, null, cancellable);
new ListCommand(new Imap.MailboxParameter(processed.get_fullpath()), can_xlist), list_results,
null, cancellable);
if (response.status != Status.OK) {
throw new ImapError.SERVER_ERROR("Server reports LIST error for path %s: %s", path.to_string(),
@ -89,7 +102,7 @@ private class Geary.Imap.Account : BaseObject {
list_results.size, path.get_fullpath());
}
return (list_results == 1) ? list_results[0] : null;
return (list_results.size == 1) ? list_results[0] : null;
}
public async Gee.List<MailboxInformation>? list_children_command(FolderPath? parent, Cancellable? cancellable = null)
@ -103,14 +116,14 @@ private class Geary.Imap.Account : BaseObject {
ListCommand cmd;
if (processed == null) {
cmd = new ListCommand.wildcarded("", "%", can_xlist);
cmd = new ListCommand.wildcarded("", new MailboxParameter("%"), can_xlist);
} else {
string specifier = processed.get_fullpath();
string delim = processed.get_root().default_separator;
specified += specifier.has_suffix(delim) ? "%" : (delim + "%");
specifier += specifier.has_suffix(delim) ? "%" : (delim + "%");
cmd = new ListCommand(specifier, can_xlist);
cmd = new ListCommand(new Imap.MailboxParameter(specifier), can_xlist);
}
Gee.List<MailboxInformation> list_results = new Gee.ArrayList<MailboxInformation>();
@ -118,7 +131,7 @@ private class Geary.Imap.Account : BaseObject {
cancellable);
if (response.status != Status.OK)
throw_not_found(path);
throw_not_found(processed ?? parent);
return (list_results.size > 0) ? list_results : null;
}
@ -129,12 +142,12 @@ private class Geary.Imap.Account : BaseObject {
Geary.FolderPath? processed = process_path(path, null, path.get_root().default_separator);
if (processed == null)
throw new ImapError.INVALID_PATH("Invalid path %s", path.to_string());
throw new ImapError.INVALID("Invalid path %s", path.to_string());
Gee.List<StatusData> status_results = new Gee.ArrayList<StatusData>();
CompletionStatusResponse response = yield send_command_async(
new StatusCommand(processed.get_fullpath(), StatusDataType.all()), null, status_results,
cancellable);
new StatusCommand(new MailboxParameter(processed.get_fullpath()), StatusDataType.all()),
null, status_results, cancellable);
if (response.status != Status.OK) {
throw new ImapError.SERVER_ERROR("Server reports STATUS error for path %s: %s", path.to_string(),
@ -201,7 +214,7 @@ private class Geary.Imap.Account : BaseObject {
// 3. Parent and basename supplied, verify parent is not Inbox, as IMAP does not allow it
// to have children
if (parent != null && !empty_basename && parent.get_root().basename.up() == INBOX_NAME)
throw new ImapError.INVALID_PATH("Inbox may not have children");
throw new ImapError.INVALID("Inbox may not have children");
// 4. Parent supplied but basename is not; if parent points to Inbox, normalize it
if (parent != null && empty_basename && parent.basename.up() == INBOX_NAME)

View file

@ -6,17 +6,18 @@
public class Geary.Imap.FolderProperties : Geary.FolderProperties {
/**
* -1 if the Folder was not opened via SELECT or EXAMINE.
* -1 if the Folder was not opened via SELECT or EXAMINE. Updated as EXISTS server data
* arrives.
*/
public int select_examine_messages { get; private set; }
/**
* -1 if the FolderProperties were not obtained via a STATUS command
*/
public int status_messages { get; private set; }
public int unseen { get; private set; }
public int recent { get; private set; }
public UIDValidity? uid_validity { get; private set; }
public UID? uid_next { get; private set; }
public int unseen { get; internal set; }
public int recent { get; internal set; }
public UIDValidity? uid_validity { get; internal set; }
public UID? uid_next { get; internal set; }
public MailboxAttributes attrs { get; private set; }
// Note that unseen from SELECT/EXAMINE is the *position* of the first unseen message,

View file

@ -64,8 +64,8 @@ private class Geary.Imap.Folder : BaseObject {
session.expunge.connect(on_expunge);
session.fetch.connect(on_fetch);
session.recent.connect(on_recent);
session.coded_status_response.connect(on_coded_status_response);
session.disconnected.connect(on_disconnected);
session.coded_response_received.connect(on_coded_status_response);
//session.disconnected.connect(on_disconnected);
CompletionStatusResponse response = yield session.select_examine_async(path.get_fullpath(info.delim),
!readonly, cancellable);
@ -74,11 +74,6 @@ private class Geary.Imap.Folder : BaseObject {
// update with new information
this.readonly = Trillian.from_boolean(readonly);
int old_status_messages = properties.status_messages;
properties = new Imap.FolderProperties(mailbox.exists, mailbox.recent, properties.unseen,
mailbox.uid_validity, mailbox.uid_next, properties.attrs);
properties.set_status_message_count(old_status_messages, false);
}
public async void close_async(Cancellable? cancellable = null) throws Error {
@ -89,8 +84,8 @@ private class Geary.Imap.Folder : BaseObject {
session.expunge.disconnect(on_expunge);
session.fetch.disconnect(on_fetch);
session.recent.disconnect(on_recent);
session.coded_status_response.disconnect(on_coded_status_response);
session.disconnected.disconnect(on_disconnected);
session.coded_response_received.disconnect(on_coded_status_response);
//session.disconnected.disconnect(on_disconnected);
try {
yield session.close_mailbox_async(cancellable);
@ -104,7 +99,7 @@ private class Geary.Imap.Folder : BaseObject {
}
private void on_exists(int count) {
properties.messages = count;
properties.set_select_examine_message_count(count);
exists(count);
}
@ -124,10 +119,23 @@ private class Geary.Imap.Folder : BaseObject {
}
private void on_coded_status_response(CodedStatusResponse coded_response) {
switch (coded_response.response_code_type) {
case ResponseCodeType.UIDNEXT:
properties.uid_next = coded_response.get_uid_next();
break;
try {
switch (coded_response.response_code_type) {
case ResponseCodeType.UIDNEXT:
properties.uid_next = coded_response.get_uid_next();
break;
case ResponseCodeType.UIDVALIDITY:
properties.uid_validity = coded_response.get_uid_validity();
break;
case ResponseCodeType.UNSEEN:
properties.unseen = coded_response.get_unseen();
break;
}
} catch (ImapError ierr) {
debug("Unable to parse CodedStatusResponse %s: %s", coded_response.to_string(),
ierr.message);
}
}
@ -150,13 +158,18 @@ private class Geary.Imap.Folder : BaseObject {
public async Gee.List<Geary.Email>? list_email_async(MessageSet msg_set, Geary.Email.Field fields,
Cancellable? cancellable = null) throws Error {
/*
if (mailbox == null)
throw new EngineError.OPEN_REQUIRED("%s not opened", to_string());
return yield mailbox.list_set_async(msg_set, fields, cancellable);
*/
return null;
}
public async void remove_email_async(MessageSet msg_set, Cancellable? cancellable = null) throws Error {
/*
if (mailbox == null)
throw new EngineError.OPEN_REQUIRED("%s not opened", to_string());
@ -168,10 +181,12 @@ private class Geary.Imap.Folder : BaseObject {
// mailbox could've closed during call
if (mailbox != null)
yield mailbox.expunge_email_async(msg_set, cancellable);
*/
}
public async void mark_email_async(MessageSet msg_set, Geary.EmailFlags? flags_to_add,
Geary.EmailFlags? flags_to_remove, Cancellable? cancellable = null) throws Error {
/*
if (mailbox == null)
throw new EngineError.OPEN_REQUIRED("%s not opened", to_string());
@ -181,23 +196,28 @@ private class Geary.Imap.Folder : BaseObject {
out msg_flags_remove);
yield mailbox.mark_email_async(msg_set, msg_flags_add, msg_flags_remove, cancellable);
*/
}
public async void copy_email_async(MessageSet msg_set, Geary.FolderPath destination,
Cancellable? cancellable = null) throws Error {
/*
if (mailbox == null)
throw new EngineError.OPEN_REQUIRED("%s not opened", to_string());
yield mailbox.copy_email_async(msg_set, destination, cancellable);
*/
}
public async void move_email_async(MessageSet msg_set, Geary.FolderPath destination,
Cancellable? cancellable = null) throws Error {
/*
if (mailbox == null)
throw new EngineError.OPEN_REQUIRED("%s not opened", to_string());
yield copy_email_async(msg_set, destination, cancellable);
yield remove_email_async(msg_set, cancellable);
*/
}
public string to_string() {

View file

@ -49,9 +49,9 @@ public class Geary.Imap.FetchedData : Object {
// watch for empty return values
if (has_value)
fetched_data.set_data(data_item, decoder.decode(list.get_required(ctr + 1)));
fetched_data.map.set(data_item, decoder.decode(list.get_required(ctr + 1)));
else
fetched_data.set_data(data_item, decoder.decode(NilParameter.instance));
fetched_data.map.set(data_item, decoder.decode(NilParameter.instance));
}
}

View file

@ -54,17 +54,17 @@ public class Geary.Imap.MailboxInformation : Object {
}
public static MailboxInformation decode(ServerData server_data) throws ImapError {
StringParameter cmd = data.get_as_string(1);
StringParameter cmd = server_data.get_as_string(1);
if (!cmd.equals_ci(ListCommand.NAME) && !cmd.equals_ci(ListCommand.XLIST_NAME))
throw ImapError.PARSE_ERROR("Not LIST or XLIST data: %s", server_data.to_string());
throw new ImapError.PARSE_ERROR("Not LIST or XLIST data: %s", server_data.to_string());
ListParameter attrs = data.get_as_list(2);
ListParameter attrs = server_data.get_as_list(2);
Gee.Collection<MailboxAttribute> attrlist = new Gee.ArrayList<MailboxAttribute>();
foreach (Parameter attr in attrs.get_all()) {
StringParameter? stringp = attr as StringParameter;
if (stringp == null) {
debug("Bad list attribute \"%s\": Attribute not a string value",
data.to_string());
server_data.to_string());
continue;
}
@ -72,8 +72,8 @@ public class Geary.Imap.MailboxInformation : Object {
attrlist.add(new MailboxAttribute(stringp.value));
}
StringParameter? delim = data.get_as_nullable_string(3);
StringParameter mailbox = data.get_as_string(4);
StringParameter? delim = server_data.get_as_nullable_string(3);
StringParameter mailbox = server_data.get_as_string(4);
// Set \Inbox to standard path
MailboxInformation info;

View file

@ -38,7 +38,7 @@ public class Geary.Imap.StatusData : Object {
public static StatusData decode(ServerData server_data) throws ImapError {
if (!server_data.get_as_string(1).equals_ci(StatusCommand.NAME)) {
throw new ImapError.PARSE_ERROR("Bad STATUS command name in response \"%s\"",
response.to_string());
server_data.to_string());
}
int messages = UNSET;
@ -83,7 +83,7 @@ public class Geary.Imap.StatusData : Object {
}
} catch (ImapError ierr) {
message("Bad value at %d/%d in STATUS response \"%s\": %s", ctr, ctr + 1,
response.to_string(), ierr.message);
server_data.to_string(), ierr.message);
}
}

View file

@ -8,11 +8,12 @@ public class Geary.Imap.CodedStatusResponse : StatusResponse {
public ResponseCodeType response_code_type { get; private set; }
public ResponseCode response_code { get; private set; }
public CodedStatusResponse() {
public CodedStatusResponse(Tag tag) {
base (tag);
}
public CodedStatusResponse.reconstitute(RootParameters root) throws ImapError {
base.reconstitute(root);
public CodedStatusResponse.migrate(RootParameters root) throws ImapError {
base.migrate(root);
if (tag.is_tagged()) {
throw new ImapError.PARSE_ERROR("Not a CodedStatusResponse: tagged response: %s",

View file

@ -5,11 +5,12 @@
*/
public class Geary.Imap.CompletionStatusResponse : StatusResponse {
private CompletionStatusResponse() {
private CompletionStatusResponse(Tag tag) {
base (tag);
}
public CompletionStatusResponse.reconstitute(RootParameters root) throws ImapError {
base.reconstitute(root);
public CompletionStatusResponse.migrate(RootParameters root) throws ImapError {
base.migrate(root);
// check this is actually a CompletionStatusResponse
if (!tag.is_tagged()) {

View file

@ -7,6 +7,10 @@
public class Geary.Imap.ServerData : ServerResponse {
public ServerDataType server_data_type { get; private set; }
protected ServerData(Tag tag) {
base (tag);
}
public ServerData.migrate(RootParameters root) throws ImapError {
base.migrate(root);
}

View file

@ -18,7 +18,7 @@ public abstract class Geary.Imap.ServerResponse : RootParameters {
}
// The RootParameters are migrated and will be stripped upon exit.
public static ServerResponse migrate_from_server(RootParameters root, out Type response_type)
public static ServerResponse migrate_from_server(RootParameters root)
throws ImapError {
Tag tag = new Tag.from_parameter(root.get_as_string(0));
if (tag.is_tagged()) {
@ -28,30 +28,24 @@ public abstract class Geary.Imap.ServerResponse : RootParameters {
if (statusparam != null)
Status.decode(statusparam.value);
// tagged and has proper status, so it's a status response
response_type = Type.STATUS_RESPONSE;
return new StatusResponse.migrate(root);
} else if (tag.is_continuation()) {
// nothing to decode; everything after the tag is human-readable stuff
response_type = Type.CONTINUATION_RESPONSE;
return new ContinuationResponse.migrate(root);
}
// All CompletionStatusResponses are StatusResponses, so check for it first
if (CompletionStatusResponse.is_completion_status_response(root))
return new CompletionStatusResponse.reconstitute(root);
return new CompletionStatusResponse.migrate(root);
// All CodedStatusResponses are StatusResponses, so check for it first
if (CodedStatusResponse.is_coded_status_response(root))
return new CodedStatusResponse.reconstitute(root);
return new CodedStatusResponse.migrate(root);
if (StatusResponse.is_status_response(root))
return new StatusResponse.reconstitute(root);
return new StatusResponse.migrate(root);
if (ServerData.is_server_data(root))
return new ServerData.reconstitute(root);
return new ServerData.migrate(root);
throw new ImapError.PARSE_ERROR("Unknown server response: %s", root.to_string());
}

View file

@ -7,7 +7,8 @@
public class Geary.Imap.StatusResponse : ServerResponse {
public Status status { get; private set; }
public StatusResponse() {
public StatusResponse(Tag tag) {
base (tag);
}
public StatusResponse.migrate(RootParameters root) throws ImapError {

View file

@ -440,8 +440,9 @@ public class Geary.Imap.ClientConnection : BaseObject {
}
private void on_parameters_ready(RootParameters root) {
ServerResponse response;
try {
ServerResponse response = ServerResponse.from_server(root);
response = ServerResponse.migrate_from_server(root);
} catch (ImapError err) {
received_bad_response(root, err);
@ -469,7 +470,7 @@ public class Geary.Imap.ClientConnection : BaseObject {
return;
}
error("[%s] Unknown ServerResponse of type %s received: %s:", to_string(), response.type().name(),
error("[%s] Unknown ServerResponse of type %s received: %s:", to_string(), response.get_type().name(),
response.to_string());
}

View file

@ -53,31 +53,13 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
public ClientSessionManager(AccountInformation account_information) {
this.account_information = account_information;
}
~ClientSessionManager() {
if (is_opened)
warning("Destroying opened ClientSessionManager");
}
public async void open_async() throws Error {
if (is_opened)
throw ImapError.INVALID("ClientSessionManager is already open");
is_opened = true;
account_information.notify["imap-credentials"].connect(on_imap_credentials_notified);
}
public async void close_async() throws Error {
if (!is_opened)
return;
is_opened = false;
account_information.notify["imap-credentials"].disconnect(on_imap_credentials_notified);
// TODO: Tear down all connections
~ClientSessionManager() {
if (is_open)
warning("Destroying opened ClientSessionManager");
}
public async void open_async(Cancellable? cancellable) throws Error {
@ -304,7 +286,7 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
assert_not_reached();
}
int token = yield session_mutex.claim_async(cancellable);
int token = yield sessions_mutex.claim_async(cancellable);
if (!sessions.contains(session))
debug("Attempting to release a session not owned by client session manager: %s", session.to_string());
@ -312,7 +294,7 @@ public class Geary.Imap.ClientSessionManager : BaseObject {
if (!reserved_sessions.remove(session))
debug("Attempting to release an unreserved session: %s", session.to_string());
session_mutex.release(ref token);
sessions_mutex.release(ref token);
}
private void on_disconnected(ClientSession session, ClientSession.DisconnectReason reason) {

View file

@ -127,7 +127,7 @@ public class Geary.Imap.ClientSession : BaseObject {
* capabilities, only watch for them as they're reported. Thus, it's recommended that users
* of ClientSession issue a CapabilityCommand (if needed) before login.
*/
private Capabilities capabilities { get; private set; default = new Capabilities(0); }
public Capabilities capabilities { get; private set; default = new Capabilities(0); }
private Endpoint imap_endpoint;
private Geary.State.Machine fsm;
@ -270,7 +270,7 @@ public class Geary.Imap.ClientSession : BaseObject {
new Geary.State.Mapping(State.SELECTING, Event.CLOSE_MAILBOX, on_close_mailbox),
new Geary.State.Mapping(State.SELECTING, Event.LOGOUT, on_logout),
new Geary.State.Mapping(State.SELECTING, Event.DISCONNECT, on_disconnect),
new Geary.State.Mapping(State.SELECTING, Event.RECV_STATUS, on_selecting_recv_status),
new Geary.State.Mapping(State.SELECTING, Event.RECV_STATUS, on_recv_status),
new Geary.State.Mapping(State.SELECTING, Event.RECV_COMPLETION, on_selecting_recv_completion),
new Geary.State.Mapping(State.SELECTING, Event.SEND_ERROR, on_send_error),
new Geary.State.Mapping(State.SELECTING, Event.RECV_ERROR, on_recv_error),
@ -448,7 +448,7 @@ public class Geary.Imap.ClientSession : BaseObject {
// only use IDLE when in SELECTED or EXAMINED state
cx.set_idle_when_quiet(false);
result.proceed = true;
params.proceed = true;
return State.CONNECTING;
}
@ -487,7 +487,7 @@ public class Geary.Imap.ClientSession : BaseObject {
}
}
private void on_connected(uint state, uint event) {
private uint on_connected(uint state, uint event) {
debug("[%s] Connected", to_string());
fsm.do_post_transition(() => { connected(); });
@ -496,7 +496,7 @@ public class Geary.Imap.ClientSession : BaseObject {
return state;
}
private void on_connecting_recv_status(uint state, uint event, void *user, Object? object) {
private uint on_connecting_recv_status(uint state, uint event, void *user, Object? object) {
StatusResponse status_response = (StatusResponse) object;
if (status_response.status == Status.OK)
@ -504,7 +504,7 @@ public class Geary.Imap.ClientSession : BaseObject {
debug("[%s] Connect denied: %s", to_string(), status_response.to_string());
fsm.do_post_transition(() => { session_denied(status_response.text); });
fsm.do_post_transition(() => { session_denied(status_response.get_text()); });
return State.LOGGED_OUT;
}
@ -522,12 +522,13 @@ public class Geary.Imap.ClientSession : BaseObject {
LoginCommand cmd = new LoginCommand(credentials.user, credentials.pass);
MachineParams params = new MachineParams(cmd);
fsm.issue(Event.LOGIN, null, param);
fsm.issue(Event.LOGIN, null, params);
if (params.err != null)
throw params.err;
assert(result.proceed);
// should always proceed; only an Error could change this
assert(params.proceed);
return yield command_transaction_async(cmd, cancellable);
}
@ -562,12 +563,12 @@ public class Geary.Imap.ClientSession : BaseObject {
yield cx.starttls_async(cancellable);
debug("[%s] STARTTLS completed", to_string());
} else {
debug("[%s} STARTTLS refused: %s", to_string(), resp.status_response.to_string());
debug("[%s} STARTTLS refused: %s", to_string(), resp.status.to_string());
// throw an exception and fail rather than send credentials under suspect
// conditions
throw new ImapError.NOT_SUPPORTED("STARTTLS refused by %s: %s", to_string(),
resp.status_response.to_string());
resp.status.to_string());
}
break;
@ -781,7 +782,7 @@ public class Geary.Imap.ClientSession : BaseObject {
}
public bool supports_idle() {
return get_capabilities().has_capability(Capabilities.IDLE);
return capabilities.has_capability(Capabilities.IDLE);
}
//
@ -862,7 +863,12 @@ public class Geary.Imap.ClientSession : BaseObject {
Cancellable? cancellable) throws Error {
string? old_mailbox = current_mailbox;
Command cmd = is_select ? new SelectCommand(mailbox) : new ExamineCommand(mailbox);
// Ternary troubles
Command cmd;
if (is_select)
cmd = new SelectCommand(new MailboxParameter(mailbox));
else
cmd = new ExamineCommand(new MailboxParameter(mailbox));
MachineParams params = new MachineParams(cmd);
fsm.issue(Event.SELECT, null, params);
@ -1055,7 +1061,7 @@ public class Geary.Imap.ClientSession : BaseObject {
if (params.err != null)
throw params.err;
if (result.proceed)
if (params.proceed)
yield cx.disconnect_async(cancellable);
}
@ -1228,14 +1234,14 @@ public class Geary.Imap.ClientSession : BaseObject {
// server) in the context of send_async(), wait for it now
if (!seen_completion_responses.has_key(cmd.tag)) {
debug("[%s] Waiting for completion status response %s...", to_string(), cmd.to_string());
waiting_for_completion.set(cmd.tag, new CommandCallback(issue_command_async.callback));
waiting_for_completion.set(cmd.tag, new CommandCallback(command_transaction_async.callback));
yield;
}
// it should be seen now; if not, it's because of disconnection cancelling all the outstanding
// requests
CompletionStatusResponse? completion_response;
if (!seen_completion_response.remove(cmd.tag, out completion_response)) {
if (!seen_completion_responses.unset(cmd.tag, out completion_response)) {
assert(cx == null);
throw new ImapError.NOT_CONNECTED("Not connected to %s", imap_endpoint.to_string());
@ -1295,7 +1301,7 @@ public class Geary.Imap.ClientSession : BaseObject {
// update state machine before notifying subscribers, who may turn around and query ClientSession
fsm.issue(Event.RECV_STATUS, null, coded_response, null);
coded_status_response_received(coded_response);
coded_response_received(coded_response);
}
private void on_received_completion_status_response(CompletionStatusResponse completion_status_response) {
@ -1309,14 +1315,14 @@ public class Geary.Imap.ClientSession : BaseObject {
// this command to the server ... this mechanism (seen_completion_response and
// waiting_for_completion) assures that in either case issue_command_async() returns
// when the command is completed
seen_completion_response.set(completion_status_response.tag, completion_status_response);
seen_completion_responses.set(completion_status_response.tag, completion_status_response);
CommandCallback? cmd_cb;
if (waiting_for_completion.remove(completion_status_response.tag, out cmd_cb))
Idle.schedule(cmd_cb.callback);
if (waiting_for_completion.unset(completion_status_response.tag, out cmd_cb))
Idle.add(cmd_cb.callback);
}
private void notify(ServerData server_data) throws ImapError {
private void notify_received_data(ServerData server_data) throws ImapError {
switch (server_data.server_data_type) {
case ServerDataType.CAPABILITY:
// update ClientSession capabilities before firing signal, so external signal
@ -1372,7 +1378,7 @@ public class Geary.Imap.ClientSession : BaseObject {
// send ServerData to upper layers for processing and storage
try {
notify(server_data);
notify_received_data(server_data);
} catch (ImapError ierr) {
debug("[%s] Failure notifying of server data: %s %s", to_string(), server_data.to_string(),
ierr.message);