Skip to content

Commit

Permalink
Fixed ImapFolder.Sort() to always return the UIDs in the correct order.
Browse files Browse the repository at this point in the history
If the IMAP server did not support ESEARCH, the order of the returned
UniqueIds was always sorted in ascending order even if that is not
the order of the UIDs returned by the IMAP server in the untagged
`SORT` response.

Fixes issue #789
  • Loading branch information
jstedfast committed Dec 18, 2018
1 parent 020eea8 commit 9c09be9
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 12 deletions.
2 changes: 1 addition & 1 deletion MailKit/Net/Imap/ImapFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4508,7 +4508,7 @@ async Task<IList<int>> GetIndexesAsync (IList<UniqueId> uids, bool doAsync, Canc
{
var command = string.Format ("SEARCH UID {0}\r\n", UniqueIdSet.ToString (uids));
var ic = new ImapCommand (Engine, cancellationToken, this, command);
var results = new SearchResults ();
var results = new SearchResults (SortOrder.Ascending);

if ((Engine.Capabilities & ImapCapabilities.ESearch) != 0)
ic.RegisterUntaggedHandler ("ESEARCH", ESearchMatchesAsync);
Expand Down
12 changes: 5 additions & 7 deletions MailKit/Net/Imap/ImapFolderSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,8 @@ static string BuildSortOrder (IList<OrderBy> orderBy)

static async Task SearchMatchesAsync (ImapEngine engine, ImapCommand ic, int index, bool doAsync)
{
var uids = new UniqueIdSet (SortOrder.Ascending);
var results = (SearchResults) ic.UserData;
var uids = results.UniqueIds;
ImapToken token;
uint uid;

Expand Down Expand Up @@ -387,7 +387,6 @@ static async Task ESearchMatchesAsync (ImapEngine engine, ImapCommand ic, int in
{
var token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
var results = (SearchResults) ic.UserData;
UniqueIdSet uids = null;
int parenDepth = 0;
//bool uid = false;
string atom;
Expand Down Expand Up @@ -500,18 +499,17 @@ static async Task ESearchMatchesAsync (ImapEngine engine, ImapCommand ic, int in
case "ALL":
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "ESEARCH", token);

uids = ImapEngine.ParseUidSet (token, ic.Folder.UidValidity, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
var uids = ImapEngine.ParseUidSet (token, ic.Folder.UidValidity, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

results.Count = uids.Count;
results.UniqueIds = uids;
break;
default:
throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "ESEARCH", token);
}

token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
} while (true);

results.UniqueIds = uids ?? new UniqueIdSet ();
}

async Task<SearchResults> SearchAsync (string query, bool doAsync, CancellationToken cancellationToken)
Expand All @@ -531,7 +529,7 @@ async Task<SearchResults> SearchAsync (string query, bool doAsync, CancellationT
if ((Engine.Capabilities & ImapCapabilities.ESearch) != 0)
ic.RegisterUntaggedHandler ("ESEARCH", ESearchMatchesAsync);
ic.RegisterUntaggedHandler ("SEARCH", SearchMatchesAsync);
ic.UserData = new SearchResults ();
ic.UserData = new SearchResults (SortOrder.Ascending);

Engine.QueueCommand (ic);

Expand Down Expand Up @@ -669,7 +667,7 @@ async Task<IList<UniqueId>> SearchAsync (SearchQuery query, bool doAsync, Cancel
// respond with "* SEARCH ..." instead of "* ESEARCH ..." even when using the extended
// search syntax.
ic.RegisterUntaggedHandler ("SEARCH", SearchMatchesAsync);
ic.UserData = new SearchResults ();
ic.UserData = new SearchResults (SortOrder.Ascending);

Engine.QueueCommand (ic);

Expand Down
5 changes: 3 additions & 2 deletions MailKit/Search/SearchResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ public class SearchResults
/// <remarks>
/// Creates a new <see cref="SearchResults"/>.
/// </remarks>
public SearchResults ()
/// <param name="order">The expected sort-order of the results.</param>
public SearchResults (SortOrder order = SortOrder.None)
{
UniqueIds = new UniqueId[0];
UniqueIds = new UniqueIdSet (order);
}

/// <summary>
Expand Down
6 changes: 4 additions & 2 deletions UnitTests/Net/Imap/ImapClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3008,8 +3008,9 @@ public void TestDovecot ()
Assert.IsFalse (matches.Min.HasValue, "MIN should not be set");
Assert.AreEqual (0, matches.Count, "COUNT should not be set");
Assert.AreEqual (14, matches.UniqueIds.Count);
var expectedSortByReverseArrivalResults = new uint[] { 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8 };
for (int i = 0; i < matches.UniqueIds.Count; i++)
Assert.AreEqual (i + 1, matches.UniqueIds[i].Id);
Assert.AreEqual (expectedSortByReverseArrivalResults[i], matches.UniqueIds[i].Id);

destination.GetStreams (UniqueIdRange.All, GetStreamsCallback);
destination.GetStreams (new int[] { 0, 1, 2 }, GetStreamsCallback);
Expand Down Expand Up @@ -3632,8 +3633,9 @@ public async void TestDovecotAsync ()
Assert.IsFalse (matches.Min.HasValue, "MIN should not be set");
Assert.AreEqual (0, matches.Count, "COUNT should not be set");
Assert.AreEqual (14, matches.UniqueIds.Count);
var expectedSortByReverseArrivalResults = new uint[] { 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8 };
for (int i = 0; i < matches.UniqueIds.Count; i++)
Assert.AreEqual (i + 1, matches.UniqueIds[i].Id);
Assert.AreEqual (expectedSortByReverseArrivalResults[i], matches.UniqueIds[i].Id);

await destination.GetStreamsAsync (UniqueIdRange.All, GetStreamsCallback);
await destination.GetStreamsAsync (new int[] { 0, 1, 2 }, GetStreamsCallback);
Expand Down

0 comments on commit 9c09be9

Please sign in to comment.