Major restructuration: OUT-497
authorThomas
Thu, 06 Sep 2018 09:29:19 +0200
branchOUT-497
changeset 2359 0e6191d039e4
parent 2358 5d193f09df27
child 2360 f01523e581fa
Major restructuration: - Remove FormRegionPrivacyStatus - Create new WatchedWindow as base class for WatchedExplorers and WatchedInspectors - Move all logic from FormRegionPrivacy to WatchedWindow - Use Explorer.SelectionChanged and Inspectors.Newinspector events instead of FormRegionPrivacyStatus.FormRegionShowing to detect opening of mail item. - Rework of RibbonCustomizations. State of pEp button now stored in WatchedWindow instead of FormRegionPrivacyStatus
Extensions/MailItemExtensions.cs
FPPMessage.cs
ThisAddIn.cs
UI/FormControlPreviewMessage.xaml.cs
UI/FormRegionPreviewUnencrypted.cs
UI/RibbonCustomizations.cs
Wrappers/WatchedExplorer.cs
Wrappers/WatchedInspector.cs
Wrappers/WatchedWindow.cs
pEpForOutlook.csproj
--- a/Extensions/MailItemExtensions.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/Extensions/MailItemExtensions.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -2392,6 +2392,16 @@
         }
 
         /// <summary>
+        /// Gets the WatchedExplorer or WatchedInspector in which the mail item resides.
+        /// </summary>
+        /// <param name="omi">The Outlook mail item to process with.</param>
+        /// <returns>The WatchedExplorer or WatchedInspector the mail item resides in or null if an error occured.</returns>
+        public static WatchedWindow GetWatchedParentWindow(this Outlook.MailItem omi)
+        {
+            return Globals.ThisAddIn.GetWatchedParentWindow(omi);
+        }
+
+        /// <summary>
         /// Gets the parsed transport message headers (MIME headers) of the given Outlook mail item.
         /// This will internally use the MAPI property PidTagTransportMessageHeaders.
         /// Warning: This can return null.
--- a/FPPMessage.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/FPPMessage.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -270,6 +270,9 @@
                             // Save the EntryId
                             PEPDatabase.StoreFPPEntryId(this.CurrentMessage.ForceProtectionId, this.CurrentEntryId);
 
+                            // Define a mail item
+                            Outlook.MailItem omi = null;
+
                             // Modify body
                             if (this.CurrentMessage?.LongMsg?.Contains(Globals.PEP_WEBSITE_READER_LINK) == true)
                             {
@@ -277,7 +280,6 @@
                                 this.CurrentMessage.LongMsg = FPPMessage.PEP_FPP_MESSAGE_BODY_PLAIN_PEP_INSTALLED;
 
                                 // Get mail item
-                                Outlook.MailItem omi = null;
                                 try
                                 {
                                     omi = Globals.ThisAddIn.Application.Session.GetItemFromID(this.CurrentEntryId);
@@ -359,10 +361,6 @@
                                     {
                                         Log.Error("ContinueProcessing: Error saving modified Initial Message. " + ex.ToString());
                                     }
-                                    finally
-                                    {
-                                        omi = null;
-                                    }
                                 }
                             }
 
@@ -370,21 +368,36 @@
                             status = this.CreateAndSendNextFPPMessage(MessageType.AnswerMessage);
 
                             // Set form regions
-                            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
+                            try
+                            {
+                                if (omi == null)
+                                {
+                                    omi = Globals.ThisAddIn.Application.Session.GetItemFromID(this.CurrentEntryId);
+                                }
+                                WatchedWindow window = omi.GetWatchedParentWindow();
+                                WindowFormRegionCollection formRegions = Globals.FormRegions[window.Window];
 
-                            // Set unencrypted preview if necessary
-                            if (formRegions?.FormRegionPreviewUnencrypted?.Visible == true)
-                            {
-                                formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(this.CurrentMessage);
-                                Log.Verbose("ContinueProcessing: Mirror displayed.");
+                                // Set unencrypted preview if necessary
+                                if (formRegions?.FormRegionPreviewUnencrypted?.Visible == true)
+                                {
+                                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(this.CurrentMessage);
+                                    Log.Verbose("FPPMessage.ContinueProcessing: Mirror displayed.");
+                                }
+
+                                // Update rating if necessary
+                                if (manuallyTriggered)
+                                {
+                                    var rating = AdapterExtensions.ReevaluateFPPMessageRating(this.CurrentMessage);
+                                    window.SetRating(rating);
+                                }
                             }
-
-                            // Update rating if necessary
-                            if (manuallyTriggered &&
-                                (formRegions?.FormRegionPrivacyStatus?.Visible == true))
+                            catch (Exception ex)
                             {
-                                var rating = AdapterExtensions.ReevaluateFPPMessageRating(this.CurrentMessage);
-                                formRegions.FormRegionPrivacyStatus.SetRating(rating);
+                                Log.Error("FPPMessage.ContinueProcessing: Error during setting form region and rating. " + ex.ToString());
+                            }
+                            finally
+                            {
+                                omi = null;
                             }
                         }
                     }
@@ -750,7 +763,7 @@
                             Log.Verbose("DecryptMessage: FormRegionPreviewUnencrypted not visible.");
                         }
 
-                        formRegions.FormRegionPrivacyStatus?.UpdateFormRegion(true);
+                        omi.GetWatchedParentWindow()?.UpdateFormRegion(true);
                     }
 
                     status = Globals.ReturnStatus.Success;
--- a/ThisAddIn.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/ThisAddIn.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -3,7 +3,6 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
-using System.Diagnostics;
 using System.Globalization;
 using System.IO;
 using System.Runtime.InteropServices;
@@ -55,8 +54,11 @@
         private System.Windows.Forms.Timer  inboxCleaner                = null;
 
         private List<WatchedExplorer>       watchedExplorers            = new List<WatchedExplorer>();
+        private List<WatchedInspector>      watchedInspectors           = new List<WatchedInspector>();
         private object                      mutexWatchedExplorers       = new object();
+        private object                      mutexWatchedInspectors      = new object();
         private Outlook.Explorers           explorers                   = null;
+        private Outlook.Inspectors          inspectors                  = null;
 
         /**************************************************************
          * 
@@ -221,6 +223,18 @@
         }
 
         /// <summary>
+        /// Adds a new WatchedInspector to the list of watched inspectors.
+        /// </summary>
+        /// <param name="watchedInspector">The WatchedInspector to add.</param>
+        internal void AddToWatchedInspectors(WatchedInspector watchedInspector)
+        {
+            lock (mutexWatchedInspectors)
+            {
+                this.watchedInspectors.Add(watchedInspector);
+            }
+        }
+
+        /// <summary>
         /// Removes a WatchedExplorer from the list of watched explorers.
         /// </summary>
         /// <param name="watchedExplorer">The WatchedExplorer to remove.</param>
@@ -233,6 +247,124 @@
         }
 
         /// <summary>
+        /// Removes a WatchedInspector from the list of watched inspectors.
+        /// </summary>
+        /// <param name="WatchedInspector">The WatchedInspector to remove.</param>
+        internal void RemoveFromWatchedInspectors(WatchedInspector watchedInspector)
+        {
+            lock (mutexWatchedInspectors)
+            {
+                this.watchedInspectors.Remove(watchedInspector);
+            }
+        }
+
+        /// <summary>
+        /// Gets the WatchedExplorer or WatchedInspector in which the given mail item resides.
+        /// </summary>
+        /// <param name="omi">The Outlook mail item to process with.</param>
+        /// <returns>The WatchedExplorer or WatchedInspector the mail item resides in or null if an error occured.</returns>
+        internal WatchedWindow GetWatchedParentWindow(Outlook.MailItem omi)
+        {
+            try
+            {
+                // First, check all watched explorers
+                foreach (var watchedExplorer in this.watchedExplorers)
+                {
+                    if (watchedExplorer?.CurrentMailItem?.Equals(omi) == true)
+                    {
+                        return watchedExplorer;
+                    }
+                }
+
+                // If window hasn't been found yet, check inspectors
+                foreach (var watchedInspector in this.watchedInspectors)
+                {
+                    if (watchedInspector?.CurrentMailItem?.Equals(omi) == true)
+                    {
+                        return watchedInspector;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("GetWatchedParentWindow: Error getting window. " + ex.ToString());
+            }
+
+            // If no window has been found, return null
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the watched window for an Inspector or Explorer object.
+        /// </summary>
+        /// <param name="window">The Inspector or Explorer window to get its WatchedWindow for.</param>
+        /// <returns>The watched window or null if not found.</returns>
+        internal WatchedWindow GetWatchedWindow(dynamic window)
+        {
+            Outlook.Explorer explorer = null;
+            Outlook.Inspector inspector = null;
+            WatchedWindow watchedWindow = null;
+
+            try
+            {
+                // First, try if window is an explorer
+                explorer = window as Outlook.Explorer;
+                if (explorer != null)
+                {
+                    if (this.watchedExplorers.Count == 1)
+                    {
+                        watchedWindow = this.watchedExplorers[0];
+                    }
+                    else
+                    {
+                        foreach (var watchedExplorer in this.watchedExplorers)
+                        {
+                            if (watchedExplorer?.Explorer?.Equals(explorer) == true)
+                            {
+                                watchedWindow = watchedExplorer;
+                                break;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    // If window is no explorer, try if it is an inspector
+                    inspector = window as Outlook.Inspector;
+                    if (inspector != null)
+                    {
+                        if (this.watchedInspectors.Count == 1)
+                        {
+                            watchedWindow = this.watchedInspectors[0];
+                        }
+                        else
+                        {
+                            foreach (var watchedInspector in this.watchedInspectors)
+                            {
+                                if (watchedInspector?.Inspector?.Equals(inspector) == true)
+                                {
+                                    watchedWindow = watchedInspector;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("GetWatchedWindow: Error occured. " + ex.ToString());
+            }
+            finally
+            {
+                explorer = null;
+                inspector = null;
+            }
+
+            return watchedWindow;
+        }
+        
+        /// <summary>
         /// This updates the accounts list in pEp settings with the ones found in Outlook, adding new accounts and removing
         /// all accounts that are not there anymore.
         /// </summary>
@@ -513,6 +645,29 @@
         }
 
         /// <summary>
+        /// Sends a request to recalculate the message rating of all open windows (except one) again.
+        /// </summary>
+        /// <param name="windowToExclude">The window to not calculate its rating for</param>
+        internal void RecalculateAllWindows(WatchedWindow windowToExclude)
+        {
+            for (int i = 0; i < this.watchedExplorers.Count; i++)
+            {
+                if ((windowToExclude as WatchedExplorer)?.Equals(this.watchedExplorers[i]) != true)
+                {
+                    this.watchedExplorers[i].RequestRatingAndUIUpdate();
+                }
+            }
+
+            for (int i = 0; i < this.watchedInspectors.Count; i++)
+            {
+                if ((windowToExclude as WatchedInspector)?.Equals(this.watchedInspectors[i]) != true)
+                {
+                    this.watchedInspectors[i].RequestRatingAndUIUpdate();
+                }
+            }
+        }
+
+        /// <summary>
         /// Registers each own identity in the pEp engine.
         /// An own identity represents each account in Outlook.
         /// </summary>
@@ -2515,13 +2670,11 @@
                     this._OutlookOptions.ReadOptionsFromRegistry();
                     this._OutlookOptions.SetRegistryValues();
 
-                    // Connect watched folders
-                    Log.Info("ThisAddIn_Startup: Connect Watched folders");
+                    // Connect watched objects
+                    Log.Info("ThisAddIn_Startup: Connect Watched objects");
                     this.ConnectWatchedFolders();
-
-                    // Connect watched explorers
-                    Log.Info("ThisAddIn_Startup: Connect Watched explorers");
                     this.ConnectWatchedExplorers(true);
+                    this.ConnectWatchedInspectors(true);
 
                     // Connect application events
                     Log.Info("ThisAddIn_Startup: Connect Application Events");
@@ -2618,22 +2771,62 @@
         }
 
         /// <summary>
-        /// Disconnects all explorer events.
+        /// Event handler for when a new explorer is being opened and 
+        /// added to the Explorers collection.
         /// </summary>
-        private void DisconnectWatchedExplorers()
+        /// <param name="explorer">The newly opened explorer.</param>
+        private void Explorers_NewExplorer(Outlook.Explorer explorer)
         {
-            this.explorers.NewExplorer -= Explorers_NewExplorer;
-            this.explorers = null;
+            this.AddToWatchedExplorers(new WatchedExplorer(explorer));
         }
 
         /// <summary>
-        /// Event handler for when a new explorer is being opened and 
-        /// added to the Explorers collection.
+        /// Connects all inspectors with their respective events and the Inspectors collection
+        /// with the Newinspector event.
+        /// <param name="connect">Whether to connect or disconnect the inspectors.</param>
         /// </summary>
-        /// <param name="Explorer">The newly opened explorer.</param>
-        private void Explorers_NewExplorer(Outlook.Explorer explorer)
+        private void ConnectWatchedInspectors(bool connect)
         {
-            this.AddToWatchedExplorers(new WatchedExplorer(explorer));
+            try
+            {
+                if (connect)
+                {
+                    this.inspectors = this.Application.Inspectors;
+
+                    for (int i = 1; i <= this.inspectors.Count; i++)
+                    {
+                        this.watchedInspectors.Add(new WatchedInspector(this.inspectors[i]));
+                    }
+
+                    this.inspectors.NewInspector += Explorers_NewInspector;
+                }
+                else
+                {
+                    this.inspectors.NewInspector -= Explorers_NewInspector;
+
+                    for (int i = 0; i < this.watchedInspectors.Count; i++)
+                    {
+                        this.RemoveFromWatchedInspectors(this.watchedInspectors[i]);
+                        this.watchedInspectors[i].Dispose();
+                    }
+
+                    this.inspectors = null;
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("ConnectWatchedInspectors: Error occured. " + ex.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a new inspector is being opened and 
+        /// added to the Inspectors collection.
+        /// </summary>
+        /// <param name="inspector">The newly opened inspector.</param>
+        private void Explorers_NewInspector(Outlook.Inspector inspector)
+        {
+            this.AddToWatchedInspectors(new WatchedInspector(inspector));
         }
 
         /// <summary>
@@ -2876,6 +3069,7 @@
 
             // Disconnect watched items
             this.ConnectWatchedExplorers(false);
+            this.ConnectWatchedInspectors(false);
 
             // Save configuration
             this._Settings.SaveToRegistry();
--- a/UI/FormControlPreviewMessage.xaml.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/UI/FormControlPreviewMessage.xaml.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -352,8 +352,8 @@
                             // Update UI
                             try
                             {
-                                WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
-                                formRegions?.FormRegionPrivacyStatus?.SetRating(pEpCOMServerAdapterLib.pEpRating.pEpRatingUnencrypted);
+                                WatchedWindow watchedWindow = Globals.ThisAddIn.GetWatchedWindow(Globals.ThisAddIn.Application.ActiveWindow());
+                                watchedWindow.SetRating(pEpCOMServerAdapterLib.pEpRating.pEpRatingUndefined);
                             }
                             catch (Exception ex)
                             {
--- a/UI/FormRegionPreviewUnencrypted.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/UI/FormRegionPreviewUnencrypted.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -337,24 +337,8 @@
                 // Decrypt the current mail item
                 omi = this.OutlookItem as Outlook.MailItem;
 
-                // Try to get the mirror from the FormRegionPrivacyStatus
-                try
-                {
-                    WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
-                    if (this.Equals(formRegions.FormRegionPreviewUnencrypted))
-                    {
-                        decryptedMessage = formRegions.FormRegionPrivacyStatus?.Mirror;
-                    }                   
-                }
-                catch (Exception ex)
-                {
-                    decryptedMessage = null;
-                    Log.Error("CreateResponseItem: Error getting mirror from FormRegionPrivacyStatus. " + ex.ToString());
-                }
-
                 // Use mirror or create it from original
-                if ((decryptedMessage != null) ||
-                    ((PEPMessage.Create(omi, out message) == Globals.ReturnStatus.Success) &&
+                if (((PEPMessage.Create(omi, out message) == Globals.ReturnStatus.Success) &&
                      (msgProcessor.Decrypt(message, out decryptedMessage))))
                 {
                     // Create reply of current item
--- a/UI/RibbonCustomizations.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/UI/RibbonCustomizations.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -24,6 +24,23 @@
          */
         private static Office.IRibbonUI ribbon;
 
+        private static bool        DISABLE_FORCE_PROTECTION_DEFAULT    = false;
+        private static bool        FORCE_PROTECTION_DEFAULT            = false;
+        private static bool        FORCE_UNENCRYPTED_DEFAULT           = false;
+        private static bool        IS_DRAFT_DEFAULT                    = false;
+        private static bool        NEVER_UNSECURE_DEFAULT              = false;
+        private static pEpRating   RATING_DEFAULT                      = pEpRating.pEpRatingUndefined;
+
+        private enum MessageProperties
+        {
+            DisableForceProtection,
+            ForceProtection,
+            ForceUnencrypted,
+            IsDraft,
+            NeverUnsecure,
+            Rating
+        }
+
         /**************************************************************
          * 
          * Constructors
@@ -50,7 +67,7 @@
         /// <returns>True if the Force Protection option is disabled for the current mail item, otherwise false.</returns>
         internal bool GetDisableForceProtection(Office.IRibbonControl control)
         {
-            return this.GetFormRegionPrivacyStatus(control)?.DisableForceProtection ?? false;
+            return RibbonCustomizations.GetRibbonProperty(control, MessageProperties.DisableForceProtection);
         }
 
         /// <summary>
@@ -62,7 +79,7 @@
         {
             try
             {
-                this.GetFormRegionPrivacyStatus(control).DisableForceProtection = disable;
+                RibbonCustomizations.SetRibbonProperty(control, MessageProperties.DisableForceProtection, disable);
             }
             catch (Exception ex)
             {
@@ -77,7 +94,7 @@
         /// <returns>True if the current mail item is forcefully protected, otherwise false.</returns>
         internal bool GetForceProtection(Office.IRibbonControl control)
         {
-            return this.GetFormRegionPrivacyStatus(control)?.ForceProtection ?? false;
+            return RibbonCustomizations.GetRibbonProperty(control, MessageProperties.ForceProtection);
         }
 
         /// <summary>
@@ -89,7 +106,7 @@
         {
             try
             {
-                this.GetFormRegionPrivacyStatus(control).ForceProtection = forceProtection;
+                RibbonCustomizations.SetRibbonProperty(control, MessageProperties.ForceProtection, forceProtection);
             }
             catch (Exception ex)
             {
@@ -104,7 +121,7 @@
         /// <returns>True if the current mail item is forcefully unencrypted, otherwise false.</returns>
         internal bool GetForceUnencrypted(Office.IRibbonControl control)
         {
-            return this.GetFormRegionPrivacyStatus(control)?.ForceUnencrypted ?? false;
+            return RibbonCustomizations.GetRibbonProperty(control, MessageProperties.ForceUnencrypted);
         }
 
         /// <summary>
@@ -116,7 +133,7 @@
         {
             try
             {
-                this.GetFormRegionPrivacyStatus(control).ForceUnencrypted = forceUnencrypted;
+                RibbonCustomizations.SetRibbonProperty(control, MessageProperties.ForceUnencrypted, forceUnencrypted);
             }
             catch (Exception ex)
             {
@@ -131,19 +148,19 @@
         /// <returns>True if the current mail item has the Never Unsecure option set, otherwise false.</returns>
         internal bool GetNeverUnsecure(Office.IRibbonControl control)
         {
-            return this.GetFormRegionPrivacyStatus(control)?.NeverUnsecure ?? false;
+            return RibbonCustomizations.GetRibbonProperty(control, MessageProperties.NeverUnsecure);
         }
 
         /// <summary>
         /// Sets whether the current mail item should be forcefully unencrypted or not.
         /// </summary>
         /// <param name="control">The current button control.</param>
-        /// <param name="neverUnsecure">Whether to enable Force Unencrypted or not.</param>
+        /// <param name="neverUnsecure">Whether to enable Never Unsecure or not.</param>
         internal void SetNeverUnsecure(Office.IRibbonControl control, bool neverUnsecure)
         {
             try
             {
-                this.GetFormRegionPrivacyStatus(control).NeverUnsecure = neverUnsecure;
+                RibbonCustomizations.SetRibbonProperty(control, MessageProperties.NeverUnsecure, neverUnsecure);
             }
             catch (Exception ex)
             {
@@ -158,7 +175,7 @@
         /// <returns>The pEpRating of the current message or undefined if an error occured.</returns>
         private pEpRating GetRating(Office.IRibbonControl control)
         {
-            return this.GetFormRegionPrivacyStatus(control)?.Rating ?? pEpRating.pEpRatingUndefined;
+            return RibbonCustomizations.GetRibbonProperty(control, MessageProperties.Rating);
         }
 
         /**************************************************************
@@ -176,6 +193,87 @@
             RibbonCustomizations.ribbon?.Invalidate();
         }
 
+        private static dynamic GetRibbonProperty(Office.IRibbonControl control, MessageProperties property)
+        {
+            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control?.Context);
+
+            switch (property)
+            {
+                case MessageProperties.DisableForceProtection:
+                    {
+                        return window?.DisableForceProtection ?? RibbonCustomizations.DISABLE_FORCE_PROTECTION_DEFAULT;
+                    }
+                case MessageProperties.ForceProtection:
+                    {
+                        return window?.ForceProtection ?? RibbonCustomizations.FORCE_PROTECTION_DEFAULT;
+                    }
+                case MessageProperties.ForceUnencrypted:
+                    {
+                        return window?.ForceUnencrypted ?? RibbonCustomizations.FORCE_UNENCRYPTED_DEFAULT;
+                    }
+                case MessageProperties.IsDraft:
+                    {
+                        return window?.IsDraft ?? RibbonCustomizations.IS_DRAFT_DEFAULT;
+                    }
+                case MessageProperties.NeverUnsecure:
+                    {
+                        return window?.NeverUnsecure ?? RibbonCustomizations.NEVER_UNSECURE_DEFAULT;
+                    }
+                case MessageProperties.Rating:
+                    {
+                        return window?.Rating ?? RibbonCustomizations.RATING_DEFAULT;
+                    }
+                default:
+                    break;
+            }
+
+            return null;
+        }
+
+        private static void SetRibbonProperty(Office.IRibbonControl control, MessageProperties property, dynamic value)
+        {
+            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control.Context);
+
+            if (window != null)
+            {
+                switch (property)
+                {
+                    case MessageProperties.DisableForceProtection:
+                        {
+                            window.DisableForceProtection = (bool)value;
+                        }
+                        break;
+                    case MessageProperties.ForceProtection:
+                        {
+                            window.ForceProtection = (bool)value;
+                        }
+                        break;
+                    case MessageProperties.ForceUnencrypted:
+                        {
+                            window.ForceUnencrypted = (bool)value;
+                        }
+                        break;
+                    case MessageProperties.IsDraft:
+                        {
+                            window.IsDraft = (bool)value;
+                        }
+                        break;
+                    case MessageProperties.NeverUnsecure:
+                        {
+                            window.NeverUnsecure = (bool)value;
+                        }
+                        break;
+                    case MessageProperties.Rating:
+                        {
+                            window.SetRating((pEpRating)value);
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
         /// <summary>
         /// Gets the Outlook contact item that is associated with a given control's parent
         /// window (Inspector / Explorer). Can return null.
@@ -252,44 +350,6 @@
         }
 
         /// <summary>
-        /// Gets the FormRegionPrivacyStatus that is associated with a given control's parent
-        /// window (Inspector / Explorer). Can return null.
-        /// </summary>
-        /// <param name="control">The control to get the associated form region for.</param>
-        /// <returns>The associated FormRegionPrivacyStatus or null if an error occured.</returns>
-        private FormRegionPrivacyStatus GetFormRegionPrivacyStatus(Office.IRibbonControl control)
-        {
-            dynamic window = null;
-            FormRegionPrivacyStatus formRegion = null;
-
-            try
-            {
-                // Get the parent window
-                window = control.Context as Outlook.Explorer;
-                if (window == null)
-                {
-                    window = control.Context as Outlook.Inspector;
-                }
-
-                if (window != null)
-                {
-                    formRegion = Globals.FormRegions[window].FormRegionPrivacyStatus;
-                }
-            }
-            catch (Exception ex)
-            {
-                formRegion = null;
-                Log.Error("GetFormRegionPrivacyStatus: Error getting form region. " + ex.ToString());
-            }
-            finally
-            {
-                window = null;
-            }
-
-            return formRegion;
-        }
-
-        /// <summary>
         /// Gets the Outlook mail item that is associated with a given control's parent
         /// window (Inspector / Explorer). Can return null.
         /// </summary>
@@ -567,11 +627,11 @@
                                 // Update UI
                                 if (string.IsNullOrEmpty(value as string))
                                 {
-                                    this.GetFormRegionPrivacyStatus(control)?.RequestRatingAndUIUpdate();
+                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
                                 }
                                 else
                                 {
-                                    this.GetFormRegionPrivacyStatus(control)?.SetRating(pEpRating.pEpRatingReliable);
+                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.SetRating(pEpRating.pEpRatingReliable);
                                 }
                                 break;
                             }
@@ -606,7 +666,7 @@
                                     omi.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, value);
 
                                     // Update UI
-                                    this.GetFormRegionPrivacyStatus(control)?.RequestRatingAndUIUpdate();
+                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
                                 }
 
                                 break;
@@ -768,7 +828,7 @@
             try
             {
                 Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
-                this.GetFormRegionPrivacyStatus(control)?.BuildAndShowManager();
+                Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
             }
             catch (Exception ex)
             {
@@ -911,7 +971,7 @@
         /// </summary>
         public string ButtonPrivacyStatus_GetScreentip(Office.IRibbonControl control)
         {
-            return Properties.Resources.PrivacyStatus_FormText;            
+            return Properties.Resources.PrivacyStatus_FormText;
         }
 
         /// <summary>
@@ -946,7 +1006,7 @@
                         {
                             omi = this.GetMailItem(control);
                             visible = ((omi?.GetIsDraft() == true) ||
-                                       (this.GetIsDecryptAlwaysEnabled(control)));                     
+                                       (this.GetIsDecryptAlwaysEnabled(control)));
                         }
                     }
                 }
@@ -970,7 +1030,7 @@
         public void ButtonSMIME_Clicked(Office.IRibbonControl control, bool pressed, ref bool cancel)
         {
             cancel = false;
-            this.GetFormRegionPrivacyStatus(control)?.RequestRatingAndUIUpdate();
+            Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
         }
 
         ///////////////////////////////////////////////////////////
@@ -1002,13 +1062,13 @@
             /* The button is disabled if
              *  - Rating is lower than reliable
              *  - Force Protection or Never Unsecure are enabled and not overridden
-             */ 
+             */
             if (((this.GetRating(control) < pEpRating.pEpRatingReliable) ||
                  (this.GetNeverUnsecure(control))) ||
                  ((this.GetForceProtection(control)) && (this.GetDisableForceProtection(control) == false)))
             {
                 return false;
-            }            
+            }
             else
             {
                 return true;
@@ -1149,7 +1209,7 @@
 
             if (this.GetIsPEPEnabled(control))
             {
-                enabled = ((this.GetRating(control) == pEpRating.pEpRatingUnencrypted) && 
+                enabled = ((this.GetRating(control) == pEpRating.pEpRatingUnencrypted) &&
                            (this.GetForceUnencrypted(control) == false));
             }
             else
@@ -1174,7 +1234,7 @@
         /// </summary>
         public bool ToggleButtonForceProtection_GetPressed(Office.IRibbonControl control)
         {
-            return ((this.GetForceProtection(control)) && 
+            return ((this.GetForceProtection(control)) &&
                     (this.GetDisableForceProtection(control) == false));
         }
 
@@ -1214,9 +1274,9 @@
         public bool ToggleButtonNeverUnsecure_GetEnabled(Office.IRibbonControl control)
         {
             // Enabled if not forcefully unencrypted, rating >= Reliable (or force protection), no S/MIME enabled and no BCC recipients
-             return (((this.GetRating(control) >= pEpRating.pEpRatingReliable) || (this.GetForceProtection(control)) && (this.ToggleButtonForceProtection_GetEnabled(control))) &&
-                     (this.GetForceUnencrypted(control) == false) &&
-                     (this.GetIsSMIMEEnabled(control) == false));
+            return (((this.GetRating(control) >= pEpRating.pEpRatingReliable) || (this.GetForceProtection(control)) && (this.ToggleButtonForceProtection_GetEnabled(control))) &&
+                    (this.GetForceUnencrypted(control) == false) &&
+                    (this.GetIsSMIMEEnabled(control) == false));
         }
 
         /// <summary>
@@ -1491,7 +1551,7 @@
                 if (explorer != null)
                 {
                     visible = (explorer.ActiveInlineResponse == null);
-                }                
+                }
             }
             catch (Exception ex)
             {
@@ -1642,7 +1702,7 @@
             switch (ribbonID)
             {
                 case "Microsoft.Outlook.Explorer":
-                    if (Globals.OutlookVersion == Globals.Version.Outlook2010 )
+                    if (Globals.OutlookVersion == Globals.Version.Outlook2010)
                     {
                         return GetResourceText("pEp.UI.RibbonCustomizationsExplorer2010.xml");
                     }
--- a/Wrappers/WatchedExplorer.cs	Tue Sep 04 11:14:15 2018 +0200
+++ b/Wrappers/WatchedExplorer.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -6,10 +6,12 @@
     /// <summary>
     /// Stores an Outlook Explorer with connected events.
     /// </summary>
-    public class WatchedExplorer : IDisposable
+    public class WatchedExplorer : WatchedWindow
     {
-        private Outlook.Explorer                explorer                   = null;
-        private CryptableMailItem               inlineResponseItem         = null;
+        private Outlook.Explorer        _Explorer               = null;
+
+        private string                  lastProcessedEntryId    = null;
+        private CryptableMailItem       inlineResponseItem      = null;
 
         /**************************************************************
          * 
@@ -23,23 +25,36 @@
         /// <param name="explorer">The explorer to watch.</param>
         public WatchedExplorer(Outlook.Explorer explorer)
         {
-            this.explorer = explorer;
+            this._Explorer = explorer;
 
-            if (this.explorer != null)
+            if (this._Explorer != null)
             {
                 this.ConnectWatchedExplorerEvents(true);
             }
         }
 
+        #region Properties
+
         /// <summary>
-        /// Destructor.
+        /// Gets the Explorer that is wrapped by this WatchedExplorer.
         /// </summary>
-        ~WatchedExplorer()
+        public Outlook.Explorer Explorer
         {
-            this.Dispose(true);
+            get { return this._Explorer; }
         }
 
+        /// <summary>
+        /// Gets the Explorer that is wrapped by this WatchedExplorer.
+        /// </summary>
+        public override dynamic Window
+        {
+            get { return this.Explorer; }
+        }
+
+        #endregion
+
         #region Methods
+
         /**************************************************************
          * 
          * Methods
@@ -47,18 +62,10 @@
          *************************************************************/
 
         /// <summary>
-        /// Releases all resources and disconnects internal events.
-        /// </summary>
-        public void Dispose()
-        {
-            this.Dispose(true);
-        }
-
-        /// <summary>
         /// Clean up any resources being used.
         /// </summary>
         /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected virtual void Dispose(bool disposing)
+        protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
@@ -66,9 +73,10 @@
                 this.ConnectWatchedExplorerEvents(false);
 
                 // Set Outlook objects to null
-                this.explorer = null;
-                this.inlineResponseItem?.Dispose();
-                this.inlineResponseItem = null;
+                this._Explorer = null;
+
+                // Dispose base class
+                base.Dispose(disposing);
             }
         }
 
@@ -82,13 +90,15 @@
             {
                 if (connect)
                 {
-                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close += Explorer_Close;
-                    ((Outlook.ExplorerEvents_10_Event)this.explorer).InlineResponseClose += Explorer_InlineResponseClose;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).Close += Explorer_Close;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).InlineResponseClose += Explorer_InlineResponseClose;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).SelectionChange += Explorer_SelectionChange;
                 }
                 else
                 {
-                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close -= Explorer_Close;
-                    ((Outlook.ExplorerEvents_10_Event)this.explorer).InlineResponseClose -= Explorer_InlineResponseClose;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).Close -= Explorer_Close;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).InlineResponseClose -= Explorer_InlineResponseClose;
+                    ((Outlook.ExplorerEvents_10_Event)this._Explorer).SelectionChange -= Explorer_SelectionChange;
                 }
             }
             catch (Exception ex)
@@ -96,7 +106,6 @@
                 Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
             }
         }
-
         #endregion
 
         #region Event Handling
@@ -127,10 +136,10 @@
              * securely instead of to the server's draft folder.
              * Note: the form region's CMI is already disposed at this point,
              * so that its Write event will never be called.
-             */ 
+             */
             try
             {
-                omi = this.explorer?.ActiveInlineResponse as Outlook.MailItem;
+                omi = this._Explorer?.ActiveInlineResponse as Outlook.MailItem;
 
                 if (omi != null)
                 {
@@ -148,6 +157,77 @@
             }
         }
 
+        private void Explorer_SelectionChange()
+        {
+            Outlook.Selection selection = null;
+            try
+            {
+                // Process the newly selected item
+                selection = this._Explorer.Selection;
+
+                /* Do only process the item if one individual item is selected.
+                 * Do not process a selected range of items.
+                 */
+                if (selection.Count == 1)
+                {
+                    this.CurrentMailItem = selection[1] as Outlook.MailItem;
+                    if (this.CurrentMailItem != null)
+                    {
+                        // Check if inline response
+                        Outlook.MailItem inlineResponse = null;
+                        bool isInlineResponse = false;
+                        try
+                        {
+                            inlineResponse = this._Explorer?.ActiveInlineResponse as Outlook.MailItem;
+                            if (inlineResponse != null)
+                            {
+                                isInlineResponse = true;
+                                this.CurrentMailItem = inlineResponse;
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("Explorer_SelectionChange: Error determining whether it is an inline response. " + ex.ToString());
+                        }
+                        finally
+                        {
+                            inlineResponse = null;
+                        }
+
+                        /* If a different mail is clicked in an Window, the SelectionChange
+                         * event is always called twice. To prevent a double processing, we only
+                         * process a mail item if it is different from the last one that has been
+                         * processed.
+                         */
+                        string entryId = isInlineResponse ? null : this.CurrentMailItem?.EntryID;
+                        if (entryId?.Equals(lastProcessedEntryId, StringComparison.InvariantCultureIgnoreCase) == true)
+                        {
+                            Log.Verbose("Explorer_SelectionChange: Same EntryId as last item. Skipped processing of item with EntryId " + entryId);
+                            return;
+                        }
+                        else
+                        {
+                            this.lastProcessedEntryId = entryId;
+                        }
+
+                        // Initialize mail item
+                        this.InitializeMailItem(isInlineResponse);
+                    }
+                    else
+                    {
+                        Log.Error("Explorer_SelectionChange: Error getting current mail item.");
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error("Explorer_SelectionChange: Error. " + e.Message);
+            }
+            finally
+            {
+                selection = null;
+            }
+        }
         #endregion
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/WatchedInspector.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -0,0 +1,142 @@
+´╗┐using System;
+using Outlook = Microsoft.Office.Interop.Outlook;
+
+namespace pEp
+{
+    /// <summary>
+    /// Stores an Outlook Explorer with connected events.
+    /// </summary>
+    public class WatchedInspector : WatchedWindow
+    {
+        private Outlook.Inspector   _Inspector      = null;
+
+        /**************************************************************
+         * 
+         * Constructors/Destructors
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        /// <param name="inspector">The inspector to watch.</param>
+        public WatchedInspector(Outlook.Inspector inspector)
+        {
+            this._Inspector = inspector;
+
+            if (this._Inspector != null)
+            {
+                this.ConnectWatchedInspectorEvents();
+
+                // Set mail item
+                this.CurrentMailItem = this._Inspector.CurrentItem as Outlook.MailItem;
+
+                if (this.CurrentMailItem != null)
+                {
+                    this.InitializeMailItem();
+                }
+                else
+                {
+                    Log.Error("WatchedInspector: Error getting current mail item.");
+                }
+            }
+        }
+
+        #region Properties
+        /// <summary>
+        /// Gets the Inspector that is wrapped by this WatchedInspector
+        /// </summary>
+        public Outlook.Inspector Inspector
+        {
+            get { return this._Inspector; }
+        }
+
+        /// <summary>
+        /// Gets the Explorer that is wrapped by this WatchedExplorer.
+        /// </summary>
+        public override dynamic Window
+        {
+            get { return this.Inspector; }
+        }
+        #endregion
+
+        #region Methods
+        /**************************************************************
+         * 
+         * Methods
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing &&
+                this._Inspector != null)
+            {
+                // Disconnect all events
+                this.DisconnectWatchedInspectorEvents();
+
+                // Set Outlook objects to null
+                this._Inspector = null;
+
+                // Dispose base class
+                base.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Connects the events for this watched explorer
+        /// </summary>
+        private void ConnectWatchedInspectorEvents()
+        {
+            if (this._Inspector != null)
+            {
+                ((Outlook.InspectorEvents_10_Event)this._Inspector).Close += WatchedInspector_Close;
+            }
+        }
+
+        /// <summary>
+        /// Disconnects the events from this watched explorer
+        /// </summary>
+        private void DisconnectWatchedInspectorEvents()
+        {
+            if (this._Inspector != null)
+            {
+                ((Outlook.InspectorEvents_10_Event)this._Inspector).Close -= WatchedInspector_Close;
+
+            }
+        }
+
+        #endregion
+
+        #region Event Handling
+        /**************************************************************
+         * 
+         * Event Handling
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Event handler for when a watched inspector is being closed.
+        /// </summary>
+        private void WatchedInspector_Close()
+        {
+            Globals.ThisAddIn.RemoveFromWatchedInspectors(this);
+
+            this.Dispose();
+        }
+
+        /// <summary>
+        /// Event handler for when the processing of an item in the WatchedInspector has finished.
+        /// </summary>
+        private void Inspector_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/WatchedWindow.cs	Thu Sep 06 09:29:19 2018 +0200
@@ -0,0 +1,1428 @@
+´╗┐using pEp.UI;
+using pEpCOMServerAdapterLib;
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using Outlook = Microsoft.Office.Interop.Outlook;
+
+namespace pEp
+{
+    /// <summary>
+    /// Stores an Outlook Window with connected events.
+    /// </summary>
+    public abstract class WatchedWindow : IDisposable
+    {
+        private CryptableMailItem               cryptableMailItem           = null;
+        private bool                            displayMirrorRequested      = false;
+        private HandshakeDialog                 handshakeDialog             = null;
+        private bool                            isEnabled                   = true;
+        private bool                            isStarted                   = false;
+        private bool                            processingOngoing           = false;
+        private bool                            refreshOngoing              = false;
+        private bool                            repeatProcessing            = false;
+        private int                             repeatCounter               = 0;
+        private const int                       maxRepeatCount              = 5;
+
+        private Outlook.MailItem                _CurrentMailItem            = null;
+
+        public enum WindowTypes
+        {
+            Undefined,
+            Inspector,
+            Explorer
+        }
+
+        #region Properties
+        /// <summary>
+        /// The rating of the currently selected message.
+        /// </summary>
+        private pEpRating _Rating = pEpRating.pEpRatingUndefined;
+
+        /// <summary>
+        /// The mail item that is connected to this Inspector/Explorer window.
+        /// </summary>
+        public Outlook.MailItem CurrentMailItem
+        {
+            get
+            {
+                return this._CurrentMailItem;
+            }
+            protected set
+            {
+                this._CurrentMailItem = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets whether to disable the Force Protection option.
+        /// </summary>
+        public bool DisableForceProtection { get; set; } = false;
+
+        /// <summary>
+        /// Gets or sets whether to send this message forcefully protected.
+        /// </summary>
+        public bool ForceProtection { get; set; } = false;
+
+        /// <summary>
+        /// Gets or sets whether to send this message forcefully unencrypted.
+        /// </summary>
+        public bool ForceUnencrypted { get; set; } = false;
+
+        /// <summary>
+        /// Gets or sets whether the message is a draft message.
+        /// </summary>
+        public bool IsDraft { get; set; } = false;
+
+        /// <summary>
+        /// Gets or sets whether to always store this message as if on an untrusted server.
+        /// </summary>
+        public bool NeverUnsecure { get; set; } = false;
+
+        /// <summary>
+        /// Gets the rating of this message.
+        /// </summary>
+        public pEpRating Rating
+        {
+            get { return this._Rating; }
+        }
+
+        /// <summary>
+        /// Gets the associated Explorer/Inspector window. To be overwritten by child class.
+        /// </summary>
+        public abstract dynamic Window { get; }
+
+        /// <summary>
+        /// Sets the rating of this message and updates the UI.
+        /// </summary>
+        /// <param name="rating">The message rating.</param>
+        public void SetRating(pEpRating rating)
+        {
+            this._Rating = rating;
+            RibbonCustomizations.Invalidate();
+        }
+
+        /// <summary>
+        /// The timer that schedules the updates of this window.
+        /// </summary>
+        public System.Windows.Forms.Timer TimerRefresh { get; set; } = new System.Windows.Forms.Timer();
+        #endregion
+
+        #region Constructors / Destructors
+
+        /// <summary>
+        /// Destructor.
+        /// </summary>
+        ~WatchedWindow()
+        {
+            this.Dispose(true);
+        }
+        #endregion
+
+        #region Methods
+        /**************************************************************
+         * 
+         * Methods
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Releases all resources and disconnects internal events.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+        }
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                // Set Outlook objects to null
+                this._CurrentMailItem = null;
+            }
+        }
+              
+        /// <summary>
+        /// Builds the latest state of the encryption status manager then shows the UI.
+        /// </summary>
+        public void BuildAndShowManager()
+        {
+            /* Resolve all recipients -- this ensures the identities list is correctly populated
+             * 
+             * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
+             * This is because the resolve process can modify the contents of the mail item which triggers an event.
+             * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
+             * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
+             * cannot be resolved (no address).
+             */
+            try
+            {
+                this.ResolveAllRecipients();
+            }
+            catch (Exception ex)
+            {
+                Log.Verbose("BuildAndShowManager: Error resolving recipients. " + ex.ToString());
+            }
+
+            // Build the dialog
+            try
+            {
+                // The PEPMessage to build the dialog with
+                PEPMessage message = null;
+
+                // The own identity to build the dialog with
+                PEPIdentity myself = this.cryptableMailItem?.Myself;
+
+                // If message is a draft, create it directly from the Outlook mail item
+                if (this.IsDraft)
+                {
+                    Log.Verbose("BuildAndShowManager: Creating PEPMessage from draft.");
+
+                    if (PEPMessage.Create(this._CurrentMailItem, out message) != Globals.ReturnStatus.Success)
+                    {
+                        Log.Error("BuildAndShowManager: Error creating PEPMessage from draft.");
+                        message = null;
+                    }
+                    else
+                    {
+                        // Calculate rating
+                        message.Rating = message.GetOutgoingRating();
+
+                        // If Force Protection is set, assign a random GUID
+                        if ((this.ForceProtection) &&
+                            (this.DisableForceProtection == false))
+                        {
+                            message.ForceProtectionId = Guid.NewGuid().ToString();
+                        }
+
+                        // If message is Force Unencrypted, assign it
+                        message.ForceUnencrypted = this.ForceUnencrypted;
+                    }
+                }
+                else
+                {
+                    // Else, use either the cryptable mail item's associated mirror or message
+                    message = this.cryptableMailItem?.Mirror ?? this.cryptableMailItem?.Message;
+                    Log.Verbose(string.Format("BuildAndShowManager: Message {0} retrieved from CryptableMailItem", ((message != null) ? "successfully" : "could not be")));
+
+                    // As fallback, if we don't have a message yet, create it
+                    if (message == null)
+                    {
+                        Log.Verbose("BuildAndShowManager: Using fallback method to get message.");
+
+                        Outlook.MailItem mirror = null;
+
+                        try
+                        {
+                            // For securely stored mails, try to look up mirror
+                            if (this._CurrentMailItem?.GetIsSecurelyStored() == true)
+                            {
+                                mirror = this._CurrentMailItem?.GetMirror();
+
+                                if (mirror != null)
+                                {
+                                    // If mirror is found, use it to create PEPMessage
+                                    Log.Verbose("BuildAndShowManager: Mirror found.");
+
+                                    if (PEPMessage.Create(mirror, out message) != Globals.ReturnStatus.Success)
+                                    {
+                                        message = null;
+                                        Log.Error("BuildAndShowManager: Error creating PEPMessage.");
+                                    }
+                                    else
+                                    {
+                                        message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
+                                    }
+                                }
+                                else
+                                {
+                                    // If no mirror is found, decrypt message and use decrypted one (do not 
+                                    // decrypt forcefully protected messages).
+                                    if ((PEPMessage.Create(this._CurrentMailItem, out message) == Globals.ReturnStatus.Success) &&
+                                        (string.IsNullOrEmpty(message.ForceProtectionId)))
+                                    {
+                                        var msgProcessor = new MsgProcessor();
+                                        PEPMessage decryptedMsg = null;
+                                        string[] keyList;
+                                        pEpDecryptFlags flags = pEpDecryptFlags.pEpDecryptFlagsNone;
+                                        pEpRating rating = msgProcessor.Decrypt(ref message, out decryptedMsg, out keyList, ref flags);
+                                        if (decryptedMsg != null)
+                                        {
+                                            message = decryptedMsg;
+                                        }
+                                        message.Rating = rating;
+                                    }
+                                    else
+                                    {
+                                        message = null;
+                                        Log.Error("BuildAndShowManager: Error creating PEPMessage from mirror.");
+                                    }
+                                }
+                            }
+
+                            // If we don't have a PEPMessage yet, create it
+                            if (message == null)
+                            {
+                                Log.Verbose("BuildAndShowManager: Creating PEPMessage.");
+
+                                if (PEPMessage.Create(this._CurrentMailItem, out message) != Globals.ReturnStatus.Success)
+                                {
+                                    message = null;
+                                    Log.Error("BuildAndShowManager: Error creating PEPMessage.");
+                                }
+                                else
+                                {
+                                    message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
+                                }
+                            }
+
+                            // Get myself identiy if we don't have it yet
+                            if (myself == null)
+                            {
+                                myself = this._CurrentMailItem.GetMyselfIdentity();
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("FormRegionPrivacyStatus.Message: Error converting message. " + ex.ToString());
+                        }
+                        finally
+                        {
+                            mirror = null;
+                        }
+                    }
+                }
+
+                // Build dialog
+                if (message != null)
+                {
+                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
+                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
+                    handshakeDialog.Closed += HandshakeDialog_Closed;
+                    handshakeDialog.Show();
+                }
+                else
+                {
+                    throw new Exception("Could not build handshake dialog. Message is null.");
+                }
+            }
+            catch (Exception ex)
+            {
+                Globals.StopAndSendCrashReport(ex);
+            }
+        }
+
+        /// <summary>
+        /// Schedules for the pEp rating and UI (including displayed mirror) to be updated.
+        /// This can be called many times with no issue as the update is only run every n milliseconds.
+        /// </summary>
+        public void RequestRatingAndUIUpdate()
+        {
+            if (this.isEnabled)
+            {
+                this.TimerRefresh.Enabled = true;
+            }
+        }
+
+        /// <summary>
+        /// Immediately starts the update of UI rating based on the associated mail item.
+        /// This will start decryption as necessary and also will update the displayed mirror.
+        /// This method by-passes the refresh timer completely.
+        /// WARNING: This method assumes the message is fully downloaded already.
+        /// </summary>
+        private void ImmediateRatingAndUIUpdate()
+        {
+            if ((this.isEnabled) &&
+                (this.cryptableMailItem != null))
+            {
+                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
+
+                // Start the rating calculation/decryption process
+                this.cryptableMailItem.StartProcessing();
+                this.processingOngoing = true;
+            }
+        }
+
+        /// <summary>
+        /// Resets the Enabled status of this form region and recalculates the rating if necessary.
+        /// </summary>
+        /// <param name="enable">Whether to enable the form region.</param>
+        public void UpdateFormRegion(bool enable)
+        {
+            this.SetIsEnabled(enable);
+
+            // Refresh the UI
+            if (enable)
+            {
+                this.ResolveAllRecipients();
+                this.RequestRatingAndUIUpdate();
+            }
+        }
+
+        /// <summary>
+        /// Workaround method to update the current inspector window. This is done by moving the mail item
+        /// to a temporary folder first and then back to the current folder. Both folders CANNOT be the same.
+        /// As a fallback, the mail item stays in the temporary folder if moving back to the current folder
+        /// fails.
+        /// </summary>
+        private void UpdateInspector()
+        {
+            Outlook.Application application = null;
+            Outlook.Folder currentFolder = null;
+            Outlook.Folder tempFolder = null;
+            Outlook.Inspector currentInspector = null;
+            Outlook.Inspector newInspector = null;
+            Outlook.MailItem tempMailItem = null;
+            Outlook.Store store = null;
+            Outlook.MailItem omi = this.CurrentMailItem;
+
+            if (omi != null)
+            {
+                try
+                {
+                    application = omi.Application;
+                    currentInspector = omi.GetInspector;
+                    currentFolder = omi.Parent as Outlook.Folder;
+
+                    if ((currentInspector != null) &&
+                        (application != null) &&
+                        (currentFolder != null))
+                    {
+                        var left = currentInspector.Left;
+                        var top = currentInspector.Top;
+                        var width = currentInspector.Width;
+                        var height = currentInspector.Height;
+                        var windowState = currentInspector.WindowState;
+
+                        /* Check, if in trusted store. In that case, use the default drafts folder
+                         * as temporary folder. If the store is untrusted, use the pEp drafts folder.
+                         */
+                        store = currentFolder.Store;
+                        if (store?.GetIsSecureStorageEnabled() ?? false)
+                        {
+                            tempFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
+                        }
+                        else
+                        {
+                            tempFolder = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
+                        }
+
+                        if (tempFolder != null)
+                        {
+                            tempMailItem = omi.Move(tempFolder) as Outlook.MailItem;
+
+                            if (tempMailItem != null)
+                            {
+                                try
+                                {
+                                    omi = tempMailItem.Move(currentFolder) as Outlook.MailItem;
+                                }
+                                catch
+                                {
+                                    omi = tempMailItem.Copy();
+                                }
+
+                                newInspector = application.Inspectors.Add(omi);
+
+                                if (windowState == Outlook.OlWindowState.olNormalWindow)
+                                {
+                                    newInspector.Left = left;
+                                    newInspector.Top = top;
+                                    newInspector.Width = width;
+                                    newInspector.Height = height;
+                                }
+
+                                newInspector.Display();
+                                newInspector.WindowState = windowState;
+
+                                repeatProcessing = false;
+                            }
+                        }
+                        else
+                        {
+                            Log.Error("UpdateInspector: Cannot get temporary folder.");
+                        }
+                    }
+                    else
+                    {
+                        Log.Verbose("UpdateInspector: Error retrieving inspector window or application.");
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Log.Verbose("UpdateInspector: Error updating inspector window. " + ex.ToString());
+                }
+                finally
+                {
+                    application = null;
+                    currentInspector = null;
+                    newInspector = null;
+                    omi = null;
+                    tempMailItem = null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Clears the associated unencrypted preview and displays the given note (if any).
+        /// </summary>
+        /// <param name="note">The note to display.</param>
+        private void SetNote(string note = null)
+        {
+            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
+
+            if ((formRegions != null) &&
+                (string.IsNullOrEmpty(note) == false))
+            {
+                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
+                    (formRegions.FormRegionPreviewUnencrypted.Visible))
+                {
+                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetNote(note);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets whether processing of the mail item is enabled.
+        /// This should commonly be set from the .GetIsPEPEnabled() value.
+        /// </summary>
+        private void SetIsEnabled(bool enabled)
+        {
+            PEPIdentity currIdent;
+            Globals.ReturnStatus sts;
+            Outlook.Recipient currUser = null;
+            Outlook.Account currAccount = null;
+            Outlook.Account sendingAccount = null;
+            Outlook.NameSpace ns = null;
+
+            this.isEnabled = enabled;
+
+            if (enabled)
+            {
+                // Do not allow initialization more than once
+                if (this.isStarted == false)
+                {
+                    /* It's possible for new draft MailItems to be created outside the context of an account.
+                     * In this situation the SendUsingAccount will always be null which of course breaks several pEp operations.
+                     * The operations themselves cannot make the assumption about what account information to use.
+                     * Therefore, the situation is detected here and for draft mail items a null SendUsingAccount will be 
+                     * set with the session's default account.
+                     */
+                    try
+                    {
+                        ns = Globals.ThisAddIn.Application.Session;
+
+                        if (this.IsDraft)
+                        {
+                            sendingAccount = this._CurrentMailItem.SendUsingAccount;
+                            currUser = ns.CurrentUser;
+
+                            if (sendingAccount == null)
+                            {
+                                sts = PEPIdentity.Create(currUser, out currIdent);
+
+                                if (sts == Globals.ReturnStatus.Success)
+                                {
+                                    sendingAccount = AccountExtensions.GetDefaultAccount(Outlook.OlDefaultFolders.olFolderDrafts);
+                                    if (sendingAccount != null)
+                                    {
+                                        this._CurrentMailItem.SendUsingAccount = currAccount;
+                                    }
+                                }
+                            }
+
+                            // Check if account is already registered in pEp list and add it if necessary
+                            var acctSettings = Globals.ThisAddIn.Settings.GetAccountSettings(sendingAccount?.SmtpAddress);
+                            if (acctSettings == null)
+                            {
+                                Log.Verbose("SetIsEnabled: New account detected. Creating pEp settings.");
+
+                                // Create pEp settings for the new account
+                                acctSettings = sendingAccount.CreatePEPSettings();
+
+                                // Add account to list
+                                Globals.ThisAddIn.Settings.AccountsAddedWhileRunningList.Add(acctSettings?.SmtpAddress);
+                                Log.Verbose("SetIsEnabled: New account registered in pEp settings.");
+
+                                // Generate key
+                                Globals.ThisAddIn.RegisterMyself(acctSettings);
+                                Log.Verbose("SetIsEnabled: Myself registered.");
+
+                                // Set rules and view filters
+                                Globals.ThisAddIn.SetRulesAndViewFilters(sendingAccount);
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Error("SetIsEnabled: Error occured. " + ex.ToString());
+                    }
+                    finally
+                    {
+                        currAccount = null;
+                        currUser = null;
+                        ns = null;
+                        sendingAccount = null;
+                    }
+
+                    // Connect refresh timer
+                    this.TimerRefresh.Tick += TimerRefresh_Tick;
+                    this.isStarted = true;
+                }
+            }
+            else
+            {
+                // Stop and disconnect the refresh timer
+                this.TimerRefresh.Stop();
+                this.TimerRefresh.Enabled = false;
+                this.TimerRefresh.Tick -= TimerRefresh_Tick;
+
+                this.isStarted = false;
+            }
+        }
+
+        /// <summary>
+        /// Resolves all recipients of the Outlook mail item.
+        /// </summary>
+        private void ResolveAllRecipients()
+        {
+            if ((this.isEnabled) &&
+                (this.cryptableMailItem != null))
+            {
+                /*
+                 * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
+                 * This is because the resolve process can modify the contents of the mail item which triggers an event.
+                 * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
+                 * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
+                 * cannot be resolved(no address).
+                 */
+                try
+                {
+                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
+                    this.cryptableMailItem.ResolveAllRecipients();
+                    this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("Error resolving recipients. " + ex.ToString());
+                }
+            }
+        }
+        #endregion
+
+        #region Event Handling
+        /**************************************************************
+         * 
+         * Event Handling
+         * 
+         *************************************************************/
+
+        protected void InitializeMailItem(bool isInlineResponse = false)
+        {
+            bool enableFormRegion = false;
+            bool cancelOpenEvent = false;
+            bool isSecureAttachedMail = false;
+            string messageId = null;
+
+            try
+            {      
+                // Check if draft
+                this.IsDraft = this._CurrentMailItem.GetIsDraft();
+
+                /* Set immediately a provisional rating in order to have a less flickery
+                 * UI experience.
+                 * The provisional rating is either a stored rating or, in case we have a
+                 * reply message, the rating of the original (the item we reply to).
+                 * This provisional rating will be replace with the real one once the full
+                 * processing is complete.
+                 */
+                pEpRating provisionalRating = pEpRating.pEpRatingUndefined;
+
+                // Try to get an original rating (in case of reply messages)
+                if ((this.IsDraft) &&
+                    (this._CurrentMailItem?.Recipients?.Count > 0))
+                {
+                    string originalRatingString = this._CurrentMailItem.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING) as string;
+
+                    // If we have an original rating, parse it and set it.
+                    if (string.IsNullOrEmpty(originalRatingString) == false)
+                    {
+                        provisionalRating = AdapterExtensions.ParseRatingString(originalRatingString);
+                    }
+                }
+                else
+                {
+                    // Try to get rating from db
+                    provisionalRating = PEPDatabase.GetRating(this._CurrentMailItem.EntryID);
+
+                    // If there is no rating in the db, use stored or default rating
+                    if (provisionalRating == pEpRating.pEpRatingUndefined)
+                    {
+                        provisionalRating = this._CurrentMailItem.GetStoredRating() ?? pEpRating.pEpRatingUndefined;
+                    }
+                }
+
+                // Only set rating if one has been retrieved
+                if (provisionalRating != pEpRating.pEpRatingUndefined)
+                {
+                    this.SetRating(provisionalRating);
+                    Log.Verbose("FormRegionPrivacyStatus_FormRegionShowing: Provisional rating {0} shown.", Enum.GetName(typeof(pEpRating), provisionalRating));
+                }
+
+
+                // Do not process S/MIME messages
+                if (this._CurrentMailItem.GetIsSMIMEEnabled())
+                {
+                    Log.Verbose("FormRegionPrivacyStatus_FormRegionShowing: S/MIME message detected. Won't be processed.");
+
+                    // Set unencrypted rating
+                    this.SetRating(pEpRating.pEpRatingUnencrypted);
+
+                    // Set icon(s) if necessary     
+                    if ((IsDraft == false) &&
+                        (this._CurrentMailItem.SetEncryptionIcons()))
+                    {
+                        try
+                        {
+                            this._CurrentMailItem.Save();
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error saving message after changing icon. " + ex.ToString());
+                        }
+                    }
+
+                    return;
+                }
+
+                /* Check if item is attached mail. For performance reasons,
+                 * only do the whole check if an item has been loaded to the
+                 * cache of attached mails and if item might be secure.
+                 */
+                if ((PEPAttachment.AttachedMailsCache.Count > 0) &&
+                    (this._CurrentMailItem.Attachments?.Count == 2))
+                {
+                    try
+                    {
+                        // Check if mail item is an attached mail
+                        if (this._CurrentMailItem.GetIsAttachedMail(out messageId))
+                        {
+                            Outlook.MailItem mirror = null;
+                            PEPMessage pEpMessage;
+
+                            // Try to get the mirror
+                            mirror = this._CurrentMailItem.GetMirror(messageId);
+
+                            // If mirror was not found, decrypt and create mirror
+                            if (mirror != null)
+                            {
+                                isSecureAttachedMail = true;
+                            }
+                            else
+                            {
+                                if ((PEPMessage.Create(this._CurrentMailItem, out pEpMessage) == Globals.ReturnStatus.Success) &&
+                                    (pEpMessage.IsSecure))
+                                {
+                                    PEPMessage decryptedMessage;
+                                    MsgProcessor msgProcessor = new MsgProcessor();
+                                    if (msgProcessor.Decrypt(pEpMessage, out decryptedMessage))
+                                    {
+                                        isSecureAttachedMail = true;
+                                        mirror = this._CurrentMailItem.CreateMirrorOMI(messageId);
+                                        decryptedMessage.ApplyTo(mirror, true, false);
+                                        mirror?.Save();
+                                    }
+                                    else
+                                    {
+                                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Decryption of attached mail was not successful.");
+                                    }
+                                }
+                            }
+
+                            // Check if attachment is being opened or if only the preview is needed
+                            if (CryptableMailItem.PreviewAttachedMailId?.Equals(messageId) != true)
+                            {
+                                // Display mirror and cancel opening of original
+                                cancelOpenEvent = true;
+                                mirror?.Display();
+                            }
+
+                            // Not needed anymore after this point
+                            CryptableMailItem.PreviewAttachedMailId = null;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        messageId = null;
+                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error checking for attached mail. " + ex.ToString());
+                    }
+                }
+
+                this.cryptableMailItem = new CryptableMailItem(this._CurrentMailItem, provisionalRating);
+
+                // Set inline response property
+                this.cryptableMailItem.IsInlineResponse = isInlineResponse;
+
+                // Set properties for encrypted attached mail
+                if (isSecureAttachedMail)
+                {
+                    this.cryptableMailItem.MessageId = messageId;
+                    this.cryptableMailItem.IsSecureAttachedMail = true;
+                }
+
+                // Connect cryptable mail item events
+                if (this.cryptableMailItem != null)
+                {
+                    // If we don't open the original, set property and return
+                    if (cancelOpenEvent)
+                    {
+                        this.cryptableMailItem.Open += MailItem_Open;
+                        this.cryptableMailItem.CancelOpen = true;
+                        return;
+                    }
+                    else
+                    {
+                        try
+                        {
+                            this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
+                            this.cryptableMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
+                            this.cryptableMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
+                            this.cryptableMailItem.Send += MailItem_Send;
+
+                            if (this.cryptableMailItem.IsSecurelyStored)
+                            {
+                                this.cryptableMailItem.Open += MailItem_Open;
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error occured. " + ex.ToString());
+                        }
+
+                        if (this._CurrentMailItem.GetIsPEPEnabled())
+                        {
+                            // If pEp is enabled, show the form region
+                            enableFormRegion = true;
+                        }
+                        else
+                        {
+                            /* If pEp is disabled, process item and show form region in the following cases:
+                             * 1. Incoming items: if decrypt always option is set
+                             * 2. Outgoing items: if EnableProtection option is set
+                             *                    Note: if this property isn't set, subscribe to originally 
+                             *                          encrypted status update event handler in case the 
+                             *                          current code runs before CryptableMailItem.MailItem_Reply
+                             *                          or CryptableMailItem.MailItem_Forward.
+                             */
+                            if (this.IsDraft)
+                            {
+                                enableFormRegion = true;
+                                this.cryptableMailItem.OriginallyEncryptedStatusUpdated += CryptableMailItem_OriginallyEncryptedStatusUpdated;
+                            }
+                            else
+                            {
+                                enableFormRegion = this._CurrentMailItem.GetIsDecryptAlwaysEnabled();
+                            }
+                        }
+                    }
+                }
+
+                // Update pEp enabled status
+                this.SetIsEnabled(enableFormRegion);
+
+                if (this.isEnabled)
+                {
+                    // If forcefully protected, run dedicated decryption
+                    if (this._CurrentMailItem.GetIsForcefullyProtected())
+                    {
+                        FPPMessage fppMessage = new FPPMessage(this._CurrentMailItem);
+                        if ((fppMessage?.GetMessageType() != null) ||
+                            (fppMessage?.CurrentMessage?.IsSecure == true))
+                        {
+                            fppMessage.ProcessIncoming(true);
+                        }
+                        else
+                        {
+                            this.TimerRefresh_Tick(null, new EventArgs());
+                        }
+                    }
+                    else
+                    {
+                        // Call the timer tick method manually to refresh data with no delay
+                        this.TimerRefresh_Tick(null, new EventArgs());
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                Log.Error("Window_SelectionChange: Error. " + e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the form region is closed.
+        /// </summary>
+        protected void FormRegionPrivacyStatus_FormRegionClosed(object sender, EventArgs e)
+        {
+            // Disconnect cryptable mail item
+            if (this.cryptableMailItem != null)
+            {
+                try
+                {
+                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
+                    this.cryptableMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
+                    this.cryptableMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
+                    this.cryptableMailItem.Open -= MailItem_Open;
+                    this.cryptableMailItem.Send -= MailItem_Send;
+                    this.cryptableMailItem.OriginallyEncryptedStatusUpdated -= CryptableMailItem_OriginallyEncryptedStatusUpdated;
+                }
+                catch { }
+
+                this.cryptableMailItem.Dispose();
+                this.cryptableMailItem = null;
+            }
+
+            // Disconnect other
+            this.SetIsEnabled(false);
+        }
+
+        /// <summary>
+        /// Event handler for when the processing is completed in the associated mail item.
+        /// This will then update the form region UI and the privacy status window as needed.
+        /// </summary>
+        private void MailItem_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
+        {
+            Log.Verbose("MailItem_ProcessingComplete: Decryption completed.");
+
+            try
+            {
+                // Marshal code back to UI thread as necessary
+                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
+                {
+                    if (this.isEnabled)
+                    {
+                        try
+                        {
+                            this.SetRating(e.ProcessedRating);
+
+                            // Set MAPI properties if needed
+                            if (e.PropertiesToSet?.Count > 0)
+                            {
+                                this._CurrentMailItem?.SetMAPIProperties(e.PropertiesToSet);
+                            }
+                            Log.Verbose("MailItem_ProcessingComplete: Status bar updated with rating " + Enum.GetName(typeof(pEpRating), e.ProcessedRating));
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Verbose("MailItem_ProcessingComplete: Error. " + ex.ToString());
+                        }
+
+                        if (repeatProcessing &&
+                            (repeatCounter++ < maxRepeatCount))
+                        {
+                            repeatProcessing = false;
+                            this.RequestRatingAndUIUpdate();
+                        }
+                        else
+                        {
+                            /* Check if the mail item is in Outbox and update the inspector window if possible.
+                             * This is the case when a submitted, but not yet sent email is opened again when working 
+                             * offline or without internet connection. Without this update, Outlook removes the message class 
+                             * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
+                             * opened again (i.e. is lost).
+                             */
+                            try
+                            {
+                                if ((this._CurrentMailItem?.GetIsSubmitted() == true) &&
+                                    (this.IsDraft))
+                                {
+                                    UpdateInspector();
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
+                            }
+
+                            /* Create the unencrypted preview if the mail item is encrypted and
+                             * it is in an encrypted (untrusted) store
+                             * 
+                             * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
+                             * it also is initialized after FormRegionPreviewUnencrypted.
+                             */
+                            try
+                            {
+                                if (this.cryptableMailItem.IsSecurelyStored || this.cryptableMailItem.IsSecureAttachedMail)
+                                {
+                                    Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
+                                    this.cryptableMailItem.StartGetMirror(this.cryptableMailItem.MessageId);
+                                }
+                                else
+                                {
+                                    this.SetNote();
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
+                                // While rare, just log the issue and stop the process
+                                Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
+                            }
+
+                            /* OUT-470: Workaround until this is implemented in the engine:
+                             * Only enable Force Protection if all recipients are grey
+                             */
+                            if (this.IsDraft)
+                            {
+                                bool disableForceProtection = false;
+                                Outlook.Recipients recipients = null;
+                                Outlook.Recipient recipient = null;
+                                PEPIdentity pEpIdentity = null;
+
+                                try
+                                {
+                                    recipients = this._CurrentMailItem?.Recipients;
+                                    if (recipients?.Count > 0)
+                                    {
+                                        for (int i = 1; i <= recipients.Count; i++)
+                                        {
+                                            recipient = recipients[i];
+                                            if ((PEPIdentity.Create(recipient, out pEpIdentity, false) == Globals.ReturnStatus.Success) &&
+                                                ((PEPIdentity.GetIsOwnIdentity(pEpIdentity.Address) ||
+                                                 (ThisAddIn.PEPEngine.IdentityRating(pEpIdentity.ToCOMType()) >= pEpRating.pEpRatingReliable))))
+                                            {
+                                                disableForceProtection = true;
+                                                Log.Verbose("ToggleButtonForceProtection_GetEnabled: Secure recipient found. Disabling force protection.");
+                                                break;
+                                            }
+                                        }
+                                    }
+                                    else
+                                    {
+                                        // If there aren't any recipients (anymore), reset values
+                                        this.DisableForceProtection = false;
+                                        this.ForceProtection = false;
+                                        this.NeverUnsecure = false;
+                                        this.ForceUnencrypted = false;
+                                    }
+                                }
+                                catch (Exception ex)
+                                {
+                                    Log.Error("ToggleButtonForceProtection_GetEnabled: Error occured. " + ex.ToString());
+                                }
+                                finally
+                                {
+                                    recipient = null;
+                                    recipients = null;
+                                }
+
+                                this.DisableForceProtection = disableForceProtection;
+                            }
+                        }
+                    }
+                }));
+            }
+            catch (Exception ex)
+            {
+                Log.Error("MailItem_ProcessingComplete: Error setting UI state, " + ex.ToString());
+            }
+
+            this.processingOngoing = false;
+        }
+
+        /// <summary>
+        /// Event handler for when the get mirror locating process is complete for the associated mail item.
+        /// This will then update the unencrypted preview in the UI.
+        /// </summary>
+        private void MailItem_GetMirrorCompleted(object sender, CryptableMailItem.GetMirrorCompletedEventArgs e)
+        {
+            try
+            {
+                // Marshal code back to UI thread as necessary
+                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
+                {
+                    if (this.isEnabled)
+                    {
+                        WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
+
+                        // If the message was forcefully protected, there is no mirror and we show the actual message
+                        if ((e.Mirror == null) &&
+                            (this._CurrentMailItem?.GetIsForcefullyProtected() == true))
+                        {
+                            PEPMessage mirror = null;
+                            if (PEPMessage.Create(this._CurrentMailItem, out mirror) == Globals.ReturnStatus.Success)
+                            {
+                                e.Mirror = mirror;
+                            }
+                        }
+
+                        if ((e.Mirror == null) &&
+                            (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.Failure))
+                        {
+                            this.SetNote(Properties.Resources.Message_OpenError);
+                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, failure during decryption.");
+                        }
+                        else if ((e.Mirror == null) &&
+                                 (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
+                        {
+                            this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
+                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
+                        }
+                        else
+                        {
+                            if (formRegions != null)
+                            {
+                                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
+                                    (formRegions.FormRegionPreviewUnencrypted.Visible))
+                                {
+                                    formRegions.FormRegionPreviewUnencrypted.DisplayState.OriginalEntryId = this._CurrentMailItem?.EntryID;
+                                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
+                                }
+
+                                Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
+                            }
+                        }
+
+                        // Display the mirror if necessary
+                        if ((this.cryptableMailItem != null) &&
+                            (this.displayMirrorRequested))
+                        {
+                            this.cryptableMailItem.DisplayMirror();
+                            this.displayMirrorRequested = false;
+                        }
+                    }
+                }));
+            }
+            catch (Exception ex)
+            {
+                Log.Error("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Event handler for the mail item originally encrypted status updated.
+        /// This event is fired after the status has been updated with parent information following a
+        /// forward or reply mail item event (on a different, likely parent, mail item).
+        /// </summary>
+        protected void CryptableMailItem_OriginallyEncryptedStatusUpdated(object sender, EventArgs e)
+        {
+            // Process the mail item now that the cache is updated
+            if (this.cryptableMailItem.IsOriginallyEncrypted)
+            {
+                this.cryptableMailItem.StartProcessing();
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a mail item is being opened in an inspector.
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
+        /// </summary>
+        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
+        /// If the event procedure sets this argument to True, the open operation is not completed 
+        /// and the inspector is not displayed.</param>
+        protected void MailItem_Open(ref bool cancel)
+        {
+            bool result;
+
+            if ((this.isEnabled) &&
+                (this.cryptableMailItem != null))
+            {
+                // If cryptable mail item is not to be opened, cancel opening
+                if (this.cryptableMailItem.CancelOpen)
+                {
+                    cancel = true;
+                }
+                else if ((this.cryptableMailItem.IsSecurelyStored) &&
+                         (this.cryptableMailItem.IsIncoming || this.cryptableMailItem.IsOriginallyEncrypted || !this.cryptableMailItem.IsDraft))
+                {
+                    // Try to open the mirror
+                    result = this.cryptableMailItem.DisplayMirror();
+
+                    if (result == false)
+                    {
+                        // Set flag to open after decryption/mirror location
+                        this.displayMirrorRequested = true;
+                    }
+
+                    // Always cancel opening the original
+                    cancel = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a mail item is sent.
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
+        /// </summary>
+        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
+        /// If the event procedure sets this argument to True, the send operation is not completed 
+        /// and the inspector is left open.</param>
+        protected void MailItem_Send(ref bool cancel)
+        {
+            DialogResult result;
+
+            if (this.isEnabled)
+            {
+                if ((this.cryptableMailItem.IsBeingProcessed) ||
+                    (this.processingOngoing))
+                {
+                    Log.Verbose("MailItem_Send cancelled. Mail item still being processed.");
+                    cancel = true;
+                    return;
+                }
+
+                // Show warning message if needed
+                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
+                    (this.Rating < pEpRating.pEpRatingUnreliable) &&
+                    (this.cryptableMailItem.IsOriginallyEncrypted))
+                {
+
+#if READER_RELEASE_MODE
+                    FormReaderSplash warningMessage = new FormReaderSplash(true);
+                    result = warningMessage.ShowDialog();
+
+                    if (result != DialogResult.OK)
+                    {
+                        // Cancel sending
+                        cancel = true;
+                    }
+#else
+                    result = MessageBox.Show(Properties.Resources.Message_WarningSecurityLoss,
+                                             Properties.Resources.Message_TitleConfirmOperation,
+                                             MessageBoxButtons.YesNo,
+                                             MessageBoxIcon.Warning);
+
+                    if (result == DialogResult.No)
+                    {
+                        // Cancel sending
+                        cancel = true;
+                    }
+#endif
+                }
+
+                if (cancel == false)
+                {
+                    // Set pEp options if needed
+                    if ((this.ForceProtection) &&
+                        (this.DisableForceProtection == false))
+                    {
+                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceProtection, Guid.NewGuid().ToString());
+                    }
+                    else if (this.ForceUnencrypted)
+                    {
+                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, true);
+                    }
+
+                    if (this.NeverUnsecure)
+                    {
+                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, true);
+                    }
+
+                    // Stop and disconnect the refresh timer
+                    // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
+                    this.TimerRefresh.Stop();
+                    this.TimerRefresh.Enabled = false;
+                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a mail item property is changed.
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
+        /// </summary>
+        /// <param name="propertyName">The name of the property that was changed.</param>
+        protected void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
+        {
+            switch (e.PropertyName.ToUpperInvariant())
+            {
+                case "BCC":
+                    {
+                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
+                        break;
+                    }
+                case "CC":
+                    {
+                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
+                        break;
+                    }
+                case "SENTONBEHALFOFNAME":
+                    {
+                        // Always fired with "SENDUSINGACCOUNT" so is ignored
+                        break;
+                    }
+                case "SENDUSINGACCOUNT":
+                    {
+                        // Update pEp enabled status
+                        this.isStarted = false;
+                        this.SetIsEnabled((this.CurrentMailItem)?.GetEnableFormRegion() ?? false);
+
+                        // Refresh the UI
+                        this.ResolveAllRecipients();
+                        this.RequestRatingAndUIUpdate();
+                        RibbonCustomizations.Invalidate();
+
+                        break;
+                    }
+                case "TO":
+                    {
+                        if (this.isEnabled)
+                        {
+                            this.RequestRatingAndUIUpdate();
+                        }
+                        break;
+                    }
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a handshake dialog was updated.
+        /// </summary>
+        protected void HandshakeDialog_Updated(object sender, EventArgs e)
+        {
+            // Update current form region
+            this.RequestRatingAndUIUpdate();
+            
+            /* If a handshake is performed while having the same message open both in an inspector
+             * and an Window window, the one that didn't trigger the handshake won't get updated
+             * automatically. Therefore, after a handshake, we also update all other open windows.
+             */
+            try
+            {
+                Globals.ThisAddIn.RecalculateAllWindows(this);                
+            }
+            catch (Exception ex)
+            {
+                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when a handshake dialog was closed.
+        /// </summary>
+        protected void HandshakeDialog_Closed(object sender, EventArgs e)
+        {
+            if (this.handshakeDialog != null)
+            {
+                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
+                this.handshakeDialog.Closed -= HandshakeDialog_Closed;
+                this.handshakeDialog = null;
+            }
+        }
+
+        /// <summary>
+        /// Event handler called after the refresh timer has elapsed.
+        /// </summary>
+        private void TimerRefresh_Tick(object sender, EventArgs e)
+        {
+            bool tryAgain = false;
+#pragma warning disable 219
+            bool markForDownload = false;
+#pragma warning restore 219
+            this.TimerRefresh.Enabled = false; // Only once
+            Outlook.OlDownloadState dlState;
+
+            /* The Refresh/UI_Update process:
+             * There are the following components:
+             *   1. TimerRefresh_Tick
+             *        This is the main timer tick event handler called any time
+             *        a refresh was requested (RequestRatingAndUIUpdate) and hasn't been run yet. 
+             *        A refresh is requested either at initialization or when a property changes
+             *        (such as MailItem_PropertyChanged). It is on a timer as many 
+             *        property change events could occur rapidy, but only one refresh should
+             *        occur for performance reasons.
+             * 
+             *   2. ImmediateRatingAndUIUpdate
+             *        This will re-calculate the mail item's rating.
+             *        This internally just calls CryptableMailItem.StartProcessing.
+             * 
+             *   3. MailItem_ProcessingCompleted
+             *        When processing of the mail item is complete, this even handler will be called.
+             *        This will update the UI with the latest rating then call StartGetMirror.
+             *        The CopyStateToUI method is used which means any open privacy status form will also
+             *        be updated.
+             * 
+             *   4. MailItem_GetMirrorComplete
+             *        This is the final step in updating the UI, after a mirror is located, it's contents
+             *        will be shown in the unencrypted preview.
+             * 
+             * The general calling sequence is as shown above 1->4 with each component calling the next.
+             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
+             */
+
+            // Ensure the tick method is not called more than once
+            if ((this.isEnabled) &&
+                (refreshOngoing == false))
+            {
+                this.refreshOngoing = true;
+
+                if ((this.cryptableMailItem != null) &&
+                    (this.cryptableMailItem.IsBeingProcessed == false))
+                {
+                    // Attempt to get the download state
+                    try
+                    {
+                        dlState = this.cryptableMailItem.DownloadState;
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Warning("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
+
+                        // Assume everything is downloaded, but try to download again as well
+                        dlState = Outlook.OlDownloadState.olFullItem;
+                        markForDownload = true;
+                    }
+
+                    if (dlState == Outlook.OlDownloadState.olFullItem)
+                    {
+                        this.ImmediateRatingAndUIUpdate();
+                    }
+                    else
+                    {
+                        markForDownload = true;
+                    }
+
+                    /* 12/16/2016: It could be verified via testing that setting the MarkForDownload property
+                     * can be a way to crash Outlook under certain circumstances (e.g. with IMAP on Outlook 2010 or on Windows 7). 
+                     * This then is not caught by a try/catch block and therefore has to be considered an Outlook bug.
+                     * It seems that in newer versions of Outlook/Windows, they fixed it, causing exceptions, if at all.
+                     * For now, the following is commented out to prevent a crash. If at any point we see that header-only
+                     * messages cause bigger issues, this decision has to be reevaluated.
+                     */
+                    //if (markForDownload)
+                    //{
+                    //    // Try to mark the message for full download
+                    //    try
+                    //    {
+                    //        this.cryptableMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
+                    //        tryAgain = true;
+                    //    }
+                    //    catch (Exception ex)
+                    //    {
+                    //        Log.Warning("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
+                    //    }
+                    //}
+                }
+                else
+                {
+                    repeatProcessing = true;
+                }
+
+                // Set the timer to refresh again later automatically
+                if (tryAgain)
+                {
+                    this.TimerRefresh.Interval = 100;
+                    this.TimerRefresh.Enabled = true;
+                }
+
+                this.refreshOngoing = false;
+            }
+        }
+
+        #endregion
+    }
+}
--- a/pEpForOutlook.csproj	Tue Sep 04 11:14:15 2018 +0200
+++ b/pEpForOutlook.csproj	Thu Sep 06 09:29:19 2018 +0200
@@ -411,12 +411,6 @@
     <Compile Include="UI\FormRegionPreviewUnencrypted.Designer.cs">
       <DependentUpon>FormRegionPreviewUnencrypted.cs</DependentUpon>
     </Compile>
-    <Compile Include="UI\FormRegionPrivacyStatus.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="UI\FormRegionPrivacyStatus.Designer.cs">
-      <DependentUpon>FormRegionPrivacyStatus.cs</DependentUpon>
-    </Compile>
     <Compile Include="CryptableMailItem.cs" />
     <Compile Include="Properties\AssemblyInfo.cs">
       <SubType>Code</SubType>
@@ -430,6 +424,8 @@
     </Compile>
     <Compile Include="UI\ValueConverters.cs" />
     <Compile Include="Wrappers\WatchedExplorer.cs" />
+    <Compile Include="Wrappers\WatchedInspector.cs" />
+    <Compile Include="Wrappers\WatchedWindow.cs" />
     <EmbeddedResource Include="Properties\Resources.hi.resx">
       <Generator>PublicResXFileCodeGenerator</Generator>
       <LastGenOutput>Resources.hi.Designer.cs</LastGenOutput>