diff --git a/src/client/composer/composer-window.vala b/src/client/composer/composer-window.vala index d0a83e43..7351e2f8 100644 --- a/src/client/composer/composer-window.vala +++ b/src/client/composer/composer-window.vala @@ -667,28 +667,39 @@ public class ComposerWindow : Gtk.Window { update_from_field(); } + private bool can_save() { + return (drafts_folder != null && drafts_folder.get_open_state() == Geary.Folder.OpenState.BOTH + && !drafts_folder.properties.create_never_returns_id && editor.can_undo()); + } + public bool should_close() { - if (!editor.can_undo()) - return true; + bool try_to_save = can_save(); present(); AlertDialog dialog; - if (drafts_folder == null) { + if (drafts_folder == null && try_to_save) { dialog = new ConfirmationDialog(this, _("Do you want to discard the unsaved message?"), null, Stock._DISCARD); - } else { + } else if (try_to_save) { dialog = new TernaryConfirmationDialog(this, _("Do you want to discard this message?"), null, Stock._KEEP, Stock._DISCARD, Gtk.ResponseType.CLOSE); + } else { + dialog = new ConfirmationDialog(this, + _("Do you want to discard this message?"), null, Stock._DISCARD); } Gtk.ResponseType response = dialog.run(); if (response == Gtk.ResponseType.CANCEL || response == Gtk.ResponseType.DELETE_EVENT) { return false; // Cancel } else if (response == Gtk.ResponseType.OK) { - save_and_exit.begin(); // Save - return false; + if (try_to_save) { + save_and_exit.begin(); // Save + return false; + } else { + return true; + } } else { delete_and_exit.begin(); // Discard return false; @@ -798,6 +809,11 @@ public class ComposerWindow : Gtk.Window { destroy(); // Only close window after draft is deleted; this closes the drafts folder. } + private void on_drafts_opened(Geary.Folder.OpenState open_state, int count) { + if (open_state == Geary.Folder.OpenState.BOTH) + reset_draft_timer(); + } + // Returns the drafts folder for the current From account. private async void open_drafts_folder_async(Cancellable cancellable) throws Error { yield close_drafts_folder_async(cancellable); @@ -808,9 +824,11 @@ public class ComposerWindow : Gtk.Window { if (folder == null) return; // No drafts folder. - yield folder.open_async(Geary.Folder.OpenFlags.FAST_OPEN, cancellable); + yield folder.open_async(Geary.Folder.OpenFlags.FAST_OPEN | Geary.Folder.OpenFlags.NO_DELAY, + cancellable); drafts_folder = folder; + drafts_folder.opened.connect(on_drafts_opened); } private async void close_drafts_folder_async(Cancellable? cancellable = null) throws Error { @@ -818,6 +836,7 @@ public class ComposerWindow : Gtk.Window { return; // Close existing folder. + drafts_folder.opened.disconnect(on_drafts_opened); yield drafts_folder.close_async(cancellable); drafts_folder = null; } @@ -835,7 +854,7 @@ public class ComposerWindow : Gtk.Window { } private async void save_async(Cancellable? cancellable) { - if (drafts_folder == null) + if (drafts_folder == null || !can_save()) return; draft_save_label.label = DRAFT_SAVING_TEXT; @@ -1555,7 +1574,7 @@ public class ComposerWindow : Gtk.Window { // Resets the draft save timeout. private void reset_draft_timer() { - if (!editor.can_undo()) + if (!can_save()) return; draft_save_label.label = ""; diff --git a/src/engine/api/geary-aggregated-folder-properties.vala b/src/engine/api/geary-aggregated-folder-properties.vala index ea165e25..986b9e6c 100644 --- a/src/engine/api/geary-aggregated-folder-properties.vala +++ b/src/engine/api/geary-aggregated-folder-properties.vala @@ -23,7 +23,7 @@ private class Geary.AggregatedFolderProperties : Geary.FolderProperties { */ public AggregatedFolderProperties(bool is_local_only, bool is_virtual) { // Set defaults. - base(0, 0, Trillian.UNKNOWN, Trillian.UNKNOWN, Trillian.UNKNOWN, is_local_only, is_virtual); + base(0, 0, Trillian.UNKNOWN, Trillian.UNKNOWN, Trillian.UNKNOWN, is_local_only, is_virtual, false); } /** diff --git a/src/engine/api/geary-folder-properties.vala b/src/engine/api/geary-folder-properties.vala index f40cf7cb..2f571da6 100644 --- a/src/engine/api/geary-folder-properties.vala +++ b/src/engine/api/geary-folder-properties.vala @@ -59,8 +59,16 @@ public abstract class Geary.FolderProperties : BaseObject { */ public bool is_virtual { get; private set; } + /** + * True if APPEND on the folder will never return the created UID. This is + * for servers that don't support UIDPLUS. Most servers support UIDPLUS, + * so this will usually be false. + */ + public bool create_never_returns_id { get; protected set; } + protected FolderProperties(int email_total, int email_unread, Trillian has_children, - Trillian supports_children, Trillian is_openable, bool is_local_only, bool is_virtual) { + Trillian supports_children, Trillian is_openable, bool is_local_only, bool is_virtual, + bool create_never_returns_id) { this.email_total = email_total; this.email_unread = email_unread; this.has_children = has_children; @@ -68,6 +76,7 @@ public abstract class Geary.FolderProperties : BaseObject { this.is_openable = is_openable; this.is_local_only = is_local_only; this.is_virtual = is_virtual; + this.create_never_returns_id = create_never_returns_id; } } diff --git a/src/engine/api/geary-search-folder.vala b/src/engine/api/geary-search-folder.vala index 518b409a..672853f8 100644 --- a/src/engine/api/geary-search-folder.vala +++ b/src/engine/api/geary-search-folder.vala @@ -14,7 +14,7 @@ public class Geary.SearchFolderRoot : Geary.FolderRoot { public class Geary.SearchFolderProperties : Geary.FolderProperties { public SearchFolderProperties(int total, int unread) { - base(total, unread, Trillian.FALSE, Trillian.FALSE, Trillian.TRUE, true, true); + base(total, unread, Trillian.FALSE, Trillian.FALSE, Trillian.TRUE, true, true, false); } public void set_total(int total) { diff --git a/src/engine/imap-db/outbox/smtp-outbox-folder-properties.vala b/src/engine/imap-db/outbox/smtp-outbox-folder-properties.vala index 18734393..535e3efa 100644 --- a/src/engine/imap-db/outbox/smtp-outbox-folder-properties.vala +++ b/src/engine/imap-db/outbox/smtp-outbox-folder-properties.vala @@ -6,7 +6,7 @@ private class Geary.SmtpOutboxFolderProperties : Geary.FolderProperties { public SmtpOutboxFolderProperties(int total, int unread) { - base (total, unread, Trillian.FALSE, Trillian.FALSE, Trillian.TRUE, true, false); + base (total, unread, Trillian.FALSE, Trillian.FALSE, Trillian.TRUE, true, false, false); } public void set_total(int total) { diff --git a/src/engine/imap/api/imap-folder-properties.vala b/src/engine/imap/api/imap-folder-properties.vala index 4b7b4b34..c0621863 100644 --- a/src/engine/imap/api/imap-folder-properties.vala +++ b/src/engine/imap/api/imap-folder-properties.vala @@ -67,7 +67,7 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties { // give the base class a zero email_unread, as the notion of "unknown" doesn't exist in // its contract base (messages, email_unread, Trillian.UNKNOWN, Trillian.UNKNOWN, Trillian.UNKNOWN, false, - false); + false, false); select_examine_messages = messages; status_messages = -1; @@ -82,7 +82,7 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties { public FolderProperties.status(StatusData status, MailboxAttributes attrs) { base (status.messages, status.unseen, Trillian.UNKNOWN, Trillian.UNKNOWN, Trillian.UNKNOWN, - false, false); + false, false, false); select_examine_messages = -1; status_messages = status.messages; @@ -213,5 +213,9 @@ public class Geary.Imap.FolderProperties : Geary.FolderProperties { // update base class value (which clients see) email_unread = count; } + + public void set_from_session_capabilities(Capabilities capabilities) { + create_never_returns_id = !capabilities.supports_uidplus(); + } } diff --git a/src/engine/imap/api/imap-folder.vala b/src/engine/imap/api/imap-folder.vala index 71741ad3..72c2c23c 100644 --- a/src/engine/imap/api/imap-folder.vala +++ b/src/engine/imap/api/imap-folder.vala @@ -95,6 +95,8 @@ private class Geary.Imap.Folder : BaseObject { session.status_response_received.connect(on_status_response); session.disconnected.connect(on_disconnected); + properties.set_from_session_capabilities(session.capabilities); + StatusResponse response = yield session.select_async( new MailboxSpecifier.from_folder_path(path, info.delim), cancellable); if (response.status != Status.OK) {