GetSignature(MailAccount account, DraftCreationReason reason)
+ {
if (account.Preferences.IsSignatureEnabled)
{
var signatureId = reason == DraftCreationReason.Empty ?
@@ -718,26 +664,88 @@ namespace Wino.Core.Services
{
var signature = await _signatureService.GetSignatureAsync(signatureId.Value);
- if (string.IsNullOrWhiteSpace(builder.HtmlBody))
- {
- builder.HtmlBody = $"{gapHtml}{signature.HtmlBody}";
- }
- else
- {
- builder.HtmlBody = $"{gapHtml}{signature.HtmlBody}{gapHtml}{builder.HtmlBody}";
- }
+ return signature.HtmlBody;
}
}
- else
+
+ return null;
+ }
+
+ private MimeMessage CreateEmptyDraft(BodyBuilder builder, MimeMessage message, DraftCreationOptions draftCreationOptions, string signature)
+ {
+ builder.HtmlBody = CreateHtmlGap();
+ if (draftCreationOptions.MailToUri != null)
{
- builder.HtmlBody = $"{gapHtml}{builder.HtmlBody}";
+ if (draftCreationOptions.MailToUri.Subject != null)
+ message.Subject = draftCreationOptions.MailToUri.Subject;
+
+ if (draftCreationOptions.MailToUri.Body != null)
+ {
+ builder.HtmlBody = $"""{draftCreationOptions.MailToUri.Body}
""" + builder.HtmlBody;
+ }
+
+ if (draftCreationOptions.MailToUri.To.Any())
+ message.To.AddRange(draftCreationOptions.MailToUri.To.Select(x => new MailboxAddress(x, x)));
+
+ if (draftCreationOptions.MailToUri.Cc.Any())
+ message.Cc.AddRange(draftCreationOptions.MailToUri.Cc.Select(x => new MailboxAddress(x, x)));
+
+ if (draftCreationOptions.MailToUri.Bcc.Any())
+ message.Bcc.AddRange(draftCreationOptions.MailToUri.Bcc.Select(x => new MailboxAddress(x, x)));
+ }
+
+ if (signature != null)
+ builder.HtmlBody += signature;
+
+ return message;
+ }
+
+ private MimeMessage CreateReferencedDraft(BodyBuilder builder, MimeMessage message, DraftCreationOptions draftCreationOptions, MailAccount account, string signature)
+ {
+ var reason = draftCreationOptions.Reason;
+ var referenceMessage = draftCreationOptions.ReferencedMessage.MimeMessage;
+
+ var gap = CreateHtmlGap();
+ builder.HtmlBody = gap + CreateHtmlForReferencingMessage(referenceMessage);
+
+ if (signature != null)
+ {
+ builder.HtmlBody = gap + signature + builder.HtmlBody;
+ }
+
+ // Manage "To"
+ if (reason == DraftCreationReason.Reply || reason == DraftCreationReason.ReplyAll)
+ {
+ // Reply to the sender of the message
+ if (referenceMessage.ReplyTo.Count > 0)
+ message.To.AddRange(referenceMessage.ReplyTo);
+ else if (referenceMessage.From.Count > 0)
+ message.To.AddRange(referenceMessage.From);
+ else if (referenceMessage.Sender != null)
+ message.To.Add(referenceMessage.Sender);
+
+ if (reason == DraftCreationReason.ReplyAll)
+ {
+ // Include all of the other original recipients
+ message.To.AddRange(referenceMessage.To.Where(x => x is MailboxAddress mailboxAddress && !mailboxAddress.Address.Equals(account.Address, StringComparison.OrdinalIgnoreCase)));
+ message.Cc.AddRange(referenceMessage.Cc.Where(x => x is MailboxAddress mailboxAddress && !mailboxAddress.Address.Equals(account.Address, StringComparison.OrdinalIgnoreCase)));
+ }
+
+ // Manage "ThreadId-ConversationId"
+ if (!string.IsNullOrEmpty(referenceMessage.MessageId))
+ {
+ message.InReplyTo = referenceMessage.MessageId;
+ message.References.AddRange(referenceMessage.References);
+ message.References.Add(referenceMessage.MessageId);
+ }
+
+ message.Headers.Add("Thread-Topic", referenceMessage.Subject);
}
// Manage Subject
if (reason == DraftCreationReason.Forward && !referenceMessage.Subject.StartsWith("FW: ", StringComparison.OrdinalIgnoreCase))
message.Subject = $"FW: {referenceMessage.Subject}";
- else if ((reason == DraftCreationReason.Reply || reason == DraftCreationReason.ReplyAll) &&
- !referenceMessage.Subject.StartsWith("RE: ", StringComparison.OrdinalIgnoreCase))
+ else if ((reason == DraftCreationReason.Reply || reason == DraftCreationReason.ReplyAll) && !referenceMessage.Subject.StartsWith("RE: ", StringComparison.OrdinalIgnoreCase))
message.Subject = $"RE: {referenceMessage.Subject}";
else if (referenceMessage != null)
message.Subject = referenceMessage.Subject;
@@ -751,63 +759,7 @@ namespace Wino.Core.Services
}
}
- if (!string.IsNullOrEmpty(builder.HtmlBody))
- {
- builder.TextBody = HtmlAgilityPackExtensions.GetPreviewText(builder.HtmlBody);
- }
-
- message.Body = builder.ToMessageBody();
-
- // Apply mail-to protocol parameters if exists.
-
- if (draftCreationOptions.MailtoParameters != null)
- {
- if (draftCreationOptions.TryGetMailtoValue(DraftCreationOptions.MailtoSubjectParameterKey, out string subjectParameter))
- message.Subject = subjectParameter;
-
- if (draftCreationOptions.TryGetMailtoValue(DraftCreationOptions.MailtoBodyParameterKey, out string bodyParameter))
- {
- builder.TextBody = bodyParameter;
- builder.HtmlBody = bodyParameter;
-
- message.Body = builder.ToMessageBody();
- }
-
- static InternetAddressList ExtractRecipients(string parameterValue)
- {
- var list = new InternetAddressList();
-
- var splittedRecipients = parameterValue.Split(',');
-
- foreach (var recipient in splittedRecipients)
- list.Add(new MailboxAddress(recipient, recipient));
-
- return list;
-
- }
-
- if (draftCreationOptions.TryGetMailtoValue(DraftCreationOptions.MailtoToParameterKey, out string toParameter))
- message.To.AddRange(ExtractRecipients(toParameter));
-
- if (draftCreationOptions.TryGetMailtoValue(DraftCreationOptions.MailtoCCParameterKey, out string ccParameter))
- message.Cc.AddRange(ExtractRecipients(ccParameter));
-
- if (draftCreationOptions.TryGetMailtoValue(DraftCreationOptions.MailtoBCCParameterKey, out string bccParameter))
- message.Bcc.AddRange(ExtractRecipients(bccParameter));
- }
- else
- {
- // Update TextBody from existing HtmlBody if exists.
- }
-
- using MemoryStream memoryStream = new();
- message.WriteTo(FormatOptions.Default, memoryStream);
- byte[] buffer = memoryStream.GetBuffer();
- int count = (int)memoryStream.Length;
-
- return Convert.ToBase64String(buffer);
-
- // return message;
+ return message;
// Generates html representation of To/Cc/From/Time and so on from referenced message.
string CreateHtmlForReferencingMessage(MimeMessage referenceMessage)
@@ -820,28 +772,22 @@ namespace Wino.Core.Services
visitor.Visit(referenceMessage);
htmlMimeInfo += $"""
-
-
- From: {ParticipantsToHtml(referenceMessage.From)}
- Sent: {referenceMessage.Date.ToLocalTime()}
- To: {ParticipantsToHtml(referenceMessage.To)}
- {(referenceMessage.Cc.Count > 0 ? $"Cc: {ParticipantsToHtml(referenceMessage.Cc)}
" : string.Empty)}
- Subject: {referenceMessage.Subject}
-
-
- {visitor.HtmlBody}
-
- """;
+
+
+ From: {ParticipantsToHtml(referenceMessage.From)}
+ Sent: {referenceMessage.Date.ToLocalTime()}
+ To: {ParticipantsToHtml(referenceMessage.To)}
+ {(referenceMessage.Cc.Count > 0 ? $"Cc: {ParticipantsToHtml(referenceMessage.Cc)}
" : string.Empty)}
+ Subject: {referenceMessage.Subject}
+
+
+ {visitor.HtmlBody}
+
+ """;
return htmlMimeInfo;
}
- string CreateHtmlGap()
- {
- var template = $"""
""";
- return string.Concat(Enumerable.Repeat(template, 5));
- }
-
static string ParticipantsToHtml(InternetAddressList internetAddresses) =>
string.Join("; ", internetAddresses.Mailboxes
.Select(x => $"{x.Name ?? Translator.UnknownSender} <{x.Address ?? Translator.UnknownAddress}>"));
diff --git a/Wino.Core/Services/WinoRequestDelegator.cs b/Wino.Core/Services/WinoRequestDelegator.cs
index 6a270239..b47196ba 100644
--- a/Wino.Core/Services/WinoRequestDelegator.cs
+++ b/Wino.Core/Services/WinoRequestDelegator.cs
@@ -111,7 +111,7 @@ namespace Wino.Core.Services
QueueSynchronization(accountId);
}
- public async Task ExecuteAsync(DraftPreperationRequest draftPreperationRequest)
+ public async Task ExecuteAsync(DraftPreparationRequest draftPreperationRequest)
{
var request = new CreateDraftRequest(draftPreperationRequest);
diff --git a/Wino.Mail.ViewModels/AppShellViewModel.cs b/Wino.Mail.ViewModels/AppShellViewModel.cs
index 5ae4b34a..f037ab81 100644
--- a/Wino.Mail.ViewModels/AppShellViewModel.cs
+++ b/Wino.Mail.ViewModels/AppShellViewModel.cs
@@ -302,7 +302,7 @@ namespace Wino.Mail.ViewModels
}
else
{
- bool hasMailtoActivation = _launchProtocolService.MailtoParameters != null;
+ bool hasMailtoActivation = _launchProtocolService.MailToUri != null;
if (hasMailtoActivation)
{
@@ -774,16 +774,13 @@ namespace Wino.Mail.ViewModels
var draftOptions = new DraftCreationOptions
{
Reason = DraftCreationReason.Empty,
-
- // Include mail to parameters for parsing mailto if any.
- MailtoParameters = _launchProtocolService.MailtoParameters
+ MailToUri = _launchProtocolService.MailToUri
};
- var createdBase64EncodedMimeMessage = await _mailService.CreateDraftMimeBase64Async(account.Id, draftOptions).ConfigureAwait(false);
- var createdDraftMailMessage = await _mailService.CreateDraftAsync(account, createdBase64EncodedMimeMessage).ConfigureAwait(false);
+ var (draftMailCopy, draftBase64MimeMessage) = await _mailService.CreateDraftAsync(account, draftOptions).ConfigureAwait(false);
- var draftPreperationRequest = new DraftPreperationRequest(account, createdDraftMailMessage, createdBase64EncodedMimeMessage);
- await _winoRequestDelegator.ExecuteAsync(draftPreperationRequest);
+ var draftPreparationRequest = new DraftPreparationRequest(account, draftMailCopy, draftBase64MimeMessage);
+ await _winoRequestDelegator.ExecuteAsync(draftPreparationRequest);
}
protected override async void OnAccountUpdated(MailAccount updatedAccount)
diff --git a/Wino.Mail.ViewModels/ComposePageViewModel.cs b/Wino.Mail.ViewModels/ComposePageViewModel.cs
index e99adb70..966daf57 100644
--- a/Wino.Mail.ViewModels/ComposePageViewModel.cs
+++ b/Wino.Mail.ViewModels/ComposePageViewModel.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
-using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -58,7 +57,7 @@ namespace Wino.Mail.ViewModels
private MessageImportance selectedMessageImportance;
[ObservableProperty]
- private bool isCCBCCVisible = true;
+ private bool isCCBCCVisible;
[ObservableProperty]
private string subject;
@@ -77,21 +76,20 @@ namespace Wino.Mail.ViewModels
[ObservableProperty]
private bool isDraggingOverImagesDropZone;
- public ObservableCollection IncludedAttachments { get; set; } = new ObservableCollection();
-
- public ObservableCollection Accounts { get; set; } = new ObservableCollection();
- public ObservableCollection ToItems { get; set; } = new ObservableCollection();
- public ObservableCollection CCItemsItems { get; set; } = new ObservableCollection();
- public ObservableCollection BCCItems { get; set; } = new ObservableCollection();
+ public ObservableCollection IncludedAttachments { get; set; } = [];
+ public ObservableCollection Accounts { get; set; } = [];
+ public ObservableCollection ToItems { get; set; } = [];
+ public ObservableCollection CCItems { get; set; } = [];
+ public ObservableCollection BCCItems { get; set; } = [];
- public List ToolbarSections { get; set; } = new List()
- {
+ public List ToolbarSections { get; set; } =
+ [
new EditorToolbarSection(){ SectionType = EditorToolbarSectionType.Format },
new EditorToolbarSection(){ SectionType = EditorToolbarSectionType.Insert },
new EditorToolbarSection(){ SectionType = EditorToolbarSectionType.Draw },
new EditorToolbarSection(){ SectionType = EditorToolbarSectionType.Options }
- };
+ ];
private EditorToolbarSection selectedToolbarSection;
@@ -190,7 +188,7 @@ namespace Wino.Mail.ViewModels
// Save recipients.
SaveAddressInfo(ToItems, CurrentMimeMessage.To);
- SaveAddressInfo(CCItemsItems, CurrentMimeMessage.Cc);
+ SaveAddressInfo(CCItems, CurrentMimeMessage.Cc);
SaveAddressInfo(BCCItems, CurrentMimeMessage.Bcc);
SaveImportance();
@@ -239,12 +237,7 @@ namespace Wino.Mail.ViewModels
{
if (GetHTMLBodyFunction != null)
{
- var htmlBody = await GetHTMLBodyFunction();
-
- if (!string.IsNullOrEmpty(htmlBody))
- {
- bodyBuilder.HtmlBody = Regex.Unescape(htmlBody);
- }
+ bodyBuilder.HtmlBody = await GetHTMLBodyFunction();
}
if (!string.IsNullOrEmpty(bodyBuilder.HtmlBody))
@@ -309,7 +302,7 @@ namespace Wino.Mail.ViewModels
// Check if there is any delivering mail address from protocol launch.
- if (_launchProtocolService.MailtoParameters != null)
+ if (_launchProtocolService.MailToUri != null)
{
// TODO
//var requestedMailContact = await GetAddressInformationAsync(_launchProtocolService.MailtoParameters, ToItems);
@@ -322,7 +315,7 @@ namespace Wino.Mail.ViewModels
// DialogService.InfoBarMessage("Invalid Address", "Address is not a valid e-mail address.", InfoBarMessageType.Warning);
// Clear the address.
- _launchProtocolService.MailtoParameters = null;
+ _launchProtocolService.MailToUri = null;
}
}
@@ -427,15 +420,18 @@ namespace Wino.Mail.ViewModels
// Extract information
ToItems.Clear();
- CCItemsItems.Clear();
+ CCItems.Clear();
BCCItems.Clear();
LoadAddressInfo(replyingMime.To, ToItems);
- LoadAddressInfo(replyingMime.Cc, CCItemsItems);
+ LoadAddressInfo(replyingMime.Cc, CCItems);
LoadAddressInfo(replyingMime.Bcc, BCCItems);
LoadAttachments(replyingMime.Attachments);
+ if (replyingMime.Cc.Any() || replyingMime.Bcc.Any())
+ IsCCBCCVisible = true;
+
Subject = replyingMime.Subject;
CurrentMimeMessage = replyingMime;
diff --git a/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs b/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs
index 8aae0408..bf1a722d 100644
--- a/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs
+++ b/Wino.Mail.ViewModels/MailRenderingPageViewModel.cs
@@ -117,7 +117,7 @@ namespace Wino.Mail.ViewModels
#endregion
public INativeAppService NativeAppService { get; }
- public IStatePersistanceService StatePersistanceService { get; }
+ public IStatePersistanceService StatePersistenceService { get; }
public IPreferencesService PreferencesService { get; }
public MailRenderingPageViewModel(IDialogService dialogService,
@@ -127,14 +127,14 @@ namespace Wino.Mail.ViewModels
Core.Domain.Interfaces.IMailService mailService,
IFileService fileService,
IWinoRequestDelegator requestDelegator,
- IStatePersistanceService statePersistanceService,
+ IStatePersistanceService statePersistenceService,
IClipboardService clipboardService,
IUnsubscriptionService unsubscriptionService,
IPreferencesService preferencesService,
IWinoServerConnectionManager winoServerConnectionManager) : base(dialogService)
{
NativeAppService = nativeAppService;
- StatePersistanceService = statePersistanceService;
+ StatePersistenceService = statePersistenceService;
PreferencesService = preferencesService;
_winoServerConnectionManager = winoServerConnectionManager;
_clipboardService = clipboardService;
@@ -255,37 +255,27 @@ namespace Wino.Mail.ViewModels
if (initializedMailItemViewModel == null) return;
// Create new draft.
- var draftOptions = new DraftCreationOptions();
-
- if (operation == MailOperation.Reply)
- draftOptions.Reason = DraftCreationReason.Reply;
- else if (operation == MailOperation.ReplyAll)
- draftOptions.Reason = DraftCreationReason.ReplyAll;
- else if (operation == MailOperation.Forward)
- draftOptions.Reason = DraftCreationReason.Forward;
-
- // TODO: Separate mailto related stuff out of DraftCreationOptions and provide better
- // model for draft preperation request. Right now it's a mess.
-
- draftOptions.ReferenceMailCopy = initializedMailItemViewModel.MailCopy;
- draftOptions.ReferenceMimeMessage = initializedMimeMessageInformation.MimeMessage;
-
- var createdMimeMessage = await _mailService.CreateDraftMimeBase64Async(initializedMailItemViewModel.AssignedAccount.Id, draftOptions).ConfigureAwait(false);
-
- var createdDraftMailMessage = await _mailService.CreateDraftAsync(initializedMailItemViewModel.AssignedAccount,
- createdMimeMessage,
- initializedMimeMessageInformation.MimeMessage,
- initializedMailItemViewModel).ConfigureAwait(false);
-
- var draftPreperationRequest = new DraftPreperationRequest(initializedMailItemViewModel.AssignedAccount,
- createdDraftMailMessage,
- createdMimeMessage)
+ var draftOptions = new DraftCreationOptions()
{
- ReferenceMimeMessage = initializedMimeMessageInformation.MimeMessage,
- ReferenceMailCopy = initializedMailItemViewModel.MailCopy
+ Reason = operation switch
+ {
+ MailOperation.Reply => DraftCreationReason.Reply,
+ MailOperation.ReplyAll => DraftCreationReason.ReplyAll,
+ MailOperation.Forward => DraftCreationReason.Forward,
+ _ => DraftCreationReason.Empty
+ },
+ ReferencedMessage = new ReferencedMessage()
+ {
+ MimeMessage = initializedMimeMessageInformation.MimeMessage,
+ MailCopy = initializedMailItemViewModel.MailCopy
+ }
};
- await _requestDelegator.ExecuteAsync(draftPreperationRequest);
+ var (draftMailCopy, draftBase64MimeMessage) = await _mailService.CreateDraftAsync(initializedMailItemViewModel.AssignedAccount, draftOptions).ConfigureAwait(false);
+
+ var draftPreparationRequest = new DraftPreparationRequest(initializedMailItemViewModel.AssignedAccount, draftMailCopy, draftBase64MimeMessage, initializedMailItemViewModel.MailCopy);
+
+ await _requestDelegator.ExecuteAsync(draftPreparationRequest);
}
else if (initializedMailItemViewModel != null)
@@ -453,7 +443,7 @@ namespace Wino.Mail.ViewModels
OnPropertyChanged(nameof(IsImageRenderingDisabled));
- StatePersistanceService.IsReadingMail = true;
+ StatePersistenceService.IsReadingMail = true;
});
}
@@ -477,7 +467,7 @@ namespace Wino.Mail.ViewModels
Attachments.Clear();
MenuItems.Clear();
- StatePersistanceService.IsReadingMail = false;
+ StatePersistenceService.IsReadingMail = false;
}
private void LoadAddressInfo(InternetAddressList list, ObservableCollection collection)
diff --git a/Wino.Mail/Activation/ProtocolActivationHandler.cs b/Wino.Mail/Activation/ProtocolActivationHandler.cs
index 37e116dd..e8ff99ed 100644
--- a/Wino.Mail/Activation/ProtocolActivationHandler.cs
+++ b/Wino.Mail/Activation/ProtocolActivationHandler.cs
@@ -1,8 +1,8 @@
using System.Threading.Tasks;
-using System.Web;
using CommunityToolkit.Mvvm.Messaging;
using Windows.ApplicationModel.Activation;
using Wino.Core.Domain.Interfaces;
+using Wino.Core.Domain.Models.Launch;
using Wino.Messaging.Client.Authorization;
using Wino.Messaging.Client.Shell;
@@ -36,11 +36,7 @@ namespace Wino.Activation
else if (protocolString.StartsWith(MailtoProtocolTag))
{
// mailto activation. Try to parse params.
-
- var replaced = protocolString.Replace(MailtoProtocolTag, "mailto=");
- replaced = Wino.Core.Extensions.StringExtensions.ReplaceFirst(replaced, "?", "&");
-
- _launchProtocolService.MailtoParameters = HttpUtility.ParseQueryString(replaced);
+ _launchProtocolService.MailToUri = new MailToUri(protocolString);
if (_nativeAppService.IsAppRunning())
{
diff --git a/Wino.Mail/Services/LaunchProtocolService.cs b/Wino.Mail/Services/LaunchProtocolService.cs
deleted file mode 100644
index 40a699ed..00000000
--- a/Wino.Mail/Services/LaunchProtocolService.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System.Collections.Specialized;
-using Wino.Core.Domain.Interfaces;
-
-namespace Wino.Core.UWP.Services
-{
- public class LaunchProtocolService : ILaunchProtocolService
- {
- public object LaunchParameter { get; set; }
- public NameValueCollection MailtoParameters { get; set; }
- }
-}
diff --git a/Wino.Mail/Views/ComposePage.xaml b/Wino.Mail/Views/ComposePage.xaml
index 9db25cf4..571d05f0 100644
--- a/Wino.Mail/Views/ComposePage.xaml
+++ b/Wino.Mail/Views/ComposePage.xaml
@@ -493,7 +493,7 @@
VerticalAlignment="Center"
Click="ShowCCBCCClicked"
GotFocus="CCBBCGotFocus"
- Visibility="{x:Bind ViewModel.IsCCBCCVisible, Mode=OneWay}">
+ Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(ViewModel.IsCCBCCVisible), Mode=OneWay}">
+ Visibility="{x:Bind ViewModel.IsCCBCCVisible, Mode=OneWay}" />
+ Visibility="{x:Bind ViewModel.IsCCBCCVisible, Mode=OneWay}" />
+ Visibility="{x:Bind ViewModel.IsCCBCCVisible, Mode=OneWay}" />
+ Visibility="{x:Bind ViewModel.IsCCBCCVisible, Mode=OneWay}" />
-
CommandBarItems.xaml
@@ -892,4 +891,4 @@
-->
-
+
\ No newline at end of file