Skip to content

Commit

Permalink
Refactored ImapFolder's Open and Close methods to split sync/async
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Dec 21, 2023
1 parent cadd149 commit ef88e77
Showing 1 changed file with 122 additions and 58 deletions.
180 changes: 122 additions & 58 deletions MailKit/Net/Imap/ImapFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,32 +331,55 @@ static Task UntaggedQResyncFetchHandler (ImapEngine engine, ImapCommand ic, int
return ic.Folder.OnUntaggedFetchResponse (engine, index, doAsync, ic.CancellationToken);
}

async Task<FolderAccess> OpenAsync (ImapCommand ic, FolderAccess access, bool doAsync, CancellationToken cancellationToken)
ImapCommand QueueOpen (FolderAccess access, uint uidValidity, ulong highestModSeq, IList<UniqueId> 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;

Expand All @@ -373,41 +396,52 @@ async Task<FolderAccess> OpenAsync (ImapCommand ic, FolderAccess access, bool do
return Access;
}

Task<FolderAccess> OpenAsync (FolderAccess access, uint uidValidity, ulong highestModSeq, IList<UniqueId> 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<FolderAccess> 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 ();
}

/// <summary>
Expand Down Expand Up @@ -462,7 +496,9 @@ Task<FolderAccess> OpenAsync (FolderAccess access, uint uidValidity, ulong highe
/// </exception>
public override FolderAccess Open (FolderAccess access, uint uidValidity, ulong highestModSeq, IList<UniqueId> 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);
}

/// <summary>
Expand Down Expand Up @@ -517,10 +553,12 @@ public override FolderAccess Open (FolderAccess access, uint uidValidity, ulong
/// </exception>
public override Task<FolderAccess> OpenAsync (FolderAccess access, uint uidValidity, ulong highestModSeq, IList<UniqueId> 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<FolderAccess> 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));
Expand All @@ -540,7 +578,9 @@ Task<FolderAccess> 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;
}

/// <summary>
Expand Down Expand Up @@ -581,7 +621,9 @@ Task<FolderAccess> OpenAsync (FolderAccess access, bool doAsync, CancellationTok
/// </exception>
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);
}

/// <summary>
Expand Down Expand Up @@ -622,10 +664,12 @@ public override FolderAccess Open (FolderAccess access, CancellationToken cancel
/// </exception>
public override Task<FolderAccess> 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);

Expand All @@ -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) {
Expand Down Expand Up @@ -691,7 +739,15 @@ async Task CloseAsync (bool expunge, bool doAsync, CancellationToken cancellatio
/// </exception>
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 ();
}

/// <summary>
Expand Down Expand Up @@ -727,9 +783,17 @@ public override void Close (bool expunge = false, CancellationToken cancellation
/// <exception cref="ImapCommandException">
/// The server replied with a NO or BAD response.
/// </exception>
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<IMailFolder> GetCreatedFolderAsync (string encodedName, string id, bool specialUse, bool doAsync, CancellationToken cancellationToken)
Expand Down

0 comments on commit ef88e77

Please sign in to comment.