[geary/pantheon_mail: 29/32] convert last buttons from pill-toolbar method



commit f79e03683ada7b3cefec9bb57e39fb240b50d258
Author: Daniel Foré <daniel elementary io>
Date:   Tue Nov 24 16:44:45 2015 -0800

    convert last buttons from pill-toolbar method

 src/client/application/geary-controller.vala |  975 +++++++++++++-------------
 src/client/components/main-toolbar.vala      |   37 +-
 2 files changed, 509 insertions(+), 503 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index d2919cd..c9e9f95 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -53,52 +53,51 @@ public class GearyController : Geary.BaseObject {
     public const string ACTION_SEARCH = "GearySearch";
     public const string ACTION_CONVERSATION_LIST = "GearyConversationList";
     public const string ACTION_TOGGLE_SEARCH = "GearyToggleSearch";
-    
+
     public const string PROP_CURRENT_CONVERSATION ="current-conversations";
-    
+
     public const int MIN_CONVERSATION_COUNT = 50;
-    
+
     private const string DELETE_MESSAGE_LABEL = _("Delete conversation");
     private const string DELETE_MESSAGE_TOOLTIP_SINGLE = _("Delete conversation (Shift+Delete)");
     private const string DELETE_MESSAGE_TOOLTIP_MULTIPLE = _("Delete conversations (Shift+Delete)");
     private const string DELETE_MESSAGE_ICON_NAME = "edit-delete-symbolic";
-    
+
     // This refers to the action ("move email to the trash"), not the Trash folder itself
     private const string TRASH_MESSAGE_TOOLTIP_SINGLE = _("Move conversation to Trash (Delete, Backspace)");
     private const string TRASH_MESSAGE_TOOLTIP_MULTIPLE = _("Move conversations to Trash (Delete, 
Backspace)");
     private const string TRASH_MESSAGE_ICON_NAME = "user-trash-symbolic";
-    
+
     // This refers to the action ("archive an email"), not the Archive folder itself
-    private const string ARCHIVE_MESSAGE_LABEL = _("_Archive");
     private const string ARCHIVE_MESSAGE_TOOLTIP_SINGLE = _("Archive conversation (A)");
     private const string ARCHIVE_MESSAGE_TOOLTIP_MULTIPLE = _("Archive conversations (A)");
     private const string ARCHIVE_MESSAGE_ICON_NAME = "mail-archive-symbolic";
-    
+
     private const string MARK_AS_SPAM_LABEL = _("Mark as S_pam");
     private const string MARK_AS_NOT_SPAM_LABEL = _("Mark as not S_pam");
-    
+
     private const string MARK_MESSAGE_MENU_TOOLTIP_SINGLE = _("Mark conversation");
     private const string MARK_MESSAGE_MENU_TOOLTIP_MULTIPLE = _("Mark conversations");
     private const string LABEL_MESSAGE_TOOLTIP_SINGLE = _("Add label to conversation");
     private const string LABEL_MESSAGE_TOOLTIP_MULTIPLE = _("Add label to conversations");
     private const string MOVE_MESSAGE_TOOLTIP_SINGLE = _("Move conversation");
     private const string MOVE_MESSAGE_TOOLTIP_MULTIPLE = _("Move conversations");
-    
+
     private const int SELECT_FOLDER_TIMEOUT_USEC = 100 * 1000;
     private const int SEARCH_TIMEOUT_MSEC = 250;
-    
+
     private const string PROP_ATTEMPT_OPEN_ACCOUNT = "attempt-open-account";
-    
+
     public MainWindow main_window { get; private set; }
-    
+
     public Geary.App.ConversationMonitor? current_conversations { get; private set; default = null; }
-    
+
     public AutostartManager? autostart_manager { get; private set; default = null; }
-    
+
     public LoginDialog? login_dialog { get; private set; default = null; }
-    
+
     public MenuModel app_menu { get; private set; }
-    
+
     private Geary.Account? current_account = null;
     private Gee.HashMap<Geary.Account, Geary.App.EmailStore> email_stores
         = new Gee.HashMap<Geary.Account, Geary.App.EmailStore>();
@@ -131,44 +130,44 @@ public class GearyController : Geary.BaseObject {
     private Geary.Nonblocking.Mutex untrusted_host_prompt_mutex = new Geary.Nonblocking.Mutex();
     private Gee.HashSet<Geary.Endpoint> validating_endpoints = new Gee.HashSet<Geary.Endpoint>();
     private Geary.Revokable? revokable = null;
-    
+
     // List of windows we're waiting to close before Geary closes.
     private Gee.List<ComposerWidget> waiting_to_close = new Gee.ArrayList<ComposerWidget>();
-    
+
     /**
      * Fired when the currently selected account has changed.
      */
     public signal void account_selected(Geary.Account? account);
-    
+
     /**
      * Fired when the currently selected folder has changed.
      */
     public signal void folder_selected(Geary.Folder? folder);
-    
+
     /**
      * Fired when the currently selected conversation(s) has/have changed.
      */
     public signal void conversations_selected(Gee.Set<Geary.App.Conversation>? conversations,
         Geary.Folder? current_folder);
-    
+
     /**
      * Fired when the number of conversations changes.
      */
     public signal void conversation_count_changed(int count);
-    
+
     /**
      * Fired when the search text is changed according to the controller.  This accounts
      * for a brief typmatic delay.
      */
     public signal void search_text_changed(string keywords);
-    
+
     public GearyController() {
     }
-    
+
     ~GearyController() {
         assert(current_account == null);
     }
-    
+
     /**
      * Starts the controller and brings up Geary.
      */
@@ -176,29 +175,29 @@ public class GearyController : Geary.BaseObject {
         // This initializes the IconFactory, important to do before the actions are created (as they
         // refer to some of Geary's custom icons)
         IconFactory.instance.init();
-        
+
         // Setup actions.
         setup_actions();
         GearyApplication.instance.load_ui_file("accelerators.ui");
-        
+
         // Listen for attempts to close the application.
         GearyApplication.instance.exiting.connect(on_application_exiting);
-        
+
         // Create DB upgrade dialog.
         upgrade_dialog = new UpgradeDialog();
         upgrade_dialog.notify[UpgradeDialog.PROP_VISIBLE_NAME].connect(display_main_window_if_ready);
-        
+
         // Create the main window (must be done after creating actions.)
         main_window = new MainWindow(GearyApplication.instance);
         main_window.on_shift_key.connect(on_shift_key);
         main_window.notify["has-toplevel-focus"].connect(on_has_toplevel_focus);
-        
+
         enable_message_buttons(false);
-        
+
         Geary.Engine.instance.account_available.connect(on_account_available);
         Geary.Engine.instance.account_unavailable.connect(on_account_unavailable);
         Geary.Engine.instance.untrusted_host.connect(on_untrusted_host);
-        
+
         // Connect to various UI signals.
         main_window.conversation_list_view.conversations_selected.connect(on_conversations_selected);
         main_window.conversation_list_view.conversation_activated.connect(on_conversation_activated);
@@ -220,36 +219,36 @@ public class GearyController : Geary.BaseObject {
         main_window.conversation_viewer.save_attachments.connect(on_save_attachments);
         main_window.conversation_viewer.save_buffer_to_file.connect(on_save_buffer_to_file);
         main_window.conversation_viewer.edit_draft.connect(on_edit_draft);
-        
+
         new_messages_monitor = new NewMessagesMonitor(should_notify_new_messages);
         main_window.folder_list.set_new_messages_monitor(new_messages_monitor);
-        
+
         // New messages indicator (Ubuntuism)
         new_messages_indicator = NewMessagesIndicator.create(new_messages_monitor);
         new_messages_indicator.application_activated.connect(on_indicator_activated_application);
         new_messages_indicator.composer_activated.connect(on_indicator_activated_composer);
         new_messages_indicator.inbox_activated.connect(on_indicator_activated_inbox);
-        
+
         unity_launcher = new UnityLauncher(new_messages_monitor);
-        
+
         // libnotify
         libnotify = new Libnotify(new_messages_monitor);
         libnotify.invoked.connect(on_libnotify_invoked);
-        
+
         // This is fired after the accounts are ready.
         Geary.Engine.instance.opened.connect(on_engine_opened);
-        
+
         main_window.conversation_list_view.grab_focus();
-        
+
         // instantiate here to ensure that Config is initialized and ready
         autostart_manager = new AutostartManager();
-        
+
         // initialize revokable
         save_revokable(null, null);
-        
+
         // Start Geary.
         try {
-            yield Geary.Engine.instance.open_async(GearyApplication.instance.get_user_data_directory(), 
+            yield Geary.Engine.instance.open_async(GearyApplication.instance.get_user_data_directory(),
                 GearyApplication.instance.get_resource_directory(), new SecretMediator());
             if (Geary.Engine.instance.get_accounts().size == 0) {
                 create_account();
@@ -258,7 +257,7 @@ public class GearyController : Geary.BaseObject {
             error("Error opening Geary.Engine instance: %s", e.message);
         }
     }
-    
+
     /**
      * At the moment, this is non-reversible, i.e. once closed a GearyController cannot be
      * re-opened.
@@ -267,7 +266,7 @@ public class GearyController : Geary.BaseObject {
         Geary.Engine.instance.account_available.disconnect(on_account_available);
         Geary.Engine.instance.account_unavailable.disconnect(on_account_unavailable);
         Geary.Engine.instance.untrusted_host.disconnect(on_untrusted_host);
-        
+
         // Connect to various UI signals.
         main_window.conversation_list_view.conversations_selected.disconnect(on_conversations_selected);
         main_window.conversation_list_view.conversation_activated.disconnect(on_conversation_activated);
@@ -289,26 +288,26 @@ public class GearyController : Geary.BaseObject {
         main_window.conversation_viewer.save_attachments.disconnect(on_save_attachments);
         main_window.conversation_viewer.save_buffer_to_file.disconnect(on_save_buffer_to_file);
         main_window.conversation_viewer.edit_draft.disconnect(on_edit_draft);
-        
+
         // hide window while shutting down, as this can take a few seconds under certain conditions
         main_window.hide();
-        
+
         // drop the Revokable, which will commit it if necessary
         save_revokable(null, null);
-        
+
         // close the ConversationMonitor
         try {
             if (current_conversations != null) {
                 debug("Stopping conversation monitor for %s...", current_conversations.folder.to_string());
-                
+
                 bool closing = yield current_conversations.stop_monitoring_async(null);
-                
+
                 // If not an Inbox, wait for it to close so all pending operations are flushed
                 if (closing) {
                     debug("Waiting for %s to close...", current_conversations.folder.to_string());
                     yield current_conversations.folder.wait_for_close_async(null);
                 }
-                
+
                 debug("Stopped conversation monitor for %s", current_conversations.folder.to_string());
             }
         } catch (Error err) {
@@ -317,25 +316,25 @@ public class GearyController : Geary.BaseObject {
         } finally {
             current_conversations = null;
         }
-        
+
         // close all Inboxes
         foreach (Geary.Folder inbox in inboxes.values) {
             try {
                 debug("Closing %s...", inbox.to_string());
-                
+
                 // close and wait for all pending operations to be flushed
                 yield inbox.close_async(null);
-                
+
                 debug("Waiting for %s to close completely...", inbox.to_string());
-                
+
                 yield inbox.wait_for_close_async(null);
-                
+
                 debug("Closed %s", inbox.to_string());
             } catch (Error err) {
                 message("Error closing Inbox %s at shutdown: %s", inbox.to_string(), err.message);
             }
         }
-        
+
         // close all Accounts
         foreach (Geary.Account account in email_stores.keys) {
             try {
@@ -346,9 +345,9 @@ public class GearyController : Geary.BaseObject {
                 message("Error closing account %s at shutdown: %s", account.to_string(), err.message);
             }
         }
-        
+
         main_window.destroy();
-        
+
         // Turn off the lights and lock the door behind you
         try {
             debug("Closing Engine...");
@@ -358,7 +357,7 @@ public class GearyController : Geary.BaseObject {
             message("Error closing Geary Engine instance: %s", err.message);
         }
     }
-    
+
     private void add_accelerator(string accelerator, string action) {
         GtkUtil.add_accelerator(GearyApplication.instance.ui_manager, GearyApplication.instance.actions,
             accelerator, action);
@@ -366,12 +365,12 @@ public class GearyController : Geary.BaseObject {
 
     private Gtk.ActionEntry[] create_actions() {
         Gtk.ActionEntry[] entries = new Gtk.ActionEntry[0];
-        
+
         Gtk.ActionEntry accounts = { ACTION_ACCOUNTS, null, TRANSLATABLE, "<Ctrl>M",
             null, on_accounts };
         accounts.label = _("A_ccounts");
         entries += accounts;
-        
+
         Gtk.ActionEntry prefs = { ACTION_PREFERENCES, Stock._PREFERENCES, TRANSLATABLE, "<Ctrl>E",
             null, on_preferences };
         prefs.label = _("_Preferences");
@@ -388,7 +387,7 @@ public class GearyController : Geary.BaseObject {
         Gtk.ActionEntry quit = { ACTION_QUIT, Stock._QUIT, TRANSLATABLE, "<Ctrl>Q", null, on_quit };
         quit.label = _("_Quit");
         entries += quit;
-        
+
         Gtk.ActionEntry mark_menu = { ACTION_MARK_AS_MENU, null, TRANSLATABLE, null, _("Mark conversation"),
             on_show_mark_menu };
         mark_menu.label = _("_Mark as...");
@@ -406,7 +405,7 @@ public class GearyController : Geary.BaseObject {
         mark_unread.label = _("Mark as _Unread");
         entries += mark_unread;
         add_accelerator("<Shift>U", ACTION_MARK_AS_UNREAD);
-        
+
         Gtk.ActionEntry mark_starred = { ACTION_MARK_AS_STARRED, "star-symbolic", TRANSLATABLE, "S", null,
             on_mark_as_starred };
         mark_starred.label = _("_Star");
@@ -416,13 +415,13 @@ public class GearyController : Geary.BaseObject {
             null, on_mark_as_unstarred };
         mark_unstarred.label = _("U_nstar");
         entries += mark_unstarred;
-        
+
         Gtk.ActionEntry mark_spam = { ACTION_MARK_AS_SPAM, null, TRANSLATABLE, "<Ctrl>J", null,
             on_mark_as_spam };
         mark_spam.label = MARK_AS_SPAM_LABEL;
         entries += mark_spam;
         add_accelerator("exclam", ACTION_MARK_AS_SPAM); // Exclamation mark (!)
-        
+
         Gtk.ActionEntry copy_menu = { ACTION_COPY_MENU, null, TRANSLATABLE, "L",
             _("Add label"), null };
         copy_menu.label = _("_Label");
@@ -432,45 +431,45 @@ public class GearyController : Geary.BaseObject {
         move_menu.label = _("_Move");
         entries += move_menu;
 
-        Gtk.ActionEntry new_message = { ACTION_NEW_MESSAGE, null, null, "<Ctrl>N", 
+        Gtk.ActionEntry new_message = { ACTION_NEW_MESSAGE, null, null, "<Ctrl>N",
             _("Compose new message (Ctrl+N, N)"), on_new_message };
         entries += new_message;
         add_accelerator("N", ACTION_NEW_MESSAGE);
 
-        Gtk.ActionEntry reply_to_message = { ACTION_REPLY_TO_MESSAGE, null, _("_Reply"), "<Ctrl>R",
+        Gtk.ActionEntry reply_to_message = { ACTION_REPLY_TO_MESSAGE, null, null, "<Ctrl>R",
             _("Reply (Ctrl+R, R)"), on_reply_to_message_action };
         entries += reply_to_message;
         add_accelerator("R", ACTION_REPLY_TO_MESSAGE);
-        
-        Gtk.ActionEntry reply_all_message = { ACTION_REPLY_ALL_MESSAGE, null, _("R_eply All"),
-            "<Ctrl><Shift>R", _("Reply all (Ctrl+Shift+R, Shift+R)"), 
+
+        Gtk.ActionEntry reply_all_message = { ACTION_REPLY_ALL_MESSAGE, null, null,
+            "<Ctrl><Shift>R", _("Reply all (Ctrl+Shift+R, Shift+R)"),
             on_reply_all_message_action };
         entries += reply_all_message;
         add_accelerator("<Shift>R", ACTION_REPLY_ALL_MESSAGE);
-        
-        Gtk.ActionEntry forward_message = { ACTION_FORWARD_MESSAGE, null, _("_Forward"), "<Ctrl>L", 
+
+        Gtk.ActionEntry forward_message = { ACTION_FORWARD_MESSAGE, null, null, "<Ctrl>L",
             _("Forward (Ctrl+L, F)"), on_forward_message_action };
         entries += forward_message;
         add_accelerator("F", ACTION_FORWARD_MESSAGE);
-        
+
         Gtk.ActionEntry find_in_conversation = { ACTION_FIND_IN_CONVERSATION, null, null, "<Ctrl>F",
             null, on_find_in_conversation_action };
         entries += find_in_conversation;
         add_accelerator("slash", ACTION_FIND_IN_CONVERSATION);
-        
+
         Gtk.ActionEntry find_next_in_conversation = { ACTION_FIND_NEXT_IN_CONVERSATION, null, null,
             "<Ctrl>G", null, on_find_next_in_conversation_action };
         entries += find_next_in_conversation;
-        
+
         Gtk.ActionEntry find_previous_in_conversation = { ACTION_FIND_PREVIOUS_IN_CONVERSATION,
             null, null, "<Shift><Ctrl>G", null, on_find_previous_in_conversation_action };
         entries += find_previous_in_conversation;
-        
+
         Gtk.ActionEntry archive_message = { ACTION_ARCHIVE_MESSAGE, ARCHIVE_MESSAGE_ICON_NAME,
-            ARCHIVE_MESSAGE_LABEL, "A", null, on_archive_message };
+            null, "A", null, on_archive_message };
         archive_message.tooltip = ARCHIVE_MESSAGE_TOOLTIP_SINGLE;
         entries += archive_message;
-        
+
         // although this action changes according to the account's capabilities, set to Delete
         // until they're known so the "translatable" string doesn't first appear
         Gtk.ActionEntry trash_message = { ACTION_TRASH_MESSAGE, TRASH_MESSAGE_ICON_NAME,
@@ -478,31 +477,31 @@ public class GearyController : Geary.BaseObject {
         trash_message.tooltip = TRASH_MESSAGE_TOOLTIP_SINGLE;
         entries += trash_message;
         add_accelerator("BackSpace", ACTION_TRASH_MESSAGE);
-        
+
         Gtk.ActionEntry delete_message = { ACTION_DELETE_MESSAGE, DELETE_MESSAGE_ICON_NAME,
             null, "<Shift>Delete", null, on_delete_message };
         delete_message.label = DELETE_MESSAGE_LABEL;
         delete_message.tooltip = DELETE_MESSAGE_TOOLTIP_SINGLE;
         entries += delete_message;
         add_accelerator("<Shift>BackSpace", ACTION_DELETE_MESSAGE);
-        
+
         Gtk.ActionEntry empty_menu = { ACTION_EMPTY_MENU, "edit-clear-all-symbolic", null, null,
             null, null };
         empty_menu.label = _("Empty");
         empty_menu.tooltip = _("Empty Spam or Trash folders");
         entries += empty_menu;
-        
+
         Gtk.ActionEntry empty_spam = { ACTION_EMPTY_SPAM, null, null, null, null, on_empty_spam };
         empty_spam.label = _("Empty _Spam…");
         entries += empty_spam;
-        
+
         Gtk.ActionEntry empty_trash = { ACTION_EMPTY_TRASH, null, null, null, null, on_empty_trash };
         empty_trash.label = _("Empty _Trash…");
         entries += empty_trash;
-        
+
         Gtk.ActionEntry undo = { ACTION_UNDO, "edit-undo-symbolic", null, "<Ctrl>Z", null, on_revoke };
         entries += undo;
-        
+
         Gtk.ActionEntry zoom_in = { ACTION_ZOOM_IN, null, null, "<Ctrl>equal",
             null, on_zoom_in };
         entries += zoom_in;
@@ -517,35 +516,35 @@ public class GearyController : Geary.BaseObject {
             null, on_zoom_normal };
         entries += zoom_normal;
         add_accelerator("0", ACTION_ZOOM_NORMAL);
-        
+
         // Can't use the Action's "natural" accelerator because this Action is not tied to any
         // widget
         Gtk.ActionEntry search = { ACTION_SEARCH, null, null, null, null, on_search };
         entries += search;
         add_accelerator("<Ctrl>S", ACTION_SEARCH);
-        
+
         Gtk.ActionEntry conversation_list = { ACTION_CONVERSATION_LIST, null, null, null, null, 
on_conversation_list };
         entries += conversation_list;
         add_accelerator("<Ctrl>B", ACTION_CONVERSATION_LIST);
-        
+
         // No callback is connected, since we bind the toggle button to the search bar visibility
         Gtk.ActionEntry toggle_search = { ACTION_TOGGLE_SEARCH, null, null, null,
             _("Toggle search bar"), null };
         entries += toggle_search;
-        
+
         return entries;
     }
-    
+
     private Gtk.ToggleActionEntry[] create_toggle_actions() {
         Gtk.ToggleActionEntry[] entries = new Gtk.ToggleActionEntry[0];
-        
+
         Gtk.ToggleActionEntry gear_menu = { ACTION_GEAR_MENU, null, null, "F10",
             null, null, false };
         entries += gear_menu;
-        
+
         return entries;
     }
-    
+
     private void setup_actions() {
         const string[] important_actions = {
             ACTION_NEW_MESSAGE,
@@ -563,29 +562,29 @@ public class GearyController : Geary.BaseObject {
             ACTION_ABOUT,
             ACTION_QUIT,
         };
-        
+
         Gtk.ActionGroup action_group = GearyApplication.instance.actions;
-        
+
         Gtk.ActionEntry[] action_entries = create_actions();
         action_group.add_actions(action_entries, this);
         foreach (Gtk.ActionEntry e in action_entries) {
             Gtk.Action action = action_group.get_action(e.name);
             assert(action != null);
-            
+
             if (e.name in important_actions)
                 action.is_important = true;
             GearyApplication.instance.action_adapters.add(new Geary.ActionAdapter(action));
         }
-        
+
         Gtk.ToggleActionEntry[] toggle_action_entries = create_toggle_actions();
         action_group.add_toggle_actions(toggle_action_entries, this);
-        
+
         foreach (Geary.ActionAdapter a in GearyApplication.instance.action_adapters) {
             if (a.action.name in exported_actions)
                 GearyApplication.instance.add_action(a.action);
         }
         GearyApplication.instance.ui_manager.insert_action_group(action_group, 0);
-        
+
         Gtk.Builder builder = new Gtk.Builder();
         try {
             builder.add_from_file(
@@ -594,7 +593,7 @@ public class GearyController : Geary.BaseObject {
             error("Unable to parse app_menu.interface: %s", e.message);
         }
         app_menu = (MenuModel) builder.get_object("app-menu");
-        
+
         // We'd *like* to always export an app menu and just let the shell
         // decide whether to display it or not.  Unfortunately Mint (Cinnamon,
         // I believe) and maybe others will insert a menu bar for your
@@ -603,19 +602,19 @@ public class GearyController : Geary.BaseObject {
         if (Gtk.Settings.get_default().gtk_shell_shows_app_menu)
             GearyApplication.instance.set_app_menu(app_menu);
     }
-    
+
     private void open_account(Geary.Account account) {
         account.report_problem.connect(on_report_problem);
         account.email_removed.connect(on_account_email_removed);
         connect_account_async.begin(account, cancellable_open_account);
     }
-    
+
     private void close_account(Geary.Account account) {
         account.report_problem.disconnect(on_report_problem);
         account.email_removed.disconnect(on_account_email_removed);
         disconnect_account_async.begin(account);
     }
-    
+
     private Geary.Account get_account_instance(Geary.AccountInformation account_information) {
         try {
             return Geary.Engine.instance.get_account_instance(account_information);
@@ -623,24 +622,24 @@ public class GearyController : Geary.BaseObject {
             error("Error creating account instance: %s", e.message);
         }
     }
-    
+
     private void on_account_available(Geary.AccountInformation account_information) {
         Geary.Account account = get_account_instance(account_information);
-        
+
         upgrade_dialog.add_account(account, cancellable_open_account);
         open_account(account);
     }
-    
+
     private void on_account_unavailable(Geary.AccountInformation account_information) {
         close_account(get_account_instance(account_information));
     }
-    
+
     private void on_untrusted_host(Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Endpoint.SecurityType security, TlsConnection cx,
         Geary.Service service) {
         prompt_untrusted_host_async.begin(account_information, endpoint, security, cx, service);
     }
-    
+
     private async void prompt_untrusted_host_async(Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Endpoint.SecurityType security, TlsConnection cx,
         Geary.Service service) {
@@ -650,13 +649,13 @@ public class GearyController : Geary.BaseObject {
             token = yield untrusted_host_prompt_mutex.claim_async();
         } catch (Error err) {
             message("Unable to lock mutex to prompt user about invalid certificate: %s", err.message);
-            
+
             return;
         }
-        
+
         yield locked_prompt_untrusted_host_async(account_information, endpoint, security, cx,
             service);
-        
+
         try {
             untrusted_host_prompt_mutex.release(ref token);
         } catch (Error err) {
@@ -664,61 +663,61 @@ public class GearyController : Geary.BaseObject {
                 err.message);
         }
     }
-    
+
     private static void get_gcr_params(Geary.Endpoint endpoint, out Gcr.Certificate cert,
         out string peer) {
         cert = new Gcr.SimpleCertificate(endpoint.untrusted_certificate.certificate.data);
         peer = "%s:%u".printf(endpoint.remote_address.hostname, endpoint.remote_address.port);
     }
-    
+
     private async void locked_prompt_untrusted_host_async(Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Endpoint.SecurityType security, TlsConnection cx,
         Geary.Service service) {
         // possible while waiting on mutex that this endpoint became trusted or untrusted
         if (endpoint.trust_untrusted_host != Geary.Trillian.UNKNOWN)
             return;
-        
+
         // get GCR parameters
         Gcr.Certificate cert;
         string peer;
         get_gcr_params(endpoint, out cert, out peer);
-        
+
         // Geary allows for user to auto-revoke all questionable server certificates without
         // digging around in a keyring/pk manager
         if (Args.revoke_certs) {
             debug("Auto-revoking certificate for %s...", peer);
-            
+
             try {
                 gcr_trust_remove_pinned_certificate(cert, GCR_PURPOSE_SERVER_AUTH, peer, null);
             } catch (Error err) {
                 message("Unable to auto-revoke server certificate for %s: %s", peer, err.message);
-                
+
                 // drop through, not absolutely valid to do this (might also mean certificate
                 // was never pinned)
             }
         }
-        
+
         // if pinned, the user has already made an exception for this server and its certificate,
         // so go ahead w/o asking
         try {
             if (gcr_trust_is_certificate_pinned(cert, GCR_PURPOSE_SERVER_AUTH, peer, null)) {
                 debug("Certificate for %s is pinned, accepting connection...", peer);
-                
+
                 endpoint.trust_untrusted_host = Geary.Trillian.TRUE;
-                
+
                 return;
             }
         } catch (Error err) {
             message("Unable to check if server certificate for %s is pinned, assuming not: %s",
                 peer, err.message);
         }
-        
+
         // if these are in validation, there are complex GTK and workflow issues from simply
         // presenting the prompt now, so caller who connected will need to do it on their own dime
         if (!validating_endpoints.contains(endpoint))
             prompt_for_untrusted_host(main_window, account_information, endpoint, service, false);
     }
-    
+
     private void prompt_for_untrusted_host(Gtk.Window? parent, Geary.AccountInformation account_information,
         Geary.Endpoint endpoint, Geary.Service service, bool is_validation) {
         CertificateWarningDialog dialog = new CertificateWarningDialog(parent, account_information,
@@ -727,15 +726,15 @@ public class GearyController : Geary.BaseObject {
             case CertificateWarningDialog.Result.TRUST:
                 endpoint.trust_untrusted_host = Geary.Trillian.TRUE;
             break;
-            
+
             case CertificateWarningDialog.Result.ALWAYS_TRUST:
                 endpoint.trust_untrusted_host = Geary.Trillian.TRUE;
-                
+
                 // get GCR parameters for pinning
                 Gcr.Certificate cert;
                 string peer;
                 get_gcr_params(endpoint, out cert, out peer);
-                
+
                 // pinning the certificate creates an exception for the next time a connection
                 // is attempted
                 debug("Pinning certificate for %s...", peer);
@@ -747,10 +746,10 @@ public class GearyController : Geary.BaseObject {
                     error_dialog.run();
                 }
             break;
-            
+
             default:
                 endpoint.trust_untrusted_host = Geary.Trillian.FALSE;
-                
+
                 // close the account; can't go any further w/o offline mode
                 try {
                     if (Geary.Engine.instance.get_accounts().has_key(account_information.email)) {
@@ -763,62 +762,62 @@ public class GearyController : Geary.BaseObject {
             break;
         }
     }
-    
+
     private void create_account() {
         Geary.AccountInformation? account_information = request_account_information(null);
         if (account_information != null)
             do_validate_until_successful_async.begin(account_information);
     }
-    
+
     private async void do_validate_until_successful_async(Geary.AccountInformation account_information,
         Cancellable? cancellable = null) {
         Geary.AccountInformation? result = account_information;
         do {
             result = yield validate_or_retry_async(result, cancellable);
         } while (result != null);
-        
+
         if (login_dialog != null)
             login_dialog.hide();
     }
-    
+
     // Returns possibly modified validation results
     private Geary.Engine.ValidationResult validation_check_endpoint_for_tls_warnings(
         Geary.AccountInformation account_information, Geary.Service service,
         Geary.Engine.ValidationResult validation_result, out bool prompted, out bool retry_required) {
         prompted = false;
         retry_required = false;
-        
+
         // use LoginDialog for parent only if available and visible
         Gtk.Window? parent;
         if (login_dialog != null && login_dialog.visible)
             parent = login_dialog;
         else
             parent = main_window;
-        
+
         Geary.Endpoint endpoint = account_information.get_endpoint_for_service(service);
-        
+
         // If Endpoint had unresolved TLS issues, prompt user about them
         if (endpoint.tls_validation_warnings != 0 && endpoint.trust_untrusted_host != Geary.Trillian.TRUE) {
             prompt_for_untrusted_host(parent, account_information, endpoint, service, true);
             prompted = true;
         }
-        
+
         // If there are still TLS connection issues that caused the connection to fail (happens on the
         // first attempt), clear those errors and retry
         if (endpoint.tls_validation_warnings != 0 && endpoint.trust_untrusted_host == Geary.Trillian.TRUE) {
             Geary.Engine.ValidationResult flag = (service == Geary.Service.IMAP)
                 ? Geary.Engine.ValidationResult.IMAP_CONNECTION_FAILED
                 : Geary.Engine.ValidationResult.SMTP_CONNECTION_FAILED;
-            
+
             if ((validation_result & flag) != 0) {
                 validation_result &= ~flag;
                 retry_required = true;
             }
         }
-        
+
         return validation_result;
     }
-    
+
     // Use after validating to see if TLS warnings were handled by the user and need to retry the
     // validation; this will also modify the validation results to better indicate issues to the user
     //
@@ -827,21 +826,21 @@ public class GearyController : Geary.BaseObject {
         Geary.AccountInformation account_information, Geary.Engine.ValidationResult validation_result,
         out bool retry_required) {
         retry_required = false;
-        
+
         // Because TLS warnings need cycles to process, sleep and give 'em a chance to do their
         // thing ... note that the signal handler does *not* invoke the user prompt dialog when the
         // login dialog is in play, so this sleep does not need to worry about user input
         yield Geary.Scheduler.sleep_ms_async(100);
-        
+
         // check each service for problems, prompting user each time for verification
         bool imap_prompted, imap_retry_required;
         validation_result = validation_check_endpoint_for_tls_warnings(account_information,
             Geary.Service.IMAP, validation_result, out imap_prompted, out imap_retry_required);
-        
+
         bool smtp_prompted, smtp_retry_required;
         validation_result = validation_check_endpoint_for_tls_warnings(account_information,
             Geary.Service.SMTP, validation_result, out smtp_prompted, out smtp_retry_required);
-        
+
         // if prompted for user acceptance of bad certificates and they agreed to both, try again
         if (imap_prompted && smtp_prompted
             && account_information.get_imap_endpoint().is_trusted_or_never_connected
@@ -853,10 +852,10 @@ public class GearyController : Geary.BaseObject {
             // if prompt requires retry or otherwise detected it, retry
             retry_required = imap_retry_required && smtp_retry_required;
         }
-        
+
         return validation_result;
     }
-    
+
     // Returns null if we are done validating, or the revised account information if we should retry.
     private async Geary.AccountInformation? validate_or_retry_async(Geary.AccountInformation 
account_information,
         Cancellable? cancellable = null) {
@@ -864,21 +863,21 @@ public class GearyController : Geary.BaseObject {
             Geary.Engine.ValidationOption.CHECK_CONNECTIONS, cancellable);
         if (result == Geary.Engine.ValidationResult.OK)
             return null;
-        
+
         // check Endpoints for trust (TLS) issues
         bool retry_required;
         result = yield validation_check_for_tls_warnings_async(account_information, result,
             out retry_required);
-        
+
         // return for retry if required; check can also change validation results, in which case
         // revalidate entirely to have them written out
         if (retry_required)
             return account_information;
-        
+
         debug("Validation failed. Prompting user for revised account information");
         Geary.AccountInformation? new_account_information =
             request_account_information(account_information, result);
-        
+
         // If the user refused to enter account information. There is currently no way that we
         // could see this--we exit in request_account_information, and the only way that an
         // exit could be canceled is if there are unsaved composer windows open (which won't
@@ -886,11 +885,11 @@ public class GearyController : Geary.BaseObject {
         // future.
         if (new_account_information == null)
             return null;
-        
+
         debug("User entered revised account information, retrying validation");
         return new_account_information;
     }
-    
+
     // Attempts to validate and add an account.  Returns a result code indicating
     // success or one or more errors.
     public async Geary.Engine.ValidationResult validate_async(
@@ -899,7 +898,7 @@ public class GearyController : Geary.BaseObject {
         // add Endpoints to set of validating endpoints to prevent the prompt from appearing
         validating_endpoints.add(account_information.get_imap_endpoint());
         validating_endpoints.add(account_information.get_smtp_endpoint());
-        
+
         Geary.Engine.ValidationResult result = Geary.Engine.ValidationResult.OK;
         try {
             result = yield Geary.Engine.instance.validate_account_information_async(account_information,
@@ -907,13 +906,13 @@ public class GearyController : Geary.BaseObject {
         } catch (Error err) {
             debug("Error validating account: %s", err.message);
             GearyApplication.instance.exit(-1); // Fatal error
-            
+
             return result;
         }
-        
+
         validating_endpoints.remove(account_information.get_imap_endpoint());
         validating_endpoints.remove(account_information.get_smtp_endpoint());
-        
+
         if (result == Geary.Engine.ValidationResult.OK) {
             Geary.AccountInformation real_account_information = account_information;
             if (account_information.is_copy()) {
@@ -922,17 +921,17 @@ public class GearyController : Geary.BaseObject {
                 real_account_information = get_real_account_information(account_information);
                 real_account_information.copy_from(account_information);
             }
-            
+
             real_account_information.store_async.begin(cancellable);
             do_update_stored_passwords_async.begin(Geary.ServiceFlag.IMAP | Geary.ServiceFlag.SMTP,
                 real_account_information);
-            
+
             debug("Successfully validated account information");
         }
-        
+
         return result;
     }
-    
+
     // Returns the "real" account info associated with a copy.  If it's not a copy, null is returned.
     public Geary.AccountInformation? get_real_account_information(
         Geary.AccountInformation account_information) {
@@ -943,10 +942,10 @@ public class GearyController : Geary.BaseObject {
                 error("Account information is out of sync: %s", e.message);
             }
         }
-        
+
         return null;
     }
-    
+
     // Prompt the user for a service, real name, username, and password, and try to start Geary.
     private Geary.AccountInformation? request_account_information(Geary.AccountInformation? old_info,
         Geary.Engine.ValidationResult result = Geary.Engine.ValidationResult.OK) {
@@ -957,26 +956,26 @@ public class GearyController : Geary.BaseObject {
         } else if (!login_dialog.get_visible()) {
             // If the dialog has been dismissed, exit here.
             GearyApplication.instance.exit();
-            
+
             return null;
         }
-        
+
         if (new_info != null)
             login_dialog.set_account_information(new_info, result);
-        
+
         login_dialog.present();
         for (;;) {
             login_dialog.show_spinner(false);
             if (login_dialog.run() != Gtk.ResponseType.OK) {
                 debug("User refused to enter account information. Exiting...");
                 GearyApplication.instance.exit(1);
-                
+
                 return null;
             }
-            
+
             login_dialog.show_spinner(true);
             new_info = login_dialog.get_account_information();
-            
+
             if ((!new_info.default_imap_server_ssl && !new_info.default_imap_server_starttls)
                 || (!new_info.default_smtp_server_ssl && !new_info.default_smtp_server_starttls)) {
                 ConfirmationDialog security_dialog = new ConfirmationDialog(main_window,
@@ -986,13 +985,13 @@ public class GearyController : Geary.BaseObject {
                 if (security_dialog.run() != Gtk.ResponseType.OK)
                     continue;
             }
-            
+
             break;
         }
-        
+
         return new_info;
     }
-    
+
     private async void do_update_stored_passwords_async(Geary.ServiceFlag services,
         Geary.AccountInformation account_information) {
         try {
@@ -1001,37 +1000,37 @@ public class GearyController : Geary.BaseObject {
             debug("Error updating stored passwords: %s", e.message);
         }
     }
-    
+
     private void on_report_problem(Geary.Account account, Geary.Account.Problem problem, Error? err) {
         debug("Reported problem: %s Error: %s", problem.to_string(), err != null ? err.message : "(N/A)");
-        
+
         switch (problem) {
             case Geary.Account.Problem.DATABASE_FAILURE:
             case Geary.Account.Problem.HOST_UNREACHABLE:
             case Geary.Account.Problem.NETWORK_UNAVAILABLE:
                 // TODO
             break;
-            
+
             case Geary.Account.Problem.RECV_EMAIL_LOGIN_FAILED:
             case Geary.Account.Problem.SEND_EMAIL_LOGIN_FAILED:
                 // At this point, we've prompted them for the password and
                 // they've hit cancel, so there's not much for us to do here.
                 close_account(account);
             break;
-            
+
             case Geary.Account.Problem.EMAIL_DELIVERY_FAILURE:
                 handle_outbox_failure(StatusBar.Message.OUTBOX_SEND_FAILURE);
             break;
-            
+
             case Geary.Account.Problem.SAVE_SENT_MAIL_FAILED:
                 handle_outbox_failure(StatusBar.Message.OUTBOX_SAVE_SENT_MAIL_FAILED);
             break;
-            
+
             default:
                 assert_not_reached();
         }
     }
-    
+
     private void handle_outbox_failure(StatusBar.Message message) {
         bool activate_message = false;
         try {
@@ -1054,7 +1053,7 @@ public class GearyController : Geary.BaseObject {
             debug("Error determining whether any outbox has messages: %s", e.message);
             activate_message = true;
         }
-        
+
         if (activate_message) {
             if (!main_window.status_bar.is_message_active(message))
                 main_window.status_bar.activate_message(message);
@@ -1063,18 +1062,18 @@ public class GearyController : Geary.BaseObject {
                     libnotify.set_error_notification(_("Error sending email"),
                         _("Geary encountered an error sending an email.  If the problem persists, please 
manually delete the email from your Outbox folder."));
                 break;
-                
+
                 case StatusBar.Message.OUTBOX_SAVE_SENT_MAIL_FAILED:
                     libnotify.set_error_notification(_("Error saving sent mail"),
                         _("Geary encountered an error saving a sent message to Sent Mail.  The message will 
stay in your Outbox folder until you delete it."));
                 break;
-                
+
                 default:
                     assert_not_reached();
             }
         }
     }
-    
+
     private void on_account_email_removed(Geary.Folder folder, Gee.Collection<Geary.EmailIdentifier> ids) {
         if (folder.special_folder_type == Geary.SpecialFolderType.OUTBOX) {
             main_window.status_bar.deactivate_message(StatusBar.Message.OUTBOX_SEND_FAILURE);
@@ -1082,15 +1081,15 @@ public class GearyController : Geary.BaseObject {
             libnotify.clear_error_notification();
         }
     }
-    
+
     private void on_sending_started() {
         main_window.status_bar.activate_message(StatusBar.Message.OUTBOX_SENDING);
     }
-    
+
     private void on_sending_finished() {
         main_window.status_bar.deactivate_message(StatusBar.Message.OUTBOX_SENDING);
     }
-    
+
     // Removes an existing account.
     public async void remove_account_async(Geary.AccountInformation account,
         Cancellable? cancellable = null) {
@@ -1101,12 +1100,12 @@ public class GearyController : Geary.BaseObject {
             message("Error removing account: %s", e.message);
         }
     }
-    
+
     public async void connect_account_async(Geary.Account account, Cancellable? cancellable = null) {
         account.folders_available_unavailable.connect(on_folders_available_unavailable);
         account.sending_monitor.start.connect(on_sending_started);
         account.sending_monitor.finish.connect(on_sending_finished);
-        
+
         bool retry = false;
         do {
             try {
@@ -1115,7 +1114,7 @@ public class GearyController : Geary.BaseObject {
                 retry = false;
             } catch (Error open_err) {
                 debug("Unable to open account %s: %s", account.to_string(), open_err.message);
-                
+
                 if (open_err is Geary.EngineError.CORRUPT)
                     retry = yield account_database_error_async(account);
                 else if (open_err is Geary.EngineError.PERMISSIONS)
@@ -1124,25 +1123,25 @@ public class GearyController : Geary.BaseObject {
                     yield account_database_version_async(account);
                 else
                     yield account_general_error_async(account);
-                
+
                 if (!retry)
                     return;
             }
         } while (retry);
-        
+
         email_stores.set(account, new Geary.App.EmailStore(account));
         inbox_cancellables.set(account, new Cancellable());
-        
+
         account.email_sent.connect(on_sent);
-        
+
         main_window.folder_list.set_user_folders_root_name(account, _("Labels"));
         display_main_window_if_ready();
     }
-    
+
     // Returns true if the caller should try opening the account again
     private async bool account_database_error_async(Geary.Account account) {
         bool retry = true;
-        
+
         // give the user two options: reset the Account local store, or exit Geary.  A third
         // could be done to leave the Account in an unopened state, but we don't currently
         // have provisions for that.
@@ -1162,22 +1161,22 @@ public class GearyController : Geary.BaseObject {
                         _("Unable to rebuild database for \"%s\"").printf(account.information.email),
                         _("Error during rebuild:\n\n%s").printf(err.message));
                     dialog.run();
-                    
+
                     retry = false;
                 }
             break;
-            
+
             default:
                 retry = false;
             break;
         }
-        
+
         if (!retry)
             GearyApplication.instance.exit(1);
-        
+
         return retry;
     }
-    
+
     private async void account_database_perms_async(Geary.Account account) {
         // some other problem opening the account ... as with other flow path, can't run
         // Geary today with an account in unopened state, so have to exit
@@ -1186,19 +1185,19 @@ public class GearyController : Geary.BaseObject {
             _("There was an error opening the local mail database for this account. This is possibly due to 
a file permissions problem.\n\nPlease check that you have read/write permissions for all files in this 
directory:\n\n%s")
                 .printf(account.information.settings_dir.get_path()));
         dialog.run();
-        
+
         GearyApplication.instance.exit(1);
     }
-    
+
     private async void account_database_version_async(Geary.Account account) {
         ErrorDialog dialog = new ErrorDialog(main_window,
             _("Unable to open local mailbox for %s").printf(account.information.email),
             _("The version number of the local mail database is formatted for a newer version of Geary. 
Unfortunately, the database cannot be \"rolled back\" to work with this version of Geary.\n\nPlease install 
the latest version of Geary and try again."));
         dialog.run();
-        
+
         GearyApplication.instance.exit(1);
     }
-    
+
     private async void account_general_error_async(Geary.Account account) {
         // some other problem opening the account ... as with other flow path, can't run
         // Geary today with an account in unopened state, so have to exit
@@ -1206,45 +1205,45 @@ public class GearyController : Geary.BaseObject {
             _("Unable to open local mailbox for %s").printf(account.information.email),
             _("There was an error opening the local account. This is probably due to connectivity 
issues.\n\nPlease check your network connection and restart Geary."));
         dialog.run();
-        
+
         GearyApplication.instance.exit(1);
     }
-    
+
     public async void disconnect_account_async(Geary.Account account, Cancellable? cancellable = null) {
         cancel_inbox(account);
-        
+
         previous_non_search_folder = null;
         main_window.search_bar.set_search_text(""); // Reset search.
         if (current_account == account) {
             cancel_folder();
             switch_to_first_inbox(); // Switch folder.
         }
-        
+
         account.folders_available_unavailable.disconnect(on_folders_available_unavailable);
         account.sending_monitor.start.disconnect(on_sending_started);
         account.sending_monitor.finish.disconnect(on_sending_finished);
-        
+
         main_window.folder_list.remove_account(account);
-        
+
         if (inboxes.has_key(account)) {
             try {
                 yield inboxes.get(account).close_async(cancellable);
             } catch (Error close_inbox_err) {
                 debug("Unable to close monitored inbox: %s", close_inbox_err.message);
             }
-            
+
             inboxes.unset(account);
         }
-        
+
         try {
             yield account.close_async(cancellable);
         } catch (Error close_err) {
             debug("Unable to close account %s: %s", account.to_string(), close_err.message);
         }
-        
+
         inbox_cancellables.unset(account);
         email_stores.unset(account);
-        
+
         // If there are no accounts available, exit.  (This can happen if the user declines to
         // enter a password on their account.)
         try {
@@ -1254,7 +1253,7 @@ public class GearyController : Geary.BaseObject {
             message("Error enumerating accounts: %s", e.message);
         }
     }
-    
+
     /**
      * Returns true if we've attempted to open all accounts at this point.
      */
@@ -1268,10 +1267,10 @@ public class GearyController : Geary.BaseObject {
         } catch(Error e) {
             error("Could not open accounts: %s", e.message);
         }
-        
+
         return true;
     }
-    
+
     /**
      * Displays the main window if we're ready.  Otherwise does nothing.
      */
@@ -1280,7 +1279,7 @@ public class GearyController : Geary.BaseObject {
             !cancellable_open_account.is_cancelled() && !Args.hidden_startup)
             main_window.show_all();
     }
-    
+
     /**
      * Returns the number of accounts that exist in Geary.  Note that not all accounts may be
      * open.  Zero is returned on an error.
@@ -1291,10 +1290,10 @@ public class GearyController : Geary.BaseObject {
         } catch (Error e) {
             debug("Error getting number of accounts: %s", e.message);
         }
-        
+
         return 0; // on error
     }
-    
+
     // Returns the number of open accounts.
     private int get_num_open_accounts() throws Error {
         int num = 0;
@@ -1303,10 +1302,10 @@ public class GearyController : Geary.BaseObject {
             if (a.is_open())
                 num++;
         }
-        
+
         return num;
     }
-    
+
     // Update widgets and such to match capabilities of the current folder ... sensitivity is handled
     // by other utility methods
     private void update_ui() {
@@ -1315,22 +1314,22 @@ public class GearyController : Geary.BaseObject {
             current_folder_supports_trash() || !(current_folder is Geary.FolderSupport.Remove),
             current_account.can_support_archive);
     }
-    
+
     private void on_folder_selected(Geary.Folder? folder) {
         debug("Folder %s selected", folder != null ? folder.to_string() : "(null)");
-        
+
         // If the folder is being unset, clear the message list and exit here.
         if (folder == null) {
             current_folder = null;
             main_window.conversation_list_store.clear();
             main_window.main_toolbar.folder = null;
             folder_selected(null);
-            
+
             return;
         }
-        
+
         folder_to_select = folder;
-        
+
         // To prevent the user from selecting folders too quickly, we prevent additional selection
         // changes to occur until after a timeout has expired from the last one
         int64 now = get_monotonic_time();
@@ -1344,119 +1343,119 @@ public class GearyController : Geary.BaseObject {
         } else {
             do_select_folder.begin(folder_to_select, on_select_folder_completed);
             folder_to_select = null;
-            
+
             next_folder_select_allowed_usec = now + SELECT_FOLDER_TIMEOUT_USEC;
         }
     }
-    
+
     private bool on_select_folder_timeout() {
         select_folder_timeout_id = 0;
         next_folder_select_allowed_usec = 0;
-        
+
         if (folder_to_select != null)
             do_select_folder.begin(folder_to_select, on_select_folder_completed);
-        
+
         folder_to_select = null;
-        
+
         return false;
     }
-    
+
     private async void do_select_folder(Geary.Folder folder) throws Error {
         if (folder == current_folder)
             return;
-        
+
         debug("Switching to %s...", folder.to_string());
-        
+
         closed_folder();
-        
+
         // This function is not reentrant.  It should be, because it can be
         // called reentrant-ly if you select folders quickly enough.  This
         // mutex lock is a bandaid solution to make the function safe to
         // reenter.
         int mutex_token = yield select_folder_mutex.claim_async(cancellable_folder);
-        
+
         bool current_is_inbox = inboxes.values.contains(current_folder);
-        
+
         Cancellable? conversation_cancellable = (current_is_inbox ?
             inbox_cancellables.get(folder.account) : cancellable_folder);
-        
+
         // clear Revokable, as Undo is only available while a folder is selected
         save_revokable(null, null);
-        
+
         // stop monitoring for conversations and close the folder
         if (current_conversations != null) {
             yield current_conversations.stop_monitoring_async(null);
             current_conversations = null;
         }
-        
+
         // re-enable copy/move to the last selected folder
         if (current_folder != null) {
             main_window.main_toolbar.copy_folder_menu.enable_disable_folder(current_folder, true);
             main_window.main_toolbar.move_folder_menu.enable_disable_folder(current_folder, true);
         }
-        
+
         current_folder = folder;
-        
+
         if (current_account != folder.account) {
             current_account = folder.account;
             account_selected(current_account);
-            
+
             // If we were waiting for an account to be selected before issuing mailtos, do that now.
             if (pending_mailtos.size > 0) {
                 foreach(string mailto in pending_mailtos)
                     compose_mailto(mailto);
-                
+
                 pending_mailtos.clear();
             }
         }
-        
+
         folder_selected(current_folder);
-        
+
         if (!(current_folder is Geary.SearchFolder))
             previous_non_search_folder = current_folder;
-        
+
         main_window.main_toolbar.copy_folder_menu.clear();
         main_window.main_toolbar.move_folder_menu.clear();
         foreach(Geary.Folder f in current_folder.account.list_folders()) {
             main_window.main_toolbar.copy_folder_menu.add_folder(f);
             main_window.main_toolbar.move_folder_menu.add_folder(f);
         }
-        
+
         // disable copy/move to the new folder
         if (current_folder != null) {
             main_window.main_toolbar.copy_folder_menu.enable_disable_folder(current_folder, false);
             main_window.main_toolbar.move_folder_menu.enable_disable_folder(current_folder, false);
         }
-        
+
         update_ui();
-        
+
         current_conversations = new Geary.App.ConversationMonitor(current_folder, 
Geary.Folder.OpenFlags.NO_DELAY,
             ConversationListStore.REQUIRED_FIELDS, MIN_CONVERSATION_COUNT);
-        
+
         if (inboxes.values.contains(current_folder)) {
             // Inbox selected, clear new messages if visible
             clear_new_messages("do_select_folder (inbox)", null);
         }
-        
+
         current_conversations.scan_error.connect(on_scan_error);
         current_conversations.seed_completed.connect(on_seed_completed);
         current_conversations.seed_completed.connect(on_conversation_count_changed);
         current_conversations.scan_completed.connect(on_conversation_count_changed);
         current_conversations.conversations_added.connect(on_conversation_count_changed);
         current_conversations.conversation_removed.connect(on_conversation_count_changed);
-        
+
         if (!current_conversations.is_monitoring)
             yield current_conversations.start_monitoring_async(conversation_cancellable);
-        
+
         select_folder_mutex.release(ref mutex_token);
-        
+
         debug("Switched to %s", folder.to_string());
     }
-    
+
     private void on_scan_error(Error err) {
         debug("Scan error: %s", err.message);
     }
-    
+
     private void on_seed_completed() {
         // Done scanning.  Check if we have enough messages to fill the conversation list; if not,
         // trigger a load_more();
@@ -1465,44 +1464,44 @@ public class GearyController : Geary.BaseObject {
             on_load_more();
         }
     }
-    
+
     private void on_conversation_count_changed() {
         if (current_conversations != null)
             conversation_count_changed(current_conversations.get_conversation_count());
     }
-    
+
     private void on_libnotify_invoked(Geary.Folder? folder, Geary.Email? email) {
         new_messages_monitor.clear_all_new_messages();
-        
+
         if (folder == null || email == null || !can_switch_conversation_view())
             return;
-        
+
         main_window.folder_list.select_folder(folder);
         Geary.App.Conversation? conversation = current_conversations.get_conversation_for_email(email.id);
         if (conversation != null)
             main_window.conversation_list_view.select_conversation(conversation);
     }
-    
+
     private void on_indicator_activated_application(uint32 timestamp) {
         main_window.present_with_time(timestamp);
     }
-    
+
     private void on_indicator_activated_composer(uint32 timestamp) {
         main_window.present_with_time(timestamp);
         on_new_message();
     }
-    
+
     private void on_indicator_activated_inbox(Geary.Folder folder, uint32 timestamp) {
         main_window.present_with_time(timestamp);
-        
+
         main_window.folder_list.select_folder(folder);
     }
-    
+
     private void on_load_more() {
         debug("on_load_more");
         current_conversations.min_window_count += MIN_CONVERSATION_COUNT;
     }
-    
+
     private void on_select_folder_completed(Object? source, AsyncResult result) {
         try {
             do_select_folder.end(result);
@@ -1510,32 +1509,32 @@ public class GearyController : Geary.BaseObject {
             debug("Unable to select folder: %s", err.message);
         }
     }
-    
+
     private void on_conversations_selected(Gee.Set<Geary.App.Conversation> selected) {
         selected_conversations = selected;
         conversations_selected(selected_conversations, current_folder);
     }
-    
+
     private void on_conversation_activated(Geary.App.Conversation activated) {
         // Currently activating a conversation is only available for drafts folders.
         if (current_folder == null || current_folder.special_folder_type !=
             Geary.SpecialFolderType.DRAFTS)
             return;
-        
+
         // TODO: Determine how to map between conversations and drafts correctly.
         on_edit_draft(activated.get_latest_recv_email(Geary.App.Conversation.Location.IN_FOLDER));
     }
-    
+
     private void on_edit_draft(Geary.Email draft) {
         create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE, draft, null, null, true);
     }
-    
+
     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_engine_opened() {
         // Locate the first account so we can select its inbox when available.
         try {
@@ -1546,14 +1545,14 @@ public class GearyController : Geary.BaseObject {
                 debug("No accounts found.");
                 return;
             }
-            
+
             all_accounts.sort(Geary.AccountInformation.compare_ascending);
             account_to_select = Geary.Engine.instance.get_account_instance(all_accounts.get(0));
         } catch (Error e) {
             debug("Error selecting first inbox: %s", e.message);
         }
     }
-    
+
     // Meant to be called inside the available block of on_folders_available_unavailable,
     // after we've located the first account.
     private Geary.Folder? get_initial_selection_folder(Geary.Folder folder_being_added) {
@@ -1564,10 +1563,10 @@ public class GearyController : Geary.BaseObject {
             // This is the first account being added, so select the inbox.
             return inboxes.get(folder_being_added.account);
         }
-        
+
         return null;
     }
-    
+
     private void on_folders_available_unavailable(Gee.Collection<Geary.Folder>? available,
         Gee.Collection<Geary.Folder>? unavailable) {
         if (available != null && available.size > 0) {
@@ -1579,29 +1578,29 @@ public class GearyController : Geary.BaseObject {
                     if (!main_window.main_toolbar.move_folder_menu.has_folder(folder))
                         main_window.main_toolbar.move_folder_menu.add_folder(folder);
                 }
-                
+
                 // monitor the Inbox for notifications
                 if (folder.special_folder_type == Geary.SpecialFolderType.INBOX &&
                     !inboxes.has_key(folder.account)) {
                     inboxes.set(folder.account, folder);
                     Geary.Folder? select_folder = get_initial_selection_folder(folder);
-                    
+
                     if (select_folder != null) {
                         // First we try to select the Inboxes branch inbox if
                         // it's there, falling back to the main folder list.
                         if (!main_window.folder_list.select_inbox(select_folder.account))
                             main_window.folder_list.select_folder(select_folder);
                     }
-                    
+
                     folder.open_async.begin(Geary.Folder.OpenFlags.NONE, 
inbox_cancellables.get(folder.account));
-                    
+
                     new_messages_monitor.add_folder(folder, inbox_cancellables.get(folder.account));
                 }
-                
+
                 folder.special_folder_type_changed.connect(on_special_folder_type_changed);
             }
         }
-        
+
         if (unavailable != null) {
             foreach (Geary.Folder folder in unavailable) {
                 main_window.folder_list.remove_folder(folder);
@@ -1611,66 +1610,66 @@ public class GearyController : Geary.BaseObject {
                     if (main_window.main_toolbar.move_folder_menu.has_folder(folder))
                         main_window.main_toolbar.move_folder_menu.remove_folder(folder);
                 }
-                
+
                 if (folder.special_folder_type == Geary.SpecialFolderType.INBOX &&
                     inboxes.has_key(folder.account)) {
                     inboxes.unset(folder.account);
                     new_messages_monitor.remove_folder(folder);
                 }
-                
+
                 folder.special_folder_type_changed.disconnect(on_special_folder_type_changed);
             }
         }
     }
-    
+
     private void cancel_folder() {
         Cancellable old_cancellable = cancellable_folder;
         cancellable_folder = new Cancellable();
-        
+
         old_cancellable.cancel();
     }
-    
+
     // Like cancel_folder() but doesn't cancel outstanding operations, allowing them to complete
     // in the background
     private void closed_folder() {
         cancellable_folder = new Cancellable();
     }
-    
+
     private void cancel_inbox(Geary.Account account) {
         if (!inbox_cancellables.has_key(account)) {
             debug("Unable to cancel inbox operation for %s", account.to_string());
             return;
         }
-        
+
         Cancellable old_cancellable = inbox_cancellables.get(account);
         inbox_cancellables.set(account, new Cancellable());
 
         old_cancellable.cancel();
     }
-    
+
     private void cancel_search() {
         Cancellable old_cancellable = cancellable_search;
         cancellable_search = new Cancellable();
-        
+
         old_cancellable.cancel();
     }
-    
+
     private void cancel_context_dependent_buttons() {
         Cancellable old_cancellable = cancellable_context_dependent_buttons;
         cancellable_context_dependent_buttons = new Cancellable();
-        
+
         old_cancellable.cancel();
     }
-    
+
     // We need to include the second parameter, or valac doesn't recognize the function as matching
     // GearyApplication.exiting's signature.
     private bool on_application_exiting(GearyApplication sender, bool panicked) {
         if (close_composition_windows())
             return true;
-        
+
         return sender.cancel_exit();
     }
-    
+
     private void on_quit() {
         GearyApplication.instance.exit();
     }
@@ -1727,25 +1726,25 @@ public class GearyController : Geary.BaseObject {
                 current_account.can_support_archive);
         }
     }
-    
+
     // this signal does not necessarily indicate that the application previously didn't have
     // focus and now it does
     private void on_has_toplevel_focus() {
         clear_new_messages("on_has_toplevel_focus", null);
     }
-    
+
     private void on_accounts() {
         AccountDialog dialog = new AccountDialog(main_window);
         dialog.show_all();
         dialog.run();
         dialog.destroy();
     }
-    
+
     private void on_preferences() {
         PreferencesDialog dialog = new PreferencesDialog(main_window);
         dialog.run();
     }
-    
+
     // latest_sent_only uses Email's Date: field, which corresponds to how they're sorted in the
     // ConversationViewer
     private Gee.ArrayList<Geary.EmailIdentifier> get_conversation_email_ids(
@@ -1759,27 +1758,27 @@ public class GearyController : Geary.BaseObject {
         } else {
             add_to.add_all(conversation.get_email_ids());
         }
-        
+
         return add_to;
     }
-    
+
     private Gee.Collection<Geary.EmailIdentifier> get_conversation_collection_email_ids(
         Gee.Collection<Geary.App.Conversation> conversations, bool latest_sent_only) {
         Gee.ArrayList<Geary.EmailIdentifier> ret = new Gee.ArrayList<Geary.EmailIdentifier>();
-        
+
         foreach(Geary.App.Conversation c in conversations)
             get_conversation_email_ids(c, latest_sent_only, ret);
-        
+
         return ret;
     }
-    
+
     private Gee.ArrayList<Geary.EmailIdentifier> get_selected_email_ids(bool latest_sent_only) {
         Gee.ArrayList<Geary.EmailIdentifier> ids = new Gee.ArrayList<Geary.EmailIdentifier>();
         foreach (Geary.App.Conversation conversation in selected_conversations)
             get_conversation_email_ids(conversation, latest_sent_only, ids);
         return ids;
     }
-    
+
     private void mark_email(Gee.Collection<Geary.EmailIdentifier> ids,
         Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove) {
         if (ids.size > 0) {
@@ -1787,7 +1786,7 @@ public class GearyController : Geary.BaseObject {
                 ids, flags_to_add, flags_to_remove, cancellable_folder);
         }
     }
-    
+
     private void on_show_mark_menu() {
         bool unread_selected = false;
         bool read_selected = false;
@@ -1796,7 +1795,7 @@ public class GearyController : Geary.BaseObject {
         foreach (Geary.App.Conversation conversation in selected_conversations) {
             if (conversation.is_unread())
                 unread_selected = true;
-            
+
             // Only check the messages that "Mark as Unread" would mark, so we
             // don't add the menu option and have it not do anything.
             //
@@ -1818,7 +1817,7 @@ public class GearyController : Geary.BaseObject {
         actions.get_action(ACTION_MARK_AS_UNREAD).set_visible(read_selected);
         actions.get_action(ACTION_MARK_AS_STARRED).set_visible(unstarred_selected);
         actions.get_action(ACTION_MARK_AS_UNSTARRED).set_visible(starred_selected);
-        
+
         if (current_folder.special_folder_type != Geary.SpecialFolderType.DRAFTS &&
             current_folder.special_folder_type != Geary.SpecialFolderType.OUTBOX) {
             if (current_folder.special_folder_type == Geary.SpecialFolderType.SPAM) {
@@ -1836,11 +1835,11 @@ public class GearyController : Geary.BaseObject {
             actions.get_action(ACTION_MARK_AS_SPAM).label = MARK_AS_SPAM_LABEL;
         }
     }
-    
+
     private void on_visible_conversations_changed(Gee.Set<Geary.App.Conversation> visible) {
         clear_new_messages("on_visible_conversations_changed", visible);
     }
-    
+
     private bool should_notify_new_messages(Geary.Folder folder) {
         // A monitored folder must be selected to squelch notifications;
         // if conversation list is at top of display, don't display
@@ -1849,46 +1848,46 @@ public class GearyController : Geary.BaseObject {
             || main_window.conversation_list_view.vadjustment.value != 0.0
             || !main_window.has_toplevel_focus;
     }
-    
+
     // Clears messages if conditions are true: anything in should_notify_new_messages() is
     // false and the supplied visible messages are visible in the conversation list view
     private void clear_new_messages(string caller, Gee.Set<Geary.App.Conversation>? supplied) {
         if (current_folder == null || !new_messages_monitor.get_folders().contains(current_folder)
             || should_notify_new_messages(current_folder))
             return;
-        
+
         Gee.Set<Geary.App.Conversation> visible =
             supplied ?? main_window.conversation_list_view.get_visible_conversations();
-        
+
         foreach (Geary.App.Conversation conversation in visible) {
             if (new_messages_monitor.are_any_new_messages(current_folder, conversation.get_email_ids())) {
                 debug("Clearing new messages: %s", caller);
                 new_messages_monitor.clear_new_messages(current_folder);
-                
+
                 break;
             }
         }
     }
-    
+
     private void on_mark_conversations(Gee.Collection<Geary.App.Conversation> conversations,
         Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove,
         bool latest_only = false) {
         mark_email(get_conversation_collection_email_ids(conversations, latest_only),
             flags_to_add, flags_to_remove);
     }
-    
+
     private void on_conversation_viewer_mark_messages(Gee.Collection<Geary.EmailIdentifier> emails,
         Geary.EmailFlags? flags_to_add, Geary.EmailFlags? flags_to_remove) {
         mark_email(emails, flags_to_add, flags_to_remove);
     }
-    
+
     private void on_mark_as_read() {
         Geary.EmailFlags flags = new Geary.EmailFlags();
         flags.add(Geary.EmailFlags.UNREAD);
-        
+
         Gee.ArrayList<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
         mark_email(ids, null, flags);
-        
+
         foreach (Geary.EmailIdentifier id in ids)
             main_window.conversation_viewer.mark_manual_read(id);
     }
@@ -1896,10 +1895,10 @@ public class GearyController : Geary.BaseObject {
     private void on_mark_as_unread() {
         Geary.EmailFlags flags = new Geary.EmailFlags();
         flags.add(Geary.EmailFlags.UNREAD);
-        
+
         Gee.ArrayList<Geary.EmailIdentifier> ids = get_selected_email_ids(true);
         mark_email(ids, flags, null);
-        
+
         foreach (Geary.EmailIdentifier id in ids)
             main_window.conversation_viewer.mark_manual_read(id);
     }
@@ -1915,7 +1914,7 @@ public class GearyController : Geary.BaseObject {
         flags.add(Geary.EmailFlags.FLAGGED);
         mark_email(get_selected_email_ids(false), null, flags);
     }
-    
+
     private async void mark_as_spam_async(Cancellable? cancellable) {
         Geary.Folder? destination_folder = null;
         if (current_folder.special_folder_type != Geary.SpecialFolderType.SPAM) {
@@ -1934,15 +1933,15 @@ public class GearyController : Geary.BaseObject {
                 debug("Error getting inbox folder: %s", e.message);
             }
         }
-        
+
         if (destination_folder != null)
             on_move_conversation(destination_folder);
     }
-    
+
     private void on_mark_as_spam() {
         mark_as_spam_async.begin(null);
     }
-    
+
     private void copy_email(Gee.Collection<Geary.EmailIdentifier> ids,
         Geary.FolderPath destination) {
         if (ids.size > 0) {
@@ -1950,25 +1949,25 @@ public class GearyController : Geary.BaseObject {
                 ids, destination, cancellable_folder);
         }
     }
-    
+
     private void on_copy_conversation(Geary.Folder destination) {
         copy_email(get_selected_email_ids(false), destination.path);
     }
-    
+
     private void on_move_conversation(Geary.Folder destination) {
         // Nothing to do if nothing selected.
         if (selected_conversations == null || selected_conversations.size == 0)
             return;
-        
+
         Gee.List<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
         if (ids.size == 0)
             return;
-        
+
         Geary.FolderSupport.Move? supports_move = current_folder as Geary.FolderSupport.Move;
         if (supports_move != null)
             move_conversation_async.begin(supports_move, ids, destination.path, cancellable_folder);
     }
-    
+
     private async void move_conversation_async(Geary.FolderSupport.Move source_folder,
         Gee.List<Geary.EmailIdentifier> ids, Geary.FolderPath destination, Cancellable? cancellable) {
         try {
@@ -1979,7 +1978,7 @@ public class GearyController : Geary.BaseObject {
                 err.message);
         }
     }
-    
+
     private void on_open_attachment(Geary.Attachment attachment) {
         if (GearyApplication.instance.config.ask_open_attachment) {
             QuestionDialog ask_to_open = new QuestionDialog.with_checkbox(main_window,
@@ -1988,11 +1987,11 @@ public class GearyController : Geary.BaseObject {
                 Stock._OPEN_BUTTON, Stock._CANCEL, _("Don't _ask me again"), false);
             if (ask_to_open.run() != Gtk.ResponseType.OK)
                 return;
-            
+
             // only save checkbox state if OK was selected
             GearyApplication.instance.config.ask_open_attachment = !ask_to_open.is_checked;
         }
-        
+
         // Open the attachment if we know what to do with it.
         if (!open_uri(attachment.file.get_uri())) {
             // Failing that, trigger a save dialog.
@@ -2001,28 +2000,28 @@ public class GearyController : Geary.BaseObject {
             on_save_attachments(attachment_list);
         }
     }
-    
+
     private bool do_overwrite_confirmation(File to_overwrite) {
         string primary = _("A file named \"%s\" already exists.  Do you want to replace it?").printf(
             to_overwrite.get_basename());
         string secondary = _("The file already exists in \"%s\".  Replacing it will overwrite its 
contents.").printf(
             to_overwrite.get_parent().get_basename());
-        
+
         ConfirmationDialog dialog = new ConfirmationDialog(main_window, primary, secondary, _("_Replace"));
-        
+
         return (dialog.run() == Gtk.ResponseType.OK);
     }
-    
+
     private Gtk.FileChooserConfirmation on_confirm_overwrite(Gtk.FileChooser chooser) {
         // this is only called when choosing one file
         return do_overwrite_confirmation(chooser.get_file()) ? Gtk.FileChooserConfirmation.ACCEPT_FILENAME
             : Gtk.FileChooserConfirmation.SELECT_AGAIN;
     }
-    
+
     private void on_save_attachments(Gee.List<Geary.Attachment> attachments) {
         if (attachments.size == 0)
             return;
-        
+
         Gtk.FileChooserAction action = (attachments.size == 1)
             ? Gtk.FileChooserAction.SAVE
             : Gtk.FileChooserAction.SELECT_FOLDER;
@@ -2039,37 +2038,37 @@ public class GearyController : Geary.BaseObject {
         }
         dialog.set_create_folders(true);
         dialog.set_local_only(false);
-        
+
         bool accepted = (dialog.run() == Gtk.ResponseType.ACCEPT);
         string? filename = dialog.get_filename();
-        
+
         dialog.destroy();
-        
+
         if (!accepted || Geary.String.is_empty(filename))
             return;
-        
+
         File destination = File.new_for_path(filename);
-        
+
         // Proceeding, save this as last destination directory
         last_save_directory = (attachments.size == 1) ? destination.get_parent() : destination;
-        
+
         debug("Saving attachments to %s", destination.get_path());
-        
+
         // Save each one, checking for overwrite only if multiple attachments are being written
         foreach (Geary.Attachment attachment in attachments) {
             File source_file = attachment.file;
             File dest_file = (attachments.size == 1) ? destination : 
destination.get_child(attachment.file.get_basename());
-            
+
             if (attachments.size > 1 && dest_file.query_exists() && !do_overwrite_confirmation(dest_file))
                 return;
-            
+
             debug("Copying %s to %s...", source_file.get_path(), dest_file.get_path());
-            
+
             source_file.copy_async.begin(dest_file, FileCopyFlags.OVERWRITE, Priority.DEFAULT, null,
                 null, on_save_completed);
         }
     }
-    
+
     private void on_save_completed(Object? source, AsyncResult result) {
         try {
             ((File) source).copy_async.end(result);
@@ -2078,7 +2077,7 @@ public class GearyController : Geary.BaseObject {
                 error.message);
         }
     }
-    
+
     private void on_save_buffer_to_file(string? filename, Geary.Memory.Buffer buffer) {
         Gtk.FileChooserDialog dialog = new Gtk.FileChooserDialog(null, main_window, 
Gtk.FileChooserAction.SAVE,
             Stock._CANCEL, Gtk.ResponseType.CANCEL, Stock._SAVE, Gtk.ResponseType.ACCEPT, null);
@@ -2090,22 +2089,22 @@ public class GearyController : Geary.BaseObject {
         dialog.confirm_overwrite.connect(on_confirm_overwrite);
         dialog.set_create_folders(true);
         dialog.set_local_only(false);
-        
+
         bool accepted = (dialog.run() == Gtk.ResponseType.ACCEPT);
         string? accepted_filename = dialog.get_filename();
-        
+
         dialog.destroy();
-        
+
         if (!accepted || Geary.String.is_empty(accepted_filename))
             return;
-        
+
         File destination = File.new_for_path(accepted_filename);
-        
+
         // Proceeding, save this as last destination directory
         last_save_directory = destination.get_parent();
-        
+
         debug("Saving buffer to %s", destination.get_path());
-        
+
         // Create the file where the image will be saved and get the output stream.
         try {
             FileOutputStream outs = destination.replace(null, false, FileCreateFlags.REPLACE_DESTINATION,
@@ -2117,7 +2116,7 @@ public class GearyController : Geary.BaseObject {
             message("Unable to save buffer to \"%s\": %s", filename, err.message);
         }
     }
-    
+
     private void on_save_buffer_to_file_completed(Object? source, AsyncResult result) {
         try {
             ((FileOutputStream) source).splice_async.end(result);
@@ -2125,29 +2124,29 @@ public class GearyController : Geary.BaseObject {
             message("Failed to save buffer to file: %s", err.message);
         }
     }
-    
+
     // Opens a link in an external browser.
     private bool open_uri(string _link) {
         string link = _link;
-        
+
         // Support web URLs that ommit the protocol.
         if (!link.contains(":"))
             link = "http://"; + link;
-        
+
         bool ret = false;
         try {
             ret = Gtk.show_uri(main_window.get_screen(), link, Gdk.CURRENT_TIME);
         } catch (Error err) {
             debug("Unable to open URL. %s", err.message);
         }
-        
+
         return ret;
     }
-    
+
     private bool close_composition_windows() {
         Gee.List<ComposerWidget> composers_to_destroy = new Gee.ArrayList<ComposerWidget>();
         bool quit_cancelled = false;
-        
+
         // If there's composer windows open, give the user a chance to save or cancel.
         foreach(ComposerWidget cw in composer_widgets) {
             // Check if we should close the window immediately, or if we need to wait.
@@ -2166,29 +2165,29 @@ public class GearyController : Geary.BaseObject {
                 ((ComposerContainer) cw.parent).vanish();
             }
         }
-        
+
         // Safely destroy windows.
         foreach(ComposerWidget cw in composers_to_destroy)
             ((ComposerContainer) cw.parent).close_container();
-        
+
         // If we cancelled the quit we can bail here.
         if (quit_cancelled) {
             waiting_to_close.clear();
-            
+
             return false;
         }
-        
+
         // If there's still windows saving, we can't exit just yet.  Hide the main window and wait.
         if (waiting_to_close.size > 0) {
             main_window.hide();
-            
+
             return false;
         }
-        
+
         // If we deleted all composer windows without the user cancelling, we can exit.
         return true;
     }
-    
+
     // message is the email from whose menu this reply or forward was triggered.  If null,
     // this was triggered from the headerbar or shortcut.
     private void create_reply_forward_widget(ComposerWidget.ComposeType compose_type,
@@ -2201,23 +2200,23 @@ public class GearyController : Geary.BaseObject {
             quote = null;
         create_compose_widget(compose_type, message, quote);
     }
-    
+
     private void create_compose_widget(ComposerWidget.ComposeType compose_type,
         Geary.Email? referred = null, string? quote = null, string? mailto = null,
         bool is_draft = false) {
         create_compose_widget_async.begin(compose_type, referred, quote, mailto, is_draft);
     }
-    
+
     private async void create_compose_widget_async(ComposerWidget.ComposeType compose_type,
         Geary.Email? referred = null, string? quote = null, string? mailto = null,
         bool is_draft = false) {
         if (current_account == null)
             return;
-        
+
         bool inline;
         if (!should_create_new_composer(compose_type, referred, quote, is_draft, out inline))
             return;
-        
+
         ComposerWidget widget;
         if (mailto != null) {
             widget = new ComposerWidget.from_mailto(current_account, mailto);
@@ -2232,7 +2231,7 @@ public class GearyController : Geary.BaseObject {
                     message("Could not load full message: %s", e.message);
                 }
             }
-            
+
             widget = new ComposerWidget(current_account, compose_type, full, quote, is_draft);
             if (is_draft) {
                 yield widget.restore_draft_state_async(current_account);
@@ -2240,13 +2239,13 @@ public class GearyController : Geary.BaseObject {
             }
         }
         widget.show_all();
-        
+
         // We want to keep track of the open composer windows, so we can allow the user to cancel
         // an exit without losing their data.
         composer_widgets.add(widget);
         debug(@"Creating composer of type $(widget.compose_type); $(composer_widgets.size) composers total");
         widget.destroy.connect(on_composer_widget_destroy);
-        
+
         if (inline) {
             if (widget.state == ComposerWidget.ComposerState.NEW ||
                 widget.state == ComposerWidget.ComposerState.PANED)
@@ -2258,11 +2257,11 @@ public class GearyController : Geary.BaseObject {
             widget.state = ComposerWidget.ComposerState.DETACHED;
         }
     }
-    
+
     private bool should_create_new_composer(ComposerWidget.ComposeType? compose_type,
         Geary.Email? referred, string? quote, bool is_draft, out bool inline) {
         inline = true;
-        
+
         // In we're replying, see whether we already have a reply for that message.
         if (compose_type != null && compose_type != ComposerWidget.ComposeType.NEW_MESSAGE) {
             foreach (ComposerWidget cw in composer_widgets) {
@@ -2276,17 +2275,17 @@ public class GearyController : Geary.BaseObject {
             inline = !any_inline_composers();
             return true;
         }
-        
+
         // If there are no inline composers, go ahead!
         if (!any_inline_composers())
             return true;
-        
+
         // If we're resuming a draft with open composers, open in a new window.
         if (is_draft) {
             inline = false;
             return true;
         }
-        
+
         // If we're creating a new message, and there's already a new message open, focus on
         // it if it hasn't been modified; otherwise open a new composer in a new window.
         if (compose_type == ComposerWidget.ComposeType.NEW_MESSAGE) {
@@ -2302,7 +2301,7 @@ public class GearyController : Geary.BaseObject {
                 }
             }
         }
-        
+
         // Find out what to do with the inline composers.
         // TODO: Remove this in favor of automatically saving drafts
         main_window.present();
@@ -2320,121 +2319,121 @@ public class GearyController : Geary.BaseObject {
         }
         return false;
     }
-    
+
     public bool can_switch_conversation_view() {
         bool inline;
         return should_create_new_composer(null, null, null, false, out inline);
     }
-    
+
     public bool any_inline_composers() {
         foreach (ComposerWidget cw in composer_widgets)
             if (cw.state != ComposerWidget.ComposerState.DETACHED)
                 return true;
         return false;
     }
-    
+
     private void on_composer_widget_destroy(Gtk.Widget sender) {
         composer_widgets.remove((ComposerWidget) sender);
         debug(@"Destroying composer of type $(((ComposerWidget) sender).compose_type); "
             + @"$(composer_widgets.size) composers remaining");
-        
+
         if (waiting_to_close.remove((ComposerWidget) sender)) {
             // If we just removed the last window in the waiting to close list, it's time to exit!
             if (waiting_to_close.size == 0)
                 GearyApplication.instance.exit();
         }
     }
-    
+
     private void on_new_message() {
         create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE);
     }
-    
+
     private void on_reply_to_message(Geary.Email message) {
         create_reply_forward_widget(ComposerWidget.ComposeType.REPLY, message);
     }
-    
+
     private void on_reply_to_message_action() {
         create_reply_forward_widget(ComposerWidget.ComposeType.REPLY, null);
     }
-    
+
     private void on_reply_all_message(Geary.Email message) {
         create_reply_forward_widget(ComposerWidget.ComposeType.REPLY_ALL, message);
     }
-    
+
     private void on_reply_all_message_action() {
         create_reply_forward_widget(ComposerWidget.ComposeType.REPLY_ALL, null);
     }
-    
+
     private void on_forward_message(Geary.Email message) {
         create_reply_forward_widget(ComposerWidget.ComposeType.FORWARD, message);
     }
-    
+
     private void on_forward_message_action() {
         create_reply_forward_widget(ComposerWidget.ComposeType.FORWARD, null);
     }
-    
+
     private void on_find_in_conversation_action() {
         main_window.conversation_viewer.show_find_bar();
     }
-    
+
     private void on_find_next_in_conversation_action() {
         main_window.conversation_viewer.find(true);
     }
-    
+
     private void on_find_previous_in_conversation_action() {
         main_window.conversation_viewer.find(false);
     }
-    
+
     private void on_archive_message() {
         archive_or_delete_selection_async.begin(true, false, cancellable_folder,
             on_archive_or_delete_selection_finished);
     }
-    
+
     private void on_trash_message() {
         archive_or_delete_selection_async.begin(false, true, cancellable_folder,
             on_archive_or_delete_selection_finished);
     }
-    
+
     private void on_delete_message() {
         archive_or_delete_selection_async.begin(false, false, cancellable_folder,
             on_archive_or_delete_selection_finished);
     }
-    
+
     private void on_empty_spam() {
         on_empty_trash_or_spam(Geary.SpecialFolderType.SPAM);
     }
-    
+
     private void on_empty_trash() {
         on_empty_trash_or_spam(Geary.SpecialFolderType.TRASH);
     }
-    
+
     private void on_empty_trash_or_spam(Geary.SpecialFolderType special_folder_type) {
         // Account must be in place, must have the specified special folder type, and that folder
         // must support Empty in order for this command to proceed
         if (current_account == null)
             return;
-        
+
         Geary.Folder? folder = null;
         try {
             folder = current_account.get_special_folder(special_folder_type);
         } catch (Error err) {
             debug("%s: Unable to get special folder %s: %s", current_account.to_string(),
                 special_folder_type.to_string(), err.message);
-            
+
             // fall through
         }
-        
+
         if (folder == null)
             return;
-        
+
         Geary.FolderSupport.Empty? emptyable = folder as Geary.FolderSupport.Empty;
         if (emptyable == null) {
             debug("%s: Special folder %s (%s) does not support emptying", current_account.to_string(),
                 folder.path.to_string(), special_folder_type.to_string());
-            
+
             return;
         }
-        
+
         ConfirmationDialog dialog = new ConfirmationDialog(main_window,
             _("Empty all email from your %s folder?").printf(special_folder_type.get_display_name()),
             _("This removes the email from Geary and your email server.")
@@ -2442,11 +2441,11 @@ public class GearyController : Geary.BaseObject {
             _("Empty %s").printf(special_folder_type.get_display_name()));
         dialog.use_secondary_markup(true);
         dialog.set_focus_response(Gtk.ResponseType.CANCEL);
-        
+
         if (dialog.run() == Gtk.ResponseType.OK)
             empty_folder_async.begin(emptyable, cancellable_folder);
     }
-    
+
     private async void empty_folder_async(Geary.FolderSupport.Empty emptyable, Cancellable? cancellable) {
         try {
             yield do_empty_folder_async(emptyable, cancellable);
@@ -2454,17 +2453,17 @@ public class GearyController : Geary.BaseObject {
             // don't report to user if cancelled
             if (cancellable is IOError.CANCELLED)
                 return;
-            
+
             ErrorDialog dialog = new ErrorDialog(main_window,
                 _("Error emptying %s").printf(emptyable.get_display_name()), err.message);
             dialog.run();
         }
     }
-    
+
     private async void do_empty_folder_async(Geary.FolderSupport.Empty emptyable, Cancellable? cancellable)
         throws Error {
         yield emptyable.open_async(Geary.Folder.OpenFlags.NONE, cancellable);
-        
+
         // be sure to close in all code paths
         try {
             yield emptyable.empty_folder_async(cancellable);
@@ -2476,44 +2475,44 @@ public class GearyController : Geary.BaseObject {
             }
         }
     }
-    
+
     private bool current_folder_supports_trash() {
         return (current_folder != null && current_folder.special_folder_type != Geary.SpecialFolderType.TRASH
             && !current_folder.properties.is_local_only && current_account != null
             && (current_folder as Geary.FolderSupport.Move) != null);
     }
-    
+
     public bool confirm_delete(int num_messages) {
         main_window.present();
         AlertDialog dialog = new ConfirmationDialog(main_window, ngettext(
             "Do you want to permanently delete this message?",
             "Do you want to permanently delete these messages?", num_messages),
             null, _("Delete"));
-        
+
         return (dialog.run() == Gtk.ResponseType.OK);
     }
-    
+
     private async void archive_or_delete_selection_async(bool archive, bool trash,
         Cancellable? cancellable) throws Error {
         if (!can_switch_conversation_view())
             return;
-        
+
         if (main_window.conversation_viewer.current_conversation != null
             && main_window.conversation_viewer.current_conversation == last_deleted_conversation) {
             debug("Not archiving/trashing/deleting; viewed conversation is last deleted conversation");
             return;
         }
-        
+
         last_deleted_conversation = selected_conversations.size > 0
             ? Geary.traverse<Geary.App.Conversation>(selected_conversations).first() : null;
-        
+
         // Return focus to the conversation list from the clicked toolbar button.
         main_window.conversation_list_view.grab_focus();
-        
+
         Gee.List<Geary.EmailIdentifier> ids = get_selected_email_ids(false);
         if (archive) {
             debug("Archiving selected messages");
-            
+
             Geary.FolderSupport.Archive? supports_archive = current_folder as Geary.FolderSupport.Archive;
             if (supports_archive == null) {
                 debug("Folder %s doesn't support archive", current_folder.to_string());
@@ -2521,13 +2520,13 @@ public class GearyController : Geary.BaseObject {
                 save_revokable(yield supports_archive.archive_email_async(ids, cancellable),
                     _("Undo archive (Ctrl+Z)"));
             }
-            
+
             return;
         }
-        
+
         if (trash) {
             debug("Trashing selected messages");
-            
+
             if (current_folder_supports_trash()) {
                 Geary.FolderPath trash_path = (yield current_account.get_required_special_folder_async(
                     Geary.SpecialFolderType.TRASH, cancellable)).path;
@@ -2535,18 +2534,18 @@ public class GearyController : Geary.BaseObject {
                 if (supports_move != null) {
                     save_revokable(yield supports_move.move_email_async(ids, trash_path, cancellable),
                         _("Undo trash (Ctrl+Z)"));
-                    
+
                     return;
                 }
             }
-            
+
             debug("Folder %s doesn't support move or account %s doesn't have a trash folder",
                 current_folder.to_string(), current_account.to_string());
             return;
         }
-        
+
         debug("Deleting selected messages");
-        
+
         Geary.FolderSupport.Remove? supports_remove = current_folder as Geary.FolderSupport.Remove;
         if (supports_remove == null) {
             debug("Folder %s doesn't support remove", current_folder.to_string());
@@ -2557,7 +2556,7 @@ public class GearyController : Geary.BaseObject {
                 last_deleted_conversation = null;
         }
     }
-    
+
     private void on_archive_or_delete_selection_finished(Object? source, AsyncResult result) {
         try {
             archive_or_delete_selection_async.end(result);
@@ -2565,72 +2564,72 @@ public class GearyController : Geary.BaseObject {
             debug("Unable to archive/trash/delete messages: %s", e.message);
         }
     }
-    
+
     private void save_revokable(Geary.Revokable? new_revokable, string? description) {
         // disconnect old revokable & blindly commit it
         if (revokable != null) {
             revokable.notify[Geary.Revokable.PROP_VALID].disconnect(on_revokable_valid_changed);
             revokable.notify[Geary.Revokable.PROP_IN_PROCESS].disconnect(update_revokable_action);
             revokable.committed.disconnect(on_revokable_committed);
-            
+
             revokable.commit_async.begin();
         }
-        
+
         // store new revokable
         revokable = new_revokable;
-        
+
         // connect to new revokable
         if (revokable != null) {
             revokable.notify[Geary.Revokable.PROP_VALID].connect(on_revokable_valid_changed);
             revokable.notify[Geary.Revokable.PROP_IN_PROCESS].connect(update_revokable_action);
             revokable.committed.connect(on_revokable_committed);
         }
-        
+
         Gtk.Action undo_action = GearyApplication.instance.get_action(ACTION_UNDO);
         undo_action.tooltip = (revokable != null && description != null) ? description : _("Undo (Ctrl+Z)");
-        
+
         update_revokable_action();
     }
-    
+
     private void update_revokable_action() {
         Gtk.Action undo_action = GearyApplication.instance.get_action(ACTION_UNDO);
         undo_action.sensitive = revokable != null && revokable.valid && !revokable.in_process;
     }
-    
+
     private void on_revokable_valid_changed() {
         // remove revokable if it goes invalid
         if (revokable != null && !revokable.valid)
             save_revokable(null, null);
     }
-    
+
     private void on_revokable_committed(Geary.Revokable? committed_revokable) {
         if (committed_revokable == null)
             return;
-        
+
         // use existing description
         Gtk.Action undo_action = GearyApplication.instance.get_action(ACTION_UNDO);
         save_revokable(committed_revokable, undo_action.tooltip);
     }
-    
+
     private void on_revoke() {
         if (revokable != null && revokable.valid)
             revokable.revoke_async.begin(null, on_revoke_completed);
     }
-    
+
     private void on_revoke_completed(Object? object, AsyncResult result) {
         // Don't use the "revokable" instance because it might have gone null before this callback
         // was reached
         Geary.Revokable? origin = object as Geary.Revokable;
         if (origin == null)
             return;
-        
+
         try {
             origin.revoke_async.end(result);
         } catch (Error err) {
             debug("Unable to revoke operation: %s", err.message);
         }
     }
-    
+
     private void on_zoom_in() {
         main_window.conversation_viewer.web_view.zoom_in();
     }
@@ -2642,19 +2641,19 @@ public class GearyController : Geary.BaseObject {
     private void on_zoom_normal() {
         main_window.conversation_viewer.web_view.zoom_level = 1.0f;
     }
-    
+
     private void on_search() {
         main_window.search_bar.give_search_focus();
     }
-    
+
     private void on_conversation_list() {
         main_window.conversation_list_view.grab_focus();
     }
-    
+
     private void on_sent(Geary.RFC822.Message rfc822) {
         Libnotify.play_sound("message-sent-email");
     }
-    
+
     private void on_link_selected(string link) {
         if (link.down().has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
             compose_mailto(link);
@@ -2666,7 +2665,7 @@ public class GearyController : Geary.BaseObject {
     // Disables all single-message buttons and enables all multi-message buttons.
     public void enable_multiple_message_buttons() {
         update_tooltips();
-        
+
         // Single message only buttons.
         GearyApplication.instance.actions.get_action(ACTION_REPLY_TO_MESSAGE).sensitive = false;
         GearyApplication.instance.actions.get_action(ACTION_REPLY_ALL_MESSAGE).sensitive = false;
@@ -2681,7 +2680,7 @@ public class GearyController : Geary.BaseObject {
             current_folder_supports_trash();
         GearyApplication.instance.actions.get_action(ACTION_DELETE_MESSAGE).sensitive =
             (current_folder is Geary.FolderSupport.Remove);
-        
+
         cancel_context_dependent_buttons();
         enable_context_dependent_buttons_async.begin(true, cancellable_context_dependent_buttons);
     }
@@ -2689,12 +2688,12 @@ public class GearyController : Geary.BaseObject {
     // Enables or disables the message buttons on the toolbar.
     public void enable_message_buttons(bool sensitive) {
         update_tooltips();
-        
+
         // No reply/forward in drafts folder.
         bool respond_sensitive = sensitive;
         if (current_folder != null && current_folder.special_folder_type == Geary.SpecialFolderType.DRAFTS)
             respond_sensitive = false;
-        
+
         GearyApplication.instance.actions.get_action(ACTION_REPLY_TO_MESSAGE).sensitive = respond_sensitive;
         GearyApplication.instance.actions.get_action(ACTION_REPLY_ALL_MESSAGE).sensitive = respond_sensitive;
         GearyApplication.instance.actions.get_action(ACTION_FORWARD_MESSAGE).sensitive = respond_sensitive;
@@ -2706,11 +2705,11 @@ public class GearyController : Geary.BaseObject {
             && current_folder_supports_trash();
         GearyApplication.instance.actions.get_action(ACTION_DELETE_MESSAGE).sensitive = sensitive
             && (current_folder is Geary.FolderSupport.Remove);
-        
+
         cancel_context_dependent_buttons();
         enable_context_dependent_buttons_async.begin(sensitive, cancellable_context_dependent_buttons);
     }
-    
+
     private async void enable_context_dependent_buttons_async(bool sensitive, Cancellable? cancellable) {
         Gee.MultiMap<Geary.EmailIdentifier, Type>? selected_operations = null;
         try {
@@ -2725,32 +2724,32 @@ public class GearyController : Geary.BaseObject {
             debug("Error checking for what operations are supported in the selected conversations: %s",
                 e.message);
         }
-        
+
         // Exit here if the user has cancelled.
         if (cancellable != null && cancellable.is_cancelled())
             return;
-        
+
         Gee.HashSet<Type> supported_operations = new Gee.HashSet<Type>();
         if (selected_operations != null)
             supported_operations.add_all(selected_operations.get_values());
-        
+
         GearyApplication.instance.actions.get_action(ACTION_MARK_AS_MENU).sensitive =
             sensitive && (supported_operations.contains(typeof(Geary.FolderSupport.Mark)));
         GearyApplication.instance.actions.get_action(ACTION_COPY_MENU).sensitive =
             sensitive && (supported_operations.contains(typeof(Geary.FolderSupport.Copy)));
     }
-    
+
     // Updates tooltip text depending on number of conversations selected.
     private void update_tooltips() {
         bool single = selected_conversations.size == 1;
-        
+
         GearyApplication.instance.actions.get_action(ACTION_MARK_AS_MENU).tooltip = single ?
             MARK_MESSAGE_MENU_TOOLTIP_SINGLE : MARK_MESSAGE_MENU_TOOLTIP_MULTIPLE;
         GearyApplication.instance.actions.get_action(ACTION_COPY_MENU).tooltip = single ?
             LABEL_MESSAGE_TOOLTIP_SINGLE : LABEL_MESSAGE_TOOLTIP_MULTIPLE;
         GearyApplication.instance.actions.get_action(ACTION_MOVE_MENU).tooltip = single ?
             MOVE_MESSAGE_TOOLTIP_SINGLE : MOVE_MESSAGE_TOOLTIP_MULTIPLE;
-        
+
         GearyApplication.instance.actions.get_action(ACTION_ARCHIVE_MESSAGE).tooltip = single ?
             ARCHIVE_MESSAGE_TOOLTIP_SINGLE : ARCHIVE_MESSAGE_TOOLTIP_MULTIPLE;
         GearyApplication.instance.actions.get_action(ACTION_TRASH_MESSAGE).tooltip = single ?
@@ -2758,27 +2757,27 @@ public class GearyController : Geary.BaseObject {
         GearyApplication.instance.actions.get_action(ACTION_DELETE_MESSAGE).tooltip = single ?
             DELETE_MESSAGE_TOOLTIP_SINGLE : DELETE_MESSAGE_TOOLTIP_MULTIPLE;
     }
-    
+
     public void compose_mailto(string mailto) {
         if (current_account == null) {
             // Schedule the send for after we have an account open.
             pending_mailtos.add(mailto);
-            
+
             return;
         }
-        
+
         create_compose_widget(ComposerWidget.ComposeType.NEW_MESSAGE, null, null, mailto);
     }
-    
+
     // Returns a list of composer windows for an account, or null if none.
     public Gee.List<ComposerWidget>? get_composer_widgets_for_account(Geary.AccountInformation account) {
         Gee.LinkedList<ComposerWidget> ret = Geary.traverse<ComposerWidget>(composer_widgets)
             .filter(w => w.account.information == account)
             .to_linked_list();
-        
+
         return ret.size >= 1 ? ret : null;
     }
-    
+
     private void do_search(string search_text) {
         Geary.SearchFolder? folder = null;
         try {
@@ -2786,76 +2785,76 @@ public class GearyController : Geary.BaseObject {
                 Geary.SpecialFolderType.SEARCH);
         } catch (Error e) {
             debug("Could not get search folder: %s", e.message);
-            
+
             return;
         }
-        
+
         if (search_text == "") {
             if (previous_non_search_folder != null && current_folder is Geary.SearchFolder)
                 main_window.folder_list.select_folder(previous_non_search_folder);
-            
+
             main_window.folder_list.remove_search();
             search_text_changed("");
             folder.clear();
-            
+
             return;
         }
-        
+
         if (current_account == null)
             return;
-        
+
         cancel_search(); // Stop any search in progress.
-        
+
         folder.search(search_text, GearyApplication.instance.config.get_search_strategy(),
             cancellable_search);
-        
+
         main_window.folder_list.set_search(folder);
         search_text_changed(main_window.search_bar.search_text);
     }
-    
+
     private void on_search_text_changed(string search_text) {
         // So we don't thrash the disk as the user types, we run the actual
         // search after a quick delay when they finish typing.
         if (search_timeout_id != 0)
             Source.remove(search_timeout_id);
-        
+
         search_timeout_id = Timeout.add(SEARCH_TIMEOUT_MSEC, on_search_timeout, Priority.LOW);
     }
-    
+
     private bool on_search_timeout() {
         search_timeout_id = 0;
-        
+
         do_search(main_window.search_bar.search_text);
-        
+
         return false;
     }
-    
+
     /**
      * Returns a read-only set of currently selected conversations.
      */
     public Gee.Set<Geary.App.Conversation> get_selected_conversations() {
         return selected_conversations.read_only_view;
     }
-    
+
     // Find the first inbox we know about and switch to it.
     private void switch_to_first_inbox() {
         try {
             if (Geary.Engine.instance.get_accounts().values.size == 0)
                 return; // No account!
-            
+
             // Look through our accounts, grab the first inbox we can find.
             Geary.Folder? first_inbox = null;
-            
+
             foreach(Geary.AccountInformation info in Geary.Engine.instance.get_accounts().values) {
                 first_inbox = get_account_instance(info).get_special_folder(Geary.SpecialFolderType.INBOX);
-                
+
                 if (first_inbox != null)
                     break;
             }
-            
+
             if (first_inbox == null)
                 return;
-            
+
             // Attempt the selection.  Try the inboxes branch first.
             if (!main_window.folder_list.select_inbox(first_inbox.account))
                 main_window.folder_list.select_folder(first_inbox);
diff --git a/src/client/components/main-toolbar.vala b/src/client/components/main-toolbar.vala
index cef2e3a..3719600 100644
--- a/src/client/components/main-toolbar.vala
+++ b/src/client/components/main-toolbar.vala
@@ -53,8 +53,6 @@ public class MainToolbar : Gtk.Box {
         this.bind_property("show-close-button-right", conversation_header, "show-close-button",
             BindingFlags.SYNC_CREATE);
 
-        bool rtl = get_direction() == Gtk.TextDirection.RTL;
-
         // Assemble mark menu.
         GearyApplication.instance.load_ui_file("toolbar_mark_menu.ui");
         Gtk.Menu mark_menu = (Gtk.Menu) 
GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMarkMenu");
@@ -94,14 +92,20 @@ public class MainToolbar : Gtk.Box {
         folder_header.add_end(new Gtk.Separator(Gtk.Orientation.VERTICAL));
 
         // Reply buttons
-        insert.clear();
-        insert.add(conversation_header.create_toolbar_button(rtl ? "mail-reply-sender-rtl-symbolic"
-            : "mail-reply-sender-symbolic", GearyController.ACTION_REPLY_TO_MESSAGE));
-        insert.add(conversation_header.create_toolbar_button(rtl ? "mail-reply-all-rtl-symbolic"
-            : "mail-reply-all-symbolic", GearyController.ACTION_REPLY_ALL_MESSAGE));
-        insert.add(conversation_header.create_toolbar_button(rtl ? "mail-forward-rtl-symbolic"
-            : "mail-forward-symbolic", GearyController.ACTION_FORWARD_MESSAGE));
-        conversation_header.add_start(conversation_header.create_pill_buttons(insert));
+        Gtk.Button reply = new Gtk.Button();
+        reply.related_action = 
GearyApplication.instance.actions.get_action(GearyController.ACTION_REPLY_TO_MESSAGE);
+        reply.tooltip_text = reply.related_action.tooltip;
+        reply.image = new Gtk.Image.from_icon_name("mail-reply-sender", Gtk.IconSize.LARGE_TOOLBAR); 
//FIXME: For some reason doing Button.from_icon_name doesn't work
+
+        Gtk.Button reply_all = new Gtk.Button();
+        reply_all.related_action = 
GearyApplication.instance.actions.get_action(GearyController.ACTION_REPLY_ALL_MESSAGE);
+        reply_all.tooltip_text = reply_all.related_action.tooltip;
+        reply_all.image = new Gtk.Image.from_icon_name("mail-reply-all", Gtk.IconSize.LARGE_TOOLBAR); 
//FIXME: For some reason doing Button.from_icon_name doesn't work
+
+        Gtk.Button forward = new Gtk.Button();
+        forward.related_action = 
GearyApplication.instance.actions.get_action(GearyController.ACTION_FORWARD_MESSAGE);
+        forward.tooltip_text = forward.related_action.tooltip;
+        forward.image = new Gtk.Image.from_icon_name("mail-forward", Gtk.IconSize.LARGE_TOOLBAR); //FIXME: 
For some reason doing Button.from_icon_name doesn't work
 
         // Mark, copy, move.
         Gtk.MenuButton mark = new Gtk.MenuButton();
@@ -119,6 +123,9 @@ public class MainToolbar : Gtk.Box {
         move.popup = move_folder_menu;
         move.tooltip_text = _("Move conversation");
 
+        conversation_header.pack_start(reply);
+        conversation_header.pack_start(reply_all);
+        conversation_header.pack_start(forward);
         conversation_header.pack_start(mark);
         conversation_header.pack_start(tag);
         conversation_header.pack_start(move);
@@ -128,9 +135,10 @@ public class MainToolbar : Gtk.Box {
         trash_delete.tooltip_text = trash_delete.related_action.tooltip;
         trash_delete.image = new Gtk.Image.from_icon_name("edit-delete", Gtk.IconSize.LARGE_TOOLBAR); 
//FIXME: For some reason doing Button.from_icon_name doesn't work
 
-        insert.clear();
-        insert.add(archive_button = conversation_header.create_toolbar_button(null, 
GearyController.ACTION_ARCHIVE_MESSAGE, true));
-        Gtk.Box archive_trash_delete = conversation_header.create_pill_buttons(insert);
+        Gtk.Button archive = new Gtk.Button();
+        archive.related_action = 
GearyApplication.instance.actions.get_action(GearyController.ACTION_ARCHIVE_MESSAGE);
+        archive.tooltip_text = archive.related_action.tooltip;
+        archive.image = new Gtk.Image.from_icon_name("mail-archive", Gtk.IconSize.LARGE_TOOLBAR); //FIXME: 
For some reason doing Button.from_icon_name doesn't work
 
         Gtk.Button undo = new Gtk.Button();
         undo.related_action = GearyApplication.instance.actions.get_action(GearyController.ACTION_UNDO);
@@ -138,7 +146,6 @@ public class MainToolbar : Gtk.Box {
         undo.related_action.notify["tooltip"].connect(() => { undo.tooltip_text = 
undo.related_action.tooltip; });
         undo.image = new Gtk.Image.from_icon_name("edit-undo", Gtk.IconSize.LARGE_TOOLBAR); //FIXME: For 
some reason doing Button.from_icon_name doesn't work
 
-
         Gtk.MenuButton menu = new Gtk.MenuButton();
         menu.image = new Gtk.Image.from_icon_name("open-menu", Gtk.IconSize.LARGE_TOOLBAR);
         menu.popup = new Gtk.Menu.from_model(GearyApplication.instance.controller.app_menu);
@@ -146,7 +153,7 @@ public class MainToolbar : Gtk.Box {
 
         conversation_header.pack_end(menu);
         conversation_header.pack_end(undo);
-        conversation_header.add_end(archive_trash_delete);
+        conversation_header.pack_end(archive);
         conversation_header.pack_end(trash_delete);
 
         pack_start(folder_header, false, false);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]