iCloud special imap handling.

This commit is contained in:
Burak Kaan Köse
2025-01-21 23:57:58 +01:00
parent 05280dfd42
commit 20010e77ae
21 changed files with 433 additions and 250 deletions

View File

@@ -27,7 +27,7 @@ namespace Wino.Core.Domain.Interfaces
string dontAskAgainConfigurationKey = "");
Task<bool> ShowCustomThemeBuilderDialogAsync();
Task<AccountCreationDialogResult> ShowAccountProviderSelectionDialogAsync(List<IProviderDetail> availableProviders);
IAccountCreationDialog GetAccountCreationDialog(MailProviderType type);
IAccountCreationDialog GetAccountCreationDialog(AccountCreationDialogResult accountCreationDialogResult);
Task<List<SharedFile>> PickFilesAsync(params object[] typeFilters);
Task<string> PickFilePathAsync(string saveFileName);
}

View File

@@ -3,7 +3,7 @@ using Wino.Core.Domain.Entities.Shared;
namespace Wino.Core.Domain.Interfaces
{
public interface ICustomServerAccountCreationDialog : IAccountCreationDialog
public interface IImapAccountCreationDialog : IAccountCreationDialog
{
/// <summary>
/// Returns the custom server information from the dialog..

View File

@@ -0,0 +1,10 @@
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Models.Accounts;
namespace Wino.Core.Domain.Interfaces
{
public interface ISpecialImapProviderConfigResolver
{
CustomServerInformation GetServerInformation(MailAccount account, AccountCreationDialogResult dialogResult);
}
}

View File

@@ -2,5 +2,5 @@
namespace Wino.Core.Domain.Models.Accounts
{
public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, string AccountColorHex = "");
public record AccountCreationDialogResult(MailProviderType ProviderType, string AccountName, SpecialImapProviderDetails SpecialImapProviderDetails);
}

View File

@@ -0,0 +1,6 @@
using Wino.Core.Domain.Enums;
namespace Wino.Core.Domain.Models.Accounts
{
public record SpecialImapProviderDetails(string Address, string Password, string SenderName, SpecialImapProvider SpecialImapProvider);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,76 @@
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Messaging.UI;
namespace Wino.Core.UWP.Controls
{
public sealed partial class AccountCreationDialogControl : UserControl, IRecipient<CopyAuthURLRequested>
{
private string copyClipboardURL;
public event EventHandler CancelClicked;
public AccountCreationDialogState State
{
get { return (AccountCreationDialogState)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(nameof(State), typeof(AccountCreationDialogState), typeof(AccountCreationDialogControl), new PropertyMetadata(AccountCreationDialogState.Idle, new PropertyChangedCallback(OnStateChanged)));
public AccountCreationDialogControl()
{
InitializeComponent();
}
private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is AccountCreationDialogControl dialog)
{
dialog.UpdateVisualStates();
}
}
private void UpdateVisualStates() => VisualStateManager.GoToState(this, State.ToString(), false);
public async void Receive(CopyAuthURLRequested message)
{
copyClipboardURL = message.AuthURL;
await Task.Delay(2000);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
AuthHelpDialogButton.Visibility = Windows.UI.Xaml.Visibility.Visible;
});
}
private void ControlLoaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
WeakReferenceMessenger.Default.Register(this);
}
private void ControlUnloaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
WeakReferenceMessenger.Default.UnregisterAll(this);
}
private async void CopyClicked(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (string.IsNullOrEmpty(copyClipboardURL)) return;
var clipboardService = WinoApplication.Current.Services.GetService<IClipboardService>();
await clipboardService.CopyClipboardAsync(copyClipboardURL);
}
private void CancelButtonClicked(object sender, Windows.UI.Xaml.RoutedEventArgs e) => CancelClicked?.Invoke(this, null);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,50 +1,58 @@
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using System.Threading;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.UWP;
using Wino.Messaging.UI;
namespace Wino.Dialogs
{
public sealed partial class AccountCreationDialog : BaseAccountCreationDialog, IRecipient<CopyAuthURLRequested>
public sealed partial class AccountCreationDialog : ContentDialog, IAccountCreationDialog
{
private string copyClipboardURL;
public CancellationTokenSource CancellationTokenSource { get; private set; }
public AccountCreationDialogState State
{
get { return (AccountCreationDialogState)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(nameof(State), typeof(AccountCreationDialogState), typeof(AccountCreationDialog), new PropertyMetadata(AccountCreationDialogState.Idle));
public AccountCreationDialog()
{
InitializeComponent();
WeakReferenceMessenger.Default.Register(this);
}
public override void OnStateChanged(AccountCreationDialogState state)
// Prevent users from dismissing it by ESC key.
public void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args)
{
var tt = VisualStateManager.GoToState(this, state.ToString(), true);
}
public async void Receive(CopyAuthURLRequested message)
{
copyClipboardURL = message.AuthURL;
await Task.Delay(2000);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
if (args.Result == ContentDialogResult.None)
{
AuthHelpDialogButton.Visibility = Windows.UI.Xaml.Visibility.Visible;
});
args.Cancel = true;
}
}
private void CancelClicked(object sender, Windows.UI.Xaml.RoutedEventArgs e) => Complete(true);
private async void CopyClicked(object sender, Windows.UI.Xaml.RoutedEventArgs e)
public void ShowDialog(CancellationTokenSource cancellationTokenSource)
{
if (string.IsNullOrEmpty(copyClipboardURL)) return;
CancellationTokenSource = cancellationTokenSource;
var clipboardService = WinoApplication.Current.Services.GetService<IClipboardService>();
await clipboardService.CopyClipboardAsync(copyClipboardURL);
_ = ShowAsync();
}
public void Complete(bool cancel)
{
State = cancel ? AccountCreationDialogState.Canceled : AccountCreationDialogState.Completed;
// Unregister from closing event.
Closing -= DialogClosing;
if (cancel && !CancellationTokenSource.IsCancellationRequested)
{
CancellationTokenSource.Cancel();
}
Hide();
}
private void CancelClicked(object sender, System.EventArgs e) => Complete(true);
}
}

View File

@@ -1,60 +0,0 @@
using System.Threading;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
namespace Wino.Dialogs
{
public abstract class BaseAccountCreationDialog : ContentDialog, IAccountCreationDialog
{
public AccountCreationDialogState State
{
get { return (AccountCreationDialogState)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
public CancellationTokenSource CancellationTokenSource { get; private set; }
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(nameof(State), typeof(AccountCreationDialogState), typeof(BaseAccountCreationDialog), new PropertyMetadata(AccountCreationDialogState.Idle, OnStateChanged));
private static void OnStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dialog = d as BaseAccountCreationDialog;
dialog.OnStateChanged((AccountCreationDialogState)e.NewValue);
}
public abstract void OnStateChanged(AccountCreationDialogState state);
// Prevent users from dismissing it by ESC key.
public void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args)
{
if (args.Result == ContentDialogResult.None)
{
args.Cancel = true;
}
}
public void ShowDialog(CancellationTokenSource cancellationTokenSource)
{
CancellationTokenSource = cancellationTokenSource;
_ = ShowAsync();
}
public void Complete(bool cancel)
{
State = cancel ? AccountCreationDialogState.Canceled : AccountCreationDialogState.Completed;
// Unregister from closing event.
Closing -= DialogClosing;
if (cancel && !CancellationTokenSource.IsCancellationRequested)
{
CancellationTokenSource.Cancel();
}
Hide();
}
}
}

View File

@@ -85,6 +85,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
@@ -103,20 +104,27 @@
Source="{x:Bind SelectedMailProvider.ProviderImage, Mode=OneWay}" />
<TextBox
x:Name="SpecialImapAddress"
x:Name="DisplayNameTextBox"
Grid.Row="1"
TextChanged="InputChanged"
Header="Display Name"
PlaceholderText="eg. John Doe"
TextChanged="InputChanged" />
<TextBox
x:Name="SpecialImapAddress"
Grid.Row="2"
Header="E-mail Address"
PlaceholderText="eg. johndoe@testmail.com" />
PlaceholderText="eg. johndoe@testmail.com"
TextChanged="InputChanged" />
<PasswordBox
x:Name="AppSpecificPassword"
PasswordChanged="ImapPasswordChanged"
Grid.Row="2"
Header="App-Specific Password" />
Grid.Row="3"
Header="App-Specific Password"
PasswordChanged="ImapPasswordChanged" />
<HyperlinkButton
Grid.Row="3"
Grid.Row="4"
HorizontalAlignment="Right"
Click="AppSpecificHelpButtonClicked"
Content="How do I get app-specific password?" />

View File

@@ -21,6 +21,7 @@ namespace Wino.Core.UWP.Dialogs
public static readonly DependencyProperty IsSpecialImapServerPartVisibleProperty = DependencyProperty.Register(nameof(IsSpecialImapServerPartVisible), typeof(bool), typeof(NewAccountDialog), new PropertyMetadata(false));
public static readonly DependencyProperty SelectedMailProviderProperty = DependencyProperty.Register(nameof(SelectedMailProvider), typeof(ProviderDetail), typeof(NewAccountDialog), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedProviderChanged)));
/// <summary>
/// Gets or sets current selected mail provider in the dialog.
/// </summary>
@@ -69,6 +70,17 @@ namespace Wino.Core.UWP.Dialogs
private void CreateClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
if (IsSpecialImapServerPartVisible)
{
// Special imap detail input.
var details = new SpecialImapProviderDetails(SpecialImapAddress.Text.Trim(), AppSpecificPassword.Password.Trim(), DisplayNameTextBox.Text.Trim(), SelectedMailProvider.SpecialImapProvider);
Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim(), details);
Hide();
return;
}
Validate();
if (IsSecondaryButtonEnabled)
@@ -85,7 +97,7 @@ namespace Wino.Core.UWP.Dialogs
}
else
{
Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim());
Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim(), null);
Hide();
}
}
@@ -106,7 +118,9 @@ namespace Wino.Core.UWP.Dialogs
bool shouldEnable = SelectedMailProvider != null
&& SelectedMailProvider.IsSupported
&& !string.IsNullOrEmpty(AccountNameTextbox.Text)
&& (IsSpecialImapServerPartVisible ? (!string.IsNullOrEmpty(AppSpecificPassword.Password) && EmailValidation.EmailValidator.Validate(SpecialImapAddress.Text)) : true);
&& (IsSpecialImapServerPartVisible ? (!string.IsNullOrEmpty(AppSpecificPassword.Password)
&& !string.IsNullOrEmpty(DisplayNameTextBox.Text)
&& EmailValidation.EmailValidator.Validate(SpecialImapAddress.Text)) : true);
IsPrimaryButtonEnabled = shouldEnable;
}

View File

@@ -132,7 +132,7 @@ namespace Wino.Core.UWP.Services
return file;
}
public virtual IAccountCreationDialog GetAccountCreationDialog(MailProviderType type)
public virtual IAccountCreationDialog GetAccountCreationDialog(AccountCreationDialogResult accountCreationDialogResult)
{
return new AccountCreationDialog
{

View File

@@ -84,6 +84,9 @@
<ItemGroup>
<Compile Include="Activation\ActivationHandler.cs" />
<Compile Include="BasePage.cs" />
<Compile Include="Controls\AccountCreationDialogControl.xaml.cs">
<DependentUpon>AccountCreationDialogControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ControlConstants.cs" />
<Compile Include="Controls\CustomWrapPanel.cs" />
<Compile Include="Controls\EqualGridPanel.cs" />
@@ -115,7 +118,6 @@
<Compile Include="Dialogs\AccountPickerDialog.xaml.cs">
<DependentUpon>AccountPickerDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Dialogs\BaseAccountCreationDialog.cs" />
<Compile Include="Dialogs\CustomMessageDialogInformationContainer.cs" />
<Compile Include="Dialogs\CustomThemeBuilderDialog.xaml.cs">
<DependentUpon>CustomThemeBuilderDialog.xaml</DependentUpon>
@@ -341,6 +343,10 @@
</Content>
</ItemGroup>
<ItemGroup>
<Page Include="Controls\AccountCreationDialogControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\WinoAppTitleBar.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@@ -626,13 +626,21 @@ namespace Wino.Core.Synchronizers.Mail
IImapClient availableClient = null;
retry:
try
{
availableClient = await _clientPool.GetClientAsync().ConfigureAwait(false);
var strategy = _imapSynchronizationStrategyProvider.GetSynchronizationStrategy(availableClient);
return await strategy.HandleSynchronizationAsync(availableClient, folder, this, cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
_clientPool.Release(availableClient, false);
goto retry;
}
catch (Exception)
{

View File

@@ -28,18 +28,25 @@ namespace Wino.Mail.ViewModels
{
public partial class AccountManagementViewModel : AccountManagementPageViewModelBase
{
private readonly ISpecialImapProviderConfigResolver _specialImapProviderConfigResolver;
private readonly IImapTestService _imapTestService;
public IMailDialogService MailDialogService { get; }
public AccountManagementViewModel(IMailDialogService dialogService,
IWinoServerConnectionManager winoServerConnectionManager,
INavigationService navigationService,
IAccountService accountService,
ISpecialImapProviderConfigResolver specialImapProviderConfigResolver,
IProviderService providerService,
IImapTestService imapTestService,
IStoreManagementService storeManagementService,
IAuthenticationProvider authenticationProvider,
IPreferencesService preferencesService) : base(dialogService, winoServerConnectionManager, navigationService, accountService, providerService, storeManagementService, authenticationProvider, preferencesService)
{
MailDialogService = dialogService;
_specialImapProviderConfigResolver = specialImapProviderConfigResolver;
_imapTestService = imapTestService;
}
[RelayCommand]
@@ -93,7 +100,7 @@ namespace Wino.Mail.ViewModels
if (accountCreationDialogResult != null)
{
creationDialog = MailDialogService.GetAccountCreationDialog(accountCreationDialogResult.ProviderType);
creationDialog = MailDialogService.GetAccountCreationDialog(accountCreationDialogResult);
CustomServerInformation customServerInformation = null;
@@ -101,17 +108,20 @@ namespace Wino.Mail.ViewModels
{
ProviderType = accountCreationDialogResult.ProviderType,
Name = accountCreationDialogResult.AccountName,
AccountColorHex = accountCreationDialogResult.AccountColorHex,
SpecialImapProvider = accountCreationDialogResult.SpecialImapProviderDetails?.SpecialImapProvider ?? SpecialImapProvider.None,
Id = Guid.NewGuid()
};
creationDialog.ShowDialog(accountCreationCancellationTokenSource);
await Task.Delay(1000);
creationDialog.State = AccountCreationDialogState.SigningIn;
string tokenInformation = string.Empty;
// Custom server implementation requires more async waiting.
if (creationDialog is ICustomServerAccountCreationDialog customServerDialog)
if (creationDialog is IImapAccountCreationDialog customServerDialog)
{
// Pass along the account properties and perform initial navigation on the imap frame.
customServerDialog.StartImapConnectionSetup(createdAccount);
@@ -130,20 +140,35 @@ namespace Wino.Mail.ViewModels
}
else
{
// OAuth authentication is handled here.
// Server authenticates, returns the token info here.
if (accountCreationDialogResult.SpecialImapProviderDetails != null)
{
createdAccount.SenderName = accountCreationDialogResult.SpecialImapProviderDetails.SenderName;
createdAccount.Address = customServerInformation.Address;
var tokenInformationResponse = await WinoServerConnectionManager
.GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
createdAccount,
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
// Special imap provider testing dialog. This is only available for iCloud and Yahoo.
customServerInformation = _specialImapProviderConfigResolver.GetServerInformation(createdAccount, accountCreationDialogResult);
customServerInformation.Id = Guid.NewGuid();
customServerInformation.AccountId = createdAccount.Id;
if (creationDialog.State == AccountCreationDialogState.Canceled)
throw new AccountSetupCanceledException();
await _imapTestService.TestImapConnectionAsync(customServerInformation, true);
}
else
{
// OAuth authentication is handled here.
// Server authenticates, returns the token info here.
createdAccount.Address = tokenInformationResponse.Data.AccountAddress;
var tokenInformationResponse = await WinoServerConnectionManager
.GetResponseAsync<TokenInformationEx, AuthorizationRequested>(new AuthorizationRequested(accountCreationDialogResult.ProviderType,
createdAccount,
createdAccount.ProviderType == MailProviderType.Gmail), accountCreationCancellationTokenSource.Token);
tokenInformationResponse.ThrowIfFailed();
if (creationDialog.State == AccountCreationDialogState.Canceled)
throw new AccountSetupCanceledException();
createdAccount.Address = tokenInformationResponse.Data.AccountAddress;
tokenInformationResponse.ThrowIfFailed();
}
}
// Address is still doesn't have a value for API synchronizers.
@@ -183,7 +208,7 @@ namespace Wino.Mail.ViewModels
await AccountService.UpdateProfileInformationAsync(createdAccount.Id, profileSynchronizationResult.ProfileInformation);
}
if (creationDialog is ICustomServerAccountCreationDialog customServerAccountCreationDialog)
if (creationDialog is IImapAccountCreationDialog customServerAccountCreationDialog)
customServerAccountCreationDialog.ShowPreparingFolders();
else
creationDialog.State = AccountCreationDialogState.PreparingFolders;
@@ -227,14 +252,6 @@ namespace Wino.Mail.ViewModels
await AccountService.CreateRootAliasAsync(createdAccount.Id, createdAccount.Address);
}
// TODO: Temporary disabled. Is this even needed? Users can configure special folders manually later on if discovery fails.
// Check if Inbox folder is available for the account after synchronization.
//var isInboxAvailable = await _folderService.IsInboxAvailableForAccountAsync(createdAccount.Id);
//if (!isInboxAvailable)
// throw new Exception(Translator.Exception_InboxNotAvailable);
// Send changes to listeners.
ReportUIChange(new AccountCreatedMessage(createdAccount));
@@ -250,6 +267,10 @@ namespace Wino.Mail.ViewModels
{
// Ignore
}
catch (ImapClientPoolException clientPoolException)
{
DialogService.InfoBarMessage(Translator.Info_AccountCreationFailedTitle, clientPoolException.InnerException.Message, InfoBarMessageType.Error);
}
catch (Exception ex)
{
Log.Error(ex, WinoErrors.AccountCreation);

View File

@@ -7,6 +7,7 @@ using Windows.UI.Xaml.Media.Animation;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
using Wino.Messaging.Client.Mails;
using Wino.Views.ImapSetup;
@@ -24,7 +25,7 @@ namespace Wino.Dialogs
IRecipient<ImapSetupNavigationRequested>,
IRecipient<ImapSetupBackNavigationRequested>,
IRecipient<ImapSetupDismissRequested>,
ICustomServerAccountCreationDialog
IImapAccountCreationDialog
{
private TaskCompletionSource<CustomServerInformation> _getServerInfoTaskCompletionSource = new TaskCompletionSource<CustomServerInformation>();
@@ -86,7 +87,7 @@ namespace Wino.Dialogs
}
public void StartImapConnectionSetup(MailAccount account) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), account, new DrillInNavigationTransitionInfo());
public void StartImapConnectionSetup(AccountCreationDialogResult accountCreationDialogResult) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), accountCreationDialogResult, new DrillInNavigationTransitionInfo());
private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => WeakReferenceMessenger.Default.UnregisterAll(this);

View File

@@ -10,6 +10,7 @@ using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.UWP.Extensions;
@@ -29,18 +30,27 @@ namespace Wino.Services
}
public override IAccountCreationDialog GetAccountCreationDialog(MailProviderType type)
public override IAccountCreationDialog GetAccountCreationDialog(AccountCreationDialogResult accountCreationDialogResult)
{
if (type == MailProviderType.IMAP4)
if (accountCreationDialogResult.SpecialImapProviderDetails == null)
{
return new NewImapSetupDialog
if (accountCreationDialogResult.ProviderType == MailProviderType.IMAP4)
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
return new NewImapSetupDialog
{
RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
};
}
else
{
return base.GetAccountCreationDialog(accountCreationDialogResult);
}
}
else
{
return base.GetAccountCreationDialog(type);
// Special IMAP provider like iCloud or Yahoo.
return base.GetAccountCreationDialog(accountCreationDialogResult);
}
}

View File

@@ -9,6 +9,7 @@ using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Exceptions;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.AutoDiscovery;
using Wino.Messaging.Client.Mails;
@@ -35,6 +36,10 @@ namespace Wino.Views.ImapSetup
{
DisplayNameBox.Text = accountProperties.Name;
}
else if (e.Parameter is AccountCreationDialogResult creationDialogResult)
{
WeakReferenceMessenger.Default.Send(new ImapSetupNavigationRequested(typeof(TestingImapConnectionPage), creationDialogResult));
}
}
private async void SignInClicked(object sender, RoutedEventArgs e)

View File

@@ -23,6 +23,7 @@ namespace Wino.Services
services.AddTransient<IContactService, ContactService>();
services.AddTransient<ISignatureService, SignatureService>();
services.AddTransient<IContextMenuItemService, ContextMenuItemService>();
services.AddTransient<ISpecialImapProviderConfigResolver, SpecialImapProviderConfigResolver>();
services.AddSingleton<IThreadingStrategyProvider, ThreadingStrategyProvider>();
services.AddTransient<IOutlookThreadingStrategy, OutlookThreadingStrategy>();

View File

@@ -0,0 +1,46 @@
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Accounts;
namespace Wino.Services
{
public class SpecialImapProviderConfigResolver : ISpecialImapProviderConfigResolver
{
private readonly CustomServerInformation iCloudServerConfig = new CustomServerInformation()
{
IncomingServer = "imap.mail.me.com",
IncomingServerPort = "993",
IncomingServerType = CustomIncomingServerType.IMAP4,
IncomingServerSocketOption = ImapConnectionSecurity.Auto,
IncomingAuthenticationMethod = ImapAuthenticationMethod.Auto,
OutgoingServer = "smtp.mail.me.com",
OutgoingServerPort = "587",
OutgoingServerSocketOption = ImapConnectionSecurity.Auto,
OutgoingAuthenticationMethod = ImapAuthenticationMethod.Auto,
MaxConcurrentClients = 5,
};
public CustomServerInformation GetServerInformation(MailAccount account, AccountCreationDialogResult dialogResult)
{
CustomServerInformation resolvedConfig = null;
if (dialogResult.SpecialImapProviderDetails.SpecialImapProvider == SpecialImapProvider.iCloud)
{
resolvedConfig = iCloudServerConfig;
// iCloud takes username before the @icloud part for incoming, but full address as outgoing.
resolvedConfig.IncomingServerUsername = dialogResult.SpecialImapProviderDetails.Address.Split('@')[0];
resolvedConfig.OutgoingServerUsername = dialogResult.SpecialImapProviderDetails.Address;
}
// Fill in account details.
resolvedConfig.Address = dialogResult.SpecialImapProviderDetails.Address;
resolvedConfig.IncomingServerPassword = dialogResult.SpecialImapProviderDetails.Password;
resolvedConfig.OutgoingServerPassword = dialogResult.SpecialImapProviderDetails.Password;
resolvedConfig.DisplayName = dialogResult.SpecialImapProviderDetails.SenderName;
return resolvedConfig;
}
}
}