From 58be11374bba0b412256b213921273a2d6829651 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Tue, 26 Dec 2023 15:13:36 -0500 Subject: [PATCH] Refactored ImapFolderFetch.cs's GetStreams methods to split sync/async Part of an ongoing effort to fix issue #1335 --- MailKit/Net/Imap/ImapFolderFetch.cs | 347 +++++++++++++--------------- 1 file changed, 163 insertions(+), 184 deletions(-) diff --git a/MailKit/Net/Imap/ImapFolderFetch.cs b/MailKit/Net/Imap/ImapFolderFetch.cs index f89b063a1b..d3b172e052 100644 --- a/MailKit/Net/Imap/ImapFolderFetch.cs +++ b/MailKit/Net/Imap/ImapFolderFetch.cs @@ -935,6 +935,13 @@ public override Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsync, Ca } } + void ProcessFetchResponse (ImapCommand ic) + { + ProcessResponseCodes (ic, null); + + ic.ThrowIfNotOk ("FETCH"); + } + ImapCommand QueueFetchPreviewTextCommand (FetchSummaryContext sctx, KeyValuePair pair, int octets, CancellationToken cancellationToken) { var uids = pair.Value; @@ -974,10 +981,7 @@ void FetchPreviewText (FetchSummaryContext sctx, Dictionary try { Engine.Run (ic); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); } finally { ctx.Dispose (); } @@ -993,10 +997,7 @@ async Task FetchPreviewTextAsync (FetchSummaryContext sctx, Dictionary Fetch (IList uids, IFetchReques Engine.Run (ic); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); } } finally { MessageExpunged -= ctx.OnMessageExpunged; @@ -1273,10 +1271,7 @@ public override async Task> FetchAsync (IList u await Engine.RunAsync (ic).ConfigureAwait (false); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); } } finally { MessageExpunged -= ctx.OnMessageExpunged; @@ -1387,10 +1382,7 @@ public override IList Fetch (IList indexes, IFetchRequest Engine.Run (ic); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (previewText) GetPreviewText (ctx, cancellationToken); @@ -1459,10 +1451,7 @@ public override async Task> FetchAsync (IList indexe await Engine.RunAsync (ic).ConfigureAwait (false); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (previewText) await GetPreviewTextAsync (ctx, cancellationToken).ConfigureAwait (false); @@ -1587,10 +1576,7 @@ public override IList Fetch (int min, int max, IFetchRequest re Engine.Run (ic); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (previewText) GetPreviewText (ctx, cancellationToken); @@ -1661,10 +1647,7 @@ public override async Task> FetchAsync (int min, int max, await Engine.RunAsync (ic).ConfigureAwait (false); - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (previewText) await GetPreviewTextAsync (ctx, cancellationToken).ConfigureAwait (false); @@ -2218,10 +2201,7 @@ ImapCommand QueueGetHeaders (UniqueId uid, CancellationToken cancellationToken, void ProcessGetHeadersResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (uid, "HEADER", out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested message headers."); @@ -2361,10 +2341,7 @@ ImapCommand QueueGetHeaders (UniqueId uid, string partSpecifier, CancellationTok void ProcessGetHeadersResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, string[] tags, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (uid, tags[0], out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested body part headers."); @@ -2618,10 +2595,7 @@ ImapCommand QueueGetHeaders (int index, CancellationToken cancellationToken, ITr void ProcessGetHeadersResponse (ImapCommand ic, FetchStreamContext ctx, int index, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (index, "HEADER", out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested message headers."); @@ -2761,10 +2735,7 @@ ImapCommand QueueGetHeaders (int index, string partSpecifier, CancellationToken void ProcessGetHeadersResponse (ImapCommand ic, FetchStreamContext ctx, int index, string[] tags, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (index, tags[0], out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested body part headers."); @@ -3018,10 +2989,7 @@ ImapCommand QueueGetMessage (UniqueId uid, CancellationToken cancellationToken, void ProcessGetMessageResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (uid, string.Empty, out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested message."); @@ -3157,10 +3125,7 @@ ImapCommand QueueGetMessage (int index, CancellationToken cancellationToken, ITr void ProcessGetMessageResponse (ImapCommand ic, FetchStreamContext ctx, int index, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (index, string.Empty, out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested message."); @@ -3300,10 +3265,7 @@ ImapCommand QueueGetBodyPart (UniqueId uid, string partSpecifier, CancellationTo void ProcessGetBodyPartResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, string[] tags, out ChainedStream chained, out bool dispose) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); chained = new ChainedStream (); dispose = false; @@ -3612,10 +3574,7 @@ ImapCommand QueueGetBodyPart (int index, string partSpecifier, CancellationToken void ProcessGetBodyPartResponse (ImapCommand ic, FetchStreamContext ctx, int index, string[] tags, out ChainedStream chained, out bool dispose) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); chained = new ChainedStream (); dispose = false; @@ -3908,10 +3867,7 @@ ImapCommand QueueGetStream (UniqueId uid, int offset, int count, CancellationTok void ProcessGetStreamResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (uid, string.Empty, out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested stream."); @@ -4086,10 +4042,7 @@ ImapCommand QueueGetStream (int index, int offset, int count, CancellationToken void ProcessGetStreamResponse (ImapCommand ic, FetchStreamContext ctx, int index, out Section section) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (index, string.Empty, out section, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested stream."); @@ -4255,10 +4208,7 @@ ImapCommand QueueGetStream (UniqueId uid, string section, CancellationToken canc void ProcessGetStreamResponse (ImapCommand ic, FetchStreamContext ctx, UniqueId uid, string section, out Section s) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (uid, section, out s, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested stream."); @@ -4601,10 +4551,7 @@ ImapCommand QueueGetStream (int index, string section, CancellationToken cancell void ProcessGetStreamResponse (ImapCommand ic, FetchStreamContext ctx, int index, string section, out Section s) { - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); + ProcessFetchResponse (ic); if (!ctx.TryGetSection (index, section, out s, true)) throw new MessageNotFoundException ("The IMAP server did not return the requested stream."); @@ -4961,7 +4908,7 @@ public override async Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsy } } - async Task GetStreamsAsync (IList uids, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress) + void ValidateArguments (IList uids, object callback) { if (uids == null) throw new ArgumentNullException (nameof (uids)); @@ -4970,105 +4917,17 @@ async Task GetStreamsAsync (IList uids, object callback, bool doAsync, throw new ArgumentNullException (nameof (callback)); CheckState (true, false); - - if (uids.Count == 0) - return; - - var ctx = new FetchStreamCallbackContext (this, callback, progress); - var command = "UID FETCH %s (BODY.PEEK[])\r\n"; - - try { - foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) { - ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); - ic.UserData = ctx; - - Engine.QueueCommand (ic); - - await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); - - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); - } - } finally { - ctx.Dispose (); - } } - async Task GetStreamsAsync (IList indexes, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress) + IEnumerable QueueGetStreams (FetchStreamCallbackContext ctx, IList uids, object callback, CancellationToken cancellationToken) { - if (indexes == null) - throw new ArgumentNullException (nameof (indexes)); - - if (callback == null) - throw new ArgumentNullException (nameof (callback)); - - CheckState (true, false); - CheckAllowIndexes (); - - if (indexes.Count == 0) - return; - - var command = new StringBuilder ("FETCH "); - ImapUtils.FormatIndexSet (Engine, command, indexes); - command.Append (" (UID BODY.PEEK[])\r\n"); - - var ic = new ImapCommand (Engine, cancellationToken, this, command.ToString ()); - var ctx = new FetchStreamCallbackContext (this, callback, progress); - - ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); - ic.UserData = ctx; - - Engine.QueueCommand (ic); - - try { - await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); - - ProcessResponseCodes (ic, null); - - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); - } finally { - ctx.Dispose (); - } - } - - async Task GetStreamsAsync (int min, int max, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress) - { - if (min < 0) - throw new ArgumentOutOfRangeException (nameof (min)); - - if (max != -1 && max < min) - throw new ArgumentOutOfRangeException (nameof (max)); - - if (callback == null) - throw new ArgumentNullException (nameof (callback)); - - CheckState (true, false); - CheckAllowIndexes (); - - if (min == Count) - return; - - var command = string.Format ("FETCH {0} (UID BODY.PEEK[])\r\n", GetFetchRange (min, max)); - var ic = new ImapCommand (Engine, cancellationToken, this, command); - var ctx = new FetchStreamCallbackContext (this, callback, progress); + foreach (var ic in Engine.CreateCommands (cancellationToken, this, "UID FETCH %s (BODY.PEEK[])\r\n", uids)) { + ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); + ic.UserData = ctx; - ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); - ic.UserData = ctx; - - Engine.QueueCommand (ic); - - try { - await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); - - ProcessResponseCodes (ic, null); + Engine.QueueCommand (ic); - if (ic.Response != ImapCommandResponse.Ok) - throw ImapCommandException.Create ("FETCH", ic); - } finally { - ctx.Dispose (); + yield return ic; } } @@ -5116,7 +4975,18 @@ async Task GetStreamsAsync (int min, int max, object callback, bool doAsync, Can /// public virtual void GetStreams (IList uids, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) { - GetStreamsAsync (uids, callback, false, cancellationToken, progress).GetAwaiter ().GetResult (); + ValidateArguments (uids, callback); + + if (uids.Count == 0) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + foreach (var ic in QueueGetStreams (ctx, uids, callback, cancellationToken)) { + Engine.Run (ic); + + ProcessFetchResponse (ic); + } + } } /// @@ -5162,9 +5032,47 @@ public virtual void GetStreams (IList uids, ImapFetchStreamCallback ca /// /// The server replied with a NO or BAD response. /// - public virtual Task GetStreamsAsync (IList uids, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) + public virtual async Task GetStreamsAsync (IList uids, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) + { + ValidateArguments (uids, callback); + + if (uids.Count == 0) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + foreach (var ic in QueueGetStreams (ctx, uids, callback, cancellationToken)) { + await Engine.RunAsync (ic).ConfigureAwait (false); + + ProcessFetchResponse (ic); + } + } + } + + void ValidateArguments (IList indexes, object callback) { - return GetStreamsAsync (uids, callback, true, cancellationToken, progress); + if (indexes == null) + throw new ArgumentNullException (nameof (indexes)); + + if (callback == null) + throw new ArgumentNullException (nameof (callback)); + + CheckState (true, false); + CheckAllowIndexes (); + } + + ImapCommand QueueGetStreams (FetchStreamCallbackContext ctx, IList indexes, CancellationToken cancellationToken) + { + var command = new StringBuilder ("FETCH "); + ImapUtils.FormatIndexSet (Engine, command, indexes); + command.Append (" (UID BODY.PEEK[])\r\n"); + + var ic = new ImapCommand (Engine, cancellationToken, this, command.ToString ()); + ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); + ic.UserData = ctx; + + Engine.QueueCommand (ic); + + return ic; } /// @@ -5211,7 +5119,18 @@ public virtual Task GetStreamsAsync (IList uids, ImapFetchStreamAsyncC /// public virtual void GetStreams (IList indexes, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) { - GetStreamsAsync (indexes, callback, false, cancellationToken, progress).GetAwaiter ().GetResult (); + ValidateArguments (indexes, callback); + + if (indexes.Count == 0) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + var ic = QueueGetStreams (ctx, indexes, cancellationToken); + + Engine.Run (ic); + + ProcessFetchResponse (ic); + } } /// @@ -5257,9 +5176,47 @@ public virtual void GetStreams (IList indexes, ImapFetchStreamCallback call /// /// The server replied with a NO or BAD response. /// - public virtual Task GetStreamsAsync (IList indexes, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) + public virtual async Task GetStreamsAsync (IList indexes, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) { - return GetStreamsAsync (indexes, callback, true, cancellationToken, progress); + ValidateArguments (indexes, callback); + + if (indexes.Count == 0) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + var ic = QueueGetStreams (ctx, indexes, cancellationToken); + + await Engine.RunAsync (ic).ConfigureAwait (false); + + ProcessFetchResponse (ic); + } + } + + void ValidateArguments (int min, int max, object callback) + { + if (min < 0) + throw new ArgumentOutOfRangeException (nameof (min)); + + if (max != -1 && max < min) + throw new ArgumentOutOfRangeException (nameof (max)); + + if (callback == null) + throw new ArgumentNullException (nameof (callback)); + + CheckState (true, false); + CheckAllowIndexes (); + } + + ImapCommand QueueGetStreams (FetchStreamCallbackContext ctx, int min, int max, CancellationToken cancellationToken) + { + var command = string.Format ("FETCH {0} (UID BODY.PEEK[])\r\n", GetFetchRange (min, max)); + var ic = new ImapCommand (Engine, cancellationToken, this, command); + ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync); + ic.UserData = ctx; + + Engine.QueueCommand (ic); + + return ic; } /// @@ -5307,7 +5264,18 @@ public virtual Task GetStreamsAsync (IList indexes, ImapFetchStreamAsyncCal /// public virtual void GetStreams (int min, int max, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) { - GetStreamsAsync (min, max, callback, false, cancellationToken, progress).GetAwaiter ().GetResult (); + ValidateArguments (min, max, callback); + + if (min == Count) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + var ic = QueueGetStreams (ctx, min, max, cancellationToken); + + Engine.Run (ic); + + ProcessFetchResponse (ic); + } } /// @@ -5354,9 +5322,20 @@ public virtual void GetStreams (int min, int max, ImapFetchStreamCallback callba /// /// The server replied with a NO or BAD response. /// - public virtual Task GetStreamsAsync (int min, int max, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) + public virtual async Task GetStreamsAsync (int min, int max, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default, ITransferProgress progress = null) { - return GetStreamsAsync (min, max, callback, true, cancellationToken, progress); + ValidateArguments (min, max, callback); + + if (min == Count) + return; + + using (var ctx = new FetchStreamCallbackContext (this, callback, progress)) { + var ic = QueueGetStreams (ctx, min, max, cancellationToken); + + await Engine.RunAsync (ic).ConfigureAwait (false); + + ProcessFetchResponse (ic); + } } } }