Merge branch 'wip/76-gmail-drafts' into 'mainline'

Don't support removing an email when creating another

Closes #76

See merge request GNOME/geary!279
This commit is contained in:
Michael Gratton 2019-09-25 11:54:42 +00:00
commit 1ea567821c
8 changed files with 107 additions and 102 deletions

View file

@ -2,7 +2,7 @@
* Copyright 2016 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
* (version 2.1 or later). See the COPYING file in this distribution.
*/
/**
@ -30,17 +30,12 @@ public interface Geary.FolderSupport.Create : Folder {
* time to be set when saved. Like EmailFlags, this is optional
* if not applicable.
*
* If an id is passed, this will replace the existing message by
* deleting it after the new message is created. The new
* message's ID is returned.
*
* @see FolderProperties.create_never_returns_id
*/
public abstract async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
EmailFlags? flags,
DateTime? date_received,
EmailIdentifier? id,
GLib.Cancellable? cancellable = null)
throws GLib.Error;

View file

@ -408,8 +408,13 @@ public class Geary.App.DraftManager : BaseObject {
return false;
// make sure there's a folder to work with
if (drafts_folder == null || drafts_folder.get_open_state() == Folder.OpenState.CLOSED) {
fatal(new EngineError.SERVER_UNAVAILABLE("%s: premature drafts folder close", to_string()));
if (this.drafts_folder == null ||
this.drafts_folder.get_open_state() == CLOSED) {
fatal(
new EngineError.SERVER_UNAVAILABLE(
"%s: premature drafts folder close", to_string()
)
);
return false;
}
@ -417,44 +422,48 @@ public class Geary.App.DraftManager : BaseObject {
// at this point, only operation left is PUSH
assert(op.op_type == OperationType.PUSH);
draft_state = DraftState.STORING;
// delete old draft for all PUSHes: best effort ... since create_email_async() will handle
// replacement in a transactional-kinda-way, only outright delete if not using create
if (current_draft_id != null && op.draft == null) {
bool success = false;
try {
yield remove_support.remove_email_async(
iterate<EmailIdentifier>(current_draft_id).to_array_list());
success = true;
} catch (Error err) {
debug("%s: Unable to remove existing draft %s: %s", to_string(), current_draft_id.to_string(),
err.message);
}
// always clear draft id (assuming that retrying a failed remove is unnecessary), but
// only signal the discard if it actually was removed
current_draft_id = null;
if (success)
notify_discarded();
}
this.draft_state = DraftState.STORING;
// if draft supplied, save it
if (op.draft != null) {
try {
current_draft_id = yield create_support.create_email_async(op.draft, op.flags,
op.date_received, current_draft_id, null);
EmailIdentifier? old_id = this.current_draft_id;
this.current_draft_id =
yield this.create_support.create_email_async(
op.draft,
op.flags,
op.date_received,
null
);
yield this.remove_support.remove_email_async(
Collection.single(old_id), null
);
draft_state = DraftState.STORED;
this.draft_state = DraftState.STORED;
notify_stored(op.draft);
} catch (Error err) {
draft_state = DraftState.ERROR;
// notify subscribers
} catch (GLib.Error err) {
this.draft_state = DraftState.ERROR;
draft_failed(op.draft, err);
}
} else {
draft_state = DraftState.NOT_STORED;
this.draft_state = DraftState.NOT_STORED;
// Delete the old draft if present so it's not hanging
// around
if (this.current_draft_id != null) {
try {
yield this.remove_support.remove_email_async(
Collection.single(this.current_draft_id),
null
);
notify_discarded();
} catch (GLib.Error err) {
warning("%s: Unable to remove existing draft %s: %s",
to_string(),
current_draft_id.to_string(),
err.message);
}
}
}
return true;
@ -463,5 +472,12 @@ public class Geary.App.DraftManager : BaseObject {
public string to_string() {
return "%s DraftManager".printf(account.to_string());
}
}
private async void save_draft(EmailIdentifier id) {
}
private async void remove_draft(EmailIdentifier id) {
}
}

View file

@ -1,32 +1,41 @@
/* Copyright 2016 Software Freedom Conservancy Inc.
/*
* Copyright 2016 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
* (version 2.1 or later). See the COPYING file in this distribution.
*/
/**
* Gmail's Drafts folder supports basic operations as well as true removal of messages and creating
* new ones (IMAP APPEND).
* A draft folder for Gmail.
*
* Gmail's drafts folders supports basic operations as well as true
* removal of messages and creating new ones (IMAP APPEND).
*/
private class Geary.ImapEngine.GmailDraftsFolder :
MinimalFolder, FolderSupport.Create, FolderSupport.Remove {
private class Geary.ImapEngine.GmailDraftsFolder : MinimalFolder, FolderSupport.Create,
FolderSupport.Remove {
public GmailDraftsFolder(GmailAccount account,
ImapDB.Folder local_folder,
SpecialFolderType special_folder_type) {
base (account, local_folder, special_folder_type);
base(account, local_folder, special_folder_type);
}
public new async Geary.EmailIdentifier? create_email_async(
RFC822.Message rfc822, Geary.EmailFlags? flags, DateTime? date_received,
Geary.EmailIdentifier? id, Cancellable? cancellable = null) throws Error {
return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
public new async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
EmailFlags? flags,
DateTime? date_received,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
return yield base.create_email_async(
rfc822, flags, date_received, cancellable
);
}
public async void remove_email_async(
Gee.Collection<Geary.EmailIdentifier> email_ids,
GLib.Cancellable? cancellable = null)
public async void
remove_email_async(Gee.Collection<EmailIdentifier> email_ids,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
yield GmailFolder.true_remove_email_async(this, email_ids, cancellable);
}
}

View file

@ -13,10 +13,15 @@ private class Geary.ImapEngine.GmailFolder : MinimalFolder, FolderSupport.Archiv
base (account, local_folder, special_folder_type);
}
public new async Geary.EmailIdentifier? create_email_async(
RFC822.Message rfc822, Geary.EmailFlags? flags, DateTime? date_received,
Geary.EmailIdentifier? id, Cancellable? cancellable = null) throws Error {
return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
public new async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
EmailFlags? flags,
DateTime? date_received,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
return yield base.create_email_async(
rfc822, flags, date_received, cancellable
);
}
public async Geary.Revokable?

View file

@ -48,9 +48,14 @@ private class Geary.ImapEngine.GenericFolder : MinimalFolder,
yield expunge_all_async(cancellable);
}
public new async Geary.EmailIdentifier? create_email_async(RFC822.Message rfc822,
Geary.EmailFlags? flags, DateTime? date_received, Geary.EmailIdentifier? id,
Cancellable? cancellable = null) throws Error {
return yield base.create_email_async(rfc822, flags, date_received, id, cancellable);
public new async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
EmailFlags? flags,
DateTime? date_received,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
return yield base.create_email_async(
rfc822, flags, date_received, cancellable
);
}
}

View file

@ -1458,58 +1458,34 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
return earliest;
}
protected async Geary.EmailIdentifier? create_email_async(RFC822.Message rfc822,
Geary.EmailFlags? flags, DateTime? date_received, Geary.EmailIdentifier? id,
Cancellable? cancellable = null) throws Error {
protected async EmailIdentifier?
create_email_async(RFC822.Message rfc822,
EmailFlags? flags,
DateTime? date_received,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
check_open("create_email_async");
if (id != null)
check_id("create_email_async", id);
CreateEmail op = new CreateEmail(
this, rfc822, flags, date_received, cancellable
);
replay_queue.schedule(op);
yield op.wait_for_ready_async(cancellable);
this._account.update_folder(this);
Error? cancel_error = null;
Geary.EmailIdentifier? ret = null;
try {
CreateEmail create = new CreateEmail(this, rfc822, flags, date_received, cancellable);
replay_queue.schedule(create);
yield create.wait_for_ready_async(cancellable);
ret = create.created_id;
} catch (Error e) {
if (e is IOError.CANCELLED)
cancel_error = e;
else
throw e;
}
Geary.FolderSupport.Remove? remove_folder = this as Geary.FolderSupport.Remove;
// Remove old message.
if (id != null && remove_folder != null)
yield remove_folder.remove_email_async(iterate<EmailIdentifier>(id).to_array_list());
// If the user cancelled the operation, throw the error here.
if (cancel_error != null)
throw cancel_error;
// If the caller cancelled during the remove operation, delete the newly created message to
// safely back out.
if (cancellable != null && cancellable.is_cancelled() && ret != null && remove_folder != null)
yield remove_folder.remove_email_async(iterate<EmailIdentifier>(ret).to_array_list());
if (ret != null) {
if (op.created_id != null) {
// Server returned a UID for the new message. It was saved
// locally possibly before the server notified that the
// message exists. As such, fetch any missing parts from
// the remote to ensure it is properly filled in.
yield list_email_by_id_async(
ret, 1, ALL, INCLUDING_ID, cancellable
op.created_id, 1, ALL, INCLUDING_ID, cancellable
);
} else {
// The server didn't return a UID for the new email, so do
// a sync now to ensure it shows up immediately.
yield synchronise_remote(cancellable);
}
return ret;
return op.created_id;
}
/** Fires a {@link marked_email_removed} signal for this folder. */

View file

@ -112,7 +112,6 @@ private class Geary.Outbox.Folder :
create_email_async(RFC822.Message rfc822,
Geary.EmailFlags? flags,
GLib.DateTime? date_received,
Geary.EmailIdentifier? id = null,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
check_open();

View file

@ -87,7 +87,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
debug("Queuing message for sending: %s", message_subject(rfc822));
EmailIdentifier id = yield this.outbox.create_email_async(
rfc822, null, null, null, cancellable
rfc822, null, null, cancellable
);
this.outbox_queue.send(id);
}
@ -330,7 +330,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
try {
yield create.open_async(NO_DELAY, cancellable);
open = true;
yield create.create_email_async(raw, null, null, null, cancellable);
yield create.create_email_async(raw, null, null, cancellable);
yield wait_for_message(create, message, cancellable);
} finally {
if (open) {