CalDav synchronizer, new IMAP setup/edit page.

This commit is contained in:
Burak Kaan Köse
2026-02-15 02:20:18 +01:00
parent 64b9bfc392
commit acf0f649e8
58 changed files with 3993 additions and 1732 deletions
@@ -30,6 +30,11 @@ public class CustomServerInformation
public string OutgoingServerUsername { get; set; }
public string OutgoingServerPassword { get; set; }
public string CalDavServiceUrl { get; set; }
public string CalDavUsername { get; set; }
public string CalDavPassword { get; set; }
public ImapCalendarSupportMode CalendarSupportMode { get; set; }
/// <summary>
/// useSSL True: SslOnConnect
/// useSSL False: StartTlsWhenAvailable
@@ -65,6 +70,8 @@ public class CustomServerInformation
{ "OutgoingServerPort", OutgoingServerPort },
{ "OutgoingServerSocketOption", OutgoingServerSocketOption.ToString() },
{ "OutgoingAuthenticationMethod", OutgoingAuthenticationMethod.ToString() },
{ "CalendarSupportMode", CalendarSupportMode.ToString() },
{ "CalDavServiceUrl", CalDavServiceUrl },
{ "ProxyServer", ProxyServer },
{ "ProxyServerPort", ProxyServerPort }
};
@@ -0,0 +1,8 @@
namespace Wino.Core.Domain.Enums;
public enum ImapCalendarSupportMode
{
Disabled = 0,
CalDav = 1,
LocalOnly = 2
}
+1
View File
@@ -27,6 +27,7 @@ public enum WinoPage
SettingOptionsPage,
AliasManagementPage,
EditAccountDetailsPage,
ImapCalDavSettingsPage,
KeyboardShortcutsPage,
CalendarPage,
CalendarSettingsPage,
@@ -1,17 +1,22 @@
using System.Threading.Tasks;
using System;
using System.Threading;
using System.Threading.Tasks;
using Wino.Core.Domain.Models.AutoDiscovery;
namespace Wino.Core.Domain.Interfaces;
/// <summary>
/// Searches for Auto Discovery settings for custom mail accounts.
/// Searches for auto-discovery settings for custom mail accounts.
/// </summary>
public interface IAutoDiscoveryService
{
/// <summary>
/// Tries to return the best mail server settings using different techniques.
/// </summary>
/// <param name="mailAddress">Address to search settings for.</param>
/// <returns>CustomServerInformation with only settings applied.</returns>
Task<AutoDiscoverySettings> GetAutoDiscoverySettings(AutoDiscoveryMinimalSettings autoDiscoveryMinimalSettings);
/// <summary>
/// Tries to resolve a CalDAV endpoint for the mailbox address.
/// </summary>
Task<Uri> DiscoverCalDavServiceUriAsync(string mailAddress, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Wino.Core.Domain.Models.Calendar;
namespace Wino.Core.Domain.Interfaces;
public interface ICalDavClient
{
Task<IReadOnlyList<CalDavCalendar>> DiscoverCalendarsAsync(
CalDavConnectionSettings connectionSettings,
CancellationToken cancellationToken = default);
Task<IReadOnlyList<CalDavCalendarEvent>> GetCalendarEventsAsync(
CalDavConnectionSettings connectionSettings,
CalDavCalendar calendar,
DateTimeOffset startUtc,
DateTimeOffset endUtc,
CancellationToken cancellationToken = default);
}
@@ -0,0 +1,14 @@
using System;
using System.Threading.Tasks;
namespace Wino.Core.Domain.Interfaces;
/// <summary>
/// Persists CalDAV ICS payloads on disk for IMAP accounts.
/// </summary>
public interface ICalendarIcsFileService
{
Task SaveCalendarItemIcsAsync(Guid accountId, Guid calendarId, Guid calendarItemId, string remoteEventId, string remoteResourceHref, string eTag, string icsContent);
Task DeleteCalendarItemIcsAsync(Guid accountId, Guid calendarItemId);
Task DeleteCalendarIcsForCalendarAsync(Guid accountId, Guid calendarId);
}
@@ -1,24 +0,0 @@
using System.Threading.Tasks;
using Wino.Core.Domain.Entities.Shared;
namespace Wino.Core.Domain.Interfaces;
public interface IImapAccountCreationDialog : IAccountCreationDialog
{
/// <summary>
/// Returns the custom server information from the dialog..
/// </summary>
/// <returns>Null if canceled.</returns>
Task<CustomServerInformation> GetCustomServerInformationAsync();
/// <summary>
/// Displays preparing folders page.
/// </summary>
void ShowPreparingFolders();
/// <summary>
/// Updates account properties for the welcome imap setup dialog and starts the setup.
/// </summary>
/// <param name="account">Account properties.</param>
void StartImapConnectionSetup(MailAccount account);
}
@@ -64,8 +64,8 @@ public class AutoDiscoverySettings
}
public AutoDiscoveryProviderSetting GetImapSettings()
=> Settings?.Find(a => a.Protocol == "IMAP");
=> Settings?.Find(a => string.Equals(a.Protocol, "IMAP", StringComparison.OrdinalIgnoreCase));
public AutoDiscoveryProviderSetting GetSmptpSettings()
=> Settings?.Find(a => a.Protocol == "SMTP");
=> Settings?.Find(a => string.Equals(a.Protocol, "SMTP", StringComparison.OrdinalIgnoreCase));
}
@@ -0,0 +1,10 @@
namespace Wino.Core.Domain.Models.Calendar;
public sealed class CalDavCalendar
{
public string RemoteCalendarId { get; init; } = string.Empty;
public string Name { get; init; } = string.Empty;
public string CTag { get; init; } = string.Empty;
public string SyncToken { get; init; } = string.Empty;
}
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using Wino.Core.Domain.Enums;
namespace Wino.Core.Domain.Models.Calendar;
public sealed class CalDavCalendarEvent
{
public string RemoteEventId { get; init; } = string.Empty;
public string RemoteResourceHref { get; init; } = string.Empty;
public string ETag { get; init; } = string.Empty;
public string IcsContent { get; init; } = string.Empty;
public string Uid { get; init; } = string.Empty;
public string SeriesMasterRemoteEventId { get; init; } = string.Empty;
public bool IsSeriesMaster { get; init; }
public bool IsRecurringInstance { get; init; }
public string Title { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
public string Location { get; init; } = string.Empty;
public DateTimeOffset Start { get; init; }
public DateTimeOffset End { get; init; }
public string StartTimeZone { get; init; } = string.Empty;
public string EndTimeZone { get; init; } = string.Empty;
public string Recurrence { get; init; } = string.Empty;
public string OrganizerDisplayName { get; init; } = string.Empty;
public string OrganizerEmail { get; init; } = string.Empty;
public CalendarItemStatus Status { get; init; } = CalendarItemStatus.Accepted;
public CalendarItemVisibility Visibility { get; init; } = CalendarItemVisibility.Default;
public CalendarItemShowAs ShowAs { get; init; } = CalendarItemShowAs.Busy;
public bool IsHidden { get; init; }
public IReadOnlyList<CalDavEventAttendee> Attendees { get; init; } = [];
public IReadOnlyList<CalDavEventReminder> Reminders { get; init; } = [];
}
public sealed class CalDavEventAttendee
{
public string Name { get; init; } = string.Empty;
public string Email { get; init; } = string.Empty;
public AttendeeStatus AttendenceStatus { get; init; } = AttendeeStatus.NeedsAction;
public bool IsOrganizer { get; init; }
public bool IsOptionalAttendee { get; init; }
}
public sealed class CalDavEventReminder
{
public int DurationInSeconds { get; init; }
public CalendarItemReminderType ReminderType { get; init; } = CalendarItemReminderType.Popup;
}
@@ -0,0 +1,11 @@
using System;
namespace Wino.Core.Domain.Models.Calendar;
public sealed class CalDavConnectionSettings
{
public Uri ServiceUri { get; init; }
public string Username { get; init; } = string.Empty;
public string Password { get; init; } = string.Empty;
}
@@ -376,6 +376,47 @@
"IMAPSetupDialog_Username": "Username",
"IMAPSetupDialog_UsernamePlaceholder": "johndoe, johndoe@fabrikam.com, domain/johndoe",
"IMAPSetupDialog_UseSameConfig": "Use the same username and password for sending email",
"ImapCalDavSettingsPage_TitleCreate": "IMAP and Calendar Setup",
"ImapCalDavSettingsPage_TitleEdit": "Edit IMAP and Calendar Settings",
"ImapCalDavSettingsPage_Subtitle": "Configure IMAP/SMTP and optional calendar synchronization for this account.",
"ImapCalDavSettingsPage_BasicSectionTitle": "Basic setup",
"ImapCalDavSettingsPage_BasicSectionDescription": "Enter your identity and credentials. Wino can try to detect server settings automatically.",
"ImapCalDavSettingsPage_BasicTab": "Basic",
"ImapCalDavSettingsPage_EnableCalendarSupport": "Enable calendar support",
"ImapCalDavSettingsPage_AutoDiscoverButton": "Autodiscover mail settings",
"ImapCalDavSettingsPage_AutoDiscoverySuccessMessage": "Mail settings discovered and applied.",
"ImapCalDavSettingsPage_AdvancedSectionTitle": "Advanced configuration",
"ImapCalDavSettingsPage_AdvancedSectionDescription": "Enter server settings manually if autodiscovery is unavailable or incorrect.",
"ImapCalDavSettingsPage_AdvancedTab": "Advanced",
"ImapCalDavSettingsPage_CalendarSectionTitle": "Calendar setup",
"ImapCalDavSettingsPage_CalendarSectionDescription": "Choose how calendar data should work for this IMAP account.",
"ImapCalDavSettingsPage_CalendarModeHeader": "Calendar mode",
"ImapCalDavSettingsPage_ConnectionSecurityHeader": "Connection security",
"ImapCalDavSettingsPage_AuthenticationMethodHeader": "Authentication method",
"ImapCalDavSettingsPage_CalendarModeDisabled": "Disabled",
"ImapCalDavSettingsPage_CalendarModeCalDav": "CalDAV synchronization",
"ImapCalDavSettingsPage_CalendarModeLocalOnly": "Local calendar only",
"ImapCalDavSettingsPage_CalendarModeDisabledDescription": "Calendar is disabled for this account.",
"ImapCalDavSettingsPage_CalendarModeCalDavDescription": "Calendar items are synchronized with your CalDAV server.",
"ImapCalDavSettingsPage_CalendarModeLocalOnlyDescription": "Calendar items are stored only on this computer and are not synchronized to the network.",
"ImapCalDavSettingsPage_LocalCalendarLearnMore": "How local calendar works",
"ImapCalDavSettingsPage_LocalCalendarDialogTitle": "Local calendar only",
"ImapCalDavSettingsPage_LocalCalendarDialogMessage": "Local calendar keeps all events only on your computer. Nothing is synchronized to iCloud, Yahoo, or any other provider.",
"ImapCalDavSettingsPage_CalDavServiceUrl": "CalDAV service URL",
"ImapCalDavSettingsPage_CalDavUsername": "CalDAV username",
"ImapCalDavSettingsPage_CalDavPassword": "CalDAV password",
"ImapCalDavSettingsPage_CalDavNotRequiredMessage": "CalDAV test is only required when calendar mode is set to CalDAV synchronization.",
"ImapCalDavSettingsPage_CalDavUrlRequired": "CalDAV service URL is required.",
"ImapCalDavSettingsPage_CalDavUrlInvalid": "CalDAV service URL must be an absolute URL.",
"ImapCalDavSettingsPage_CalDavUsernameRequired": "CalDAV username is required.",
"ImapCalDavSettingsPage_CalDavPasswordRequired": "CalDAV password is required.",
"ImapCalDavSettingsPage_TestImapButton": "Test IMAP connection",
"ImapCalDavSettingsPage_TestCalDavButton": "Test CalDAV connection",
"ImapCalDavSettingsPage_ImapTestSuccessMessage": "IMAP connection test succeeded.",
"ImapCalDavSettingsPage_CalDavTestSuccessMessage": "CalDAV connection test succeeded.",
"ImapCalDavSettingsPage_SaveSuccessMessage": "Account settings validated and saved.",
"ImapCalDavSettingsPage_ICloudHint": "Use an app-specific password generated from your Apple account settings.",
"ImapCalDavSettingsPage_YahooHint": "Use an app password from your Yahoo account security settings.",
"Info_AccountCreatedMessage": "{0} is created",
"Info_AccountCreatedTitle": "Account Creation",
"Info_AccountCreationFailedTitle": "Account Creation Failed",