From 2a67a1e9616cbaf403aaf777587ce73ba1131e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 1 Nov 2025 01:04:04 +0100 Subject: [PATCH] draft header --- .../Extensions/OutlookIntegratorExtensions.cs | 14 +++++ .../Synchronizers/OutlookSynchronizer.cs | 59 +++++++++++++------ 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Wino.Core/Extensions/OutlookIntegratorExtensions.cs b/Wino.Core/Extensions/OutlookIntegratorExtensions.cs index 87051308..1073e117 100644 --- a/Wino.Core/Extensions/OutlookIntegratorExtensions.cs +++ b/Wino.Core/Extensions/OutlookIntegratorExtensions.cs @@ -323,10 +323,24 @@ public static class OutlookIntegratorExtensions var headers = new List(); + // PRIORITY: Always include WinoLocalDraftHeader first if it exists + // This is critical for draft mapping functionality + var winoDraftHeader = mime.Headers.FirstOrDefault(h => h.Field == Domain.Constants.WinoLocalDraftHeader); int includedHeaderCount = 0; + if (winoDraftHeader != null) + { + var headerValue = winoDraftHeader.Value.Length >= 995 ? winoDraftHeader.Value.Substring(0, 995) : winoDraftHeader.Value; + headers.Add(new InternetMessageHeader() { Name = winoDraftHeader.Field, Value = headerValue }); + includedHeaderCount++; + } + + // Include other headers up to the limit (excluding the already added WinoLocalDraftHeader) foreach (var header in mime.Headers) { + if (header.Field == Domain.Constants.WinoLocalDraftHeader) + continue; // Already processed above + if (!headersToIgnore.Contains(header.Field)) { var headerName = headersToModify.Contains(header.Field) ? $"X-{header.Field}" : header.Field; diff --git a/Wino.Core/Synchronizers/OutlookSynchronizer.cs b/Wino.Core/Synchronizers/OutlookSynchronizer.cs index 8afb5ac2..d06b42e0 100644 --- a/Wino.Core/Synchronizers/OutlookSynchronizer.cs +++ b/Wino.Core/Synchronizers/OutlookSynchronizer.cs @@ -98,6 +98,7 @@ public class OutlookSynchronizer : WinoSynchronizer - private MailCopy CreateMailCopyFromMessage(Message message, MailItemFolder assignedFolder) + private async Task CreateMailCopyFromMessageAsync(Message message, MailItemFolder assignedFolder) { if (message == null) return null; @@ -675,6 +676,37 @@ public class OutlookSynchronizer : WinoSynchronizer string.Equals(h.Name, Domain.Constants.WinoLocalDraftHeader, StringComparison.OrdinalIgnoreCase)); + + if (winoDraftHeader != null && Guid.TryParse(winoDraftHeader.Value, out Guid localDraftCopyUniqueId)) + { + // This message belongs to existing local draft copy. + // We don't need to create a new mail copy for this message, just update the existing one. + + bool isMappingSuccessful = await _outlookChangeProcessor.MapLocalDraftAsync( + Account.Id, + localDraftCopyUniqueId, + mailCopy.Id, + mailCopy.DraftId, + mailCopy.ThreadId); + + if (isMappingSuccessful) + { + _logger.Debug("Successfully mapped remote draft {RemoteId} to local draft {LocalId}", + mailCopy.Id, localDraftCopyUniqueId); + return null; // Don't create new mail copy, existing one was updated + } + + // Local copy doesn't exist. Continue execution to insert mail copy. + _logger.Debug("Local draft copy {LocalId} not found, creating new mail copy for {RemoteId}", + localDraftCopyUniqueId, mailCopy.Id); + } + } + return mailCopy; } @@ -687,10 +719,10 @@ public class OutlookSynchronizer : WinoSynchronizer CreateMinimalMailCopyAsync(Message message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default) + protected override async Task CreateMinimalMailCopyAsync(Message message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default) { // Use centralized method - return Task.FromResult(CreateMailCopyFromMessage(message, assignedFolder)); + return await CreateMailCopyFromMessageAsync(message, assignedFolder).ConfigureAwait(false); } private async Task GetMessageByIdAsync(string messageId, CancellationToken cancellationToken = default) @@ -1760,23 +1792,12 @@ public class OutlookSynchronizer : WinoSynchronizer> CreateNewMailPackagesAsync(Message message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default) { // Download MIME message for specific scenarios (e.g., search results, draft handling) - // During normal sync, this method should not be called - use CreateMailCopyFromMessage instead + // During normal sync, this method should not be called - use CreateMailCopyFromMessageAsync instead var mimeMessage = await DownloadMimeMessageAsync(message.Id, cancellationToken).ConfigureAwait(false); - var mailCopy = CreateMailCopyFromMessage(message, assignedFolder); + var mailCopy = await CreateMailCopyFromMessageAsync(message, assignedFolder).ConfigureAwait(false); - if (message.IsDraft.GetValueOrDefault() - && mimeMessage.Headers.Contains(Domain.Constants.WinoLocalDraftHeader) - && Guid.TryParse(mimeMessage.Headers[Domain.Constants.WinoLocalDraftHeader], out Guid localDraftCopyUniqueId)) - { - // This message belongs to existing local draft copy. - // We don't need to create a new mail copy for this message, just update the existing one. - - bool isMappingSuccessful = await _outlookChangeProcessor.MapLocalDraftAsync(Account.Id, localDraftCopyUniqueId, mailCopy.Id, mailCopy.DraftId, mailCopy.ThreadId); - - if (isMappingSuccessful) return null; - - // Local copy doesn't exists. Continue execution to insert mail copy. - } + // If draft mapping was successful, mailCopy will be null + if (mailCopy == null) return null; // Outlook messages can only be assigned to 1 folder at a time. // Therefore we don't need to create multiple copies of the same message for different folders.