Merge with default Display subject
authorThomas
Fri, 23 Oct 2020 12:33:27 +0200
branchDisplay subject
changeset 3333 37c5911cf930
parent 3321 f062e30bd7ff (current diff)
parent 3332 0874010b37fa (diff)
child 3338 7edaa142ec59
Merge with default
PEPSettings.cs
--- a/Extensions/FolderExtensions.cs	Mon Oct 19 07:57:10 2020 +0200
+++ b/Extensions/FolderExtensions.cs	Fri Oct 23 12:33:27 2020 +0200
@@ -1,7 +1,6 @@
 ´╗┐using System;
 using Outlook = Microsoft.Office.Interop.Outlook;
 
-
 namespace pEp.Extensions
 {
     internal static class FolderExtensions
@@ -91,6 +90,36 @@
         }
 
         /// <summary>
+        /// Checks if the folder is the default folder of the given type.
+        /// </summary>
+        /// <param name="folderType">The default folder type to check for.</param>
+        /// <returns>True if the folder is the default folder of the given type, otherwise false.</returns>
+        public static bool GetIsDefaultFolder(this Outlook.Folder folder, Outlook.OlDefaultFolders folderType)
+        {
+            bool result = false;
+            Outlook.Store store = null;
+            Outlook.Folder defaultFolder = null;
+
+            try
+            {
+                store = folder.Store;
+                defaultFolder = store.GetDefaultFolder(folderType) as Outlook.Folder;
+                result = (folder.FullFolderPath == defaultFolder.FullFolderPath);
+            }
+            catch (Exception ex)
+            {
+                Log.Error("GetIsDefaultFolder: Error occured. " + ex.ToString());
+            }
+            finally
+            {
+                store = null;
+                defaultFolder = null;
+            }
+
+            return result;
+        }
+
+        /// <summary>
         /// Gets the Last Used folder. Creates it if it doesn't exist.
         /// </summary>
         /// <returns>The Last Used folder or null if an error occured.</returns>
--- a/Mapi.cs	Mon Oct 19 07:57:10 2020 +0200
+++ b/Mapi.cs	Fri Oct 23 12:33:27 2020 +0200
@@ -1271,10 +1271,12 @@
         /// <param name="mapiObject">The MAPI object item to set its properties.</param>
         /// <param name="mapiProperties">The MAPI properties to set.</param>
         /// <param name="values">The values to set.</param>
+        /// <param name="save">Whether to save the MAPI object after setting the properties.</param>
         /// <returns>True if the method succeeds, otherwise false.</returns>
         private static bool SetMAPIProperties(object mapiObject,
                                               MapiProperty.MapiProp[] mapiProperties,
-                                              object[] values)
+                                              object[] values,
+                                              bool save = true)
         {
             // The return status of this method
             bool success = false;
@@ -1471,7 +1473,7 @@
                 IntPtr problems = IntPtr.Zero;
                 if (IMAPIProp.SetProps((uint)propCount, propArray, problems) == (uint)Mapi.HResult.S_OK)
                 {
-                    success = (IMAPIProp.SaveChanges((uint)Mapi.SaveOption.KEEP_OPEN_READWRITE) == (uint)Mapi.HResult.S_OK);
+                    success = save ? (IMAPIProp.SaveChanges((uint)Mapi.SaveOption.KEEP_OPEN_READWRITE) == (uint)Mapi.HResult.S_OK) : true;
                 }
             }
             catch (Exception ex)
@@ -1539,11 +1541,13 @@
         /// <param name="mapiProperties">The MAPI property to set.</param>
         /// <param name="values">The value to set.</param>
         /// <param name="useSetProps">Whether to use the IMAPIProp.SetProps method (instead of HrSetOneProp).</param>
+        /// <param name="save">Whether to save the MAPI object after setting the property.</param>
         /// <returns>True if the method succeeds, otherwise false.</returns>
         public static bool SetMAPIProperty(Outlook.MailItem omi,
                                            MapiProperty.MapiProp mapiProperty,
                                            object value,
-                                           bool useSetProps = false)
+                                           bool useSetProps = false,
+                                           bool save = true)
         {
             // Get MAPI object from mail item
             object mapiObject = omi?.MAPIOBJECT;
@@ -1553,7 +1557,7 @@
                 return false;
             }
 
-            return Mapi.SetMAPIProperty(mapiObject, Mapi.MAPIInterfaceIds.IMessage, mapiProperty, value, useSetProps);
+            return Mapi.SetMAPIProperty(mapiObject, Mapi.MAPIInterfaceIds.IMessage, mapiProperty, value, useSetProps, save);
         }
 
         /// <summary>
@@ -1567,16 +1571,18 @@
         /// <param name="mapiProperties">The MAPI property to set.</param>
         /// <param name="values">The value to set.</param>
         /// <param name="useSetProps">Whether to use the IMAPIProp.SetProps method (instead of HrSetOneProp).</param>
+        /// <param name="save">Whether to save the MAPI object after setting the property.</param>
         /// <returns>True if the method succeeds, otherwise false.</returns>
         private static bool SetMAPIProperty(object mapiObject,
                                             string mapiInterfaceId,
                                             MapiProperty.MapiProp mapiProperty,
                                             object value,
-                                            bool useSetProps = false)
+                                            bool useSetProps = false,
+                                            bool save = true)
         {
             if (useSetProps)
             {
-                return Mapi.SetMAPIProperties(mapiObject, new MapiProperty.MapiProp[] { mapiProperty }, new object[] { value });
+                return Mapi.SetMAPIProperties(mapiObject, new MapiProperty.MapiProp[] { mapiProperty }, new object[] { value }, save);
             }
 
             // The return status of this method
@@ -1777,8 +1783,15 @@
                 NativeMethods.HrSetOneProp(IMAPIProp, ptrPropValue);
 
                 // Save changes
-                Mapi.IMAPIProp mapiProp = (Mapi.IMAPIProp)Marshal.GetTypedObjectForIUnknown(IUnknown, typeof(Mapi.IMAPIProp));
-                success = (mapiProp.SaveChanges((uint)Mapi.SaveOption.KEEP_OPEN_READWRITE) == (uint)Mapi.HResult.S_OK);
+                if (save)
+                {
+                    Mapi.IMAPIProp mapiProp = (Mapi.IMAPIProp)Marshal.GetTypedObjectForIUnknown(IUnknown, typeof(Mapi.IMAPIProp));
+                    success = (mapiProp.SaveChanges((uint)Mapi.SaveOption.KEEP_OPEN_READWRITE) == (uint)Mapi.HResult.S_OK);
+                }
+                else
+                {
+                    success = true;
+                }
             }
             catch (Exception ex)
             {
--- a/PEPMessage.cs	Mon Oct 19 07:57:10 2020 +0200
+++ b/PEPMessage.cs	Fri Oct 23 12:33:27 2020 +0200
@@ -1701,6 +1701,7 @@
         {
             bool fromRecipientRemoved = false;
             bool isPGPMIMEMsg = convertToPGPMIMEAttachment ?? this.IsPGPMIMEEncrypted;
+            bool isMirror = false;
             Outlook.Attachments attachments = null;
             Outlook.Recipient newRecipient = null;
             Outlook.Recipients recipients = null;
@@ -1713,6 +1714,7 @@
 
             try
             {
+                isMirror = omi.GetIsMirror();
                 ns = Globals.ThisAddIn.Application.Session;
 
                 if (setRecipients)
@@ -2031,7 +2033,7 @@
                      * Do not do this for mirror items as we can hide the attachment in the
                      * preview manually.
                      */
-                    if (omi.GetIsMirror() == false)
+                    if (isMirror == false)
                     {
                         this.Attachments.Where(a => a.IsHidden)?.ToList()?.ForEach((attachment) =>
                         {
@@ -2139,6 +2141,13 @@
                     {
                         try
                         {
+                            // Don't add hidden Trusted Server attachments to mirror
+                            if (isMirror && this._Attachments[i].IsHidden)
+                            {
+                                Log.Verbose("ApplyTo: Skipping hidden attachment.");
+                                continue;
+                            }
+
                             this._Attachments[i].AddTo(attachments, ("attachment" + i.ToString()));
                         }
                         catch (Exception ex)
--- a/PEPSettings.cs	Mon Oct 19 07:57:10 2020 +0200
+++ b/PEPSettings.cs	Fri Oct 23 12:33:27 2020 +0200
@@ -99,6 +99,7 @@
         public static pEpCipherSuite       CIPHER_SUITE_DEFAULT                               = pEpCipherSuite.pEpCipherSuiteDefault;
         public const string                CRASH_REPORT_SEND_ADDRESS_DEFAULT                  = "crashreport@prettyeasyprivacy.com";
         public const string                CULTURE_CODE_DEFAULT                               = "en";
+        public const bool                  DELETE_MIRROR_MESSAGES_DEFAULT                     = false;
         public const string                DISCLAIMER_TEXT_DEFAULT                            = null;
         public const bool                  ENABLE_PEP_EXTENSIONS_BY_DEFAULT                   = false;
         public const bool                  ENCRYPT_ACCOUNTS_BY_DEFAULT                        = true;
@@ -219,6 +220,12 @@
         public string CrashReportSendAddress { get; private set; }
 
         /// <summary>
+        /// Gets or sets whether to delete a mirror message when the original is deleted.
+        /// Can only be set from the Registry.
+        /// </summary>
+        public bool DeleteMirrorMessages { get; private set; } = PEPSettings.DELETE_MIRROR_MESSAGES_DEFAULT;
+
+        /// <summary>
         /// Gets whether the pEp Extensions are to be enabled or not.
         /// Can only be set from the Registry.
         /// </summary>
--- a/UI/FormControlPreviewMessage.xaml	Mon Oct 19 07:57:10 2020 +0200
+++ b/UI/FormControlPreviewMessage.xaml	Fri Oct 23 12:33:27 2020 +0200
@@ -48,7 +48,7 @@
         </ResourceDictionary>
     </UserControl.Resources>
     <DockPanel Name="DockPanelLayoutRoot"
-                Margin="5">
+               Margin="5">
 
         <!--'Preview' text-->
         <TextBlock DockPanel.Dock="Top"
@@ -83,6 +83,7 @@
                 <ColumnDefinition Width="Auto" />
                 <ColumnDefinition Width="Auto" />
                 <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="Auto" />
             </Grid.ColumnDefinitions>
             <Grid.RowDefinitions>
                 <RowDefinition Height="Auto"/>
@@ -120,6 +121,7 @@
             <!-- From recipient -->
             <TextBox Grid.Row="0"
                      Grid.Column="1"
+                     Grid.ColumnSpan="2"
                      Background="Transparent"
                      FontFamily="Segoe UI"
                      FontSize="14"
@@ -134,17 +136,17 @@
 
             <!--Reply buttons-->
             <StackPanel Grid.Row="0"
-                        Grid.Column="2"
-                    Orientation="Horizontal"
-                    HorizontalAlignment="Right"
-                    VerticalAlignment="Stretch">
+                        Grid.Column="3"
+                        Orientation="Horizontal"
+                        HorizontalAlignment="Right"
+                        VerticalAlignment="Stretch">
                 <Button Name="ButtonReply"
-                    Style="{StaticResource StyleReplyButton}"                    
-                    Click="ButtonReply_Click">
+                        Style="{StaticResource StyleReplyButton}"
+                        Click="ButtonReply_Click">
                     <StackPanel Orientation="Horizontal">
                         <Image Stretch="Uniform"
-                           Source="pack://application:,,,/pEp;component/Resources/ImagePreviewReply.png"
-                           Margin="0,0,4,0" />
+                               Source="pack://application:,,,/pEp;component/Resources/ImagePreviewReply.png"
+                               Margin="0,0,4,0" />
                         <TextBlock VerticalAlignment="Center"
                                FontFamily="Segoe UI"
                                FontSize="12"
@@ -179,48 +181,48 @@
                 </Button>
             </StackPanel>
 
-            <!--'To' recipients-->
-            <StackPanel Grid.Row="1" 
-                        Grid.Column="1"
-                        Orientation="Horizontal">
-
-                <!--Recipients "To" text-->
-                <TextBlock Margin="0,0,10,0"
-                           Background="Transparent"
-                           FontFamily="Segoe UI"
-                           FontSize="11"
-                           Foreground="Gray"
-                           Text="{x:Static p:Resources.PreviewMessage_ToText}"
-                           TextWrapping="NoWrap"
-                           HorizontalAlignment="Stretch"
-                           VerticalAlignment="Center" />
+            <!--Recipients "To" text-->
+            <TextBlock Grid.Row="1" 
+                       Grid.Column="1"
+                       Margin="0,0,10,0"
+                       Background="Transparent"
+                       FontFamily="Segoe UI"
+                       FontSize="11"
+                       Foreground="Gray"
+                       Text="{x:Static p:Resources.PreviewMessage_ToText}"
+                       TextWrapping="NoWrap"
+                       HorizontalAlignment="Stretch"
+                       VerticalAlignment="Top" />
 
-                <ItemsControl ItemsSource="{Binding Message.To}"
-                              VerticalAlignment="Center">
-                    <ItemsControl.ItemsPanel>
-                        <ItemsPanelTemplate>
-                            <WrapPanel />
-                        </ItemsPanelTemplate>
-                    </ItemsControl.ItemsPanel>
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate>
-                            <TextBlock Margin="0,0,10,0"
-                                       Background="Transparent"
-                                       FontFamily="Segoe UI"
-                                       FontSize="11"
-                                       Foreground="DarkSlateGray"
-                                       Text="{Binding Address}"
-                                       TextWrapping="NoWrap"
-                                       HorizontalAlignment="Stretch"
-                                       VerticalAlignment="Center" />
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </StackPanel>
+            <!--To recipients-->
+            <ItemsControl ItemsSource="{Binding Message.To}"
+                          VerticalAlignment="Top"
+                          HorizontalAlignment="Left"
+                          Grid.Row="1"
+                          Grid.Column="2">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <WrapPanel />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <TextBlock Margin="0,0,10,0"
+                                   Background="Transparent"
+                                   FontFamily="Segoe UI"
+                                   FontSize="11"
+                                   Foreground="DarkSlateGray"
+                                   Text="{Binding Address}"
+                                   TextWrapping="NoWrap"
+                                   HorizontalAlignment="Stretch"
+                                   VerticalAlignment="Center" />
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
 
             <!--Date-->
             <TextBox Grid.Row="1"
-                     Grid.Column="2"
+                     Grid.Column="3"
                      Background="Transparent"
                      BorderThickness="0"
                      IsReadOnly="True"
@@ -233,45 +235,45 @@
                      VerticalAlignment="Center"
                      Text="{Binding Path='Date', Mode=OneWay}" />
 
+            <!--Recipients "Cc" text-->
+            <TextBlock Grid.Row="2" 
+                       Grid.Column="1"
+                       Margin="0,0,10,0"
+                       Background="Transparent"
+                       FontFamily="Segoe UI"
+                       FontSize="11"
+                       Foreground="Gray"
+                       Text="{x:Static p:Resources.PreviewMessage_CcText}"
+                       TextWrapping="NoWrap"
+                       HorizontalAlignment="Stretch"
+                       VerticalAlignment="Top"
+                       Visibility="{Binding Message.Cc, Converter={StaticResource IsListEmptyToInvertVisibility}}"/>
 
             <!--'Cc' recipients-->
-            <StackPanel Grid.Row="2" 
-                        Grid.Column="1"
-                        Orientation="Horizontal"
-                        Visibility="{Binding Message.Cc, Converter={StaticResource IsListEmptyToInvertVisibility}}">
-
-                <!--Recipients "Cc" text-->
-                <TextBlock Margin="0,0,10,0"
-                           Background="Transparent"
-                           FontFamily="Segoe UI"
-                           FontSize="11"
-                           Foreground="Gray"
-                           Text="{x:Static p:Resources.PreviewMessage_CcText}"
-                           TextWrapping="NoWrap"
-                           HorizontalAlignment="Stretch"
-                           VerticalAlignment="Center" />
-
-                <ItemsControl ItemsSource="{Binding Message.Cc}">
-                    <ItemsControl.ItemsPanel>
-                        <ItemsPanelTemplate>
-                            <WrapPanel />
-                        </ItemsPanelTemplate>
-                    </ItemsControl.ItemsPanel>
-                    <ItemsControl.ItemTemplate>
-                        <DataTemplate>
-                            <TextBlock Margin="0,0,10,0"
-                           Background="Transparent"
-                           FontFamily="Segoe UI"
-                           FontSize="11"
-                           Foreground="DarkSlateGray"
-                           Text="{Binding Address}"
-                           TextWrapping="NoWrap"
-                           HorizontalAlignment="Stretch"
-                           VerticalAlignment="Center" />
-                        </DataTemplate>
-                    </ItemsControl.ItemTemplate>
-                </ItemsControl>
-            </StackPanel>
+            <ItemsControl ItemsSource="{Binding Message.Cc}"
+                          Grid.Row="2" 
+                          Grid.Column="2"
+                          VerticalAlignment="Top"
+                          Visibility="{Binding Message.Cc, Converter={StaticResource IsListEmptyToInvertVisibility}}">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <WrapPanel />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <TextBlock Margin="0,0,10,0"
+                                   Background="Transparent"
+                                   FontFamily="Segoe UI"
+                                   FontSize="11"
+                                   Foreground="DarkSlateGray"
+                                   Text="{Binding Address}"
+                                   TextWrapping="NoWrap"
+                                   HorizontalAlignment="Stretch"
+                                   VerticalAlignment="Center" />
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
         </Grid>
 
         <!--Attachments-->
--- a/Wrappers/WatchedFolder.cs	Mon Oct 19 07:57:10 2020 +0200
+++ b/Wrappers/WatchedFolder.cs	Fri Oct 23 12:33:27 2020 +0200
@@ -80,22 +80,17 @@
             {
                 this.folder.BeforeFolderMove -= Folder_BeforeFolderMove;
                 this.folder.BeforeItemMove -= Folder_BeforeItemMove;
-
-                // Marshal.ReleaseComObject(this.folder);
                 this.folder = null;
             }
 
             if (this.items != null)
             {
                 this.items.ItemAdd -= Items_ItemAdd;
-
-                // Marshal.ReleaseComObject(this.items);
                 this.items = null;
             }
 
             // Raise the disposed event
-            if (this.Disposed != null)
-                this.Disposed.Invoke(this, new EventArgs());
+            this.Disposed?.Invoke(this, new EventArgs());
         }
 
         /**************************************************************
@@ -195,7 +190,94 @@
         /// </summary>
         private void Folder_BeforeItemMove(object item, Outlook.MAPIFolder moveTo, ref bool cancel)
         {
-            return;
+            // If the option to delete mirrors isn't set, return
+            if (Globals.ThisAddIn.Settings.DeleteMirrorMessages == false)
+            {
+                return;
+            }
+
+            // First check if we are in a secure store / untrusted server
+            Outlook.MailItem omi = null;
+            try
+            {
+                omi = item as Outlook.MailItem;
+                if (omi.GetIsInSecureStore() == false)
+                {
+                    omi = null;
+                    return;
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("Folder_BeforeItemMove: Error accessing mail item. " + ex.ToString());
+            }
+
+            /* If message gets deleted, remove its mirror from the pEp store.
+             * A message is considered to be deleted if the folder it is moved to is null (e.g. 
+             * when the user deletes the message directly with Shift+Del) or when it's moved to 
+             * the Deleted Items folder.
+             * Note: we need to remove the mirror when the message is moved to Deleted Items because
+             * there is no event raised when the user empties this folder (e.g. right-click > Empty folder).
+             */
+            bool deleteItem = false;
+            if (moveTo == null)
+            {
+                deleteItem = true;
+            }
+            else
+            {
+                Outlook.Folder moveToFolder = null;
+                try
+                {
+                    moveToFolder = moveTo as Outlook.Folder;
+                    deleteItem = moveToFolder.GetIsDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
+                }
+                catch (Exception ex)
+                {
+                    deleteItem = false;
+                    Log.Error("Folder_BeforeItemMove: Error determining folder type. " + ex.ToString());
+                }
+                finally
+                {
+                    moveToFolder = null;
+                }
+            }
+
+            // Permanently delete mirror if necessary
+            if (deleteItem)
+            {
+                Outlook.Folder parentFolder = null;
+                Outlook.Items items = null;
+                Outlook.MailItem mirror = null;
+                try
+                {
+                    mirror = omi.GetMirror();
+
+                    if (mirror != null)
+                    {
+                        mirror.PermanentlyDelete();
+                        
+                        // Delete also the mirror folder if necessary
+                        parentFolder = mirror.Parent as Outlook.Folder;
+                        items = parentFolder.Items;
+                        
+                        if (items.Count == 0)
+                        {
+                            parentFolder.Delete();
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("Folder_BeforeItemMove: Error deleting mirror. " + ex.ToString());
+                }
+                finally
+                {
+                    mirror = null;
+                }
+            }
+
+            omi = null;
         }
 
         /// <summary>