Internationalization: Use XLIST when possible: Closes #3704
This major patch switches Geary to using XLIST whenever possible to identify special folders. Because it's now possible for special folders to be identified by MailboxAttributes and/or hard-coded paths, needed to find a flexible system for the various flavors to identify them as such. Courtesy Timo Kluck.
This commit is contained in:
parent
331cc1d983
commit
c98a6b07b2
25 changed files with 425 additions and 380 deletions
1
THANKS
1
THANKS
|
|
@ -2,6 +2,7 @@ The Geary team would like to thank the following contributors:
|
|||
|
||||
Robert Ancell <robert.ancell@canonical.com>
|
||||
Christian Dywan <christian@twotoasts.de>
|
||||
Timo Kluck <tkluck@infty.nl>
|
||||
Charles Lindsay <chaz@yorba.org>
|
||||
Matthew Pirocchi <matthew@yorba.org>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,17 +20,17 @@ public class GearyController {
|
|||
}
|
||||
}
|
||||
|
||||
private class FetchSpecialFolderOperation : Geary.NonblockingBatchOperation {
|
||||
private class FetchFolderOperation : Geary.NonblockingBatchOperation {
|
||||
public Geary.Account account;
|
||||
public Geary.SpecialFolder special_folder;
|
||||
public Geary.FolderPath folder_path;
|
||||
|
||||
public FetchSpecialFolderOperation(Geary.Account account, Geary.SpecialFolder special_folder) {
|
||||
public FetchFolderOperation(Geary.Account account, Geary.FolderPath folder_path) {
|
||||
this.account = account;
|
||||
this.special_folder = special_folder;
|
||||
this.folder_path = folder_path;
|
||||
}
|
||||
|
||||
public override async Object? execute_async(Cancellable? cancellable) throws Error {
|
||||
return yield account.fetch_folder_async(special_folder.path);
|
||||
return yield account.fetch_folder_async(folder_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +311,7 @@ public class GearyController {
|
|||
if (account.get_account_information().service_provider == Geary.ServiceProvider.YAHOO)
|
||||
main_window.title = GearyApplication.NAME + "!";
|
||||
|
||||
main_window.folder_list.set_user_folders_root_name(account.get_user_folders_label());
|
||||
main_window.folder_list.set_user_folders_root_name(_("Labels"));
|
||||
load_folders.begin(cancellable_folder);
|
||||
}
|
||||
}
|
||||
|
|
@ -327,48 +327,6 @@ public class GearyController {
|
|||
|
||||
private async void load_folders(Cancellable? cancellable) {
|
||||
try {
|
||||
// add all the special folders, which are assumed to always exist
|
||||
Geary.SpecialFolderMap? special_folders = account.get_special_folder_map();
|
||||
if (special_folders != null) {
|
||||
Geary.NonblockingBatch batch = new Geary.NonblockingBatch();
|
||||
foreach (Geary.SpecialFolder special_folder in special_folders.get_all())
|
||||
batch.add(new FetchSpecialFolderOperation(account, special_folder));
|
||||
|
||||
debug("Listing special folders");
|
||||
yield batch.execute_all_async(cancellable);
|
||||
debug("Completed list of special folders");
|
||||
|
||||
foreach (int id in batch.get_ids()) {
|
||||
FetchSpecialFolderOperation op = (FetchSpecialFolderOperation)
|
||||
batch.get_operation(id);
|
||||
try {
|
||||
Geary.Folder folder = (Geary.Folder) batch.get_result(id);
|
||||
main_window.folder_list.add_special_folder(op.special_folder, folder);
|
||||
} catch (Error inner_error) {
|
||||
message("Unable to fetch special folder %s: %s",
|
||||
op.special_folder.path.to_string(), inner_error.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancellable.is_cancelled())
|
||||
return;
|
||||
|
||||
// If inbox is available (should be!), monitor it and select it for the user
|
||||
Geary.SpecialFolder? inbox = special_folders.get_folder(Geary.SpecialFolderType.INBOX);
|
||||
if (inbox != null) {
|
||||
// create and leave open the Inbox, which is constantly monitored for notifications
|
||||
inbox_folder = yield account.fetch_folder_async(inbox.path, cancellable_inbox);
|
||||
assert(inbox_folder != null);
|
||||
|
||||
yield inbox_folder.open_async(false, cancellable_inbox);
|
||||
|
||||
inbox_folder.email_locally_appended.connect(on_inbox_new_email);
|
||||
|
||||
// select the inbox and get the show started
|
||||
main_window.folder_list.select_path(inbox.path);
|
||||
}
|
||||
}
|
||||
|
||||
// pull down the root-level user folders and recursively add to sidebar
|
||||
Gee.Collection<Geary.Folder> folders = yield account.list_folders_async(null);
|
||||
if (folders != null)
|
||||
|
|
@ -730,31 +688,35 @@ public class GearyController {
|
|||
set_busy(false);
|
||||
}
|
||||
|
||||
private void on_special_folder_type_changed(Geary.Folder folder, Geary.SpecialFolderType old_type,
|
||||
Geary.SpecialFolderType new_type) {
|
||||
main_window.folder_list.remove_folder(folder);
|
||||
main_window.folder_list.add_folder(folder);
|
||||
}
|
||||
|
||||
private void on_folders_added_removed(Gee.Collection<Geary.Folder>? added,
|
||||
Gee.Collection<Geary.Folder>? removed) {
|
||||
|
||||
if (added != null && added.size > 0) {
|
||||
Gee.Set<Geary.FolderPath>? ignored_paths = account.get_ignored_paths();
|
||||
|
||||
Gee.ArrayList<Geary.Folder> skipped = new Gee.ArrayList<Geary.Folder>();
|
||||
foreach (Geary.Folder folder in added) {
|
||||
if (ignored_paths != null && ignored_paths.contains(folder.get_path()))
|
||||
skipped.add(folder);
|
||||
else {
|
||||
main_window.folder_list.add_folder(folder);
|
||||
main_window.main_toolbar.copy_folder_menu.add_folder(folder);
|
||||
main_window.main_toolbar.move_folder_menu.add_folder(folder);
|
||||
main_window.folder_list.add_folder(folder);
|
||||
main_window.main_toolbar.copy_folder_menu.add_folder(folder);
|
||||
main_window.main_toolbar.move_folder_menu.add_folder(folder);
|
||||
|
||||
// monitor the Inbox for notifications
|
||||
if (folder.get_special_folder_type() == Geary.SpecialFolderType.INBOX && inbox_folder == null) {
|
||||
inbox_folder = folder;
|
||||
inbox_folder.email_locally_appended.connect(on_inbox_new_email);
|
||||
|
||||
// select the inbox and get the show started
|
||||
main_window.folder_list.select_path(folder.get_path());
|
||||
inbox_folder.open_async.begin(false, cancellable_inbox);
|
||||
}
|
||||
|
||||
folder.special_folder_type_changed.connect(on_special_folder_type_changed);
|
||||
}
|
||||
|
||||
Gee.Collection<Geary.Folder> remaining = added;
|
||||
if (skipped.size > 0) {
|
||||
remaining = new Gee.ArrayList<Geary.Folder>();
|
||||
remaining.add_all(added);
|
||||
remaining.remove_all(skipped);
|
||||
}
|
||||
|
||||
search_folders_for_children.begin(remaining);
|
||||
search_folders_for_children.begin(added);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ public class FolderList : Sidebar.Tree {
|
|||
};
|
||||
|
||||
private class SpecialFolderBranch : Sidebar.RootOnlyBranch {
|
||||
public SpecialFolderBranch(Geary.SpecialFolder special, Geary.Folder folder) {
|
||||
base(new SpecialFolderEntry(special, folder));
|
||||
public SpecialFolderBranch(Geary.Folder folder) {
|
||||
base(new FolderEntry(folder));
|
||||
|
||||
assert(folder.get_special_folder_type() != Geary.SpecialFolderType.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -25,51 +27,18 @@ public class FolderList : Sidebar.Tree {
|
|||
}
|
||||
|
||||
public virtual string get_sidebar_name() {
|
||||
return folder.get_path().basename;
|
||||
return folder.get_display_name();
|
||||
}
|
||||
|
||||
public string? get_sidebar_tooltip() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual Icon? get_sidebar_icon() {
|
||||
return IconFactory.instance.label_icon;
|
||||
}
|
||||
|
||||
public virtual string to_string() {
|
||||
return "FolderEntry: " + get_sidebar_name();
|
||||
}
|
||||
|
||||
public bool internal_drop_received(Gdk.DragContext context, Gtk.SelectionData data) {
|
||||
// Copy or move?
|
||||
Gdk.ModifierType mask;
|
||||
double[] axes = new double[2];
|
||||
context.get_device().get_state(context.get_dest_window(), axes, out mask);
|
||||
MainWindow main_window = GearyApplication.instance.get_main_window() as MainWindow;
|
||||
if ((mask & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
||||
main_window.folder_list.copy_conversation(folder);
|
||||
} else {
|
||||
main_window.folder_list.move_conversation(folder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class SpecialFolderEntry : FolderEntry {
|
||||
public Geary.SpecialFolder special { get; private set; }
|
||||
|
||||
public SpecialFolderEntry(Geary.SpecialFolder special, Geary.Folder folder) {
|
||||
base (folder);
|
||||
this.special = special;
|
||||
}
|
||||
|
||||
public override string get_sidebar_name() {
|
||||
return special.name;
|
||||
}
|
||||
|
||||
public override Icon? get_sidebar_icon() {
|
||||
switch (special.folder_type) {
|
||||
public Icon? get_sidebar_icon() {
|
||||
switch (folder.get_special_folder_type()) {
|
||||
case Geary.SpecialFolderType.NONE:
|
||||
return IconFactory.instance.label_icon;
|
||||
|
||||
case Geary.SpecialFolderType.INBOX:
|
||||
return new ThemedIcon("mail-inbox");
|
||||
|
||||
|
|
@ -99,8 +68,23 @@ public class FolderList : Sidebar.Tree {
|
|||
}
|
||||
}
|
||||
|
||||
public override string to_string() {
|
||||
return "SpecialFolderEntry: " + get_sidebar_name();
|
||||
public virtual string to_string() {
|
||||
return "FolderEntry: " + get_sidebar_name();
|
||||
}
|
||||
|
||||
public bool internal_drop_received(Gdk.DragContext context, Gtk.SelectionData data) {
|
||||
// Copy or move?
|
||||
Gdk.ModifierType mask;
|
||||
double[] axes = new double[2];
|
||||
context.get_device().get_state(context.get_dest_window(), axes, out mask);
|
||||
MainWindow main_window = GearyApplication.instance.get_main_window() as MainWindow;
|
||||
if ((mask & Gdk.ModifierType.CONTROL_MASK) != 0) {
|
||||
main_window.folder_list.copy_conversation(folder);
|
||||
} else {
|
||||
main_window.folder_list.move_conversation(folder);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +96,8 @@ public class FolderList : Sidebar.Tree {
|
|||
private Sidebar.Branch user_folder_branch;
|
||||
internal Gee.HashMap<Geary.FolderPath, Sidebar.Entry> entries = new Gee.HashMap<
|
||||
Geary.FolderPath, Sidebar.Entry>(Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
internal Gee.HashMap<Geary.FolderPath, Sidebar.Branch> branches = new Gee.HashMap<
|
||||
Geary.FolderPath, Sidebar.Branch>(Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
|
||||
public FolderList() {
|
||||
base(new Gtk.TargetEntry[0], Gdk.DragAction.ASK, drop_handler);
|
||||
|
|
@ -136,9 +122,7 @@ public class FolderList : Sidebar.Tree {
|
|||
}
|
||||
|
||||
private void on_entry_selected(Sidebar.SelectableEntry selectable) {
|
||||
if (selectable is SpecialFolderEntry) {
|
||||
folder_selected(((SpecialFolderEntry) selectable).folder);
|
||||
} else if (selectable is FolderEntry) {
|
||||
if (selectable is FolderEntry) {
|
||||
folder_selected(((FolderEntry) selectable).folder);
|
||||
}
|
||||
}
|
||||
|
|
@ -154,31 +138,51 @@ public class FolderList : Sidebar.Tree {
|
|||
}
|
||||
|
||||
public void add_folder(Geary.Folder folder) {
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
|
||||
bool added = false;
|
||||
if (folder.get_path().get_parent() == null) {
|
||||
|
||||
Geary.SpecialFolderType special_folder_type = folder.get_special_folder_type();
|
||||
if (special_folder_type != Geary.SpecialFolderType.NONE) {
|
||||
SpecialFolderBranch branch = new SpecialFolderBranch(folder);
|
||||
graft(branch, (int) special_folder_type);
|
||||
entries.set(folder.get_path(), branch.get_root());
|
||||
branches.set(folder.get_path(), branch);
|
||||
added = true;
|
||||
} else if (folder.get_path().get_parent() == null) {
|
||||
// Top-level folder.
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
user_folder_branch.graft(user_folder_group, folder_entry);
|
||||
entries.set(folder.get_path(), folder_entry);
|
||||
branches.set(folder.get_path(), user_folder_branch);
|
||||
added = true;
|
||||
} else {
|
||||
FolderEntry folder_entry = new FolderEntry(folder);
|
||||
Sidebar.Entry? entry = get_entry_for_folder_path(folder.get_path().get_parent());
|
||||
if (entry != null) {
|
||||
user_folder_branch.graft(entry, folder_entry);
|
||||
entries.set(folder.get_path(), folder_entry);
|
||||
branches.set(folder.get_path(), user_folder_branch);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
entries.set(folder.get_path(), folder_entry);
|
||||
else
|
||||
debug("Could not add folder to folder list: %s", folder.to_string());
|
||||
if (!added) {
|
||||
debug("Could not add folder %s of type %s to folder list", folder.to_string(),
|
||||
special_folder_type.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
public void add_special_folder(Geary.SpecialFolder special, Geary.Folder folder) {
|
||||
SpecialFolderBranch branch = new SpecialFolderBranch(special, folder);
|
||||
graft(branch, (int) special.folder_type);
|
||||
entries.set(folder.get_path(), branch.get_root());
|
||||
|
||||
public void remove_folder(Geary.Folder folder) {
|
||||
Sidebar.Entry? entry = get_entry_for_folder_path(folder.get_path());
|
||||
Sidebar.Branch? branch = get_branch_for_folder_path(folder.get_path());
|
||||
if(entry != null && branch != null) {
|
||||
if (branch is SpecialFolderBranch) {
|
||||
this.prune(branch);
|
||||
} else {
|
||||
branch.prune(entry);
|
||||
}
|
||||
} else {
|
||||
debug(@"Could not remove folder $(folder.get_path())");
|
||||
}
|
||||
}
|
||||
|
||||
public void remove_all_branches() {
|
||||
|
|
@ -197,6 +201,10 @@ public class FolderList : Sidebar.Tree {
|
|||
return entries.get(path);
|
||||
}
|
||||
|
||||
private Sidebar.Branch? get_branch_for_folder_path(Geary.FolderPath path) {
|
||||
return branches.get(path);
|
||||
}
|
||||
|
||||
public override bool drag_motion(Gdk.DragContext context, int x, int y, uint time) {
|
||||
// Run the base version first.
|
||||
bool ret = base.drag_motion(context, x, y, time);
|
||||
|
|
|
|||
|
|
@ -150,11 +150,8 @@ class ImapConsole : Gtk.Window {
|
|||
break;
|
||||
|
||||
case "list":
|
||||
list(cmd, args);
|
||||
break;
|
||||
|
||||
case "xlist":
|
||||
xlist(cmd, args);
|
||||
list(cmd, args);
|
||||
break;
|
||||
|
||||
case "examine":
|
||||
|
|
@ -362,7 +359,7 @@ class ImapConsole : Gtk.Window {
|
|||
check_connected(cmd, args, 2, "<reference> <mailbox>");
|
||||
|
||||
status("Listing...");
|
||||
cx.send_async.begin(new Geary.Imap.ListCommand.wildcarded(args[0], args[1]),
|
||||
cx.send_async.begin(new Geary.Imap.ListCommand.wildcarded(args[0], args[1], (cmd.down() == "xlist")),
|
||||
null, on_list);
|
||||
}
|
||||
|
||||
|
|
@ -375,13 +372,6 @@ class ImapConsole : Gtk.Window {
|
|||
}
|
||||
}
|
||||
|
||||
private void xlist(string cmd, string[] args) throws Error {
|
||||
check_connected(cmd, args, 2, "<reference> <mailbox>");
|
||||
|
||||
status("Xlisting...");
|
||||
cx.send_async.begin(new Geary.Imap.XListCommand.wildcarded(args[0], args[1]), null, on_list);
|
||||
}
|
||||
|
||||
private void examine(string cmd, string[] args) throws Error {
|
||||
check_connected(cmd, args, 1, "<mailbox>");
|
||||
|
||||
|
|
|
|||
|
|
@ -44,10 +44,19 @@ public class Geary.DBus.Controller {
|
|||
account.report_problem.connect(on_report_problem);
|
||||
|
||||
// Open the Inbox folder.
|
||||
Geary.SpecialFolderMap? special_folders = account.get_special_folder_map();
|
||||
Geary.Folder folder = yield account.fetch_folder_async(special_folders.get_folder(
|
||||
Geary.SpecialFolderType.INBOX).path);
|
||||
Geary.Folder? folder = null;
|
||||
Gee.Collection<Geary.Folder> folders = yield account.list_folders_async(null, null);
|
||||
foreach(Geary.Folder folder_to_check in folders) {
|
||||
if(folder_to_check.get_special_folder_type() == Geary.SpecialFolderType.INBOX) {
|
||||
folder = folder_to_check;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (folder == null) {
|
||||
warning("No inbox folder found");
|
||||
return;
|
||||
}
|
||||
yield folder.open_async(false, null);
|
||||
|
||||
conversations = new Geary.DBus.Conversations(folder);
|
||||
|
|
|
|||
|
|
@ -18,12 +18,6 @@ public abstract class Geary.EngineAccount : Geary.AbstractAccount, Geary.Persona
|
|||
return account_information;
|
||||
}
|
||||
|
||||
public abstract string get_user_folders_label();
|
||||
|
||||
public abstract Geary.SpecialFolderMap? get_special_folder_map();
|
||||
|
||||
public abstract Gee.Set<Geary.FolderPath>? get_ignored_paths();
|
||||
|
||||
public abstract bool delete_is_archive();
|
||||
|
||||
public abstract async void send_email_async(Geary.ComposedEmail composed, Cancellable? cancellable = null)
|
||||
|
|
|
|||
|
|
@ -150,7 +150,6 @@ public class Geary.FolderPath : Object, Hashable, Equalable {
|
|||
if (other.get_path_length() != path_length)
|
||||
return false;
|
||||
|
||||
|
||||
bool cs = get_root().case_sensitive;
|
||||
if (other.get_root().case_sensitive != cs) {
|
||||
message("Comparing %s and %s with different case sensitivities", to_string(),
|
||||
|
|
|
|||
|
|
@ -154,6 +154,15 @@ public interface Geary.Folder : Object {
|
|||
* mark_email_async() method as well as changes occur remotely.
|
||||
*/
|
||||
public signal void email_flags_changed(Gee.Map<Geary.EmailIdentifier, Geary.EmailFlags> map);
|
||||
|
||||
/**
|
||||
* "special-folder-type-changed" is fired when the special folder type has changed.
|
||||
*
|
||||
* This will usually happen when the local account object has been updated with data
|
||||
* from the remote account.
|
||||
*/
|
||||
public signal void special_folder_type_changed(Geary.SpecialFolderType old_type,
|
||||
Geary.SpecialFolderType new_type);
|
||||
|
||||
protected abstract void notify_opened(OpenState state, int count);
|
||||
|
||||
|
|
@ -172,15 +181,22 @@ public interface Geary.Folder : Object {
|
|||
protected abstract void notify_email_flags_changed(Gee.Map<Geary.EmailIdentifier,
|
||||
Geary.EmailFlags> flag_map);
|
||||
|
||||
protected abstract void notify_special_folder_type_changed(Geary.SpecialFolderType old_type,
|
||||
Geary.SpecialFolderType new_type);
|
||||
|
||||
public abstract Geary.FolderPath get_path();
|
||||
|
||||
public abstract Geary.Trillian has_children();
|
||||
|
||||
/**
|
||||
* Returns the special folder type of the folder. If the the folder is not a special one then
|
||||
* null is returned.
|
||||
* Returns the special folder type of the folder.
|
||||
*/
|
||||
public abstract Geary.SpecialFolderType? get_special_folder_type();
|
||||
public abstract Geary.SpecialFolderType get_special_folder_type();
|
||||
|
||||
/**
|
||||
* Returns a name suitable for displaying to the user.
|
||||
*/
|
||||
public abstract string get_display_name();
|
||||
|
||||
/**
|
||||
* Returns the state of the Folder's connections to the local and remote stores.
|
||||
|
|
|
|||
|
|
@ -5,12 +5,6 @@
|
|||
*/
|
||||
|
||||
public interface Geary.Personality : Object {
|
||||
public abstract string get_user_folders_label();
|
||||
|
||||
public abstract Geary.SpecialFolderMap? get_special_folder_map();
|
||||
|
||||
public abstract Gee.Set<Geary.FolderPath>? get_ignored_paths();
|
||||
|
||||
public abstract bool delete_is_archive();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
public enum Geary.SpecialFolderType {
|
||||
NONE,
|
||||
INBOX,
|
||||
DRAFTS,
|
||||
SENT,
|
||||
|
|
@ -12,53 +13,38 @@ public enum Geary.SpecialFolderType {
|
|||
ALL_MAIL,
|
||||
SPAM,
|
||||
TRASH,
|
||||
OUTBOX
|
||||
}
|
||||
|
||||
public class Geary.SpecialFolder : Object {
|
||||
public SpecialFolderType folder_type { get; private set; }
|
||||
public string name { get; private set; }
|
||||
public Geary.FolderPath path { get; private set; }
|
||||
public int ordering { get; private set; }
|
||||
OUTBOX;
|
||||
|
||||
public SpecialFolder(SpecialFolderType folder_type, string name, FolderPath path, int ordering) {
|
||||
this.folder_type = folder_type;
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.ordering = ordering;
|
||||
}
|
||||
}
|
||||
|
||||
public class Geary.SpecialFolderMap : Object {
|
||||
private Gee.HashMap<SpecialFolderType, SpecialFolder> map = new Gee.HashMap<SpecialFolderType,
|
||||
SpecialFolder>();
|
||||
|
||||
public SpecialFolderMap() {
|
||||
}
|
||||
|
||||
public void set_folder(SpecialFolder special_folder) {
|
||||
map.set(special_folder.folder_type, special_folder);
|
||||
}
|
||||
|
||||
public SpecialFolder? get_folder(SpecialFolderType folder_type) {
|
||||
return map.get(folder_type);
|
||||
}
|
||||
|
||||
public SpecialFolder? get_folder_by_path(FolderPath path) {
|
||||
foreach (SpecialFolder folder in map.values) {
|
||||
if (folder.path == path) {
|
||||
return folder;
|
||||
}
|
||||
public unowned string get_display_name() {
|
||||
switch (this) {
|
||||
case INBOX:
|
||||
return _("Inbox");
|
||||
|
||||
case DRAFTS:
|
||||
return _("Drafts");
|
||||
|
||||
case SENT:
|
||||
return _("Sent Mail");
|
||||
|
||||
case FLAGGED:
|
||||
return _("Starred");
|
||||
|
||||
case ALL_MAIL:
|
||||
return _("All Mail");
|
||||
|
||||
case SPAM:
|
||||
return _("Spam");
|
||||
|
||||
case TRASH:
|
||||
return _("Trash");
|
||||
|
||||
case OUTBOX:
|
||||
return _("Outbox");
|
||||
|
||||
case NONE:
|
||||
default:
|
||||
return _("None");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Gee.Set<SpecialFolderType> get_supported_types() {
|
||||
return map.keys.read_only_view;
|
||||
}
|
||||
|
||||
public Gee.Collection<SpecialFolder> get_all() {
|
||||
return map.values.read_only_view;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,25 +42,14 @@ public class Geary.Imap.LogoutCommand : Command {
|
|||
|
||||
public class Geary.Imap.ListCommand : Command {
|
||||
public const string NAME = "list";
|
||||
public const string XLIST_NAME = "xlist";
|
||||
|
||||
public ListCommand(string mailbox) {
|
||||
base (NAME, { "", mailbox });
|
||||
public ListCommand(string mailbox, bool use_xlist) {
|
||||
base (use_xlist ? XLIST_NAME : NAME, { "", mailbox });
|
||||
}
|
||||
|
||||
public ListCommand.wildcarded(string reference, string mailbox) {
|
||||
base (NAME, { reference, mailbox });
|
||||
}
|
||||
}
|
||||
|
||||
public class Geary.Imap.XListCommand : Command {
|
||||
public const string NAME = "xlist";
|
||||
|
||||
public XListCommand(string mailbox) {
|
||||
base (NAME, { "", mailbox });
|
||||
}
|
||||
|
||||
public XListCommand.wildcarded(string reference, string mailbox) {
|
||||
base (NAME, { reference, mailbox });
|
||||
public ListCommand.wildcarded(string reference, string mailbox, bool use_xlist) {
|
||||
base (use_xlist ? XLIST_NAME : NAME, { reference, mailbox });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public class Geary.Imap.ListResults : Geary.Imap.CommandResults {
|
|||
StringParameter? delim = data.get_as_nullable_string(3);
|
||||
StringParameter mailbox = data.get_as_string(4);
|
||||
|
||||
if (!cmd.equals_ci(ListCommand.NAME) && !cmd.equals_ci(XListCommand.NAME)) {
|
||||
if (!cmd.equals_ci(ListCommand.NAME) && !cmd.equals_ci(ListCommand.XLIST_NAME)) {
|
||||
debug("Bad list response \"%s\": Not marked as list or xlist response",
|
||||
data.to_string());
|
||||
|
||||
|
|
@ -98,9 +98,17 @@ public class Geary.Imap.ListResults : Geary.Imap.CommandResults {
|
|||
attrlist.add(new MailboxAttribute(stringp.value));
|
||||
}
|
||||
|
||||
MailboxInformation info = new MailboxInformation(mailbox.value, delim.nullable_value,
|
||||
new MailboxAttributes(attrlist));
|
||||
|
||||
// Set \Inbox to standard path
|
||||
MailboxInformation info;
|
||||
MailboxAttributes attributes = new MailboxAttributes(attrlist);
|
||||
if (Geary.Imap.MailboxAttribute.SPECIAL_FOLDER_INBOX in attributes) {
|
||||
info = new MailboxInformation(Geary.Imap.Account.INBOX_NAME, delim.nullable_value,
|
||||
attributes);
|
||||
} else {
|
||||
info = new MailboxInformation(mailbox.value, delim.nullable_value,
|
||||
attributes);
|
||||
}
|
||||
|
||||
map.set(mailbox.value, info);
|
||||
list.add(info);
|
||||
} catch (ImapError ierr) {
|
||||
|
|
|
|||
|
|
@ -178,6 +178,62 @@ public class Geary.Imap.MailboxAttribute : Geary.Imap.Flag {
|
|||
return _allows_new;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_inbox = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_INBOX { get {
|
||||
if (_xlist_inbox == null)
|
||||
_xlist_inbox = new MailboxAttribute("\\Inbox");
|
||||
|
||||
return _xlist_inbox;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_all_mail = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_ALL_MAIL { get {
|
||||
if (_xlist_all_mail == null)
|
||||
_xlist_all_mail = new MailboxAttribute("\\AllMail");
|
||||
|
||||
return _xlist_all_mail;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_trash = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_TRASH { get {
|
||||
if (_xlist_trash == null)
|
||||
_xlist_trash = new MailboxAttribute("\\Trash");
|
||||
|
||||
return _xlist_trash;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_drafts = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_DRAFTS { get {
|
||||
if (_xlist_drafts == null)
|
||||
_xlist_drafts = new MailboxAttribute("\\Drafts");
|
||||
|
||||
return _xlist_drafts;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_sent = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_SENT { get {
|
||||
if (_xlist_sent == null)
|
||||
_xlist_sent = new MailboxAttribute("\\Sent");
|
||||
|
||||
return _xlist_sent;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_spam = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_SPAM { get {
|
||||
if (_xlist_spam == null)
|
||||
_xlist_spam = new MailboxAttribute("\\Spam");
|
||||
|
||||
return _xlist_spam;
|
||||
} }
|
||||
|
||||
private static MailboxAttribute? _xlist_starred = null;
|
||||
public static MailboxAttribute SPECIAL_FOLDER_STARRED { get {
|
||||
if (_xlist_starred == null)
|
||||
_xlist_starred = new MailboxAttribute("\\Starred");
|
||||
|
||||
return _xlist_starred;
|
||||
} }
|
||||
|
||||
public MailboxAttribute(string value) {
|
||||
base (value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,6 +183,31 @@ public class Geary.Imap.MailboxAttributes : Geary.Imap.Flags {
|
|||
|
||||
return new MailboxAttributes(attrs);
|
||||
}
|
||||
|
||||
public Geary.SpecialFolderType get_special_folder_type() {
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_INBOX))
|
||||
return Geary.SpecialFolderType.INBOX;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_ALL_MAIL))
|
||||
return Geary.SpecialFolderType.ALL_MAIL;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_TRASH))
|
||||
return Geary.SpecialFolderType.TRASH;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_DRAFTS))
|
||||
return Geary.SpecialFolderType.DRAFTS;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_SENT))
|
||||
return Geary.SpecialFolderType.SENT;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_SPAM))
|
||||
return Geary.SpecialFolderType.SPAM;
|
||||
|
||||
if (contains(MailboxAttribute.SPECIAL_FOLDER_STARRED))
|
||||
return Geary.SpecialFolderType.FLAGGED;
|
||||
|
||||
return Geary.SpecialFolderType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public class Geary.Imap.InternalDate : Geary.RFC822.Date, Geary.Imap.MessageData {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
ClientSession session = yield get_authorized_session_async(cancellable);
|
||||
|
||||
ListResults results = ListResults.decode(yield session.send_command_async(
|
||||
new ListCommand.wildcarded("", "%"), cancellable));
|
||||
new ListCommand.wildcarded("", "%", session.get_capabilities().has_capability("XLIST")),
|
||||
cancellable));
|
||||
|
||||
if (results.status_response.status != Status.OK)
|
||||
throw new ImapError.SERVER_ERROR("Server error: %s", results.to_string());
|
||||
|
|
@ -114,7 +115,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
ClientSession session = yield get_authorized_session_async(cancellable);
|
||||
|
||||
ListResults results = ListResults.decode(yield session.send_command_async(
|
||||
new ListCommand(specifier), cancellable));
|
||||
new ListCommand(specifier, session.get_capabilities().has_capability("XLIST")),
|
||||
cancellable));
|
||||
|
||||
if (results.status_response.status != Status.OK)
|
||||
throw new ImapError.SERVER_ERROR("Server error: %s", results.to_string());
|
||||
|
|
@ -126,7 +128,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
ClientSession session = yield get_authorized_session_async(cancellable);
|
||||
|
||||
ListResults results = ListResults.decode(yield session.send_command_async(
|
||||
new ListCommand(path), cancellable));
|
||||
new ListCommand(path, session.get_capabilities().has_capability("XLIST")),
|
||||
cancellable));
|
||||
|
||||
return (results.status_response.status == Status.OK) && (results.get_count() == 1);
|
||||
}
|
||||
|
|
@ -136,7 +139,8 @@ public class Geary.Imap.ClientSessionManager {
|
|||
ClientSession session = yield get_authorized_session_async(cancellable);
|
||||
|
||||
ListResults results = ListResults.decode(yield session.send_command_async(
|
||||
new ListCommand(path), cancellable));
|
||||
new ListCommand(path, session.get_capabilities().has_capability("XLIST")),
|
||||
cancellable));
|
||||
|
||||
if (results.status_response.status != Status.OK)
|
||||
throw new ImapError.SERVER_ERROR("Server error: %s", results.to_string());
|
||||
|
|
|
|||
|
|
@ -43,11 +43,26 @@ public abstract class Geary.AbstractFolder : Object, Geary.Folder {
|
|||
email_flags_changed(flag_map);
|
||||
}
|
||||
|
||||
internal virtual void notify_special_folder_type_changed(Geary.SpecialFolderType old_type,
|
||||
Geary.SpecialFolderType new_type) {
|
||||
special_folder_type_changed(old_type, new_type);
|
||||
}
|
||||
|
||||
public abstract Geary.FolderPath get_path();
|
||||
|
||||
public abstract Geary.Trillian has_children();
|
||||
|
||||
public abstract Geary.SpecialFolderType? get_special_folder_type();
|
||||
public abstract Geary.SpecialFolderType get_special_folder_type();
|
||||
|
||||
/**
|
||||
* Default is to display the basename of the Folder's path.
|
||||
*/
|
||||
public virtual string get_display_name() {
|
||||
Geary.SpecialFolderType special_folder_type = get_special_folder_type();
|
||||
|
||||
return (special_folder_type == Geary.SpecialFolderType.NONE)
|
||||
? get_path().basename : special_folder_type.get_display_name();
|
||||
}
|
||||
|
||||
public abstract Geary.Folder.OpenState get_open_state();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
*/
|
||||
|
||||
private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
||||
private static Geary.FolderPath? inbox_path = null;
|
||||
private static Geary.FolderPath? outbox_path = null;
|
||||
|
||||
private Imap.Account remote;
|
||||
private Sqlite.Account local;
|
||||
private Gee.HashMap<FolderPath, Imap.FolderProperties> properties_map = new Gee.HashMap<
|
||||
|
|
@ -12,6 +15,8 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
private SmtpOutboxFolder? outbox = null;
|
||||
private Gee.HashMap<FolderPath, GenericImapFolder> existing_folders = new Gee.HashMap<
|
||||
FolderPath, GenericImapFolder>(Hashable.hash_func, Equalable.equal_func);
|
||||
private Gee.HashSet<FolderPath> local_only = new Gee.HashSet<FolderPath>(
|
||||
Hashable.hash_func, Equalable.equal_func);
|
||||
|
||||
public GenericImapAccount(string name, string username, AccountInformation? account_info,
|
||||
File user_data_dir, Imap.Account remote, Sqlite.Account local) {
|
||||
|
|
@ -21,6 +26,16 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
this.local = local;
|
||||
|
||||
this.remote.login_failed.connect(on_login_failed);
|
||||
|
||||
if (inbox_path == null) {
|
||||
inbox_path = new Geary.FolderRoot(Imap.Account.INBOX_NAME, Imap.Account.ASSUMED_SEPARATOR,
|
||||
Imap.Folder.CASE_SENSITIVE);
|
||||
}
|
||||
|
||||
if (outbox_path == null) {
|
||||
outbox_path = new SmtpOutboxFolderRoot();
|
||||
local_only.add(outbox_path);
|
||||
}
|
||||
}
|
||||
|
||||
internal Imap.FolderProperties? get_properties_for_folder(FolderPath path) {
|
||||
|
|
@ -75,13 +90,33 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
throw remote_err;
|
||||
}
|
||||
|
||||
// Subclasses should implement this for hardcoded paths that correspond to special folders ...
|
||||
// if the server supports XLIST, this doesn't have to be implemented.
|
||||
//
|
||||
// This won't be called for INBOX or the Outbox.
|
||||
protected virtual Geary.SpecialFolderType get_special_folder_type_for_path(Geary.FolderPath path) {
|
||||
return Geary.SpecialFolderType.NONE;
|
||||
}
|
||||
|
||||
private Geary.SpecialFolderType internal_get_special_folder_type_for_path(Geary.FolderPath path) {
|
||||
if (path.equals(inbox_path))
|
||||
return Geary.SpecialFolderType.INBOX;
|
||||
|
||||
if (path.equals(outbox_path))
|
||||
return Geary.SpecialFolderType.OUTBOX;
|
||||
|
||||
return get_special_folder_type_for_path(path);
|
||||
}
|
||||
|
||||
private GenericImapFolder build_folder(Sqlite.Folder local_folder) {
|
||||
GenericImapFolder? folder = existing_folders.get(local_folder.get_path());
|
||||
if (folder != null)
|
||||
return folder;
|
||||
|
||||
folder = new GenericImapFolder(this, remote, local, local_folder,
|
||||
get_special_folder(local_folder.get_path()));
|
||||
folder = new GenericImapFolder(this, remote, local, local_folder);
|
||||
if (folder.get_special_folder_type() == Geary.SpecialFolderType.NONE)
|
||||
folder.set_special_folder_type(internal_get_special_folder_type_for_path(local_folder.get_path()));
|
||||
|
||||
existing_folders.set(folder.get_path(), folder);
|
||||
|
||||
return folder;
|
||||
|
|
@ -104,8 +139,11 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
engine_list.add(build_folder(local_folder));
|
||||
}
|
||||
|
||||
// Add Outbox to root
|
||||
if (parent == null)
|
||||
engine_list.add(outbox);
|
||||
|
||||
background_update_folders.begin(parent, engine_list, cancellable);
|
||||
engine_list.add(outbox);
|
||||
|
||||
return engine_list;
|
||||
}
|
||||
|
|
@ -163,27 +201,49 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
return;
|
||||
}
|
||||
|
||||
Gee.Set<string> local_names = new Gee.HashSet<string>();
|
||||
foreach (Geary.Folder folder in engine_folders)
|
||||
local_names.add(folder.get_path().basename);
|
||||
|
||||
Gee.Set<string> remote_names = new Gee.HashSet<string>();
|
||||
foreach (Geary.Imap.Folder folder in remote_folders) {
|
||||
remote_names.add(folder.get_path().basename);
|
||||
|
||||
// use this iteration to add discovered properties to map
|
||||
properties_map.set(folder.get_path(), folder.get_properties());
|
||||
// update all remote folders properties in the local store and active in the system
|
||||
foreach (Imap.Folder remote_folder in remote_folders) {
|
||||
try {
|
||||
yield local.update_folder_async(remote_folder, cancellable);
|
||||
} catch (Error update_error) {
|
||||
debug("Unable to update local folder %s with remote properties: %s",
|
||||
remote_folder.to_string(), update_error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Get local paths of all engine (local) folders
|
||||
Gee.Set<Geary.FolderPath> local_paths = new Gee.HashSet<Geary.FolderPath>(
|
||||
Geary.Hashable.hash_func, Geary.Equalable.equal_func);
|
||||
foreach (Geary.Folder local_folder in engine_folders)
|
||||
local_paths.add(local_folder.get_path());
|
||||
|
||||
// Get remote paths of all remote folders
|
||||
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());
|
||||
|
||||
// use this iteration to add discovered properties to map
|
||||
properties_map.set(remote_folder.get_path(), remote_folder.get_properties());
|
||||
|
||||
// also use this iteration to set the local folder's special type
|
||||
GenericImapFolder? local_folder = existing_folders.get(remote_folder.get_path());
|
||||
if (local_folder != null)
|
||||
local_folder.set_special_folder_type(remote_folder.get_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_names.contains(folder.get_path().basename))
|
||||
if (!local_paths.contains(folder.get_path()))
|
||||
to_add.add(folder);
|
||||
}
|
||||
|
||||
// If path in local but not remote (and isn't local-only, i.e. the Outbox), need to remove
|
||||
// it
|
||||
Gee.List<Geary.Folder>? to_remove = new Gee.ArrayList<Geary.Imap.Folder>();
|
||||
foreach (Geary.Folder folder in engine_folders) {
|
||||
if (!remote_names.contains(folder.get_path().basename))
|
||||
if (!remote_paths.contains(folder.get_path()) && !local_only.contains(folder.get_path()))
|
||||
to_remove.add(folder);
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +253,7 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
if (to_remove.size == 0)
|
||||
to_remove = null;
|
||||
|
||||
// For folders to add, clone them and their properties locally
|
||||
if (to_add != null) {
|
||||
foreach (Geary.Imap.Folder folder in to_add) {
|
||||
try {
|
||||
|
|
@ -204,6 +265,7 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
}
|
||||
}
|
||||
|
||||
// Create Geary.Folder objects for all added folders
|
||||
Gee.Collection<Geary.Folder> engine_added = null;
|
||||
if (to_add != null) {
|
||||
engine_added = new Gee.ArrayList<Geary.Folder>();
|
||||
|
|
@ -217,18 +279,17 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Remove local folders no longer available remotely.
|
||||
if (to_remove != null) {
|
||||
foreach (Geary.Folder folder in to_remove) {
|
||||
debug(@"Need to remove folder $folder");
|
||||
}
|
||||
}
|
||||
|
||||
if (engine_added != null)
|
||||
notify_folders_added_removed(engine_added, null);
|
||||
}
|
||||
|
||||
public override string get_user_folders_label() {
|
||||
return _("Folders");
|
||||
}
|
||||
|
||||
public override Gee.Set<Geary.FolderPath>? get_ignored_paths() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool delete_is_archive() {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -242,12 +303,5 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
|
|||
private void on_login_failed(Geary.Credentials? credentials) {
|
||||
notify_report_problem(Geary.Account.Problem.LOGIN_FAILED, credentials, null);
|
||||
}
|
||||
|
||||
private SpecialFolder? get_special_folder(FolderPath path) {
|
||||
if (get_special_folder_map() != null) {
|
||||
return get_special_folder_map().get_folder_by_path(path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ private class Geary.GenericImapFolder : Geary.AbstractFolder {
|
|||
|
||||
internal Sqlite.Folder local_folder { get; protected set; }
|
||||
internal Imap.Folder? remote_folder { get; protected set; default = null; }
|
||||
internal SpecialFolder? special_folder { get; protected set; default = null; }
|
||||
internal int remote_count { get; private set; default = -1; }
|
||||
|
||||
private weak GenericImapAccount account;
|
||||
|
|
@ -20,18 +19,19 @@ private class Geary.GenericImapFolder : Geary.AbstractFolder {
|
|||
private Sqlite.Account local;
|
||||
private EmailFlagWatcher email_flag_watcher;
|
||||
private EmailPrefetcher email_prefetcher;
|
||||
private SpecialFolderType special_folder_type;
|
||||
private bool opened = false;
|
||||
private NonblockingSemaphore remote_semaphore;
|
||||
private ReplayQueue? replay_queue = null;
|
||||
private NonblockingMutex normalize_email_positions_mutex = new NonblockingMutex();
|
||||
|
||||
public GenericImapFolder(GenericImapAccount account, Imap.Account remote, Sqlite.Account local,
|
||||
Sqlite.Folder local_folder, SpecialFolder? special_folder) {
|
||||
Sqlite.Folder local_folder) {
|
||||
this.account = account;
|
||||
this.remote = remote;
|
||||
this.local = local;
|
||||
this.local_folder = local_folder;
|
||||
this.special_folder = special_folder;
|
||||
this.special_folder_type = local_folder.get_properties().attrs.get_special_folder_type();
|
||||
|
||||
email_flag_watcher = new EmailFlagWatcher(this);
|
||||
email_flag_watcher.email_flags_changed.connect(on_email_flags_changed);
|
||||
|
|
@ -48,12 +48,18 @@ private class Geary.GenericImapFolder : Geary.AbstractFolder {
|
|||
return local_folder.get_path();
|
||||
}
|
||||
|
||||
public override Geary.SpecialFolderType? get_special_folder_type() {
|
||||
if (special_folder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return special_folder.folder_type;
|
||||
}
|
||||
public override Geary.SpecialFolderType get_special_folder_type() {
|
||||
return special_folder_type;
|
||||
}
|
||||
|
||||
public void set_special_folder_type(SpecialFolderType new_type) {
|
||||
if (special_folder_type == new_type)
|
||||
return;
|
||||
|
||||
Geary.SpecialFolderType old_type = special_folder_type;
|
||||
special_folder_type = new_type;
|
||||
|
||||
notify_special_folder_type_changed(old_type, new_type);
|
||||
}
|
||||
|
||||
private Imap.FolderProperties? get_folder_properties() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
private class Geary.GmailAccount : Geary.GenericImapAccount {
|
||||
private const string GMAIL_FOLDER = "[Gmail]";
|
||||
private const string GOOGLEMAIL_FOLDER = "[Google Mail]";
|
||||
|
||||
private static Geary.Endpoint? _imap_endpoint = null;
|
||||
public static Geary.Endpoint IMAP_ENDPOINT { get {
|
||||
|
|
@ -33,58 +34,9 @@ private class Geary.GmailAccount : Geary.GenericImapAccount {
|
|||
return _smtp_endpoint;
|
||||
} }
|
||||
|
||||
private static SpecialFolderMap? special_folder_map = null;
|
||||
private static Gee.Set<Geary.FolderPath>? ignored_paths = null;
|
||||
|
||||
public GmailAccount(string name, string username, AccountInformation account_info,
|
||||
File user_data_dir, Imap.Account remote, Sqlite.Account local) {
|
||||
base (name, username, account_info, user_data_dir, remote, local);
|
||||
|
||||
if (special_folder_map == null || ignored_paths == null)
|
||||
initialize_personality();
|
||||
}
|
||||
|
||||
private static void initialize_personality() {
|
||||
Geary.FolderPath gmail_root = new Geary.FolderRoot(GMAIL_FOLDER, Imap.Account.ASSUMED_SEPARATOR,
|
||||
true);
|
||||
Geary.FolderRoot inbox_folder = new Geary.FolderRoot(Imap.Account.INBOX_NAME,
|
||||
Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
Geary.FolderRoot outbox_folder = new SmtpOutboxFolderRoot();
|
||||
|
||||
special_folder_map = new SpecialFolderMap();
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.INBOX, _("Inbox"),
|
||||
inbox_folder, 0));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.DRAFTS, _("Drafts"),
|
||||
gmail_root.get_child("Drafts"), 1));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.SENT, _("Sent Mail"),
|
||||
gmail_root.get_child("Sent Mail"), 2));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.FLAGGED, _("Starred"),
|
||||
gmail_root.get_child("Starred"), 3));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.ALL_MAIL, _("All Mail"),
|
||||
gmail_root.get_child("All Mail"), 4));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.SPAM, _("Spam"),
|
||||
gmail_root.get_child("Spam"), 5));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.OUTBOX,
|
||||
_("Outbox"), outbox_folder, 6));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.TRASH, _("Trash"),
|
||||
gmail_root.get_child("Trash"), 7));
|
||||
|
||||
ignored_paths = new Gee.HashSet<Geary.FolderPath>(Hashable.hash_func, Equalable.equal_func);
|
||||
ignored_paths.add(gmail_root);
|
||||
ignored_paths.add(inbox_folder);
|
||||
ignored_paths.add(outbox_folder);
|
||||
}
|
||||
|
||||
public override string get_user_folders_label() {
|
||||
return _("Labels");
|
||||
}
|
||||
|
||||
public override Geary.SpecialFolderMap? get_special_folder_map() {
|
||||
return special_folder_map;
|
||||
}
|
||||
|
||||
public override Gee.Set<Geary.FolderPath>? get_ignored_paths() {
|
||||
return ignored_paths.read_only_view;
|
||||
}
|
||||
|
||||
public override bool delete_is_archive() {
|
||||
|
|
|
|||
|
|
@ -10,16 +10,8 @@ private class Geary.OtherAccount : Geary.GenericImapAccount {
|
|||
base (name, username, account_info, user_data_dir, remote, local);
|
||||
}
|
||||
|
||||
public override string get_user_folders_label() {
|
||||
return _("Folders");
|
||||
}
|
||||
|
||||
public override Geary.SpecialFolderMap? get_special_folder_map() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Gee.Set<Geary.FolderPath>? get_ignored_paths() {
|
||||
return null;
|
||||
protected override Geary.SpecialFolderType get_special_folder_type_for_path(Geary.FolderPath path) {
|
||||
return Geary.SpecialFolderType.NONE;
|
||||
}
|
||||
|
||||
public override bool delete_is_archive() {
|
||||
|
|
|
|||
|
|
@ -31,62 +31,28 @@ private class Geary.YahooAccount : Geary.GenericImapAccount {
|
|||
return _smtp_endpoint;
|
||||
} }
|
||||
|
||||
private static SpecialFolderMap? special_folder_map = null;
|
||||
private static Gee.Set<Geary.FolderPath>? ignored_paths = null;
|
||||
private Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType> special_map = new Gee.HashMap<
|
||||
Geary.FolderPath, Geary.SpecialFolderType>(Hashable.hash_func, Equalable.equal_func);
|
||||
|
||||
public YahooAccount(string name, string username, AccountInformation account_info,
|
||||
File user_data_dir, Imap.Account remote, Sqlite.Account local) {
|
||||
base (name, username, account_info, user_data_dir, remote, local);
|
||||
|
||||
if (special_folder_map == null || ignored_paths == null)
|
||||
initialize_personality();
|
||||
}
|
||||
|
||||
private static void initialize_personality() {
|
||||
special_folder_map = new SpecialFolderMap();
|
||||
FolderPath sent = new Geary.FolderRoot("Sent", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
special_map.set(sent, Geary.SpecialFolderType.SENT);
|
||||
|
||||
FolderRoot inbox_folder = new FolderRoot(Imap.Account.INBOX_NAME,
|
||||
Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
FolderRoot sent_folder = new Geary.FolderRoot("Sent", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
FolderRoot drafts_folder = new Geary.FolderRoot("Draft", Imap.Account.ASSUMED_SEPARATOR,
|
||||
false);
|
||||
FolderRoot spam_folder = new Geary.FolderRoot("Bulk Mail", Imap.Account.ASSUMED_SEPARATOR,
|
||||
false);
|
||||
FolderRoot trash_folder = new Geary.FolderRoot("Trash", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
FolderRoot outbox_folder = new SmtpOutboxFolderRoot();
|
||||
FolderPath drafts = new Geary.FolderRoot("Draft", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
special_map.set(drafts, Geary.SpecialFolderType.DRAFTS);
|
||||
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.INBOX, _("Inbox"),
|
||||
inbox_folder, 0));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.DRAFTS, _("Drafts"),
|
||||
drafts_folder, 1));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.SENT, _("Sent Mail"),
|
||||
sent_folder, 2));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.SPAM, _("Spam"),
|
||||
spam_folder, 3));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.OUTBOX,
|
||||
_("Outbox"), outbox_folder, 4));
|
||||
special_folder_map.set_folder(new SpecialFolder(Geary.SpecialFolderType.TRASH, _("Trash"),
|
||||
trash_folder, 5));
|
||||
FolderPath bulk = new Geary.FolderRoot("Bulk Mail", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
special_map.set(bulk, Geary.SpecialFolderType.SPAM);
|
||||
|
||||
ignored_paths = new Gee.HashSet<Geary.FolderPath>(Hashable.hash_func, Equalable.equal_func);
|
||||
ignored_paths.add(inbox_folder);
|
||||
ignored_paths.add(drafts_folder);
|
||||
ignored_paths.add(sent_folder);
|
||||
ignored_paths.add(spam_folder);
|
||||
ignored_paths.add(outbox_folder);
|
||||
ignored_paths.add(trash_folder);
|
||||
FolderPath trash = new Geary.FolderRoot("Trash", Imap.Account.ASSUMED_SEPARATOR, false);
|
||||
special_map.set(trash, Geary.SpecialFolderType.TRASH);
|
||||
}
|
||||
|
||||
public override string get_user_folders_label() {
|
||||
return _("Folders");
|
||||
}
|
||||
|
||||
public override Geary.SpecialFolderMap? get_special_folder_map() {
|
||||
return special_folder_map;
|
||||
}
|
||||
|
||||
public override Gee.Set<Geary.FolderPath>? get_ignored_paths() {
|
||||
return ignored_paths;
|
||||
protected override Geary.SpecialFolderType get_special_folder_type_for_path(Geary.FolderPath path) {
|
||||
return special_map.has_key(path) ? special_map.get(path) : Geary.SpecialFolderType.NONE;
|
||||
}
|
||||
|
||||
public override bool delete_is_archive() {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ private class Geary.SmtpOutboxFolder : Geary.AbstractFolder {
|
|||
return Geary.Trillian.FALSE;
|
||||
}
|
||||
|
||||
public override Geary.SpecialFolderType? get_special_folder_type() {
|
||||
public override Geary.SpecialFolderType get_special_folder_type() {
|
||||
return Geary.SpecialFolderType.OUTBOX;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public abstract class Geary.Sqlite.Database {
|
|||
return t;
|
||||
}
|
||||
|
||||
public void upgrade() throws Error {
|
||||
public int upgrade() throws Error {
|
||||
// Get the SQLite database version.
|
||||
SQLHeavy.QueryResult result = db.execute("PRAGMA user_version;");
|
||||
int db_version = result.fetch_int();
|
||||
|
|
@ -74,6 +74,8 @@ public abstract class Geary.Sqlite.Database {
|
|||
|
||||
post_upgrade(db_version);
|
||||
}
|
||||
|
||||
return db.execute("PRAGMA user_version;").fetch_int();
|
||||
}
|
||||
|
||||
private File get_upgrade_script(int version) {
|
||||
|
|
|
|||
|
|
@ -43,10 +43,8 @@ private class Geary.Sqlite.Account : Object {
|
|||
db.pre_upgrade.connect(on_pre_upgrade);
|
||||
db.post_upgrade.connect(on_post_upgrade);
|
||||
|
||||
db.upgrade();
|
||||
|
||||
// Need to clear duplicate folders (due to ticket #nnnn)
|
||||
clear_duplicate_folders();
|
||||
// upgrade and do any processing that should be done on this version of the database
|
||||
process_database(db.upgrade());
|
||||
} catch (Error err) {
|
||||
warning("Unable to open database: %s", err.message);
|
||||
|
||||
|
|
@ -296,6 +294,25 @@ private class Geary.Sqlite.Account : Object {
|
|||
// TODO Add per-version data massaging.
|
||||
}
|
||||
|
||||
// Called every run after executing db.upgrade(); this gives a chance to perform work that
|
||||
// cannot be easily expressed in an upgrade script and should happen whether an upgrade to that
|
||||
// version has happened or not
|
||||
private void process_database(int version) {
|
||||
switch (version) {
|
||||
case 3:
|
||||
try {
|
||||
clear_duplicate_folders();
|
||||
} catch (SQLHeavy.Error err) {
|
||||
debug("Unable to clear duplicate folders in version %d: %s", version, err.message);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void clear_duplicate_folders() throws SQLHeavy.Error {
|
||||
int count = 0;
|
||||
|
||||
|
|
@ -320,7 +337,7 @@ private class Geary.Sqlite.Account : Object {
|
|||
SQLHeavy.QueryResult message_result = message_query.execute();
|
||||
|
||||
if (child_result.finished && message_result.finished) {
|
||||
// no children, delete it
|
||||
// no children and no messages, delete it
|
||||
SQLHeavy.Query child_delete = db.db.prepare(
|
||||
"DELETE FROM FolderTable WHERE id=?");
|
||||
child_delete.bind_int64(0, id);
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ private class Geary.Sqlite.Folder : Object, Geary.ReferenceSemantics {
|
|||
|
||||
private ImapDatabase db;
|
||||
private FolderRow folder_row;
|
||||
private Geary.Imap.FolderProperties? properties;
|
||||
private Geary.Imap.FolderProperties properties;
|
||||
private MessageTable message_table;
|
||||
private MessageLocationTable location_table;
|
||||
private MessageAttachmentTable attachment_table;
|
||||
private ImapMessagePropertiesTable imap_message_properties_table;
|
||||
private Geary.FolderPath path;
|
||||
|
||||
internal Folder(ImapDatabase db, FolderRow folder_row, Geary.Imap.FolderProperties? properties,
|
||||
internal Folder(ImapDatabase db, FolderRow folder_row, Geary.Imap.FolderProperties properties,
|
||||
Geary.FolderPath path) throws Error {
|
||||
this.db = db;
|
||||
this.folder_row = folder_row;
|
||||
|
|
@ -61,12 +61,12 @@ private class Geary.Sqlite.Folder : Object, Geary.ReferenceSemantics {
|
|||
return path;
|
||||
}
|
||||
|
||||
public Geary.Imap.FolderProperties? get_properties() {
|
||||
// TODO: TBD: alteration/updated signals for folders
|
||||
public Geary.Imap.FolderProperties get_properties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
internal void update_properties(Geary.Imap.FolderProperties? properties) {
|
||||
internal void update_properties(Geary.Imap.FolderProperties properties) {
|
||||
// TODO: TBD: alteration/updated signals for folders
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue