diff --git a/MailKit/Net/Imap/ImapFolder.cs b/MailKit/Net/Imap/ImapFolder.cs index 76803d84ba..780f17c082 100644 --- a/MailKit/Net/Imap/ImapFolder.cs +++ b/MailKit/Net/Imap/ImapFolder.cs @@ -331,32 +331,55 @@ static Task UntaggedQResyncFetchHandler (ImapEngine engine, ImapCommand ic, int return ic.Folder.OnUntaggedFetchResponse (engine, index, doAsync, ic.CancellationToken); } - async Task OpenAsync (ImapCommand ic, FolderAccess access, bool doAsync, CancellationToken cancellationToken) + ImapCommand QueueOpen (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, CancellationToken cancellationToken) { - Reset (); + if (access != FolderAccess.ReadOnly && access != FolderAccess.ReadWrite) + throw new ArgumentOutOfRangeException (nameof (access)); - if (access == FolderAccess.ReadWrite) { - // Note: if the server does not respond with a PERMANENTFLAGS response, - // then we need to assume all flags are permanent. - PermanentFlags = SettableFlags | MessageFlags.UserDefined; - } else { - PermanentFlags = MessageFlags.None; - } + if (uids == null) + throw new ArgumentNullException (nameof (uids)); - try { - Engine.QueueCommand (ic); + CheckState (false, false); - await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); + if ((Engine.Capabilities & ImapCapabilities.QuickResync) == 0) + throw new NotSupportedException ("The IMAP server does not support the QRESYNC extension."); - ProcessResponseCodes (ic, this); + if (!Supports (FolderFeature.QuickResync)) + throw new InvalidOperationException ("The QRESYNC extension has not been enabled."); - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create (access == FolderAccess.ReadOnly ? "EXAMINE" : "SELECT", ic); - } catch { - PermanentFlags = MessageFlags.None; - throw; + string qresync; + + if ((Engine.Capabilities & ImapCapabilities.Annotate) != 0 && Engine.QuirksMode != ImapQuirksMode.SunMicrosystems) + qresync = string.Format (CultureInfo.InvariantCulture, "(ANNOTATE QRESYNC ({0} {1}", uidValidity, highestModSeq); + else + qresync = string.Format (CultureInfo.InvariantCulture, "(QRESYNC ({0} {1}", uidValidity, highestModSeq); + + if (uids.Count > 0) { + var set = UniqueIdSet.ToString (uids); + qresync += " " + set; } + qresync += "))"; + + var command = string.Format ("{0} %F {1}\r\n", SelectOrExamine (access), qresync); + var ic = new ImapCommand (Engine, cancellationToken, this, command, this); + ic.RegisterUntaggedHandler ("FETCH", UntaggedQResyncFetchHandler); + + Engine.QueueCommand (ic); + + return ic; + } + + void ProcessOpenResponse (ImapCommand ic, FolderAccess access) + { + ProcessResponseCodes (ic, this); + + if (ic.Response != ImapCommandResponse.Ok) + throw ImapCommandException.Create (access == FolderAccess.ReadOnly ? "EXAMINE" : "SELECT", ic); + } + + FolderAccess Open () + { if (Engine.Selected != null && Engine.Selected != this) { var folder = Engine.Selected; @@ -373,41 +396,52 @@ async Task OpenAsync (ImapCommand ic, FolderAccess access, bool do return Access; } - Task OpenAsync (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, bool doAsync, CancellationToken cancellationToken) + FolderAccess Open (ImapCommand ic, FolderAccess access) { - if (access != FolderAccess.ReadOnly && access != FolderAccess.ReadWrite) - throw new ArgumentOutOfRangeException (nameof (access)); - - if (uids == null) - throw new ArgumentNullException (nameof (uids)); + Reset (); - CheckState (false, false); + if (access == FolderAccess.ReadWrite) { + // Note: if the server does not respond with a PERMANENTFLAGS response, + // then we need to assume all flags are permanent. + PermanentFlags = SettableFlags | MessageFlags.UserDefined; + } else { + PermanentFlags = MessageFlags.None; + } - if ((Engine.Capabilities & ImapCapabilities.QuickResync) == 0) - throw new NotSupportedException ("The IMAP server does not support the QRESYNC extension."); + try { + Engine.Run (ic); - if (!Supports (FolderFeature.QuickResync)) - throw new InvalidOperationException ("The QRESYNC extension has not been enabled."); + ProcessOpenResponse (ic, access); + } catch { + PermanentFlags = MessageFlags.None; + throw; + } - string qresync; + return Open (); + } - if ((Engine.Capabilities & ImapCapabilities.Annotate) != 0 && Engine.QuirksMode != ImapQuirksMode.SunMicrosystems) - qresync = string.Format (CultureInfo.InvariantCulture, "(ANNOTATE QRESYNC ({0} {1}", uidValidity, highestModSeq); - else - qresync = string.Format (CultureInfo.InvariantCulture, "(QRESYNC ({0} {1}", uidValidity, highestModSeq); + async Task OpenAsync (ImapCommand ic, FolderAccess access) + { + Reset (); - if (uids.Count > 0) { - var set = UniqueIdSet.ToString (uids); - qresync += " " + set; + if (access == FolderAccess.ReadWrite) { + // Note: if the server does not respond with a PERMANENTFLAGS response, + // then we need to assume all flags are permanent. + PermanentFlags = SettableFlags | MessageFlags.UserDefined; + } else { + PermanentFlags = MessageFlags.None; } - qresync += "))"; + try { + await Engine.RunAsync (ic).ConfigureAwait (false); - var command = string.Format ("{0} %F {1}\r\n", SelectOrExamine (access), qresync); - var ic = new ImapCommand (Engine, cancellationToken, this, command, this); - ic.RegisterUntaggedHandler ("FETCH", UntaggedQResyncFetchHandler); + ProcessOpenResponse (ic, access); + } catch { + PermanentFlags = MessageFlags.None; + throw; + } - return OpenAsync (ic, access, doAsync, cancellationToken); + return Open (); } /// @@ -462,7 +496,9 @@ Task OpenAsync (FolderAccess access, uint uidValidity, ulong highe /// public override FolderAccess Open (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, CancellationToken cancellationToken = default) { - return OpenAsync (access, uidValidity, highestModSeq, uids, false, cancellationToken).GetAwaiter ().GetResult (); + var ic = QueueOpen (access, uidValidity, highestModSeq, uids, cancellationToken); + + return Open (ic, access); } /// @@ -517,10 +553,12 @@ public override FolderAccess Open (FolderAccess access, uint uidValidity, ulong /// public override Task OpenAsync (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, CancellationToken cancellationToken = default) { - return OpenAsync (access, uidValidity, highestModSeq, uids, true, cancellationToken); + var ic = QueueOpen (access, uidValidity, highestModSeq, uids, cancellationToken); + + return OpenAsync (ic, access); } - Task OpenAsync (FolderAccess access, bool doAsync, CancellationToken cancellationToken) + ImapCommand QueueOpen (FolderAccess access, CancellationToken cancellationToken) { if (access != FolderAccess.ReadOnly && access != FolderAccess.ReadWrite) throw new ArgumentOutOfRangeException (nameof (access)); @@ -540,7 +578,9 @@ Task OpenAsync (FolderAccess access, bool doAsync, CancellationTok var command = string.Format ("{0} %F{1}\r\n", SelectOrExamine (access), @params); var ic = new ImapCommand (Engine, cancellationToken, this, command, this); - return OpenAsync (ic, access, doAsync, cancellationToken); + Engine.QueueCommand (ic); + + return ic; } /// @@ -581,7 +621,9 @@ Task OpenAsync (FolderAccess access, bool doAsync, CancellationTok /// public override FolderAccess Open (FolderAccess access, CancellationToken cancellationToken = default) { - return OpenAsync (access, false, cancellationToken).GetAwaiter ().GetResult (); + var ic = QueueOpen (access, cancellationToken); + + return Open (ic, access); } /// @@ -622,10 +664,12 @@ public override FolderAccess Open (FolderAccess access, CancellationToken cancel /// public override Task OpenAsync (FolderAccess access, CancellationToken cancellationToken = default) { - return OpenAsync (access, true, cancellationToken); + var ic = QueueOpen (access, cancellationToken); + + return OpenAsync (ic, access); } - async Task CloseAsync (bool expunge, bool doAsync, CancellationToken cancellationToken) + ImapCommand QueueClose (bool expunge, CancellationToken cancellationToken) { CheckState (true, expunge); @@ -639,15 +683,19 @@ async Task CloseAsync (bool expunge, bool doAsync, CancellationToken cancellatio ic = null; } - if (ic != null) { - await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); + return ic; + } - ProcessResponseCodes (ic, null); + void ProcessCloseResponse (ImapCommand ic, bool expunge) + { + ProcessResponseCodes (ic, null); - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create (expunge ? "CLOSE" : "UNSELECT", ic); - } + if (ic.Response != ImapCommandResponse.Ok) + throw ImapCommandException.Create (expunge ? "CLOSE" : "UNSELECT", ic); + } + void Close () + { Reset (); if (Engine.Selected == this) { @@ -691,7 +739,15 @@ async Task CloseAsync (bool expunge, bool doAsync, CancellationToken cancellatio /// public override void Close (bool expunge = false, CancellationToken cancellationToken = default) { - CloseAsync (expunge, false, cancellationToken).GetAwaiter ().GetResult (); + var ic = QueueClose (expunge, cancellationToken); + + if (ic != null) { + Engine.Run (ic); + + ProcessCloseResponse (ic, expunge); + } + + Close (); } /// @@ -727,9 +783,17 @@ public override void Close (bool expunge = false, CancellationToken cancellation /// /// The server replied with a NO or BAD response. /// - public override Task CloseAsync (bool expunge = false, CancellationToken cancellationToken = default) + public override async Task CloseAsync (bool expunge = false, CancellationToken cancellationToken = default) { - return CloseAsync (expunge, true, cancellationToken); + var ic = QueueClose (expunge, cancellationToken); + + if (ic != null) { + await Engine.RunAsync (ic).ConfigureAwait (false); + + ProcessCloseResponse (ic, expunge); + } + + Close (); } async Task GetCreatedFolderAsync (string encodedName, string id, bool specialUse, bool doAsync, CancellationToken cancellationToken)