From 730b33d806aea9653eb656e3be4adcd73c10dfd6 Mon Sep 17 00:00:00 2001 From: Charles Lindsay Date: Fri, 4 Apr 2014 13:01:01 -0700 Subject: [PATCH] Don't save draft when UIDPLUS is not present: Closes bgo#713983 Without UIDPLUS Geary currently cannot determine the UID of the drafts it saves to the server, and so it cannot delete them when the draft is saved again or the message is sent. This patch simply checks if UIDPLUS is supported, and if not, does not save the draft to the server. Although a string is included in this patch, it's a duplicate of an existing string and so technically does not break string freeze. --- src/client/composer/composer-window.vala | 37 ++++++++++++++----- .../geary-aggregated-folder-properties.vala | 2 +- src/engine/api/geary-folder-properties.vala | 11 +++++- src/engine/api/geary-search-folder.vala | 2 +- .../outbox/smtp-outbox-folder-properties.vala | 2 +- .../imap/api/imap-folder-properties.vala | 8 +++- src/engine/imap/api/imap-folder.vala | 2 + 7 files changed, 49 insertions(+), 15 deletions(-) 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) {