IDLE implementation, imap synchronization strategies basics and condstore synchronization.

This commit is contained in:
Burak Kaan Köse
2025-01-19 20:35:41 +01:00
parent 46cbf443cf
commit e0f87f1374
38 changed files with 980 additions and 563 deletions

View File

@@ -5,7 +5,6 @@ using MimeKit;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Enums;
using Wino.Services.Extensions;
namespace Wino.Services.Extensions
{
@@ -22,6 +21,9 @@ namespace Wino.Services.Extensions
throw new ArgumentOutOfRangeException(nameof(mailCopyId), mailCopyId, "Invalid mailCopyId format.");
}
public static UniqueId ResolveUidStruct(string mailCopyId)
=> new UniqueId(ResolveUid(mailCopyId));
public static string CreateUid(Guid folderId, uint messageUid)
=> $"{folderId}{MailCopyUidSeparator}{messageUid}";

View File

@@ -367,16 +367,14 @@ namespace Wino.Services
public async Task<IList<uint>> GetKnownUidsForFolderAsync(Guid folderId)
{
var folder = await GetFolderAsync(folderId);
if (folder == null) return default;
var mailCopyIds = await GetMailCopyIdsByFolderIdAsync(folderId);
// Make sure we don't include Ids that doesn't have uid separator.
// Local drafts might not have it for example.
return new List<uint>(mailCopyIds.Where(a => a.Contains(MailkitClientExtensions.MailCopyUidSeparator)).Select(a => MailkitClientExtensions.ResolveUid(a)));
return new List<uint>(mailCopyIds
.Where(a => a.Contains(MailkitClientExtensions.MailCopyUidSeparator))
.Select(a => MailkitClientExtensions.ResolveUid(a)));
}
public async Task<MailAccount> UpdateSystemFolderConfigurationAsync(Guid accountId, SystemFolderConfiguration configuration)
@@ -546,7 +544,19 @@ namespace Wino.Services
{
var folders = new List<MailItemFolder>();
if (options.Type == MailSynchronizationType.FullFolders)
if (options.Type == MailSynchronizationType.IMAPIdle)
{
// Type Inbox will include Sent, Drafts and Deleted folders as well.
// For IMAP idle sync, we must include only Inbox folder.
var inboxFolder = await GetSpecialFolderByAccountIdAsync(options.AccountId, SpecialFolderType.Inbox);
if (inboxFolder != null)
{
folders.Add(inboxFolder);
}
}
else if (options.Type == MailSynchronizationType.FullFolders)
{
// Only get sync enabled folders.
@@ -570,12 +580,19 @@ namespace Wino.Services
}
else if (options.Type == MailSynchronizationType.CustomFolders)
{
// Only get the specified and enabled folders.
// Only get the specified folders.
var synchronizationFolders = await Connection.Table<MailItemFolder>()
.Where(a => a.MailAccountId == options.AccountId && options.SynchronizationFolderIds.Contains(a.Id))
.Where(a =>
a.MailAccountId == options.AccountId &&
options.SynchronizationFolderIds.Contains(a.Id))
.ToListAsync();
if (options.ExcludeMustHaveFolders)
{
return synchronizationFolders;
}
// Order is important for moving.
// By implementation, removing mail folders must be synchronized first. Requests are made in that order for custom sync.
// eg. Moving item from Folder A to Folder B. If we start syncing Folder B first, we might miss adding assignment for Folder A.

View File

@@ -984,6 +984,17 @@ namespace Wino.Services
public Task<bool> IsMailExistsAsync(string mailCopyId)
=> Connection.ExecuteScalarAsync<bool>("SELECT EXISTS(SELECT 1 FROM MailCopy WHERE Id = ?)", mailCopyId);
public async Task<List<MailCopy>> GetExistingMailsAsync(Guid folderId, IEnumerable<MailKit.UniqueId> uniqueIds)
{
var localMailIds = uniqueIds.Where(a => a != null).Select(a => MailkitClientExtensions.CreateUid(folderId, a.Id)).ToArray();
var query = new Query(nameof(MailCopy))
.WhereIn("Id", localMailIds)
.GetRawQuery();
return await Connection.QueryAsync<MailCopy>(query);
}
public Task<bool> IsMailExistsAsync(string mailCopyId, Guid folderId)
=> Connection.ExecuteScalarAsync<bool>("SELECT EXISTS(SELECT 1 FROM MailCopy WHERE Id = ? AND FolderId = ?)", mailCopyId, folderId);
}