Files
AI-Studio/app/MindWork AI Studio/Tools/Mail/MailFolderSyncPlan.cs
T
Thorsten Sommer c4400c0ff6
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Added mailboxes as local data sources (#1022)
2026-10-04 12:26:26 +02:00

63 lines
4.2 KiB
C#

using AIStudio.Tools.Databases.IndexStore;
namespace AIStudio.Tools.Mail;
/// <summary>
/// What a sync pass has to do in one folder, worked out from what the index holds and what the server reports.
/// </summary>
/// <remarks>
/// The server is asked which mails belong into the index -- those of the period, and every flagged
/// one -- and the difference to the index says the rest. A mail which was deleted, moved away, fell
/// out of the period or lost its flag drops out alike; that it may lie elsewhere still is found out
/// by its key, not here.
/// </remarks>
/// <param name="UidValidityChanged">Whether the server voided every UID of the folder. The stored locations go, and every mail counts as new: the ones the index holds are linked again by their key, without being embedded again.</param>
/// <param name="NewUids">The UIDs the index does not hold for this folder, the newest first.</param>
/// <param name="GoneUids">The UIDs the index holds for this folder which no longer belong into it, in ascending order.</param>
/// <param name="KeptUids">The UIDs the index holds and keeps, whose flags may have changed.</param>
/// <param name="ChecksFlags">Whether the flags of the kept mails have to be fetched at all.</param>
/// <param name="FlagsChangedSinceModSeq">Asks only about mails changed since this HIGHESTMODSEQ, or null to ask about every kept mail.</param>
public sealed record MailFolderSyncPlan(bool UidValidityChanged, IReadOnlyList<long> NewUids, IReadOnlyList<long> GoneUids, IReadOnlyList<long> KeptUids, bool ChecksFlags, long? FlagsChangedSinceModSeq)
{
/// <summary>
/// Works out the plan for one folder.
/// </summary>
/// <param name="storedFolder">The folder as the index stores it, or null when the index does not know it yet.</param>
/// <param name="storedLocations">The UIDs the index holds for the folder, with their flags.</param>
/// <param name="serverState">How the folder stands on the server.</param>
/// <param name="indexedUids">The UIDs which belong into the index, as the server found them.</param>
/// <returns>The plan.</returns>
public static MailFolderSyncPlan Create(MailFolderRecord? storedFolder, IReadOnlyDictionary<long, MailFlags> storedLocations, MailFolderState serverState, IReadOnlyCollection<long> indexedUids)
{
var uidValidityChanged = storedFolder is not null && storedFolder.UidValidity != serverState.UidValidity;
HashSet<long> knownUids = uidValidityChanged ? [] : storedLocations.Keys.ToHashSet();
var wantedUids = indexedUids.ToHashSet();
var newUids = wantedUids.Where(uid => !knownUids.Contains(uid)).OrderDescending().ToList();
var goneUids = knownUids.Where(uid => !wantedUids.Contains(uid)).Order().ToList();
var keptUids = knownUids.Where(wantedUids.Contains).Order().ToList();
//
// With CONDSTORE, the HIGHESTMODSEQ of the last complete pass says whether any flag changed
// since, and if so, the server names the changed mails itself. Without it, or after a pass
// which did not complete, only fetching every flag tells.
//
if (keptUids.Count is 0)
return new(uidValidityChanged, newUids, goneUids, keptUids, false, null);
if (storedFolder?.HighestModSeq is { } storedModSeq && serverState.HighestModSeq is { } currentModSeq)
return new(uidValidityChanged, newUids, goneUids, keptUids, currentModSeq != storedModSeq, storedModSeq);
return new(uidValidityChanged, newUids, goneUids, keptUids, true, null);
}
/// <summary>
/// Picks the flags which differ from what the index holds.
/// </summary>
/// <param name="storedLocations">The UIDs the index holds for the folder, with their flags.</param>
/// <param name="fetchedFlags">The flags the server reported.</param>
/// <returns>The changed flags by UID. A UID the index does not hold is left out.</returns>
public static IReadOnlyDictionary<long, MailFlags> GetChangedFlags(IReadOnlyDictionary<long, MailFlags> storedLocations, IReadOnlyDictionary<long, MailFlags> fetchedFlags) => fetchedFlags
.Where(entry => storedLocations.TryGetValue(entry.Key, out var storedFlags) && storedFlags != entry.Value)
.ToDictionary(entry => entry.Key, entry => entry.Value);
}