geary/src/engine/imap-engine/replay-ops/imap-engine-create-email.vala
Michael Gratton 744cde0c2f Don't update a folder's unread email count during normalisation
Updating the unread count after opening a folder and finding email that
has an unexpected unread status messes up the count obtained from the
server, which has already taken these messages into account.

Here, both the main normalisation process and the email flag updater are
prevented from adjusting the unread count for a folder when they
encounter email that are new and unread, or have an unread status
different from what was last seen by the engine.

See #213
2019-02-15 13:40:04 +11:00

79 lines
3 KiB
Vala

/* 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.
*/
private class Geary.ImapEngine.CreateEmail : Geary.ImapEngine.SendReplayOperation {
public Geary.EmailIdentifier? created_id { get; private set; default = null; }
private MinimalFolder engine;
private RFC822.Message? rfc822;
private Geary.EmailFlags? flags;
private DateTime? date_received;
private Cancellable? cancellable;
public CreateEmail(MinimalFolder engine, RFC822.Message rfc822, Geary.EmailFlags? flags,
DateTime? date_received, Cancellable? cancellable) {
base.only_remote("CreateEmail", OnError.RETRY);
this.engine = engine;
this.rfc822 = rfc822;
this.flags = flags;
this.date_received = date_received;
this.cancellable = cancellable;
}
public override async void replay_remote_async(Imap.FolderSession remote)
throws GLib.Error {
// Deal with cancellable manually since create_email_async cannot be cancelled.
if (cancellable.is_cancelled())
throw new IOError.CANCELLED("CreateEmail op cancelled immediately");
// use IMAP APPEND command on remote folders, which doesn't require opening a folder ...
// if retrying after a successful create, rfc822 will be null
if (rfc822 != null)
created_id = yield remote.create_email_async(rfc822, flags, date_received);
// because this command retries, the create completed, remove the RFC822 message to prevent
// creating it twice
rfc822 = null;
// If the user cancelled the operation, we need to wipe the new message to keep this
// operation atomic.
if (cancellable.is_cancelled()) {
if (created_id != null) {
yield remote.remove_email_async(
new Imap.MessageSet.uid(((ImapDB.EmailIdentifier) created_id).uid).to_list(),
null
);
}
throw new IOError.CANCELLED("CreateEmail op cancelled after create");
}
if (created_id != null) {
// TODO: need to prevent gaps that may occur here
Geary.Email created = new Geary.Email(created_id);
Gee.Map<Geary.Email, bool> results =
yield this.engine.local_folder.create_or_merge_email_async(
Geary.iterate<Geary.Email>(created).to_array_list(),
true,
this.cancellable
);
if (results.size > 0) {
created_id = Collection.get_first<Geary.Email>(results.keys).id;
} else {
created_id = null;
}
}
}
public override string describe_state() {
return "created_id: %s".printf(
this.created_id != null ? this.created_id.to_string() : "none"
);
}
}