No longer crashes when running for the first time: #3798

Problem was that the client fetches folder objects for the special folders (Inbox, Drafts, etc.) prior to fetching the full folder list and the Engine's fetch_folder_async() call wasn't prepared to handle fetches for folders not located in the local database.
This commit is contained in:
Jim Nelson 2011-07-04 13:54:00 -07:00
parent fff39e8a44
commit 7f293f9a6f
6 changed files with 92 additions and 9 deletions

View file

@ -21,6 +21,9 @@ public abstract class Geary.AbstractAccount : Object, Geary.Account {
public abstract async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
Cancellable? cancellable = null) throws Error;
public abstract async bool folder_exists_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error;
public abstract async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error;

View file

@ -32,6 +32,14 @@ public interface Geary.Account : Object {
public abstract async Gee.Collection<Geary.Folder> list_folders_async(Geary.FolderPath? parent,
Cancellable? cancellable = null) throws Error;
/**
* Returns true if the folder exists.
*
* This method never throws EngineError.NOT_FOUND.
*/
public abstract async bool folder_exists_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error;
/**
* Fetches a Folder object corresponding to the supplied path. If the backing medium does
* not have a record of a folder at the path, EngineError.NOT_FOUND will be thrown.

View file

@ -58,12 +58,46 @@ private class Geary.GenericImapAccount : Geary.EngineAccount {
return engine_list;
}
public override async bool folder_exists_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
if (yield local.folder_exists_async(path, cancellable))
return true;
return yield remote.folder_exists_async(path, cancellable);
}
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
LocalFolder local_folder = (LocalFolder) yield local.fetch_folder_async(path, cancellable);
Geary.Folder engine_folder = new EngineFolder(remote, local, local_folder);
LocalFolder? local_folder = null;
try {
local_folder = (LocalFolder) yield local.fetch_folder_async(path, cancellable);
return new EngineFolder(remote, local, local_folder);
} catch (EngineError err) {
// don't thrown NOT_FOUND's, that means we need to fall through and clone from the
// server
if (!(err is EngineError.NOT_FOUND))
throw err;
}
return engine_folder;
// clone the entire path
int length = path.get_path_length();
for (int ctr = 0; ctr < length; ctr++) {
Geary.FolderPath folder = path.get_folder_at(ctr);
if (yield local.folder_exists_async(folder))
continue;
RemoteFolder remote_folder = (RemoteFolder) yield remote.fetch_folder_async(folder,
cancellable);
yield local.clone_folder_async(remote_folder, cancellable);
}
// Fetch the local account's version of the folder for the EngineFolder
local_folder = (LocalFolder) yield local.fetch_folder_async(path, cancellable);
return new EngineFolder(remote, local, local_folder);
}
private Gee.Set<string> get_folder_names(Gee.Collection<Geary.Folder> folders) {

View file

@ -72,6 +72,15 @@ public class Geary.Imap.Account : Geary.AbstractAccount, Geary.RemoteAccount {
return folders;
}
public override async bool folder_exists_async(Geary.FolderPath path, Cancellable? cancellable = null)
throws Error {
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());
return yield session_mgr.folder_exists_async(processed.get_fullpath(), cancellable);
}
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
Geary.FolderPath? processed = process_path(path, null, path.get_root().default_separator);
@ -103,25 +112,31 @@ public class Geary.Imap.Account : Geary.AbstractAccount, Geary.RemoteAccount {
// application.
private static Geary.FolderPath? process_path(Geary.FolderPath? parent, string? basename,
string? delim) throws ImapError {
bool empty_basename = String.is_empty(basename);
// 1. Both null, done
if (parent == null && basename == null)
if (parent == null && empty_basename)
return null;
// 2. Parent null but basename not, create FolderRoot for Inbox
if (parent == null && basename != null && basename.up() == INBOX_NAME)
if (parent == null && !empty_basename && basename.up() == INBOX_NAME)
return new Geary.FolderRoot(INBOX_NAME, delim, false);
// 3. Parent and basename supplied, verify parent is not Inbox, as IMAP does not allow it
// to have children
if (parent != null && basename != null && parent.get_root().basename.up() == INBOX_NAME)
if (parent != null && !empty_basename && parent.get_root().basename.up() == INBOX_NAME)
throw new ImapError.INVALID_PATH("Inbox may not have children");
// 4. Default behavior: create child of basename or basename as root, otherwise return parent
// 4. Parent supplied but basename is not; if parent points to Inbox, normalize it
if (parent != null && empty_basename && parent.basename.up() == INBOX_NAME)
return new Geary.FolderRoot(INBOX_NAME, delim, false);
// 5. Default behavior: create child of basename or basename as root, otherwise return parent
// unmodified
if (parent != null && basename != null)
if (parent != null && !empty_basename)
return parent.get_child(basename);
if (basename != null)
if (!empty_basename)
return new Geary.FolderRoot(basename, delim, Folder.CASE_SENSITIVE);
return parent;

View file

@ -76,6 +76,15 @@ public class Geary.Imap.ClientSessionManager {
return results.get_all();
}
public async bool folder_exists_async(string path, Cancellable? cancellable = null) throws Error {
ClientSession session = yield get_authorized_session(cancellable);
ListResults results = ListResults.decode(yield session.send_command_async(
new ListCommand(session.generate_tag(), path), cancellable));
return (results.status_response.status == Status.OK) && (results.get_count() == 1);
}
public async Geary.Imap.MailboxInformation? fetch_async(string path,
Cancellable? cancellable = null) throws Error {
ClientSession session = yield get_authorized_session(cancellable);

View file

@ -85,6 +85,20 @@ public class Geary.Sqlite.Account : Geary.AbstractAccount, Geary.LocalAccount {
return folders;
}
public override async bool folder_exists_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
try {
int64 id = yield fetch_id_async(path, cancellable);
return (id != Row.INVALID_ID);
} catch (EngineError err) {
if (err is EngineError.NOT_FOUND)
return false;
else
throw err;
}
}
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {
FolderRow? row = yield folder_table.fetch_descend_async(path.as_list(), cancellable);