IMAP Improvements (#558)

* Fixing an issue where scrollviewer overrides a part of template in mail list. Adjusted zoomed out header grid's corner radius.

* IDLE implementation, imap synchronization strategies basics and condstore synchronization.

* Adding iCloud and Yahoo as special IMAP handling scenario.

* iCloud special imap handling.

* Support for killing synchronizers.

* Update privacy policy url.

* Batching condstore downloads into 50, using SORT extension for searches if supported.

* Bumping some nugets. More on the imap synchronizers.

* Delegating idle synchronizations to server to post-sync operations.

* Update mailkit to resolve qresync bug with iCloud.

* Fixing remote highest mode seq checks for qresync and condstore synchronizers.

* Yahoo custom settings.

* Bump google sdk package.

* Fixing the build issue....

* NRE on canceled token accounts during setup.

* Server crash handlers.

* Remove ARM32. Upgrade server to .NET 9.

* Fix icons for yahoo and apple.

* Fixed an issue where disabled folders causing an exception on forced sync.

* Remove smtp encoding constraint.

* Remove commented code.

* Fixing merge conflict

* Addressing double registrations for mailkit remote folder events in synchronizers.

* Making sure idle canceled result is not reported.

* Fixing custom imap server dialog opening.

* Fixing the issue with account creation making the previously selected account as selected as well.

* Fixing app close behavior and logging app close.
This commit is contained in:
Burak Kaan Köse
2025-02-15 12:53:32 +01:00
committed by GitHub
parent 30f1257983
commit ee9e41c5a7
108 changed files with 2092 additions and 1166 deletions

View File

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using System.Windows;
using H.NotifyIcon;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using Windows.Storage;
using Wino.Calendar.Services;
using Wino.Core;
@@ -188,6 +189,9 @@ namespace Wino.Server
if (isCreatedNew)
{
AppDomain.CurrentDomain.UnhandledException += ServerCrashed;
Application.Current.DispatcherUnhandledException += UIThreadCrash;
TaskScheduler.UnobservedTaskException += TaskCrashed;
// Ensure proper encodings are available for MimeKit
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
@@ -237,6 +241,12 @@ namespace Wino.Server
}
}
private void TaskCrashed(object sender, UnobservedTaskExceptionEventArgs e) => Log.Error(e.Exception, "Task crashed.");
private void UIThreadCrash(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) => Log.Error(e.Exception, "UI thread crashed.");
private void ServerCrashed(object sender, UnhandledExceptionEventArgs e) => Log.Error((Exception)e.ExceptionObject, "Server crashed.");
protected override void OnExit(ExitEventArgs e)
{
notifyIcon?.Dispose();

View File

@@ -22,6 +22,7 @@ namespace Wino.Server.Core
nameof(ServerTerminationModeChanged) => App.Current.Services.GetService<ServerTerminationModeHandler>(),
nameof(TerminateServerRequested) => App.Current.Services.GetService<TerminateServerRequestHandler>(),
nameof(ImapConnectivityTestRequested) => App.Current.Services.GetService<ImapConnectivityTestHandler>(),
nameof(KillAccountSynchronizerRequested) => App.Current.Services.GetService<KillAccountSynchronizerHandler>(),
_ => throw new Exception($"Server handler for {typeName} is not registered."),
};
}
@@ -39,6 +40,7 @@ namespace Wino.Server.Core
serviceCollection.AddTransient<ServerTerminationModeHandler>();
serviceCollection.AddTransient<TerminateServerRequestHandler>();
serviceCollection.AddTransient<ImapConnectivityTestHandler>();
serviceCollection.AddTransient<KillAccountSynchronizerHandler>();
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Server;
using Wino.Messaging.Server;
using Wino.Server.Core;
namespace Wino.Server.MessageHandlers
{
public class KillAccountSynchronizerHandler : ServerMessageHandler<KillAccountSynchronizerRequested, bool>
{
private readonly ISynchronizerFactory _synchronizerFactory;
public override WinoServerResponse<bool> FailureDefaultResponse(Exception ex)
=> WinoServerResponse<bool>.CreateErrorResponse(ex.Message);
public KillAccountSynchronizerHandler(ISynchronizerFactory synchronizerFactory)
{
_synchronizerFactory = synchronizerFactory;
}
protected override async Task<WinoServerResponse<bool>> HandleAsync(KillAccountSynchronizerRequested message, CancellationToken cancellationToken = default)
{
await _synchronizerFactory.DeleteSynchronizerAsync(message.AccountId);
return WinoServerResponse<bool>.CreateSuccessResponse(true);
}
}
}

View File

@@ -46,6 +46,7 @@ namespace Wino.Server.MessageHandlers
bool shouldReportSynchronizationResult =
message.Options.Type != MailSynchronizationType.ExecuteRequests &&
message.Options.Type != MailSynchronizationType.IMAPIdle &&
message.Source == SynchronizationSource.Client;
try
@@ -64,6 +65,12 @@ namespace Wino.Server.MessageHandlers
var isSynchronizationSucceeded = synchronizationResult.CompletedState == SynchronizationCompletedState.Success;
// IDLE requests might be canceled successfully.
if (message.Options.Type == MailSynchronizationType.IMAPIdle && synchronizationResult.CompletedState == SynchronizationCompletedState.Canceled)
{
isSynchronizationSucceeded = true;
}
// Update badge count of the notification task.
if (isSynchronizationSucceeded)
{

View File

@@ -42,7 +42,8 @@ namespace Wino.Server
IRecipient<ServerTerminationModeChanged>,
IRecipient<AccountSynchronizationProgressUpdatedMessage>,
IRecipient<AccountFolderConfigurationUpdated>,
IRecipient<CopyAuthURLRequested>
IRecipient<CopyAuthURLRequested>,
IRecipient<NewMailSynchronizationRequested>
{
private readonly System.Timers.Timer _timer;
private static object connectionLock = new object();
@@ -140,6 +141,7 @@ namespace Wino.Server
public async void Receive(AccountFolderConfigurationUpdated message) => await SendMessageAsync(MessageType.UIMessage, message);
public async void Receive(CopyAuthURLRequested message) => await SendMessageAsync(MessageType.UIMessage, message);
public async void Receive(NewMailSynchronizationRequested message) => await SendMessageAsync(MessageType.UIMessage, message);
#endregion
@@ -321,6 +323,9 @@ namespace Wino.Server
KillServer();
break;
case nameof(KillAccountSynchronizerRequested):
await ExecuteServerMessageSafeAsync(args, JsonSerializer.Deserialize<KillAccountSynchronizerRequested>(messageJson, _jsonSerializerOptions));
break;
default:
Debug.WriteLine($"Missing handler for {typeName} in the server. Check ServerContext.cs - HandleServerMessageAsync.");
break;