OUT-78: Renaming and optimization OUT-78
authorThomas
Thu, 14 Mar 2019 15:36:43 +0100
branchOUT-78
changeset 2599 4a54e3221729
parent 2598 9ec2fef7baea
child 2600 0df6cdea7e12
OUT-78: Renaming and optimization
CryptableMailItem.cs
DecryptionStack.cs
Extensions/ContactItemExtensions.cs
Extensions/MailItemExtensions.cs
FPPMessage.cs
ThisAddIn.cs
UI/FormControlPreviewMessage.xaml.cs
UI/FormRegionPreviewUnencrypted.cs
UI/FormRegionPrivacyStatus.cs
UI/RibbonCustomizations.cs
Wrappers/ExplorerWrapper.cs
Wrappers/InspectorWrapper.cs
Wrappers/MailItemWrapper.cs
Wrappers/WatchedExplorer.cs
Wrappers/WatchedInspector.cs
Wrappers/WatchedWindow.cs
Wrappers/WindowBaseWrapper.cs
pEpForOutlook.csproj
--- a/CryptableMailItem.cs	Wed Mar 13 13:50:02 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2045 +0,0 @@
-using MimeKit;
-using pEp.UI;
-using pEpCOMServerAdapterLib;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Outlook = Microsoft.Office.Interop.Outlook;
-
-namespace pEp
-{
-    /// <summary>
-    /// Wrapper for the Outlook MailItem supporting encryption.
-    /// </summary>
-    internal class CryptableMailItem : INotifyPropertyChanged,
-                                       IDisposable
-    {
-        public const string USER_PROPERTY_KEY_FORCE_UNENCRYPTED         = "sendUnencrypted";
-        public const string USER_PROPERTY_KEY_ENABLE_PROTECTION         = "enableProtection";
-        public const string USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED   = "isOriginallyEncrypted";
-        public const string USER_PROPERTY_KEY_ORIGINAL_RATING           = "originalRating";
-
-        public delegate void StdMailEventHandler(ref bool cancel);
-        public delegate void RespondMailEventHandler(object item, ref bool cancel);
-        public delegate void GenericHandler(object sender, EventArgs e);
-        public delegate void ProcessingCompletedHandler(object sender, MsgProcessor.ProcessingCompletedEventArgs e);
-        public delegate void GetMirrorCompletedHandler(object sender, GetMirrorCompletedEventArgs e);
-
-        /// <summary>
-        /// Event when the internal mail item before delete event occurs.
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event StdMailEventHandler BeforeDelete;
-
-        /// <summary>
-        /// Event when the internal mail item forward event occurs.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event RespondMailEventHandler Forward;
-
-        /// <summary>
-        /// Event when the internal mail item open event occurs.
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event StdMailEventHandler Open;
-
-        /// <summary>
-        /// Event when the internal mail item reply event occurs.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event RespondMailEventHandler Reply;
-
-        /// <summary>
-        /// Event when the internal mail item reply to all event occurs.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event RespondMailEventHandler ReplyAll;
-
-        /// <summary>
-        /// Event when the internal mail item send event occurs.
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event StdMailEventHandler Send;
-
-        /// <summary>
-        /// Event when the internal mail item write event occurs.
-        /// </summary>
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
-        public event StdMailEventHandler Write;
-
-        /// <summary>
-        /// Event when either a cryptable mail item property change occurs, or
-        /// when the internal mail item property change event occurs.
-        /// </summary>
-        public event PropertyChangedEventHandler PropertyChanged;
-
-        /// <summary>
-        /// Event when processing of this cryptable mail item is completed.
-        /// WARNING: The calling thread is a background worker.
-        /// </summary>
-        public event ProcessingCompletedHandler ProcessingCompleted;
-
-        /// <summary>
-        /// Event when the get mirror search is completed.
-        /// WARNING: The calling thread is a background worker.
-        /// </summary>
-        public event GetMirrorCompletedHandler GetMirrorCompleted;
-
-        public delegate void OriginallyEncryptedStatusUpdateHandler(object sender, EventArgs e);
-        public event OriginallyEncryptedStatusUpdateHandler OriginallyEncryptedStatusUpdated;
-
-        private pEpRating            _LastProcessedRating;
-        private Globals.ReturnStatus _LastProcessedStatus;
-
-        private bool                              disposeAfterProcessing;
-        private bool                              decrementCounter;
-        private Outlook.MailItem                  internalMailItem;
-        private BackgroundWorker                  mirrorLocator;
-        private BackgroundWorker                  processor;
-
-        private string                            draftEntryId          = null;
-        private string                            draftFileName         = null;
-        private object                            mutexMailItem         = new object();
-        private static object                     mutexConversation     = new object();
-        private static object                     mutexDecryptionList   = new object();
-        private static List<OriginalMailItem>     conversationCache     = new List<OriginalMailItem>();
-        private static Dictionary<string, string> decryptionList        = new Dictionary<string, string>();
-
-        /// <summary>
-        /// Stores the message id of an attached mail item if it is loaded into the preview.
-        /// See comments below in MailItem_BeforeAttachmentPreview event handler.
-        /// </summary>
-        public static string PreviewAttachedMailId = null;
-
-        /// <summary>
-        /// Whether to cancel the opening event of the internal mail item. Default is false.
-        /// </summary>
-        public bool CancelOpen { get; set; } = false;
-
-        /// <summary>
-        /// The messageId of the internal mail item. Only needed for special cases like attached mails.
-        /// </summary>
-        public string MessageId { get; set; } = null;
-
-        /// <summary>
-        /// Whether the internal mail item is an inline response
-        /// </summary>
-        public bool IsInlineResponse { get; set; } = false;
-
-        /// <summary>
-        /// Whether the internal mail item is an attached mail.
-        /// </summary>
-        public bool IsSecureAttachedMail { get; set; } = false;
-
-        /// <summary>
-        /// The mirror of the internal mail item stored as PEPMessage.
-        /// </summary>
-        public PEPMessage Mirror { get; set; } = null;
-
-        /// <summary>
-        /// The PEPMessage of this mail item.
-        /// </summary>
-        public PEPMessage Message { get; set; } = null;
-
-        /**************************************************************
-         * 
-         * Constructors/Destructors
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Primary constructor creating the cryptable mail item from an existing outlook mail item.
-        /// </summary>
-        /// <param name="mailItem">The mail item to wrap and make cryptable.</param>
-        /// <param name="defaultRating">The default rating for this cryptable mail item.</param>
-        /// <param name="decrementCounter">Whether or not to decrement the decryption counter after processing.</param>
-        public CryptableMailItem(Outlook.MailItem mailItem,
-                                 pEpRating? defaultRating = null,
-                                 bool decrementCounter = false)
-        {
-            this.internalMailItem = mailItem;
-            this.ConnectInternalMailItemEvents(true);
-
-            this.disposeAfterProcessing = false;
-            this.decrementCounter = decrementCounter;
-            this._LastProcessedRating = defaultRating ?? pEpRating.pEpRatingUndefined;
-            this._LastProcessedStatus = Globals.ReturnStatus.Success;
-
-            // Setup the message processor background worker
-            this.processor = new BackgroundWorker
-            {
-                WorkerSupportsCancellation = false,
-            };
-            this.processor.RunWorkerCompleted += Processor_RunWorkerCompleted;
-            this.processor.DoWork += Processor_DoWork;
-
-            // Setup the mirror locator background worker
-            this.mirrorLocator = new BackgroundWorker
-            {
-                WorkerSupportsCancellation = false
-            };
-            this.mirrorLocator.RunWorkerCompleted += MirrorLocator_RunWorkerCompleted;
-            this.mirrorLocator.DoWork += MirrorLocator_DoWork;
-        }
-
-        /// <summary>
-        /// Destructor.
-        /// </summary>
-        ~CryptableMailItem()
-        {
-            // This should have been called in code before garbage collection, but call it just in case
-            this.Dispose(true);
-        }
-
-        /**************************************************************
-         * 
-         * Event Handling
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Event hander for when an attachment is previewed. Occurs before the preview occurs
-        /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.beforeattachmentpreview.aspx
-        /// </summary>
-        /// <param name="attachment">The attachment that is about to be previewed.</param>
-        /// <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 operation is not completed
-        /// and the attachment is not previewed.</param>
-        private void MailItem_BeforeAttachmentPreview(Outlook.Attachment attachment, ref bool cancel)
-        {
-            /* Check if the attachment to be previewed is a mail item and store its messageId in the 
-             * static PreviewAttachedMailId property. This is a somewhat clumsy workaround, but is needed
-             * because we need to know upon processing of the mail item whether it is an attached mail
-             * and whether it is opened (a) or previewed (b).
-             *      => a. Cancel opening and open mirror
-             *      => b. Display mirror in preview window
-             * As all methods to store the relevant information directly in the attached mail failed, we 
-             * set the messageId during this event and query it in FormRegionPrivacyStatus_FormRegionShowing.
-             */
-            try
-            {
-                PEPAttachment attach = new PEPAttachment(attachment);
-
-                // Exclude based on file name and/or MIME type (for performance)
-                if ((attach.Data != null) &&
-                    ((Path.GetExtension(attach.FileName)?.Equals(".eml") == true) ||
-                     (Path.GetExtension(attach.FileName)?.Equals(".msg") == true) ||
-                     (attach.MimeType?.Equals("text/rfc822") == true)))
-                {
-                    // Try to convert attachment into MIME message
-                    MimeMessage message;
-                    MemoryStream memoryStream;
-                    using (memoryStream = new MemoryStream(attach.Data))
-                    {
-                        message = MimeMessage.Load(memoryStream);
-                    }
-
-                    // If conversion was successful, attachment is mail
-                    if (message != null)
-                    {
-                        string messageId = null;
-
-                        // Retrieve the mail's messageId
-                        if (message?.Headers?.Contains(HeaderId.MessageId) == true)
-                        {
-                            messageId = message.Headers?[HeaderId.MessageId];
-                        }
-
-                        // Save messageId
-                        if (string.IsNullOrEmpty(messageId) == false)
-                        {
-                            CryptableMailItem.PreviewAttachedMailId = messageId;
-                        }
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                CryptableMailItem.PreviewAttachedMailId = null;
-                Log.Error("MailItem_BeforeAttachmentPreview: Error determining if attachment is mail. " + ex.ToString());
-            }
-        }
-
-        /// <summary>
-        /// Event hander for when the internal mail item is deleted.
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff861266.aspx
-        /// </summary>
-        /// <param name="item">The item being deleted.</param>
-        /// <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 operation is not completed
-        /// and the item is not deleted.</param>
-        private void MailItem_BeforeDelete(object item, ref bool cancel)
-        {
-            this.BeforeDelete?.Invoke(ref cancel);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal mail item is forwarded.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff862702.aspx
-        /// </summary>
-        /// <param name="item">The new item being forwarded.</param>
-        /// <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 forward operation is not completed 
-        /// and the new item is not displayed.</param>
-        private void MailItem_Forward(object item, ref bool cancel)
-        {
-            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
-
-            this.Forward?.Invoke(item, ref cancel);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal 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>
-        private void MailItem_Open(ref bool cancel)
-        {
-            cancel = this.CancelOpen;
-
-            this.Open?.Invoke(ref cancel);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal 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>
-        private void MailItem_PropertyChange(string propertyName)
-        {
-            this.RaisePropertyChangedEvent(propertyName);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal mail item is replied to.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
-        /// </summary>
-        /// <param name="item">The new item being sent in response to the original message.</param>
-        /// <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 reply operation is not completed 
-        /// and the new item is not displayed.</param>
-        private void MailItem_Reply(object item, ref bool cancel)
-        {
-            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
-
-            this.Reply?.Invoke(item, ref cancel);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal mail item is replied to all recipients.
-        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
-        /// Do not try to modify the item directly
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
-        /// </summary>
-        /// <param name="item">The new item being sent in response to the original message.</param>
-        /// <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 reply operation is not completed 
-        /// and the new item is not displayed.</param>
-        private void MailItem_ReplyAll(object item, ref bool cancel)
-        {
-            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
-
-            this.ReplyAll?.Invoke(item, ref cancel);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal 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>
-        private void MailItem_Send(ref bool cancel)
-        {
-            try
-            {
-                this.Send?.Invoke(ref cancel);
-            }
-            catch (Exception)
-            {
-                throw;
-            }
-
-            this.HasBeenSent = true;
-
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the internal mail item is written (Save, SaveAs, etc...)
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff868664.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 save operation is not completed.
-        /// </param>
-        private void MailItem_Write(ref bool cancel)
-        {
-#if !READER_RELEASE_MODE
-            /* Save drafts for untrusted servers in a secure location.
-             * First we try to save it to a custom drafts folder in the pEp store
-             * and make this store visible in the favorites.
-             * If this fails, as a fallback solution, we offer to save as a message file.
-             * Note: Inline responses need to be processed differently.
-             */
-            if ((this.HasBeenSent == false) &&
-                (this.IsPEPMessage == false) &&
-                (this.internalMailItem.GetIsDraft()) &&
-                ((this.internalMailItem.GetIsInSecureStore() || this.internalMailItem.GetNeverUnsecure())))
-            {
-                bool useFallback = false;
-                Outlook.Folder parentFolder = null;
-                Outlook.Folder pEpDraftsFolder = null;
-                Outlook.Inspector currentInspector = null;
-                Outlook.Inspector newInspector = null;
-                Outlook.MailItem omi = null;
-
-                Outlook.Application app = null;
-                Outlook.Explorer activeExplorer = null;
-                Outlook.NavigationPane navPane = null;
-                Outlook.NavigationModules navModules = null;
-                Outlook.MailModule mailModule = null;
-                Outlook.NavigationGroups navGroups = null;
-                Outlook.NavigationGroup navGroup = null;
-                Outlook.NavigationFolders navFolders = null;
-
-                try
-                {
-                    // Get the pEp drafts folder and the current mail item's folder
-                    pEpDraftsFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
-
-                    // Get the caret position to later set it again
-                    bool caretPositionRetrieved = false;
-                    NativeMethods.Point caretPosition = new NativeMethods.Point(-1,-1);
-                    IntPtr inspectorHandle = IntPtr.Zero;
-
-                    try
-                    {
-                        // First, get the current process to retrieve a handle to the caret's window
-                        uint currentThreadId = NativeMethods.GetCurrentThreadId();
-                        NativeMethods.GuiThreadInfo guiThreadInfo = new NativeMethods.GuiThreadInfo();
-                        guiThreadInfo.size = Marshal.SizeOf(guiThreadInfo);
-
-                        if (NativeMethods.GetGUIThreadInfo(currentThreadId, ref guiThreadInfo))
-                        {
-                            inspectorHandle = guiThreadInfo.hwndCaret;
-
-                            // Get caret position and convert to screen coordinates
-                            if (NativeMethods.GetCaretPos(out caretPosition) &&
-                                NativeMethods.ClientToScreen(inspectorHandle, ref caretPosition))
-                            {
-                                caretPositionRetrieved = true;
-                            }
-                            else
-                            {
-                                int error = Marshal.GetLastWin32Error();
-                                Log.Error("MailItem_Write: Error getting caret position. Last Win32 error: " + error.ToString("X"));
-                            }
-                        }
-                        else
-                        {
-                            int error = Marshal.GetLastWin32Error();
-                            Log.Error("MailItem_Write: Error getting inspector Handle. Last Win32 error: " + error.ToString("X"));
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Error("MailItem_Write: Error getting caret position. " + ex.ToString());
-                    }
-
-                    /* Inline responses need a special treatment.
-                     * We cannot just intercept the Write event and check, if the item
-                     * is in the pEp folder, as it gets synced to the server anyhow if we
-                     * don't cancel the event.
-                     * So, we look up if the mail item is already present in pEp drafts and overwrite it 
-                     * with the current state if possible. If the item isn't there yet, create new item, 
-                     * move to pEp drafts folder and save current state.
-                     */
-                    if (this.IsInlineResponse)
-                    {
-                        Outlook.Items items = null;
-                        Outlook.MailItem draft = null;
-
-                        try
-                        {
-                            // Always cancel
-                            cancel = true;
-
-                            // Try to find the draft (if existing)
-                            if (string.IsNullOrEmpty(this.draftEntryId) == false)
-                            {
-                                // Get all items in the pEp drafts folder with the same subject as the current draft
-                                items = pEpDraftsFolder?.Items?.Restrict(string.Format("[Subject] = '{0}'", this.internalMailItem?.Subject));
-
-                                for (int i = 1; i <= items?.Count; i++)
-                                {
-                                    draft = items[i] as Outlook.MailItem;
-
-                                    if (draftEntryId.Equals(draft?.EntryID) == true)
-                                    {
-                                        // Draft found. Just break and continue.
-                                        break;
-                                    }
-
-                                    draft = null;
-                                }
-
-                                items = null;
-                            }
-
-                            if (PEPMessage.Create(this.internalMailItem, out PEPMessage createdMessage) == Globals.ReturnStatus.Success)
-                            {
-                                if (draft == null)
-                                {
-                                    draft = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
-                                    createdMessage.ApplyTo(draft, true, true);
-                                    draft = draft.Move(pEpDraftsFolder);
-                                    draft.Save();
-                                    this.draftEntryId = draft.EntryID;
-                                }
-                                else
-                                {
-                                    createdMessage.ApplyTo(draft, true, true);
-                                    draft.Save();
-                                }
-                            }
-                            else
-                            {
-                                Log.Error("MailItem_Write: Error creating PEPMessage.");
-                            }
-                        }
-                        catch (Exception ex)
-                        {
-                            Log.Error("MailItem_Write: Error saving inline item. " + ex.ToString());
-                        }
-                        finally
-                        {
-                            items = null;
-                            omi = null;
-                        }
-                    }
-                    else
-                    {
-                        // Get the mail item's parent folder
-                        parentFolder = this.internalMailItem.Parent as Outlook.Folder;
-
-                        // Save to pEp folder if not already there
-                        if (pEpDraftsFolder?.FullFolderPath?.Equals(parentFolder?.FullFolderPath) == false)
-                        {
-                            currentInspector = this.internalMailItem.GetInspector;
-                            omi = this.internalMailItem.Copy();
-                            omi = omi.Move(pEpDraftsFolder);
-
-                            if (currentInspector != null)
-                            {
-                                Outlook.OlWindowState windowState = currentInspector.WindowState;
-                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
-
-                                if (windowState == Outlook.OlWindowState.olNormalWindow)
-                                {
-                                    newInspector.Left = currentInspector.Left;
-                                    newInspector.Top = currentInspector.Top;
-                                    newInspector.Width = currentInspector.Width;
-                                    newInspector.Height = currentInspector.Height;
-                                }
-
-                                /* In some circumstances (e.g. ForceProtection on Exchange), the Sender information 
-                                 * may be missing. If this is the case, try to add it from the internal mail item.
-                                 */
-                                try
-                                {
-                                    // Check if there really is no useful Sender information
-                                    if ((omi != null) &&
-                                        (omi.Sender == null) &&
-                                        (string.IsNullOrEmpty(omi.SenderEmailAddress)) &&
-                                        (omi.SendUsingAccount == null))
-                                    {
-                                        // Try to add SendUsingAccount
-                                        if (this.internalMailItem.SendUsingAccount != null)
-                                        {
-                                            omi.SendUsingAccount = this.internalMailItem.SendUsingAccount;
-                                        }
-
-                                        // Try to add the Sender directly
-                                        if (this.internalMailItem.Sender != null)
-                                        {
-                                            omi.Sender = this.internalMailItem.Sender;
-                                        }
-                                    }
-                                }
-                                catch (Exception ex)
-                                {
-                                    Log.Error("MailItem_Write: Error determining/setting sender information of new Inspector. " + ex.ToString());
-                                }
-
-                                newInspector.Display();
-                                newInspector.WindowState = windowState;
-                                currentInspector.Close(Outlook.OlInspectorClose.olDiscard);
-
-                                // Set caret position again to where it was before
-                                if (caretPositionRetrieved)
-                                {
-                                    try
-                                    {
-                                        // Set cursor to the caret's previous position
-                                        NativeMethods.SetCursorPos(caretPosition.X, caretPosition.Y);
-
-                                        // Send mouse click event (mouse down and mouse up)
-                                        NativeMethods.Input[] inputs = new NativeMethods.Input[1];
-                                        inputs[0].Type = (int)NativeMethods.InputType.InputMouse;
-                                        inputs[0].Mi.Flags = (int)NativeMethods.MouseEvents.MouseEventFLeftDown | (int)NativeMethods.MouseEvents.MouseEventFLeftUp;
-
-                                        if (NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])) == 0)
-                                        {
-                                            int error = Marshal.GetLastWin32Error();
-                                            Log.Error("MailItem_Write: Error setting caret to original position. Win32 error " + error.ToString("X"));
-                                        }
-                                    }
-                                    catch (Exception ex)
-                                    {
-                                        Log.Error("MailItem_Write: Error setting caret to original position. " + ex.ToString());
-                                    }
-                                }
-                            }
-                            else
-                            {
-                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
-                                newInspector.Display();
-                            }
-
-                            cancel = true;
-                        }
-                    }
-
-                    /* Add the pEp drafts folder to favorites.
-                     * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
-                     * To make this more secure, we only proceed if the pEp store is already visible at this point.
-                     * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
-                     * to the favorites next time.
-                     */
-                    if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
-                    {
-                        // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
-                        app = Globals.ThisAddIn?.Application;
-                        activeExplorer = app?.ActiveExplorer();
-                        navPane = activeExplorer?.NavigationPane;
-                        navModules = navPane?.Modules;
-                        mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
-                        navGroups = mailModule?.NavigationGroups;
-                        navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
-                        navFolders = navGroup?.NavigationFolders;
-
-                        /* Check, if pEp drafts folder is already in favorites
-                         * WARNING: If for whatever reason, the pEp store is not visible
-                         * at this point, the Add() method crashes Outlook!
-                         */
-                        if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
-                        {
-                            if (navFolders != null)
-                            {
-                                navFolders.Add(pEpDraftsFolder);
-                            }
-                            else
-                            {
-                                Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
-                            }
-                        }
-                    }
-                    else
-                    {
-                        Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
-                    }
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("MailItem_Write: Error while saving to pEp Drafts folder. " + ex.ToString());
-                    useFallback = true;
-                }
-                finally
-                {
-                    currentInspector = null;
-                    parentFolder = null;
-                    pEpDraftsFolder = null;
-                    omi = null;
-
-                    app = null;
-                    activeExplorer = null;
-                    navPane = null;
-                    navModules = null;
-                    mailModule = null;
-                    navGroups = null;
-                    navGroup = null;
-                    navFolders = null;
-                }
-
-                if (useFallback)
-                {
-                    Log.Verbose("MailItem_Write: pEp folder could not be found or created. Trying fallback");
-
-                    // Fallback solution
-                    if (draftFileName == null)
-                    {
-                        var result = System.Windows.MessageBox.Show(Properties.Resources.DraftProtection_Warning, Properties.Resources.DraftProtection_Title, System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Exclamation);
-                        if (result == System.Windows.MessageBoxResult.Yes)
-                        {
-                            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
-                            {
-                                Filter = Properties.Resources.DraftProtection_MSG_Format + " (*.msg)|*.msg",
-                                FilterIndex = 1
-                            };
-                            if (string.IsNullOrEmpty(this.internalMailItem.Subject) == false)
-                                sfd.FileName = this.internalMailItem.Subject;
-                            var r = sfd.ShowDialog();
-                            if (r == System.Windows.Forms.DialogResult.OK)
-                            {
-                                draftFileName = sfd.FileName;
-                                this.internalMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
-                            }
-                        }
-
-                        cancel = true;
-                    }
-                    else
-                    {
-                        this.internalMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
-                        cancel = true;
-                    }
-                }
-            }
-#endif
-            this.Write?.Invoke(ref cancel);
-            return;
-        }
-
-        /**************************************************************
-         * 
-         * Property Accessors
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Returns a constant that belongs to the OlDownloadState enumeration indicating the download state of the item.
-        /// This forwards the call to the internal mail item.
-        /// See: https://msdn.microsoft.com/en-us/library/office/ff866978.aspx
-        /// </summary>
-        public Outlook.OlDownloadState DownloadState
-        {
-            get
-            {
-                lock (mutexMailItem)
-                {
-                    return (this.internalMailItem.DownloadState);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the cryptable mail item enable proctection status.
-        /// This information is stored as a user property of the wrapped mail item.
-        /// Warning: This will call .Save() on the MailItem.
-        /// </summary>
-        public bool EnableProtection
-        {
-            get
-            {
-                object propValue;
-
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored here, using the auto default value is good enough
-                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, out propValue);
-                }
-
-                return ((bool)propValue);
-            }
-            set
-            {
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored
-                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, value);
-                    this.internalMailItem.Save();
-                }
-
-                this.RaisePropertyChangedEvent(nameof(this.EnableProtection));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the cryptable mail item force unencrypted status.
-        /// This information is stored as a user property of the wrapped mail item.
-        /// Warning: This will call .Save() on the MailItem.
-        /// </summary>
-        public bool ForceUnencrypted
-        {
-            get
-            {
-                object propValue;
-
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored here, using the auto default value is good enough
-                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, out propValue);
-                }
-
-                return ((bool)propValue);
-            }
-            set
-            {
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored
-                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, value);
-                    this.internalMailItem.Save();
-                }
-
-                this.RaisePropertyChangedEvent(nameof(this.ForceUnencrypted));
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether this cryptable mail item has already been sent.
-        /// </summary>
-        public bool HasBeenSent { get; set; } = false;
-
-        /// <summary>
-        /// Gets whether this cryptable mail item is currently being processed.
-        /// </summary>
-        public bool IsBeingProcessed
-        {
-            get
-            {
-                return (this.processor.IsBusy);
-            }
-        }
-
-        /// <summary>
-        /// Gets whether the cryptable mail item is marked as a draft (unsent).
-        /// </summary>
-        public bool IsDraft
-        {
-            get
-            {
-                lock (mutexMailItem)
-                {
-                    return (this.internalMailItem.GetIsDraft());
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets whether the cryptable mail item is marked as incoming (received mail, not sent).
-        /// </summary>
-        public bool IsIncoming
-        {
-            get
-            {
-                lock (mutexMailItem)
-                {
-                    return (this.internalMailItem.GetIsIncoming());
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets whether the wrapped mail item was marked as being originally encrypted.
-        /// This should have been set by calling SetIsOriginallyEncryptedByCache() during the 
-        /// EncryptedConversationCacheUpdated event.
-        /// False is returned if the property is either false or null (doesn't exist).
-        /// </summary>
-        public bool IsOriginallyEncrypted
-        {
-            get
-            {
-                bool isOriginallyEncrypted = false;
-                lock (mutexMailItem)
-                {
-                    try
-                    {
-                        isOriginallyEncrypted = ((this.internalMailItem.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED) as bool?) == true);
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Error("IsOriginallyEncrypted: Error occured. " + ex.ToString());
-                    }
-                }
-
-                return isOriginallyEncrypted;
-            }
-        }
-
-        /// <summary>
-        /// Determines whether a cryptable mail item has been processed through pEp. This is done by checking if a pEp protocol
-        /// version is available for the item.
-        /// </summary>
-        protected bool IsPEPMessage
-        {
-            get
-            {
-                MailItemExtensions.GetPEPProperty(internalMailItem, MailItemExtensions.PEPProperty.PEPProtocolVersion, out object version);
-                return version != null;
-            }
-        }
-
-        /// <summary>
-        /// Gets if the given Outlook mail item should be securely stored (use a mirror).
-        /// </summary>
-        public bool IsSecurelyStored
-        {
-            get
-            {
-                lock (mutexMailItem)
-                {
-                    return (this.internalMailItem.GetIsSecurelyStored());
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets whether this cryptable mail item is marked to never be unsecure (always encrypted).
-        /// This information is stored as a MAPI property of the wrapped mail item.
-        /// Warning: This will call .Save() on the MailItem.
-        /// </summary>
-        public bool NeverUnsecure
-        {
-            get
-            {
-                object propValue;
-
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored here, using the auto default value is good enough
-                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, out propValue);
-                }
-
-                return ((bool)propValue);
-            }
-            set
-            {
-                lock (mutexMailItem)
-                {
-                    // Return status can be ignored
-                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, value);
-                    this.internalMailItem.Save();
-                }
-
-                this.RaisePropertyChangedEvent(nameof(this.NeverUnsecure));
-            }
-        }
-
-        /// <summary>
-        /// Gets the status after the last message processing.
-        /// This should be used to determine if a failure occured.
-        /// Success is the default if no processing has been completed.
-        /// </summary>
-        public Globals.ReturnStatus LastProcessedStatus
-        {
-            get { return (this._LastProcessedStatus); }
-        }
-
-        /// <summary>
-        /// Gets the personal identity using the internal mail item.
-        /// Warning: This can return null.
-        /// </summary>
-        public PEPIdentity Myself
-        {
-            get
-            {
-                PEPIdentity ident = null;
-                Globals.ReturnStatus sts;
-
-                lock (mutexMailItem)
-                {
-                    sts = PEPIdentity.GetOwnIdentity(this.internalMailItem, out ident);
-                }
-
-                if (sts != Globals.ReturnStatus.Success)
-                {
-                    ident = null;
-                }
-
-                return (ident);
-            }
-        }
-
-        /**************************************************************
-         * 
-         * Decryption
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Decrypts (if necessary, managing any mirrors) and returns the pEp rating for this cryptable mail item.
-        /// The calculated rating will be returned but it is already set as the property value by this method.
-        /// If rating is ever undefined: it can be assumed an error occured.
-        /// </summary>
-        private ProcessingResult ProcessAndGetRating(string entryId)
-        {
-            ProcessingResult result = new ProcessingResult();
-
-            Log.Verbose("ProcessAndGetRating: Started.");
-
-            lock (mutexMailItem)
-            {
-                bool isDraft;
-                bool isPEPInternal = false;
-                bool isSecurelyStored = false;
-                bool isSubmitted;
-                bool fullCalculation = true;
-                bool preProcessingPropertySet = false;
-                bool saveInternalMailItem = false;
-                Outlook.MailItem mirrorMailItem = null;
-                PEPMessage message = null;
-                PEPMessage mirror = null;
-                pEpDecryptFlags decryptionFlags;
-                MsgProcessor msgProcessor = new MsgProcessor();
-                Globals.ReturnStatus sts1;
-                Globals.ReturnStatus status = Globals.ReturnStatus.Success;
-
-                // Reset status
-                this._LastProcessedStatus = Globals.ReturnStatus.Success;
-
-                // Log the download status which can influence later processing
-                try
-                {
-                    Log.Verbose("ProcessAndGetRating: DownloadState=" + this.internalMailItem.DownloadState.ToString());
-                }
-                catch { }
-
-                // Detect if the mail item is a draft
-                isDraft = this.internalMailItem.GetIsDraft();
-                isSubmitted = this.internalMailItem.GetIsSubmitted();
-                Outlook.OlAccountType accountType = this.internalMailItem.GetAccountType();
-
-                // Do not processes deleted messages on IMAP
-                if ((fullCalculation) &&
-                    (accountType == Outlook.OlAccountType.olImap) &&
-                    (MapiHelper.GetProperty(this.internalMailItem, MapiProperty.PidLidImapMarkedForDeletion, "0").ToString() == "1"))
-                {
-                    Log.Verbose("ProcessAndGetRating: Deleted IMAP message detected, skipping processing");
-                    result.Rating = pEpRating.pEpRatingUndefined;
-                    fullCalculation = false;
-                }
-
-                // Check if the mail item is a mirror and use stored rating
-                if ((fullCalculation) &&
-                    (this.internalMailItem.GetIsMirror()))
-                {
-                    // Get UI rating from mirror
-                    try
-                    {
-                        if (PEPMessage.Create(this.internalMailItem, out mirror) == Globals.ReturnStatus.Success)
-                        {
-                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
-                            this.Message = mirror;
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
-                        result.Rating = mirror.Rating;
-                    }
-
-                    // If the value was undefined, don't use it. Recalculation is needed.
-                    if (result.Rating != pEpRating.pEpRatingUndefined)
-                    {
-                        Log.Verbose("ProcessAndGetRating: Mirror detected, using stored rating.");
-                        fullCalculation = false;
-                    }
-                }
-
-                /* Check if the mail item is a draft (if the Unsent flag is set)
-                 * If the message is a draft, the outgoing rating will be used, value is not stored.
-                 * This check is technically not required as the logic below will detect Outgoing messages and do the same.
-                 * However, it's potentially quicker (and more robust) to handle this special case.
-                 * Note: It's important that the message is not submitted (since it could already be encrypted).
-                 */
-                if ((fullCalculation) &&
-                    (isDraft) &&
-                    (isSubmitted == false))
-                {
-                    Log.Verbose("ProcessAndGetRating: Draft detected, using outgoing rating.");
-
-                    result.Rating = this.internalMailItem.GetOutgoingRating(true);
-                    fullCalculation = false;
-                }
-
-                // Check if untrusted server and search for mirror. Use mirror rating if available
-                isSecurelyStored = (this.internalMailItem.GetIsSecurelyStored() || this.IsSecureAttachedMail);
-                if (fullCalculation &&
-                    isSecurelyStored)
-                {
-                    // If internal mail item is attached mail, use message id for mirror lookup
-                    string messageId = null;
-                    if (this.IsSecureAttachedMail)
-                    {
-                        messageId = this.MessageId;
-                    }
-
-                    mirrorMailItem = this.internalMailItem.GetMirror(messageId);
-                    if ((mirrorMailItem != null) &&
-                        (PEPMessage.Create(mirrorMailItem, out mirror) == Globals.ReturnStatus.Success))
-                    {
-                        fullCalculation = false;
-                        this.Mirror = mirror;
-
-                        // Get UI rating from mirror
-                        try
-                        {
-                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
-                        }
-                        catch (Exception ex)
-                        {
-                            Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
-                            result.Rating = mirror.Rating;
-                        }
-
-                        this.Mirror.Rating = result.Rating;
-                    }
-                }
-
-                // Full calculation if no special cases were found
-                if (fullCalculation)
-                {
-                    // Check if message has autoconsume header and set pEp internal category if necessary
-                    try
-                    {
-                        if (this.internalMailItem.GetIsAutoConsume())
-                        {
-                            isPEPInternal = true;
-
-                            /* Set the mail item as read and apply again the category to make sure it is really set. As those
-                             * two operations require the mail item to be saved afterwards, do NOT apply it to ActiveSync 
-                             * messages, as saving with ActiveSync accounts tends to fail and then leads to "Save message?" dialogs
-                             * popping up during shutdown of Outlook. (see OUT-216).
-                             */
-                            if (accountType != Outlook.OlAccountType.olEas)
-                            {
-                                Globals.ThisAddIn.CreatePEPCategories();
-
-                                // Only one category is needed to hide the MailItem -- delete any others
-                                this.internalMailItem.Categories = Globals.PEP_INTERNAL_CATEGORY_NAME;
-                                this.internalMailItem.UnRead = false;
-                                preProcessingPropertySet = true;
-                            }
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Error("ProcessAndGetRating: Could not set pEp internal category, " + ex.ToString());
-                    }
-
-                    /* Apply a custom message class to secure mail items in secure stores (doesn't apply for pEp internal messages). This is needed for the
-                     * FormRegionPreviewUnencrypted to be shown in Outlook 2010 (technically, all versions require this according to the documentation).
-                     * See: https://msdn.microsoft.com/en-us/library/office/ff866019.aspx
-                     * In case of Outlook 2010, set message class for all messages in secure stores, as this version often downloads only mail headers in the first place
-                     * which then leads to the form region not being properly displayed at the first click (OUT-68).
-                     */
-                    if ((isPEPInternal == false) &&
-                         ((Globals.OutlookVersion == Globals.Version.Outlook2010) &&
-                          (this.internalMailItem.GetIsInSecureStore() || this.internalMailItem.GetNeverUnsecure())))
-                    {
-                        try
-                        {
-                            MapiHelper.SetProperty(this.internalMailItem, MapiProperty.PidTagMessageClass, MapiPropertyValue.PidTagMessageClassSecurePEP);
-                            preProcessingPropertySet = true;
-                        }
-                        catch (Exception ex)
-                        {
-                            Log.Error("ProcessAndGetRating: Could not set custom message class, " + ex.ToString());
-                        }
-                    }
-
-                    // Save any changes
-                    if (preProcessingPropertySet)
-                    {
-                        try
-                        {
-                            this.internalMailItem.Save();
-                        }
-                        catch (Exception ex)
-                        {
-                            Log.Error("ProcessAndGetRating: Could not save pre-processing properties, " + ex.ToString());
-                        }
-                    }
-
-                    // Process mail item
-                    sts1 = PEPMessage.Create(this.internalMailItem, out message);
-
-                    // If Key Import Wizard is open, add mail to list to process later
-                    if ((KeySyncWizard.Wizard?.IsVisible == true) &&
-                        (message.Direction == pEpMsgDirection.pEpDirIncoming) &&
-                        (message.To?.Count == 1) &&
-                        (message.From?.EqualsByAddress(message.To[0]) == true))
-                    {
-                        KeySyncWizard.Wizard?.AddToReceivedSyncMessages(message);
-                    }
-
-                    // Define decryption flags
-                    decryptionFlags = isSecurelyStored ? pEpDecryptFlags.pEpDecryptFlagUntrustedServer : pEpDecryptFlags.pEpDecryptFlagsNone;
-
-                    /* Check if the message is an attached disclaimer message.
-                     * The definition for such a message is that it's a secure attached
-                     * message with the same subject as the outer message.
-                     * See also comments in PEPAttachment.CheckIfAttachedMailAndAddToCache().
-                     */
-                    if ((message.Attachments?.Count == 1) &&
-                        (message.Attachments[0].AttachedDisclaimerMessage?.ShortMsg?.Equals(message.ShortMsg) == true))
-                    {
-                        var msg = message.Attachments[0].AttachedDisclaimerMessage.Copy();
-                        message.Attachments.Clear();
-                        for (int i = 0; i < msg.Attachments.Count; i++)
-                        {
-                            message.Attachments.Add(msg.Attachments[i]);
-                        }
-                    }
-
-                    // Process
-                    status = msgProcessor.ProcessMessage(ref message,
-                                                         sts1,
-                                                         this.internalMailItem.GetIsInSecureStore(),
-                                                         this.internalMailItem.GetIsInSentFolder(),
-                                                         isDraft,
-                                                         out mirror,
-                                                         out PEPMessage processedMessage,
-                                                         out pEpRating processedRating,
-                                                         ref decryptionFlags);
-
-                    if (status == Globals.ReturnStatus.Success)
-                    {
-                        // Handle the consumed flag marking for deletion
-                        if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagConsume))
-                        {
-                            // Delete the mail item from Outlook
-                            try
-                            {
-                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.internalMailItem.Subject + " received on " + this.internalMailItem.ReceivedTime.ToString());
-                            }
-                            catch { }
-                            this.internalMailItem.PermanentlyDelete();
-                            this.disposeAfterProcessing = true;
-
-                            Log.Verbose("ProcessAndGetRating: Processed message consumed");
-                        }
-                        else if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagIgnore))
-                        {
-                            try
-                            {
-                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.internalMailItem.Subject + " received on " + this.internalMailItem.ReceivedTime.ToString());
-                            }
-                            catch { }
-                            Log.Verbose("ProcessAndGetRating: Processed message ignored.");
-                        }
-                        else if ((Globals.ThisAddIn.OutlookOptions.ReadAsPlain) &&
-                                 (isSecurelyStored))
-                        {
-                            this.Mirror = mirror;
-                        }
-                        else
-                        {
-                            // Save processed message data to Outlook
-                            if (processedMessage != null)
-                            {
-
-                                // Set the mail item
-                                if (mirror != null)
-                                {
-                                    // Save mirror as property of this cryptable mail item
-                                    this.Mirror = mirror;
-                                    this.Mirror.Rating = processedRating;
-
-                                    if (mirrorMailItem == null)
-                                    {
-                                        // If internal mail item is attached mail, use message id for mirror creation
-                                        string messageId = null;
-                                        if (this.IsSecureAttachedMail)
-                                        {
-                                            messageId = this.MessageId;
-                                        }
-
-                                        mirrorMailItem = this.internalMailItem.CreateMirrorOMI(messageId);
-                                    }
-
-                                    // Apply message to mirror and save
-                                    processedMessage.ApplyTo(mirrorMailItem, true, true);
-
-                                    try
-                                    {
-                                        mirrorMailItem.Save();
-                                    }
-                                    catch (Exception ex)
-                                    {
-                                        Log.Error("ProcessAndGetRating: Error saving mirror item. " + ex.ToString());
-                                    }
-
-                                    // If needed, set SmartNoAttach MAPI property to hide the attachments icon
-                                    if ((accountType != Outlook.OlAccountType.olImap) &&
-                                        (processedMessage.Attachments?.Count == 0) &&
-                                        (this.internalMailItem.Attachments?.Count > 0))
-                                    {
-                                        // Note: The documented MAPI property PidLidSmartNoAttach (0x8514000B) doesn't work for some reason
-                                        result.PropertiesToSet.Add(MapiProperty.PidTagSmartNoAttach2, true);
-                                    }
-
-                                    /* If we have extra keys and are on an untrusted server, reencrypt message
-                                     * for myself and the extra keys.
-                                     */
-                                    if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagSrcModified))
-                                    {
-                                        if (message.ApplyTo(this.internalMailItem, false, false, true, false) == Globals.ReturnStatus.Success)
-                                        {
-                                            saveInternalMailItem = true;
-                                        }
-                                        else
-                                        {
-                                            Log.Error("ProcessAndGetRating: Error reencrypting with extra keys.");
-                                        }
-                                    }
-                                }
-                                else
-                                {
-                                    // Trusted server: apply message and save
-                                    processedMessage.ApplyTo(this.internalMailItem, true, false);
-                                    saveInternalMailItem = true;
-                                }
-                            }
-                            // If processed message is null (= didn't run through decryption (again)), update UI rating
-                            else
-                            {
-                                /* In rare circumstances (i.e. when a user makes a handshake using
-                                 * an FPP message) we can get here. In this case, we need to set the
-                                 * rating manually to reliable or higher (reevaluate).
-                                 */
-                                if ((string.IsNullOrEmpty(message.ForceProtectionId) == false) &&
-                                    (message.Rating == pEpRating.pEpRatingUndefined))
-                                {
-                                    message.Rating = processedRating;
-                                    processedRating = AdapterExtensions.ReevaluateFPPMessageRating(message);
-                                }
-                                else
-                                {
-                                    processedRating = AdapterExtensions.ReevaluateMessageRating(message, processedRating);
-                                }
-                            }
-                        }
-                    }
-
-                    // Remove the pEp Processing category if needed
-                    if (Globals.ThisAddIn.Settings.IsUXImprovementEnabled &&
-                        this.internalMailItem.RemovePEPProcessingCategory())
-                    {
-                        if (message?.Direction != null)
-                        {
-                            this.internalMailItem.UnRead = (message.Direction == pEpMsgDirection.pEpDirIncoming);
-                        }
-                        else
-                        {
-                            this.internalMailItem.UnRead = (this.internalMailItem.GetIsInSentFolder() == false);
-                        }
-                        saveInternalMailItem = true;
-                    }
-
-                    // Save internal mail item if necessary
-                    if (saveInternalMailItem)
-                    {
-                        bool saveError = false;
-                        try
-                        {
-                            this.internalMailItem.Save();
-                        }
-                        catch (Exception ex)
-                        {
-                            saveError = true;
-                            Log.Error("ProcessAndGetRating: Error saving internal mail item. " + ex.ToString());
-                        }
-
-                        // If an error occured during saving, try to forcefully save
-                        if (saveError)
-                        {
-                            try
-                            {
-                                int sts = Mapi.Save(this.internalMailItem, Mapi.SaveOption.KEEP_OPEN_READWRITE);
-                                Log.Verbose("ProcessAndGetRating: Saving using backup method. Return status is " + sts.ToString("X"));
-
-                                if (sts != (uint)Mapi.HResult.S_OK)
-                                {
-                                    sts = Mapi.Save(this.internalMailItem, Mapi.SaveOption.FORCE_SAVE);
-                                    Log.Verbose("ProcessAndGetRating: Saving with FORCE_SAVE flag returned " + sts.ToString("X"));
-                                }
-                            }
-                            catch (Exception ex)
-                            {
-                                Log.Error("ProcessAndGetRating: Error forcefully saving internal mail item. " + ex.ToString());
-                            }
-                        }
-                    }
-
-                    this.Message = processedMessage ?? message;
-                    this.Message.Rating = processedRating;
-                    result.Rating = processedRating;
-                }
-
-                // Save processing status
-                this._LastProcessedRating = result.Rating;
-                this._LastProcessedStatus = status;
-
-                // If it's an incoming message, do some caching (entry ids of drafts are empty)
-                if (string.IsNullOrEmpty(entryId) == false)
-                {
-                    // Save rating in db
-                    PEPDatabase.StoreOrUpdateRating(entryId, result.Rating);
-
-                    // Save message in cache
-                    if (isSecurelyStored)
-                    {
-                        if (Mirror != null)
-                        {
-                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Mirror, Rating = result.Rating });
-                        }
-                        else if ((Message != null) &&
-                                 (Message.IsSecure == false))
-                        {
-                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Message, Rating = result.Rating });
-                        }
-                    }
-                    else
-                    {
-                        PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = null, Rating = result.Rating });
-                    }
-                }
-
-                // Release objects
-                mirrorMailItem = null;
-
-                // Release the decryption lock
-                lock (mutexDecryptionList)
-                {
-                    try
-                    {
-                        if ((string.IsNullOrEmpty(entryId) == false) &&
-                            (decryptionList?.Count > 0))
-                        {
-                            decryptionList.Remove(entryId);
-                            Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
-                                        (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
-                        }
-                    }
-                    catch
-                    {
-                        Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
-                    }
-
-                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
-                }
-            }
-
-            Log.Verbose("ProcessAndGetRating: Completed. Result is " + Enum.GetName(typeof(pEpRating), result.Rating));
-
-            return result;
-        }
-
-        /// <summary>
-        /// Starts the processing of the mail item which can result in decryption or encryption of the message.
-        /// </summary>
-        /// <param name="disposeAfterComplete">Set to true in order to release/dispose the internal MailItem and this CryptableMailItem 
-        /// after processing is complete. This would be used for background processing where the reference is not maintained in the UI.
-        /// WARNING: do not set to true if you will use this MailItem or CryptableMailItem later!</param>
-        /// <returns>True if the processing started successfully, otherwise false if it is already busy.</returns>
-        public async void StartProcessing(bool isDraft, bool disposeAfterComplete = false)
-        {
-            if (this.processor.IsBusy == false)
-            {
-                string entryId = null;
-                this.disposeAfterProcessing = disposeAfterComplete;
-
-                bool process = await Task.Run(() =>
-                {
-                    int sleepTime = 1000; // 1 second in milliseconds
-                    int curWaitTime = 0;
-                    int maxWaitTime = 60000; // 1 minute in milliseconds
-                    bool isAlreadyBeingDecrypted = false;
-                    bool isAutoConsume = false;
-
-                    lock (mutexMailItem)
-                    {
-                        /* Explicitly add try/catch block to catch error getting EntryID.
-                         * This should theoretically never happen, but was seen in practice.
-                         */
-                        try
-                        {
-                            entryId = this.internalMailItem.EntryID;
-                            isAutoConsume = this.internalMailItem.GetIsAutoConsume();
-                        }
-                        catch
-                        {
-                            Log.Error("ProcessAndGetRating: internalMailItem is invalid or EntryID could not get retrieved");
-                            this._LastProcessedRating = pEpRating.pEpRatingUndefined;
-                            this._LastProcessedStatus = Globals.ReturnStatus.Failure;
-                            return false;
-                        }
-                    }
-
-                    // Make sure this mail item is not already being decrypted
-                    if (string.IsNullOrEmpty(entryId) == false)
-                    {
-                        do
-                        {
-                            /* Check if the EntryID is already in the decrypting list
-                             * If so, it is being decrypted already and we must wait
-                             * If it isn't already being decrypted, then add it to the decryption list
-                             */
-                            lock (mutexDecryptionList)
-                            {
-                                if (decryptionList.ContainsKey(entryId))
-                                {
-                                    isAlreadyBeingDecrypted = true;
-                                }
-                                else
-                                {
-                                    isAlreadyBeingDecrypted = false;
-
-                                    /* Add the entryID to the decryption list and we can start decryption
-                                     * It is important to do this all under the same lock
-                                     * 
-                                     * Note: It’s known the EntryID is not guaranteed to be unique for a given MailItem across different stores.
-                                     * However, only the EntryID is used in the decryption list.
-                                     * This is not an issue as worse-case is simply waiting for a different MailItem with the same EntryID to finish.
-                                     */
-                                    decryptionList.Add(entryId, "");
-                                    Log.Verbose("ProcessAndGetRating: Added EntryID to decryption list. " + entryId);
-                                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
-                                    break;
-                                }
-                            }
-
-                            // Wait for the other thread to finish
-                            if (isAlreadyBeingDecrypted)
-                            {
-                                // Do not process multiple times if it is an automatic message
-                                if (isAutoConsume)
-                                {
-                                    curWaitTime = maxWaitTime + 1;
-                                    Log.Verbose("ProcessAndGetRating: Setting timeout for AutoConsume message.");
-                                }
-                                else
-                                {
-                                    Log.Verbose("ProcessAndGetRating: Waiting for other decryption thread to finish. " + entryId);
-                                    Thread.Sleep(sleepTime);
-                                    curWaitTime += sleepTime;
-                                }
-                            }
-                        }
-                        while ((isAlreadyBeingDecrypted) && (curWaitTime < maxWaitTime));
-                    }
-                    else
-                    {
-                        // Log the issue unless the MailItem is an unsaved draft message
-                        if (isDraft == false)
-                        {
-                            Log.Warning("ProcessAndGetRating: EntryID does not exist, unable to lock during decryption.");
-                        }
-                        else
-                        {
-                            Log.Verbose("ProcessAndGetRating: Could not add EntryID to decryption list lock because message is an unsaved draft.");
-                        }
-                    }
-
-                    // Exit if timeout occured
-                    if ((isAlreadyBeingDecrypted) ||
-                        (curWaitTime >= maxWaitTime))
-                    {
-                        Log.Error("ProcessAndGetRating: Exited by timeout. " + (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
-
-                        // Save processing status
-                        this._LastProcessedRating = pEpRating.pEpRatingCannotDecrypt;
-                        this._LastProcessedStatus = Globals.ReturnStatus.Failure;
-
-                        // Remove entryId from decryption list
-                        lock (mutexDecryptionList)
-                        {
-                            try
-                            {
-                                decryptionList.Remove(entryId);
-                                Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
-                                            (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
-                            }
-                            catch
-                            {
-                                Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
-                            }
-
-                            Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
-                        }
-
-                        return false;
-                    }
-
-                    return true;
-                });
-
-                if (process)
-                {
-                    this.processor.RunWorkerAsync(entryId);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the processor background worker is doing work.
-        /// </summary>
-        private void Processor_DoWork(object sender, DoWorkEventArgs e)
-        {
-            e.Result = this.ProcessAndGetRating(e.Argument as string);
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the processor background worker is completed.
-        /// </summary>
-        private void Processor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
-        {
-            MsgProcessor.ProcessingCompletedEventArgs args;
-
-            // Decrement decryption counter after decryption has finished (if necessary)
-            if (this.decrementCounter)
-            {
-                ThisAddIn.DecryptionStack.DecrementDecryptionCounter();
-            }
-
-            // Catch any errors that occured during processing
-            if (e.Error != null)
-            {
-                Log.Error("Processor_RunWorkerCompleted: Error during processing of mail item. " + e.Error.ToString());
-
-                if (this.disposeAfterProcessing)
-                {
-                    this.Dispose(false);
-
-                    // Must be called last!
-                    this.DisposeInternalMailItem();
-                }
-
-                return;
-            }
-
-            // Get processing result
-            ProcessingResult result = e.Result as ProcessingResult;
-
-            // Dispose if necessary
-            if (this.disposeAfterProcessing)
-            {
-                /* If there are MAPI properties to set, we have to marshal
-                 * this call to the main thread. If not, we can just dispose it
-                 * on the current one.
-                 */
-                if (result?.PropertiesToSet?.Count > 0)
-                {
-                    KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
-                    {
-                        this.internalMailItem?.SetMAPIProperties(result.PropertiesToSet);
-
-                        this.Dispose(false);
-
-                        // Must be called last!
-                        this.DisposeInternalMailItem();
-                    }));
-                }
-                else
-                {
-                    this.Dispose(false);
-
-                    // Must be called last!
-                    this.DisposeInternalMailItem();
-                }
-            }
-            else
-            {
-                // Raise complete event (only if dispose after decryption is not true since .this reference is returned)
-                args = new MsgProcessor.ProcessingCompletedEventArgs();
-
-                // Check for errors during processing but invoke anyhow to complete process (needed to look up mirror).
-                if (e.Error == null)
-                {
-                    args.ProcessedRating = result.Rating;
-                    args.PropertiesToSet = result.PropertiesToSet;
-                }
-                else
-                {
-                    args.ProcessedRating = pEpRating.pEpRatingUndefined;
-                }
-
-                this.ProcessingCompleted?.Invoke(this, args);
-            }
-        }
-
-        /**************************************************************
-         * 
-         * Mirror Locator
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Starts the process to locate the mirror of the mail item.
-        /// </summary>
-        public void StartGetMirror(string messageId = null)
-        {
-            if (this.mirrorLocator.IsBusy == false)
-            {
-                this.mirrorLocator.RunWorkerAsync(messageId);
-            }
-
-            return;
-        }
-
-        /// <summary>
-        /// Event handler for when the mirror locator background worker is doing work.
-        /// </summary>
-        private void MirrorLocator_DoWork(object sender, DoWorkEventArgs e)
-        {
-            PEPMessage mirror = null;
-            Outlook.MailItem omi = null;
-            e.Result = null;
-            Globals.ReturnStatus sts;
-
-            Log.Verbose("MirrorLocator_DoWork: Started");
-
-            try
-            {
-                if (this.Mirror != null)
-                {
-                    // If we already have a mirror, use it
-                    e.Result = this.Mirror;
-                }
-                else
-                {
-                    // If no stored mirror is there, look it up
-                    lock (mutexMailItem)
-                    {
-                        string id = e.Argument as string;
-                        omi = this.internalMailItem.GetMirror(id);
-
-                        if (omi != null)
-                        {
-                            Log.Verbose("MirrorLocator_DoWork: Mirror found");
-
-                            sts = PEPMessage.Create(omi, out mirror);
-                        }
-                    }
-
-                    e.Result = mirror;
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.Error("MirrorLocator_DoWork: Failed to find mirror OMI, " + ex.ToString());
-            }
-            finally
-            {
-                omi = null;
-            }
-
-            Log.Verbose("MirrorLocator_DoWork: Completed");
-        }
-
-        /// <summary>
-        /// Event handler for when the mirror locator background worker is completed.
-        /// </summary>
-        private void MirrorLocator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
-        {
-            this.GetMirrorCompleted?.Invoke(this, new GetMirrorCompletedEventArgs(e.Result == null ? null : (PEPMessage)e.Result));
-            return;
-        }
-
-        /**************************************************************
-         * 
-         * Methods
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Releases all resources and disconnects internal events.
-        /// The internal mail item will NOT be released -- this is managed externally.
-        /// </summary>
-        public void Dispose()
-        {
-            this.Dispose(true);
-            // Note: GC.SuppressFinalize(this); is not called because that just seems bad
-            return;
-        }
-
-        /// <summary>
-        /// Releases the internal Outlook.MailItem wrapped by this CryptableMailItem.
-        /// In general, this shouldn't be used as the MailItems are managed externally.
-        /// However, there are some cases where the MailItem needs to be disposed and the CryptableMailItem is the only
-        /// object that maintains the reference.
-        /// </summary>
-        public void DisposeInternalMailItem()
-        {
-            if (this.internalMailItem != null)
-            {
-                // Marshal.ReleaseComObject(this.internalMailItem);
-                this.internalMailItem = null;
-            }
-
-            return;
-        }
-
-        /// <summary>
-        /// Releases resources and disconnects internal events.
-        /// This exists to make code-analysis not throw old warnings.
-        /// </summary>
-        /// <param name="disposing">True to clean up native and managed resources. 
-        /// False to clean up only native resources.</param>
-        protected virtual void Dispose(bool disposing)
-        {
-            // Free managed resources
-            if (disposing)
-            {
-                // Disconnect mail item events
-                this.ConnectInternalMailItemEvents(false);
-
-                /* The BackgroundWorker class doesn't actually implement any functionality in Dispose.
-                 * It's simply inherited from the base implementation.
-                 * Just to make this clear (especially for code analysis) it is called and documented here.
-                 */
-                if (this.processor != null)
-                {
-                    this.processor.RunWorkerCompleted -= Processor_RunWorkerCompleted;
-                    this.processor.DoWork -= Processor_DoWork;
-                    this.processor.Dispose();
-                }
-                if (this.mirrorLocator != null)
-                {
-                    this.mirrorLocator.RunWorkerCompleted -= MirrorLocator_RunWorkerCompleted;
-                    this.mirrorLocator.DoWork -= MirrorLocator_DoWork;
-                    this.mirrorLocator.Dispose();
-                }
-            }
-
-            this.internalMailItem = null;
-        }
-
-        /// <summary>
-        /// Attempts to resolve all the Recipient objects in the Recipients collection of
-        /// the internal mail item against the Address Book (similar to 'Check Names').
-        /// This will first save the mail item (if it's not a draft), then forward the call to Recipients.ResolveAll().
-        /// See: https://msdn.microsoft.com/en-us/library/office/microsoft.office.interop.outlook.recipients.resolveall
-        /// </summary>
-        public void ResolveAllRecipients()
-        {
-            lock (mutexMailItem)
-            {
-                try
-                {
-                    /* Calling Save() for drafts might cause a crash, as this then interferes
-                     * with the protected storing of drafts for untrusted servers.
-                     */
-                    if (this.internalMailItem.GetIsDraft() == false)
-                    {
-                        this.internalMailItem.Save();
-                    }
-                    bool result = this.internalMailItem.Recipients.ResolveAll();
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("ResolveAllRecipients: exception " + ex.ToString());
-                }
-            }
-
-            return;
-        }
-
-        /// <summary>
-        /// Checks if the original item was encrypted and sets the user property to the
-        /// reply/forward item if needed.
-        /// This method evokes the OriginallyEncryptedStatusUpdated because it is possible
-        /// that the FormRegionPrivacyStatus has already been initialized when this method
-        /// is run. However, it might be necessary to check if the original item was encrypted
-        /// in order to decide whether to encrypt the reply/forward, so we need to update its
-        /// status.
-        /// </summary>
-        /// <param name="replyItem">The reply/forward item</param>
-        private void SetOriginallyEncryptedStatus(Outlook.MailItem replyItem)
-        {
-            if (this._LastProcessedRating >= pEpRating.pEpRatingUnreliable)
-            {
-                replyItem?.SetOriginallyEncryptedStatus(this._LastProcessedRating);
-
-                OriginallyEncryptedStatusUpdated?.Invoke(this, new EventArgs());
-            }
-        }
-
-        /// <summary>
-        /// Displays the unencrypted mirror mail item (if it exists) associated with the wrapped mail item.
-        /// </summary>
-        /// <returns>True if successful, otherwise false.</returns>
-        public bool DisplayMirror()
-        {
-            if (this.processor.IsBusy ||
-                this.mirrorLocator.IsBusy)
-            {
-                // Don't try to locate the mirror if it's being used
-                return (false);
-            }
-            else
-            {
-                Outlook.MailItem omi = this.internalMailItem.GetMirror();
-
-                if (omi == null)
-                {
-                    return (false);
-                }
-                else
-                {
-                    omi.Display();
-                }
-            }
-
-            return true;
-        }
-
-        /**************************************************************
-         * 
-         * Event Methods
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Raises the property change event, if possible, with the given arguments.
-        /// </summary>
-        /// <param name="propertyName">The name of the property that was changed.</param>
-        private void RaisePropertyChangedEvent(string propertyName)
-        {
-            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-            return;
-        }
-
-        /// <summary>
-        /// Dis/connects all necessary events to/from the internal mail item.
-        /// This will then expose these events through the cryptable mail item directly.
-        /// </summary>
-        /// <param name="connect">Whether to connect or disconnect events.</param>
-        private void ConnectInternalMailItemEvents(bool connect)
-        {
-            if (this.internalMailItem != null)
-            {
-                /* OUT-285: This should probably never fail, but during dis/connection
-                 * of an account, this method raised an InvalidCastException, so we will 
-                 * catch any error here anyway.
-                 */
-                try
-                {
-                    // Connect or disconnect events
-                    if (connect)
-                    {
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeAttachmentPreview += MailItem_BeforeAttachmentPreview;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeDelete += MailItem_BeforeDelete;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Forward += MailItem_Forward;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Open += MailItem_Open;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).PropertyChange += MailItem_PropertyChange;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Reply += MailItem_Reply;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).ReplyAll += MailItem_ReplyAll;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Send += MailItem_Send;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Write += MailItem_Write;
-                    }
-                    else
-                    {
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeAttachmentPreview -= MailItem_BeforeAttachmentPreview;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeDelete -= MailItem_BeforeDelete;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Forward -= MailItem_Forward;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Open -= MailItem_Open;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).PropertyChange -= MailItem_PropertyChange;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Reply -= MailItem_Reply;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).ReplyAll -= MailItem_ReplyAll;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Send -= MailItem_Send;
-                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Write -= MailItem_Write;
-                    }
-                }
-                catch (Exception ex)
-                {
-                    Log.Error("ConnectInternalMailItemEvents: Error occured. " + ex.ToString());
-                }
-            }
-
-            return;
-        }
-
-        /**************************************************************
-         * 
-         * Sub-classes
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Class used to store the arguments in the GetMirrorCompleted event.
-        /// </summary>
-        internal class GetMirrorCompletedEventArgs : EventArgs
-        {
-            /// <summary>
-            /// The located mirror after the get mirror process is complete.
-            /// </summary>
-            public PEPMessage Mirror = null;
-
-            /// <summary>
-            /// Constructs a new GetMirrorCompletedEventArgs with the given arguments.
-            /// </summary>
-            /// <param name="mirror">The located mirror after the get mirror process completes.</param>
-            public GetMirrorCompletedEventArgs(PEPMessage mirror)
-            {
-                this.Mirror = mirror;
-            }
-        }
-
-        /// <summary>
-        /// Class used to store an entry in the encrypted conversation cache.
-        /// This will identify the original parent encrypted mail item.
-        /// </summary>
-        private class OriginalMailItem
-        {
-            public string ConversationId { get; set; }
-            public string ConversationIndex { get; set; }
-            public string ConversationTopic { get; set; }
-            public string EntryId { get; set; }
-            public bool IsEncrypted { get; set; }
-
-            public OriginalMailItem()
-            {
-                this.ConversationId = null;
-                this.ConversationIndex = null;
-                this.ConversationTopic = null;
-                this.EntryId = null;
-                this.IsEncrypted = false;
-            }
-        }
-
-        /// <summary>
-        /// Class used to store a processing result.
-        /// </summary>
-        internal class ProcessingResult
-        {
-            public pEpRating Rating { get; set; } = pEpRating.pEpRatingUndefined;
-            public Dictionary<MapiProperty.MapiProp, object> PropertiesToSet { get; set; } = new Dictionary<MapiProperty.MapiProp, object>();
-        }
-    }
-}
--- a/DecryptionStack.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/DecryptionStack.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -1,4 +1,5 @@
-using System;
+using pEp.Wrappers;
+using System;
 using System.Collections.Generic;
 using Outlook = Microsoft.Office.Interop.Outlook;
 
@@ -219,7 +220,7 @@
         {
             Outlook.MailItem omi = null;
             Outlook.MailItem omiCopy = null;
-            CryptableMailItem cmi = null;
+            MailItemWrapper mi = null;
 
             // Try to increment the decryption counter
             if (this.IncrementDecryptionCounter() == false)
@@ -308,13 +309,13 @@
                     else
                     {
                         // Process item
-                        cmi = new CryptableMailItem(omiCopy ?? omi, null, true);
+                        mi = new MailItemWrapper(omiCopy ?? omi, null, true);
 
                         /* Note: Make sure to dispose the MailItem after processing (pass true).
                          * This is needed as decryption is asynchronous but the MailItem reference still needs to be released.
                          * Do NOT use omi or cmi references after this point!
                          */
-                        cmi.StartProcessing(false, true);
+                        mi.StartProcessing(false, true);
                         Log.Verbose("DecryptionStack.DecryptionTimer_Tick: started decryption of item with entryId " + omi?.EntryID);
                     }
                 }
--- a/Extensions/ContactItemExtensions.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/Extensions/ContactItemExtensions.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using pEp.Wrappers;
+using System.Runtime.InteropServices;
 using Outlook = Microsoft.Office.Interop.Outlook;
 
 namespace pEp
@@ -23,7 +24,7 @@
             if (Globals.ThisAddIn.Settings.IsDisableProtectionForContactsEnabled)
             {
                 properties = contact.UserProperties;
-                up = properties.Find(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
+                up = properties.Find(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
 
                 if (up == null)
                 {
@@ -61,11 +62,11 @@
                                                bool forceUnencrypted)
         {
             Outlook.UserProperties properties = contact.UserProperties;
-            Outlook.UserProperty up = properties.Find(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
+            Outlook.UserProperty up = properties.Find(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
 
             if (up == null)
             {
-                up = contact.UserProperties.Add(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
+                up = contact.UserProperties.Add(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
                                                 Outlook.OlUserPropertyType.olYesNo, false);
             }
 
--- a/Extensions/MailItemExtensions.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/Extensions/MailItemExtensions.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -1,5 +1,6 @@
 using MimeKit;
 using pEp.Extensions;
+using pEp.Wrappers;
 using pEpCOMServerAdapterLib;
 using System;
 using System.Collections.Generic;
@@ -16,7 +17,7 @@
     /// Contains extensions for the MailItem as well as utility methods specific for pEp.
     /// </summary>
     internal static class MailItemExtensions
-    {        
+    {
         public const string                     USER_PROPERTY_KEY_ORIG_ENTRY_ID         = "origEntryID";
         public const string                     USER_PROPERTY_KEY_INSPECTOR_CLOSED      = "inspectorClosed";
         public const string                     USER_PROPERTY_KEY_IS_INCOMING           = "isIncoming";
@@ -272,7 +273,7 @@
         /// </summary>
         /// <param name="omi">The Outlook mail item to process with.</param>
         /// <param name="originalEntryId">The EntryId of the original mail item.</param>
-        public static void AddReplyIconsToOriginal(this Outlook.MailItem omi, 
+        public static void AddReplyIconsToOriginal(this Outlook.MailItem omi,
                                                    string originalEntryId)
         {
 
@@ -337,10 +338,10 @@
         public static void AvoidWinmailDatAttachment(this Outlook.MailItem omi)
         {
             // Remove all pEp user properties
-            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
-            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION);
-            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED);
-            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING);
+            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
+            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION);
+            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED);
+            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ORIGINAL_RATING);
             omi?.DeleteUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID);
             omi?.DeleteUserProperty(MailItemExtensions.USER_PROPERTY_KEY_PROCESSING_STATE);
 
@@ -706,7 +707,7 @@
 
             try
             {
-                folder = omi.Parent as Outlook.Folder;                
+                folder = omi.Parent as Outlook.Folder;
                 accountType = folder.GetAccountType();
             }
             catch
@@ -1030,11 +1031,11 @@
         {
             if (rating >= pEpRating.pEpRatingUnreliable)
             {
-                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED,
+                omi?.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED,
                                           true,
                                           Outlook.OlUserPropertyType.olYesNo);
 
-                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING,
+                omi?.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ORIGINAL_RATING,
                                           rating.ToEngineString(),
                                           Outlook.OlUserPropertyType.olText);
 
@@ -2011,7 +2012,7 @@
                 recipients = null;
                 store = null;
             }
-        }       
+        }
 
         /// <summary>
         /// Processes a mail item asynchronously and sends it out.
@@ -2178,7 +2179,7 @@
         /// <param name="omi">The Outlook mail item to process with.</param>
         /// <param name="smtpAddress">The address of the account to set.</param>
         /// <returns>True if the account is set correctly, otherwise false.</returns>
-        public static bool SetSendUsingAccount(this Outlook.MailItem omi, 
+        public static bool SetSendUsingAccount(this Outlook.MailItem omi,
                                               string smtpAddress)
         {
             bool success = false;
@@ -2630,17 +2631,8 @@
                 }
 
                 // Release objects
-                if (properties != null)
-                {
-                    // Marshal.ReleaseComObject(properties);
-                    properties = null;
-                }
-
-                if (up != null)
-                {
-                    // Marshal.ReleaseComObject(up);
-                    up = null;
-                }
+                properties = null;
+                up = null;
             }
 
             return (value);
@@ -2762,7 +2754,7 @@
         /// </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)
+        public static WindowBaseWrapper GetParentWindowWrapper(this Outlook.MailItem omi)
         {
             return Globals.ThisAddIn.GetWatchedParentWindow(omi);
         }
@@ -2944,7 +2936,7 @@
                                  *   ON : ForceUnencrypted property exists with a value of 'True'
                                  *  OFF : ForceUnencrypted property does not exist or has a value of 'False' or null
                                  */
-                                bool? forceUnencrypted = omi.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED) as bool?;
+                                bool? forceUnencrypted = omi.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED) as bool?;
 
                                 // Set value if it has been retrieved
                                 if (forceUnencrypted == true)
@@ -3058,7 +3050,7 @@
                                  *   ON : EnableProtection property exists with a value of 'True'
                                  *  OFF : EnableProtection property does not exist or has a value of 'False' or null
                                  */
-                                bool? enableProtection = (omi.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION)) as bool?;
+                                bool? enableProtection = (omi.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION)) as bool?;
 
                                 // Set value if it has been retrieved
                                 if (enableProtection == true)
@@ -3231,13 +3223,13 @@
                                 {
                                     if ((bool)value)
                                     {
-                                        omi.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
+                                        omi.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
                                                             true,
                                                             Outlook.OlUserPropertyType.olYesNo);
                                     }
                                     else
                                     {
-                                        omi.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
+                                        omi.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
                                     }
 
                                     success = true;
@@ -3339,13 +3331,13 @@
                                 {
                                     if ((bool)value)
                                     {
-                                        omi.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION,
+                                        omi.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION,
                                                             true,
                                                             Outlook.OlUserPropertyType.olYesNo);
                                     }
                                     else
                                     {
-                                        omi.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION);
+                                        omi.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION);
                                     }
 
                                     success = true;
--- a/FPPMessage.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/FPPMessage.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -367,7 +367,7 @@
                                     omi = Globals.ThisAddIn.Application.Session.GetItemFromID(this.CurrentEntryId);
                                 }
 
-                                WatchedWindow window = omi?.GetWatchedParentWindow();
+                                WindowBaseWrapper window = omi?.GetParentWindowWrapper();
                                 if (window != null)
                                 {
                                     WindowFormRegionCollection formRegions = Globals.FormRegions[window.Window];
@@ -763,7 +763,7 @@
                             Log.Verbose("DecryptMessage: FormRegionPreviewUnencrypted not visible.");
                         }
 
-                        omi.GetWatchedParentWindow()?.UpdateFormRegion(true);
+                        omi.GetParentWindowWrapper()?.UpdateFormRegion(true);
                     }
 
                     status = Globals.ReturnStatus.Success;
--- a/ThisAddIn.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/ThisAddIn.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -53,8 +53,8 @@
         private List<WatchedFolder>         watchedFolders              = new List<WatchedFolder>();
         private System.Windows.Forms.Timer  inboxCleaner                = null;
 
-        private List<WatchedExplorer>       watchedExplorers            = new List<WatchedExplorer>();
-        private List<WatchedInspector>      watchedInspectors           = new List<WatchedInspector>();
+        private List<ExplorerWrapper>       watchedExplorers            = new List<ExplorerWrapper>();
+        private List<InspectorWrapper>      watchedInspectors           = new List<InspectorWrapper>();
         private object                      mutexWatchedExplorers       = new object();
         private object                      mutexWatchedInspectors      = new object();
         private Outlook.Explorers           explorers                   = null;
@@ -214,7 +214,7 @@
         /// Adds a new WatchedExplorer to the list of watched explorers.
         /// </summary>
         /// <param name="watchedExplorer">The WatchedExplorer to add.</param>
-        internal void AddToWatchedExplorers(WatchedExplorer watchedExplorer)
+        internal void AddToWatchedExplorers(ExplorerWrapper watchedExplorer)
         {
             lock (mutexWatchedExplorers)
             {
@@ -226,7 +226,7 @@
         /// Adds a new WatchedInspector to the list of watched inspectors.
         /// </summary>
         /// <param name="watchedInspector">The WatchedInspector to add.</param>
-        internal void AddToWatchedInspectors(WatchedInspector watchedInspector)
+        internal void AddToWatchedInspectors(InspectorWrapper watchedInspector)
         {
             lock (mutexWatchedInspectors)
             {
@@ -238,7 +238,7 @@
         /// Removes a WatchedExplorer from the list of watched explorers.
         /// </summary>
         /// <param name="watchedExplorer">The WatchedExplorer to remove.</param>
-        internal void RemoveFromWatchedExplorers(WatchedExplorer watchedExplorer)
+        internal void RemoveFromWatchedExplorers(ExplorerWrapper watchedExplorer)
         {
             lock (mutexWatchedExplorers)
             {
@@ -250,7 +250,7 @@
         /// Removes a WatchedInspector from the list of watched inspectors.
         /// </summary>
         /// <param name="WatchedInspector">The WatchedInspector to remove.</param>
-        internal void RemoveFromWatchedInspectors(WatchedInspector watchedInspector)
+        internal void RemoveFromWatchedInspectors(InspectorWrapper watchedInspector)
         {
             lock (mutexWatchedInspectors)
             {
@@ -263,7 +263,7 @@
         /// </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)
+        internal WindowBaseWrapper GetWatchedParentWindow(Outlook.MailItem omi)
         {
             try
             {
@@ -299,11 +299,11 @@
         /// </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)
+        internal WindowBaseWrapper GetWindowWrapper(dynamic window)
         {
             Outlook.Explorer explorer = null;
             Outlook.Inspector inspector = null;
-            WatchedWindow watchedWindow = null;
+            WindowBaseWrapper watchedWindow = null;
 
             try
             {
@@ -687,11 +687,11 @@
         /// 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)
+        internal void RecalculateAllWindows(WindowBaseWrapper windowToExclude)
         {
             for (int i = 0; i < this.watchedExplorers.Count; i++)
             {
-                if ((windowToExclude as WatchedExplorer)?.Equals(this.watchedExplorers[i]) != true)
+                if ((windowToExclude as ExplorerWrapper)?.Equals(this.watchedExplorers[i]) != true)
                 {
                     this.watchedExplorers[i].RequestRatingAndUIUpdate();
                 }
@@ -699,7 +699,7 @@
 
             for (int i = 0; i < this.watchedInspectors.Count; i++)
             {
-                if ((windowToExclude as WatchedInspector)?.Equals(this.watchedInspectors[i]) != true)
+                if ((windowToExclude as InspectorWrapper)?.Equals(this.watchedInspectors[i]) != true)
                 {
                     this.watchedInspectors[i].RequestRatingAndUIUpdate();
                 }
@@ -2802,7 +2802,7 @@
 
                     for (int i = 1; i <= this.explorers.Count; i++)
                     {
-                        this.watchedExplorers.Add(new WatchedExplorer(this.explorers[i]));
+                        this.watchedExplorers.Add(new ExplorerWrapper(this.explorers[i]));
                     }
 
                     this.explorers.NewExplorer += Explorers_NewExplorer;
@@ -2833,7 +2833,7 @@
         /// <param name="explorer">The newly opened explorer.</param>
         private void Explorers_NewExplorer(Outlook.Explorer explorer)
         {
-            this.AddToWatchedExplorers(new WatchedExplorer(explorer));
+            this.AddToWatchedExplorers(new ExplorerWrapper(explorer));
         }
 
         /// <summary>
@@ -2851,7 +2851,7 @@
 
                     for (int i = 1; i <= this.inspectors.Count; i++)
                     {
-                        this.watchedInspectors.Add(new WatchedInspector(this.inspectors[i]));
+                        this.watchedInspectors.Add(new InspectorWrapper(this.inspectors[i]));
                     }
 
                     this.inspectors.NewInspector += Explorers_NewInspector;
@@ -2882,7 +2882,7 @@
         /// <param name="inspector">The newly opened inspector.</param>
         private void Explorers_NewInspector(Outlook.Inspector inspector)
         {
-            this.AddToWatchedInspectors(new WatchedInspector(inspector));
+            this.AddToWatchedInspectors(new InspectorWrapper(inspector));
         }
 
         /// <summary>
--- a/UI/FormControlPreviewMessage.xaml.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/UI/FormControlPreviewMessage.xaml.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -359,7 +359,7 @@
                             // Update UI
                             try
                             {
-                                WatchedWindow watchedWindow = Globals.ThisAddIn.GetWatchedWindow(Globals.ThisAddIn.Application.ActiveWindow());
+                                WindowBaseWrapper watchedWindow = Globals.ThisAddIn.GetWindowWrapper(Globals.ThisAddIn.Application.ActiveWindow());
                                 watchedWindow.SetRating(pEpCOMServerAdapterLib.pEpRating.pEpRatingUndefined);
                             }
                             catch (Exception ex)
--- a/UI/FormRegionPreviewUnencrypted.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/UI/FormRegionPreviewUnencrypted.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -1,5 +1,6 @@
 using MimeKit;
 using pEp.UI;
+using pEp.Wrappers;
 using pEpCOMServerAdapterLib;
 using System;
 using System.Windows.Input;
@@ -40,7 +41,7 @@
                 {
                     e.Cancel = true;
                 }
-                else if (string.IsNullOrEmpty(CryptableMailItem.PreviewAttachedMailId) == false)
+                else if (string.IsNullOrEmpty(MailItemWrapper.PreviewAttachedMailId) == false)
                 {
                     HeaderList headers = omi.GetParsedTransportMessageHeaders();
                     string messageId = null;
@@ -54,7 +55,7 @@
                         Log.Verbose("FormRegionPreviewUnencryptedFactory_FormRegionInitializing: Error getting MessageId from item. " + ex.ToString());
                     }
 
-                    e.Cancel = (messageId?.Equals(CryptableMailItem.PreviewAttachedMailId) != true);
+                    e.Cancel = (messageId?.Equals(MailItemWrapper.PreviewAttachedMailId) != true);
                 }
                 else
                 {
--- a/UI/FormRegionPrivacyStatus.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/UI/FormRegionPrivacyStatus.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -91,7 +91,7 @@
                 this.OutlookFormRegion.Visible = Globals.ThisAddIn.Settings.IsPrivacyStatusBarEnabled;
 
                 omi = this.OutlookItem as Outlook.MailItem;
-                WatchedWindow window = omi?.GetWatchedParentWindow();
+                WindowBaseWrapper window = omi?.GetParentWindowWrapper();
                 if (window != null)
                 {
                     this.UpdateFormRegion(window.PrivacyState);
--- a/UI/RibbonCustomizations.cs	Wed Mar 13 13:50:02 2019 +0100
+++ b/UI/RibbonCustomizations.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -27,7 +27,6 @@
         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;
 
@@ -36,7 +35,6 @@
             DisableForceProtection,
             ForceProtection,
             ForceUnencrypted,
-            IsDraft,
             NeverUnsecure,
             Rating
         }
@@ -231,9 +229,15 @@
             return formRegion;
         }
 
+        /// <summary>
+        /// Gets a property that has been set via the ribbon controls.
+        /// </summary>
+        /// <param name="control">The ribbon control for which the property has to .</param>
+        /// <param name="property">The property to get.</param>
+        /// <returns>The property value or a default value if an error occured.</returns>
         private static dynamic GetRibbonProperty(Office.IRibbonControl control, MessageProperties property)
         {
-            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control?.Context);
+            WindowBaseWrapper window = Globals.ThisAddIn?.GetWindowWrapper(control?.Context);
 
             switch (property)
             {
@@ -249,10 +253,6 @@
                     {
                         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;
@@ -268,9 +268,15 @@
             return null;
         }
 
+        /// <summary>
+        /// Sets a property value in the context of a ribbon control.
+        /// </summary>
+        /// <param name="control">The ribbon control that is connected to the property.</param>
+        /// <param name="property">The property to be set.</param>
+        /// <param name="value">The property's value to be set.</param>
         private static void SetRibbonProperty(Office.IRibbonControl control, MessageProperties property, dynamic value)
         {
-            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control.Context);
+            WindowBaseWrapper window = Globals.ThisAddIn?.GetWindowWrapper(control.Context);
 
             if (window != null)
             {
@@ -291,11 +297,6 @@
                             window.ForceUnencrypted = (bool)value;
                         }
                         break;
-                    case MessageProperties.IsDraft:
-                        {
-                            window.IsDraft = (bool)value;
-                        }
-                        break;
                     case MessageProperties.NeverUnsecure:
                         {
                             window.NeverUnsecure = (bool)value;
@@ -667,11 +668,11 @@
                                 // Update UI
                                 if (string.IsNullOrEmpty(value as string))
                                 {
-                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
+                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
                                 }
                                 else
                                 {
-                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.SetRating(pEpRating.pEpRatingReliable);
+                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.SetRating(pEpRating.pEpRatingReliable);
                                 }
                                 break;
                             }
@@ -706,7 +707,7 @@
                                     omi.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, value);
 
                                     // Update UI
-                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
+                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
                                 }
 
                                 break;
@@ -781,7 +782,7 @@
         private void UpdateUI(Office.IRibbonControl control)
         {
             RibbonCustomizations.Invalidate();
-            Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.UpdatePrivacyStateAndUI();
+            Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.UpdatePrivacyStateAndUI();
         }
 
         /**************************************************************
@@ -878,7 +879,7 @@
             try
             {
                 Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
-                Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
+                Globals.ThisAddIn.GetWindowWrapper(control.Context)?.BuildAndShowManager();
             }
             catch (Exception ex)
             {
@@ -891,7 +892,7 @@
         /// </summary>
         public System.Drawing.Bitmap ButtonPrivacyStatus_GetImage(Office.IRibbonControl control)
         {
-            return Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.PrivacyState?.Image;
+            return Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.PrivacyState?.Image;
         }
 
         /// <summary>
@@ -899,7 +900,7 @@
         /// </summary>
         public string ButtonPrivacyStatus_GetLabel(Office.IRibbonControl control)
         {
-            string label = Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.PrivacyState?.Label;
+            string label = Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.PrivacyState?.Label;
 
             // Workaround to show ampersands correctly
             if (label?.Contains(" & ") == true)
@@ -973,7 +974,7 @@
         public void ButtonSMIME_Clicked(Office.IRibbonControl control, bool pressed, ref bool cancel)
         {
             cancel = false;
-            Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
+            Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
         }
 
         ///////////////////////////////////////////////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/ExplorerWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -0,0 +1,375 @@
+using pEp.Wrappers;
+using System;
+using System.Linq;
+using System.Xml;
+using Outlook = Microsoft.Office.Interop.Outlook;
+
+namespace pEp
+{
+    /// <summary>
+    /// Stores an Outlook Explorer with connected events.
+    /// </summary>
+    public class ExplorerWrapper : WindowBaseWrapper
+    {
+        private string                  lastProcessedEntryId    = null;
+        private MailItemWrapper         inlineResponseItem      = null;
+
+        /**************************************************************
+         * 
+         * Constructors/Destructors
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        /// <param name="explorer">The explorer to watch.</param>
+        public ExplorerWrapper(Outlook.Explorer explorer)
+        {
+            this.Explorer = explorer;
+
+            if (this.Explorer != null)
+            {
+                this.ConnectWatchedExplorerEvents(true);
+            }
+        }
+
+        #region Properties
+
+        /// <summary>
+        /// Gets the Explorer that is wrapped by this WatchedExplorer.
+        /// </summary>
+        public Outlook.Explorer Explorer { get; private set; } = null;
+
+        /// <summary>
+        /// Gets the Explorer that is wrapped by this WatchedExplorer.
+        /// </summary>
+        public override dynamic Window
+        {
+            get { return this.Explorer; }
+        }
+
+        /// <summary>
+        /// Gets the window type of this window.
+        /// </summary>
+        public override WindowType Type
+        {
+            get { return WindowType.Explorer; }
+        }
+
+        #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)
+            {
+                // Disconnect all events
+                this.ConnectWatchedExplorerEvents(false);
+
+                // Disconnect cryptable mail item
+                if (this.inlineResponseItem != null)
+                {
+                    this.inlineResponseItem.Dispose();
+                    this.inlineResponseItem = null;
+                }
+
+                // Set Outlook objects to null
+                this.Explorer = null;
+
+                // Dispose base class
+                base.Dispose(disposing);
+            }
+        }
+
+        /// <summary>
+        /// Connects the events for this watched explorer.
+        /// <param name="connect">Whether to connect or disconnect the events.</param>
+        /// </summary>
+        private void ConnectWatchedExplorerEvents(bool connect)
+        {
+            try
+            {
+                if (connect)
+                {
+                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close += Explorer_Close;
+                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch += Explorer_FolderSwitch;
+                    ((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).FolderSwitch -= Explorer_FolderSwitch;
+                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose -= Explorer_InlineResponseClose;
+                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange -= Explorer_SelectionChange;
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
+            }
+        }
+        #endregion
+
+        #region Event Handling
+        /**************************************************************
+         * 
+         * Event Handling
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Event handler for when a watched explorer is being closed.
+        /// </summary>
+        private void Explorer_Close()
+        {
+            Globals.ThisAddIn.RemoveFromWatchedExplorers(this);
+            this.Dispose();
+        }
+
+        /// <summary>
+        /// Event handler for when a different folder is being selected.
+        /// </summary>
+        private void Explorer_FolderSwitch()
+        {
+            Outlook.Folder folder = null;
+            Outlook.TableView customView = null;
+            Outlook.View view = null;
+            Outlook.Views views = null;
+
+            try
+            {
+                folder = this.Explorer?.CurrentFolder as Outlook.Folder;
+
+                // If the "Last Used" contacts folder is selected, make sure the correct view is applied
+                if ((folder?.DefaultMessageClass?.Equals(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Contact) == true) &&
+                    (folder?.Name?.Equals(Properties.Resources.LastUsedFolderName) == true))
+                {
+                    view = this.Explorer.CurrentView;
+
+                    // If the current view isn't the custom one, create it if necessary
+                    if (view?.Name?.Equals(Properties.Resources.LastUsedFolderName) != true)
+                    {
+                        views = this.Explorer.CurrentFolder.Views as Outlook.Views;
+
+                        try
+                        {
+                            customView = views[Properties.Resources.LastUsedFolderName] as Outlook.TableView;
+                        }
+                        catch (Exception ex)
+                        {
+                            customView = null;
+                            Log.Info("Explorer_SelectionChange: Error getting Last Used folder view. " + ex.ToString());
+                        }
+
+                        /* If the custom view doesn't exist, create and apply it.
+                         * If it already exists, don't apply it.
+                         * Caveat: If the creation of the view went wrong at some point, it will never be set correctly. The alternative
+                         *         here would be to set it each time it's not set. This is another problem, however, as we don't know if
+                         *         the view of this folder is not the custom one because it has never been set correctly or if the user 
+                         *         selects another one. So, in the latter case, we would basically override a user decision.
+                         * Note: This whole procedure is a workaround because we can only set the Explorer's current view and not the folder's
+                         *       current view directly.
+                         */                           
+                        if (customView == null)
+                        {
+                            customView = views.Add(Properties.Resources.LastUsedFolderName, Outlook.OlViewType.olTableView, Outlook.OlViewSaveOption.olViewSaveOptionThisFolderEveryone) as Outlook.TableView;
+                            XmlDocument xmlDoc = new XmlDocument();
+                            xmlDoc.LoadXml(customView.XML);
+                            XmlNodeList childNodes = xmlDoc.LastChild.ChildNodes;
+
+                            // Create and/or set up Order By property
+                            XmlNode orderByNode = childNodes.OfType<XmlNode>().First(a => (a.Name?.Equals("orderby", StringComparison.OrdinalIgnoreCase) == true));
+                            if (orderByNode == null)
+                            {
+                                orderByNode = xmlDoc.CreateNode(XmlNodeType.Element, "orderby", string.Empty);
+                                xmlDoc.LastChild.AppendChild(orderByNode);
+                            }
+                            orderByNode.InnerXml = "<order><heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><sort>desc</sort></order>";
+
+                            // Create and/or set up Modified column
+                            XmlNode modifiedNode = childNodes.OfType<XmlNode>().FirstOrDefault(a => (a.ChildNodes.OfType<XmlNode>().FirstOrDefault(b => (b.Value?.Equals("Modified", StringComparison.OrdinalIgnoreCase) == true)) != null));
+
+                            if (modifiedNode == null)
+                            {
+                                modifiedNode = xmlDoc.CreateNode(XmlNodeType.Element, "column", string.Empty);
+
+                                // Get first column
+                                XmlNode fullNameColumn = null;
+                                foreach (var node in childNodes)
+                                {
+                                    if (((node as XmlNode)?.Name?.Equals("column", StringComparison.OrdinalIgnoreCase) == true) &&
+                                        ((node as XmlNode)?.FirstChild?.InnerText?.Equals("Full Name", StringComparison.OrdinalIgnoreCase) == true))
+                                    {
+                                        fullNameColumn = node as XmlNode;
+                                        break;
+                                    }
+                                }
+
+                                // If not found, just insert after the 4th column
+                                if (fullNameColumn == null)
+                                {
+                                    fullNameColumn = childNodes[4];
+                                }
+
+                                if (fullNameColumn != null)
+                                {
+                                    xmlDoc.LastChild.InsertAfter(modifiedNode, fullNameColumn);
+                                }
+                            }
+                            modifiedNode.InnerXml = "<heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><width>50</width><style>padding-left:3px;;text-align:left</style><editable>0</editable><format>M/d/yyyy||h:mm tt</format><displayformat>2</displayformat>";
+
+                            // Set modified XML
+                            customView.XML = xmlDoc.OuterXml;
+                            customView.Save();
+
+                            // Apply as current view
+                            this.Explorer.CurrentView = customView;
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("Explorer_FolderSwitch: Error setting Last Used folder view. " + ex.ToString());
+            }
+            finally
+            {
+                customView = null;
+                folder = null;
+                view = null;
+                views = null;
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when an inline response is being closed.
+        /// </summary>
+        private void Explorer_InlineResponseClose()
+        {
+            Outlook.MailItem omi = null;
+
+            /* Create a new CryptableMailItem. This is needed so that its
+             * MailItem_Write event gets called and the message will get saved
+             * 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;
+
+                if (omi != null)
+                {
+                    this.inlineResponseItem = new MailItemWrapper(omi, null, false)
+                    {
+                        IsInlineResponse = true
+                    };
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("WatchedExplorer_InlineResponseClose: Error setting new inline response item. " + ex.ToString());
+            }
+            finally
+            {
+                omi = null;
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the currently selected item in the explorer changes.
+        /// </summary>
+        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. Note: in Outlook 2010, there is no inline response.
+                         * IMPORTANT: Never call Explorer.ActiveInlineResponse on Outlook 2010
+                         *            as this might lead to a crash of Outlook (even inside a
+                         *            try/catch block)
+                         */
+                        bool isInlineResponse = false;
+                        if (Globals.OutlookVersion != Globals.Version.Outlook2010)
+                        {
+                            Outlook.MailItem inlineResponse = null;
+                            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.OrdinalIgnoreCase) == 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.InitializeWindow(isInlineResponse);
+                    }                    
+                    else
+                    {
+                        Log.Error("Explorer_SelectionChange: Error getting current selection.");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("Explorer_SelectionChange: Error occured: " + ex?.ToString());
+            }
+            finally
+            {
+                selection = null;
+            }
+        }
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/InspectorWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -0,0 +1,144 @@
+using System;
+using Outlook = Microsoft.Office.Interop.Outlook;
+
+namespace pEp
+{
+    /// <summary>
+    /// Stores an Outlook Inspector with connected events.
+    /// </summary>
+    public class InspectorWrapper : WindowBaseWrapper
+    {
+
+        /**************************************************************
+         * 
+         * Constructors/Destructors
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Primary constructor.
+        /// </summary>
+        /// <param name="inspector">The inspector to watch.</param>
+        public InspectorWrapper(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.InitializeWindow();
+                }
+                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; private set; } = null;
+
+        /// <summary>
+        /// Gets the Inspector that is wrapped by this WatchedInspector.
+        /// </summary>
+        public override dynamic Window
+        {
+            get { return this.Inspector; }
+        }
+
+        /// <summary>
+        /// Gets the window type of this window.
+        /// </summary>
+        public override WindowType Type
+        {
+            get { return WindowType.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)
+            {
+                // Disconnect all events
+                this.DisconnectWatchedInspectorEvents();
+
+                // Set Outlook objects to null
+                this.Inspector = null;
+
+                // Dispose base class
+                base.Dispose(disposing);
+            }
+        }
+
+        /// <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)
+        {
+            Log.Error("Inspector_ProcessingCompleted: Not implemented.");
+        }
+
+        #endregion
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/MailItemWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -0,0 +1,1947 @@
+using MimeKit;
+using pEp.UI;
+using pEpCOMServerAdapterLib;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Outlook = Microsoft.Office.Interop.Outlook;
+
+namespace pEp.Wrappers
+{
+    /// <summary>
+    /// Wrapper for the Outlook MailItem supporting encryption.
+    /// </summary>
+    internal class MailItemWrapper : INotifyPropertyChanged,
+                                     IDisposable
+    {
+        public const string USER_PROPERTY_KEY_FORCE_UNENCRYPTED         = "sendUnencrypted";
+        public const string USER_PROPERTY_KEY_ENABLE_PROTECTION         = "enableProtection";
+        public const string USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED   = "isOriginallyEncrypted";
+        public const string USER_PROPERTY_KEY_ORIGINAL_RATING           = "originalRating";
+
+        public delegate void StdMailEventHandler(ref bool cancel);
+        public delegate void RespondMailEventHandler(object item, ref bool cancel);
+        public delegate void GenericHandler(object sender, EventArgs e);
+        public delegate void ProcessingCompletedHandler(object sender, MsgProcessor.ProcessingCompletedEventArgs e);
+        public delegate void GetMirrorCompletedHandler(object sender, GetMirrorCompletedEventArgs e);
+
+        /// <summary>
+        /// Event when the internal mail item forward event occurs.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event RespondMailEventHandler Forward;
+
+        /// <summary>
+        /// Event when the internal mail item open event occurs.
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event StdMailEventHandler Open;
+
+        /// <summary>
+        /// Event when the internal mail item reply event occurs.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event RespondMailEventHandler Reply;
+
+        /// <summary>
+        /// Event when the internal mail item reply to all event occurs.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event RespondMailEventHandler ReplyAll;
+
+        /// <summary>
+        /// Event when the internal mail item send event occurs.
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event StdMailEventHandler Send;
+
+        /// <summary>
+        /// Event when the internal mail item write event occurs.
+        /// </summary>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
+        public event StdMailEventHandler Write;
+
+        /// <summary>
+        /// Event when either a cryptable mail item property change occurs, or
+        /// when the internal mail item property change event occurs.
+        /// </summary>
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        /// <summary>
+        /// Event when processing of this cryptable mail item is completed.
+        /// WARNING: The calling thread is a background worker.
+        /// </summary>
+        public event ProcessingCompletedHandler ProcessingCompleted;
+
+        /// <summary>
+        /// Event when the get mirror search is completed.
+        /// WARNING: The calling thread is a background worker.
+        /// </summary>
+        public event GetMirrorCompletedHandler GetMirrorCompleted;
+
+        public delegate void OriginallyEncryptedStatusUpdateHandler(object sender, EventArgs e);
+        public event OriginallyEncryptedStatusUpdateHandler OriginallyEncryptedStatusUpdated;
+
+        private pEpRating            _LastProcessedRating;
+        private Globals.ReturnStatus _LastProcessedStatus;
+
+        private bool                                        disposeAfterProcessing;
+        private bool                                        decrementCounter;
+        private bool                                        sent;
+        private bool                                        isClosed;
+
+        private Outlook.MailItem                            wrappedMailItem;
+        private readonly BackgroundWorker                   mirrorLocator;
+        private readonly BackgroundWorker                   processor;
+
+        private string                                      draftEntryId            = null;
+        private string                                      draftFileName           = null;
+        private readonly object                             mutexMailItem           = new object();
+        private static readonly object                      mutexConversation       = new object();
+        private static readonly object                      mutexDecryptionList     = new object();
+        private static readonly List<OriginalMailItem>      conversationCache       = new List<OriginalMailItem>();
+        private static Dictionary<string, string>           decryptionList          = new Dictionary<string, string>();
+
+        // Property fields of the wrapped item
+        private Outlook.OlDownloadState?                    _DownloadState          = null;
+        private bool?                                       _IsDraft                = null;
+        private bool?                                       _IsForcefullyProtected  = null;
+        private bool?                                       _IsIncoming             = null;
+        private bool?                                       _IsInSecureStore        = null;
+        private bool?                                       _IsMirror               = null;
+        private bool?                                       _IsOriginallyEncrypted  = null;
+        private bool?                                       _IsSecure               = null;
+
+        /// <summary>
+        /// Stores the message id of an attached mail item if it is loaded into the preview.
+        /// See comments below in MailItem_BeforeAttachmentPreview event handler.
+        /// </summary>
+        public static string PreviewAttachedMailId = null;
+
+        /// <summary>
+        /// Whether to cancel the opening event of the internal mail item. Default is false.
+        /// </summary>
+        public bool CancelOpen { get; set; } = false;
+
+        /// <summary>
+        /// The messageId of the internal mail item. Only needed for special cases like attached mails.
+        /// </summary>
+        public string MessageId { get; set; } = null;
+
+        /// <summary>
+        /// Whether the internal mail item is an inline response
+        /// </summary>
+        public bool IsInlineResponse { get; set; } = false;
+
+        /// <summary>
+        /// Whether the internal mail item is an attached mail.
+        /// </summary>
+        public bool IsSecureAttachedMail { get; set; } = false;
+
+        /// <summary>
+        /// The mirror of the internal mail item stored as PEPMessage.
+        /// </summary>
+        public PEPMessage Mirror { get; set; } = null;
+
+        /// <summary>
+        /// The PEPMessage of this mail item.
+        /// </summary>
+        public PEPMessage Message { get; set; } = null;
+
+        /**************************************************************
+         * 
+         * Constructors/Destructors
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Primary constructor creating the cryptable mail item from an existing outlook mail item.
+        /// </summary>
+        /// <param name="mailItem">The mail item to wrap and make cryptable.</param>
+        /// <param name="defaultRating">The default rating for this cryptable mail item.</param>
+        /// <param name="decrementCounter">Whether or not to decrement the decryption counter after processing.</param>
+        public MailItemWrapper(Outlook.MailItem mailItem,
+                                 pEpRating? defaultRating = null,
+                                 bool decrementCounter = false)
+        {
+            this.wrappedMailItem = mailItem;
+            this.ConnectInternalMailItemEvents(true);
+
+            this.disposeAfterProcessing = false;
+            this.decrementCounter = decrementCounter;
+            this._LastProcessedRating = defaultRating ?? pEpRating.pEpRatingUndefined;
+            this._LastProcessedStatus = Globals.ReturnStatus.Success;
+
+            // Setup the message processor background worker
+            this.processor = new BackgroundWorker
+            {
+                WorkerSupportsCancellation = false,
+            };
+            this.processor.RunWorkerCompleted += Processor_RunWorkerCompleted;
+            this.processor.DoWork += Processor_DoWork;
+
+            // Setup the mirror locator background worker
+            this.mirrorLocator = new BackgroundWorker
+            {
+                WorkerSupportsCancellation = false
+            };
+            this.mirrorLocator.RunWorkerCompleted += MirrorLocator_RunWorkerCompleted;
+            this.mirrorLocator.DoWork += MirrorLocator_DoWork;
+        }
+
+        /// <summary>
+        /// Destructor.
+        /// </summary>
+        ~MailItemWrapper()
+        {
+            // This should have been called in code before garbage collection, but call it just in case
+            this.Dispose(true);
+        }
+
+        /**************************************************************
+         * 
+         * Event Handling
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Event hander for when an attachment is previewed. Occurs before the preview occurs
+        /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.beforeattachmentpreview.aspx
+        /// </summary>
+        /// <param name="attachment">The attachment that is about to be previewed.</param>
+        /// <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 operation is not completed
+        /// and the attachment is not previewed.</param>
+        private void MailItem_BeforeAttachmentPreview(Outlook.Attachment attachment, ref bool cancel)
+        {
+            /* Check if the attachment to be previewed is a mail item and store its messageId in the 
+             * static PreviewAttachedMailId property. This is a somewhat clumsy workaround, but is needed
+             * because we need to know upon processing of the mail item whether it is an attached mail
+             * and whether it is opened (a) or previewed (b).
+             *      => a. Cancel opening and open mirror
+             *      => b. Display mirror in preview window
+             * As all methods to store the relevant information directly in the attached mail failed, we 
+             * set the messageId during this event and query it in FormRegionPrivacyStatus_FormRegionShowing.
+             */
+            try
+            {
+                PEPAttachment attach = new PEPAttachment(attachment);
+
+                // Exclude based on file name and/or MIME type (for performance)
+                if ((attach.Data != null) &&
+                    ((Path.GetExtension(attach.FileName)?.Equals(".eml") == true) ||
+                     (Path.GetExtension(attach.FileName)?.Equals(".msg") == true) ||
+                     (attach.MimeType?.Equals("text/rfc822") == true)))
+                {
+                    // Try to convert attachment into MIME message
+                    MimeMessage message;
+                    MemoryStream memoryStream;
+                    using (memoryStream = new MemoryStream(attach.Data))
+                    {
+                        message = MimeMessage.Load(memoryStream);
+                    }
+
+                    // If conversion was successful, attachment is mail
+                    if (message != null)
+                    {
+                        string messageId = null;
+
+                        // Retrieve the mail's messageId
+                        if (message?.Headers?.Contains(HeaderId.MessageId) == true)
+                        {
+                            messageId = message.Headers?[HeaderId.MessageId];
+                        }
+
+                        // Save messageId
+                        if (string.IsNullOrEmpty(messageId) == false)
+                        {
+                            MailItemWrapper.PreviewAttachedMailId = messageId;
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MailItemWrapper.PreviewAttachedMailId = null;
+                Log.Error("MailItem_BeforeAttachmentPreview: Error determining if attachment is mail. " + ex.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the internal mail item is closed. Occurs when the inspector 
+        /// associated with the item (which is an instance of the parent object) is being closed.
+        /// See https://docs.microsoft.com/de-de/office/vba/api/outlook.mailitem.close(even)
+        /// </summary>
+        /// <param name="cancel">Whether to cancel the event</param>
+        private void MailItem_Close(ref bool cancel)
+        {
+            this.isClosed = (cancel == false);
+        }
+
+        /// <summary>
+        /// Event handler for when the internal mail item is forwarded.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff862702.aspx
+        /// </summary>
+        /// <param name="item">The new item being forwarded.</param>
+        /// <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 forward operation is not completed 
+        /// and the new item is not displayed.</param>
+        private void MailItem_Forward(object item, ref bool cancel)
+        {
+            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
+            this.Forward?.Invoke(item, ref cancel);
+        }
+
+        /// <summary>
+        /// Event handler for when the internal 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>
+        private void MailItem_Open(ref bool cancel)
+        {
+            cancel = this.CancelOpen;
+            this.Open?.Invoke(ref cancel);
+        }
+
+        /// <summary>
+        /// Event handler for when the internal 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>
+        private void MailItem_PropertyChange(string propertyName)
+        {
+            this.OnPropertyChanged(propertyName);
+            return;
+        }
+
+        /// <summary>
+        /// Event handler for when the internal mail item is replied to.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
+        /// </summary>
+        /// <param name="item">The new item being sent in response to the original message.</param>
+        /// <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 reply operation is not completed 
+        /// and the new item is not displayed.</param>
+        private void MailItem_Reply(object item, ref bool cancel)
+        {
+            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
+            this.Reply?.Invoke(item, ref cancel);
+        }
+
+        /// <summary>
+        /// Event handler for when the internal mail item is replied to all recipients.
+        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
+        /// Do not try to modify the item directly
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
+        /// </summary>
+        /// <param name="item">The new item being sent in response to the original message.</param>
+        /// <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 reply operation is not completed 
+        /// and the new item is not displayed.</param>
+        private void MailItem_ReplyAll(object item, ref bool cancel)
+        {
+            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
+            this.ReplyAll?.Invoke(item, ref cancel);
+        }
+
+        /// <summary>
+        /// Event handler for when the internal 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>
+        private void MailItem_Send(ref bool cancel)
+        {
+            this.Send?.Invoke(ref cancel);
+            this.sent = true;
+        }
+
+        /// <summary>
+        /// Event handler for when the internal mail item is written (Save, SaveAs, etc...)
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff868664.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 save operation is not completed.
+        /// </param>
+        private void MailItem_Write(ref bool cancel)
+        {
+#if !READER_RELEASE_MODE
+            /* Save drafts for untrusted servers in a secure location.
+             * First we try to save it to a custom drafts folder in the pEp store
+             * and make this store visible in the favorites.
+             * If this fails, as a fallback solution, we offer to save as a message file.
+             * Note: Inline responses need to be processed differently.
+             */
+            if ((this.sent == false) &&
+                (this.IsPEPMessage == false) &&
+                (this.wrappedMailItem.GetIsDraft()) &&
+                ((this.wrappedMailItem.GetIsInSecureStore() || this.wrappedMailItem.GetNeverUnsecure())))
+            {
+                bool useFallback = false;
+                Outlook.Folder parentFolder = null;
+                Outlook.Folder pEpDraftsFolder = null;
+                Outlook.Inspector currentInspector = null;
+                Outlook.Inspector newInspector = null;
+                Outlook.MailItem omi = null;
+
+                Outlook.Application app = null;
+                Outlook.Explorer activeExplorer = null;
+                Outlook.NavigationPane navPane = null;
+                Outlook.NavigationModules navModules = null;
+                Outlook.MailModule mailModule = null;
+                Outlook.NavigationGroups navGroups = null;
+                Outlook.NavigationGroup navGroup = null;
+                Outlook.NavigationFolders navFolders = null;
+
+                try
+                {
+                    // Get the pEp drafts folder and the current mail item's folder
+                    pEpDraftsFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
+
+                    // Get the caret position to later set it again
+                    bool caretPositionRetrieved = false;
+                    NativeMethods.Point caretPosition = new NativeMethods.Point(-1,-1);
+                    IntPtr inspectorHandle = IntPtr.Zero;
+
+                    try
+                    {
+                        // First, get the current process to retrieve a handle to the caret's window
+                        uint currentThreadId = NativeMethods.GetCurrentThreadId();
+                        NativeMethods.GuiThreadInfo guiThreadInfo = new NativeMethods.GuiThreadInfo();
+                        guiThreadInfo.size = Marshal.SizeOf(guiThreadInfo);
+
+                        if (NativeMethods.GetGUIThreadInfo(currentThreadId, ref guiThreadInfo))
+                        {
+                            inspectorHandle = guiThreadInfo.hwndCaret;
+
+                            // Get caret position and convert to screen coordinates
+                            if (NativeMethods.GetCaretPos(out caretPosition) &&
+                                NativeMethods.ClientToScreen(inspectorHandle, ref caretPosition))
+                            {
+                                caretPositionRetrieved = true;
+                            }
+                            else
+                            {
+                                int error = Marshal.GetLastWin32Error();
+                                Log.Error("MailItem_Write: Error getting caret position. Last Win32 error: " + error.ToString("X"));
+                            }
+                        }
+                        else
+                        {
+                            int error = Marshal.GetLastWin32Error();
+                            Log.Error("MailItem_Write: Error getting inspector Handle. Last Win32 error: " + error.ToString("X"));
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Error("MailItem_Write: Error getting caret position. " + ex.ToString());
+                    }
+
+                    /* Inline responses need a special treatment.
+                     * We cannot just intercept the Write event and check, if the item
+                     * is in the pEp folder, as it gets synced to the server anyhow if we
+                     * don't cancel the event.
+                     * So, we look up if the mail item is already present in pEp drafts and overwrite it 
+                     * with the current state if possible. If the item isn't there yet, create new item, 
+                     * move to pEp drafts folder and save current state.
+                     */
+                    if (this.IsInlineResponse)
+                    {
+                        Outlook.Items items = null;
+                        Outlook.MailItem draft = null;
+
+                        try
+                        {
+                            // Always cancel
+                            cancel = true;
+
+                            // Try to find the draft (if existing)
+                            if (string.IsNullOrEmpty(this.draftEntryId) == false)
+                            {
+                                // Get all items in the pEp drafts folder with the same subject as the current draft
+                                items = pEpDraftsFolder?.Items?.Restrict(string.Format("[Subject] = '{0}'", this.wrappedMailItem?.Subject));
+
+                                for (int i = 1; i <= items?.Count; i++)
+                                {
+                                    draft = items[i] as Outlook.MailItem;
+
+                                    if (draftEntryId.Equals(draft?.EntryID) == true)
+                                    {
+                                        // Draft found. Just break and continue.
+                                        break;
+                                    }
+
+                                    draft = null;
+                                }
+
+                                items = null;
+                            }
+
+                            if (PEPMessage.Create(this.wrappedMailItem, out PEPMessage createdMessage) == Globals.ReturnStatus.Success)
+                            {
+                                if (draft == null)
+                                {
+                                    draft = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
+                                    createdMessage.ApplyTo(draft, true, true);
+                                    draft = draft.Move(pEpDraftsFolder);
+                                    draft.Save();
+                                    this.draftEntryId = draft.EntryID;
+                                }
+                                else
+                                {
+                                    createdMessage.ApplyTo(draft, true, true);
+                                    draft.Save();
+                                }
+                            }
+                            else
+                            {
+                                Log.Error("MailItem_Write: Error creating PEPMessage.");
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("MailItem_Write: Error saving inline item. " + ex.ToString());
+                        }
+                        finally
+                        {
+                            items = null;
+                            omi = null;
+                        }
+                    }
+                    else
+                    {
+                        // Get the mail item's parent folder
+                        parentFolder = this.wrappedMailItem.Parent as Outlook.Folder;
+
+                        // Save to pEp folder if not already there
+                        if (pEpDraftsFolder?.FullFolderPath?.Equals(parentFolder?.FullFolderPath) == false)
+                        {
+                            currentInspector = this.wrappedMailItem.GetInspector;
+                            //omi = this.internalMailItem.Copy();
+                            omi = this.wrappedMailItem.Move(pEpDraftsFolder);
+
+                            if (currentInspector != null)
+                            {
+                                Outlook.OlWindowState windowState = currentInspector.WindowState;
+                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
+
+                                if (windowState == Outlook.OlWindowState.olNormalWindow)
+                                {
+                                    newInspector.Left = currentInspector.Left;
+                                    newInspector.Top = currentInspector.Top;
+                                    newInspector.Width = currentInspector.Width;
+                                    newInspector.Height = currentInspector.Height;
+                                }
+
+                                /* In some circumstances (e.g. ForceProtection on Exchange), the Sender information 
+                                 * may be missing. If this is the case, try to add it from the internal mail item.
+                                 */
+                                try
+                                {
+                                    // Check if there really is no useful Sender information
+                                    if ((omi != null) &&
+                                        (omi.Sender == null) &&
+                                        (string.IsNullOrEmpty(omi.SenderEmailAddress)) &&
+                                        (omi.SendUsingAccount == null))
+                                    {
+                                        // Try to add SendUsingAccount
+                                        if (this.wrappedMailItem.SendUsingAccount != null)
+                                        {
+                                            omi.SendUsingAccount = this.wrappedMailItem.SendUsingAccount;
+                                        }
+
+                                        // Try to add the Sender directly
+                                        if (this.wrappedMailItem.Sender != null)
+                                        {
+                                            omi.Sender = this.wrappedMailItem.Sender;
+                                        }
+                                    }
+                                }
+                                catch (Exception ex)
+                                {
+                                    Log.Error("MailItem_Write: Error determining/setting sender information of new Inspector. " + ex.ToString());
+                                }
+
+                                newInspector.Display();
+                                newInspector.WindowState = windowState;
+                                currentInspector.Close(Outlook.OlInspectorClose.olDiscard);
+
+                                // Set caret position again to where it was before
+                                if (caretPositionRetrieved)
+                                {
+                                    try
+                                    {
+                                        // Set cursor to the caret's previous position
+                                        NativeMethods.SetCursorPos(caretPosition.X, caretPosition.Y);
+
+                                        // Send mouse click event (mouse down and mouse up)
+                                        NativeMethods.Input[] inputs = new NativeMethods.Input[1];
+                                        inputs[0].Type = (int)NativeMethods.InputType.InputMouse;
+                                        inputs[0].Mi.Flags = (int)NativeMethods.MouseEvents.MouseEventFLeftDown | (int)NativeMethods.MouseEvents.MouseEventFLeftUp;
+
+                                        if (NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])) == 0)
+                                        {
+                                            int error = Marshal.GetLastWin32Error();
+                                            Log.Error("MailItem_Write: Error setting caret to original position. Win32 error " + error.ToString("X"));
+                                        }
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        Log.Error("MailItem_Write: Error setting caret to original position. " + ex.ToString());
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
+                                newInspector.Display();
+                            }
+
+                            cancel = true;
+                        }
+                    }
+
+                    /* Add the pEp drafts folder to favorites.
+                     * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
+                     * To make this more secure, we only proceed if the pEp store is already visible at this point.
+                     * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
+                     * to the favorites next time.
+                     */
+                    if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
+                    {
+                        // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
+                        app = Globals.ThisAddIn?.Application;
+                        activeExplorer = app?.ActiveExplorer();
+                        navPane = activeExplorer?.NavigationPane;
+                        navModules = navPane?.Modules;
+                        mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
+                        navGroups = mailModule?.NavigationGroups;
+                        navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
+                        navFolders = navGroup?.NavigationFolders;
+
+                        /* Check, if pEp drafts folder is already in favorites
+                         * WARNING: If for whatever reason, the pEp store is not visible
+                         * at this point, the Add() method crashes Outlook!
+                         */
+                        if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
+                        {
+                            if (navFolders != null)
+                            {
+                                navFolders.Add(pEpDraftsFolder);
+                            }
+                            else
+                            {
+                                Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
+                            }
+                        }
+                    }
+                    else
+                    {
+                        Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("MailItem_Write: Error while saving to pEp Drafts folder. " + ex.ToString());
+                    useFallback = true;
+                }
+                finally
+                {
+                    currentInspector = null;
+                    parentFolder = null;
+                    pEpDraftsFolder = null;
+                    omi = null;
+
+                    app = null;
+                    activeExplorer = null;
+                    navPane = null;
+                    navModules = null;
+                    mailModule = null;
+                    navGroups = null;
+                    navGroup = null;
+                    navFolders = null;
+                }
+
+                if (useFallback)
+                {
+                    Log.Verbose("MailItem_Write: pEp folder could not be found or created. Trying fallback");
+
+                    // Fallback solution
+                    if (draftFileName == null)
+                    {
+                        var result = System.Windows.MessageBox.Show(Properties.Resources.DraftProtection_Warning, Properties.Resources.DraftProtection_Title, System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Exclamation);
+                        if (result == System.Windows.MessageBoxResult.Yes)
+                        {
+                            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
+                            {
+                                Filter = Properties.Resources.DraftProtection_MSG_Format + " (*.msg)|*.msg",
+                                FilterIndex = 1
+                            };
+                            if (string.IsNullOrEmpty(this.wrappedMailItem.Subject) == false)
+                                sfd.FileName = this.wrappedMailItem.Subject;
+                            var r = sfd.ShowDialog();
+                            if (r == System.Windows.Forms.DialogResult.OK)
+                            {
+                                draftFileName = sfd.FileName;
+                                this.wrappedMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
+                            }
+                        }
+
+                        cancel = true;
+                    }
+                    else
+                    {
+                        this.wrappedMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
+                        cancel = true;
+                    }
+                }
+            }
+#endif
+            this.Write?.Invoke(ref cancel);
+            return;
+        }
+
+        /**************************************************************
+         * 
+         * Property Accessors
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Returns a constant that belongs to the OlDownloadState enumeration indicating the download state of the item.
+        /// This forwards the call to the internal mail item.
+        /// See: https://msdn.microsoft.com/en-us/library/office/ff866978.aspx
+        /// </summary>
+        public Outlook.OlDownloadState DownloadState
+        {
+            get => this._DownloadState ?? ((Outlook.OlDownloadState)(this._DownloadState = this.wrappedMailItem.DownloadState));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is currently being processed.
+        /// </summary>
+        public bool IsBeingProcessed
+        {
+            get => this.processor.IsBusy;
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is marked as a draft (unsent).
+        /// </summary>
+        public bool IsDraft
+        {
+            get => this._IsDraft ?? ((bool)(this._IsDraft = this.wrappedMailItem.GetIsDraft()));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is marked as incoming (received mail, not sent).
+        /// </summary>
+        public bool IsIncoming
+        {
+            get => this._IsIncoming ?? ((bool)(this._IsIncoming = this.wrappedMailItem.GetIsIncoming()));
+        }
+
+        /// <summary>
+        /// Gets whether the wrapped mail item was marked as being originally encrypted.
+        /// This should have been set by calling SetIsOriginallyEncryptedByCache() during the 
+        /// EncryptedConversationCacheUpdated event.
+        /// False is returned if the property is either false or null (doesn't exist).
+        /// </summary>
+        public bool IsOriginallyEncrypted
+        {
+            get => this._IsOriginallyEncrypted ?? ((bool)(this._IsOriginallyEncrypted = ((this.wrappedMailItem.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED) as bool?) == true)));
+        }
+
+        /// <summary>
+        /// Determines whether the mail item has been processed through pEp. This is done by checking if a pEp protocol
+        /// version is available for the item.
+        /// </summary>
+        protected bool IsPEPMessage
+        {
+            get => (MailItemExtensions.GetPEPProperty(wrappedMailItem, MailItemExtensions.PEPProperty.PEPProtocolVersion, out object version) && (version != null));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is in a secure store (untrusted server).
+        /// </summary>
+        public bool IsInSecureStore
+        {
+            get => this._IsInSecureStore ?? ((bool)(this._IsInSecureStore = this.wrappedMailItem.GetIsInSecureStore()));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is secure (encrypted).
+        /// </summary>
+        public bool IsSecure
+        {
+            get => this._IsSecure ?? ((bool)(this._IsSecure = this.wrappedMailItem.GetIsSecure()));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is securely stored.
+        /// </summary>
+        public bool IsSecurelyStored
+        {
+            get => (((this.IsSecure || this.IsForcefullyProtected) && this.IsInSecureStore) || (this.NeverUnsecure && (this.IsMirror == false)));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is a mirror item.
+        /// </summary>
+        public bool IsMirror
+        {
+            get => this._IsMirror ?? ((bool)(this._IsMirror = this.wrappedMailItem.GetIsMirror()));
+        }
+
+        /// <summary>
+        /// Gets whether the mail item is forcefully protected.
+        /// </summary>
+        public bool IsForcefullyProtected
+        {
+            get => this._IsForcefullyProtected ?? ((bool)(this._IsForcefullyProtected = this.wrappedMailItem.GetIsForcefullyProtected()));
+        }
+
+        /// <summary>
+        /// Gets or sets whether this cryptable mail item is marked to never be unsecure (always encrypted).
+        /// This information is stored as a MAPI property of the wrapped mail item.
+        /// Warning: This will call .Save() on the MailItem.
+        /// </summary>
+        public bool NeverUnsecure
+        {
+            get
+            {
+                object propValue;
+
+                lock (mutexMailItem)
+                {
+                    // Return status can be ignored here, using the auto default value is good enough
+                    this.wrappedMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, out propValue);
+                }
+
+                return ((bool)propValue);
+            }
+            set
+            {
+                lock (mutexMailItem)
+                {
+                    // Return status can be ignored
+                    this.wrappedMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, value);
+                    this.wrappedMailItem.Save();
+                }
+
+                this.OnPropertyChanged();
+            }
+        }
+
+        /// <summary>
+        /// Gets the status after the last message processing.
+        /// This should be used to determine if a failure occured.
+        /// Success is the default if no processing has been completed.
+        /// </summary>
+        public Globals.ReturnStatus LastProcessedStatus
+        {
+            get { return (this._LastProcessedStatus); }
+        }
+
+        /// <summary>
+        /// Gets the personal identity using the internal mail item.
+        /// Warning: This can return null.
+        /// </summary>
+        public PEPIdentity Myself
+        {
+            get
+            {
+                PEPIdentity ident = null;
+                Globals.ReturnStatus sts;
+
+                lock (mutexMailItem)
+                {
+                    sts = PEPIdentity.GetOwnIdentity(this.wrappedMailItem, out ident);
+                }
+
+                if (sts != Globals.ReturnStatus.Success)
+                {
+                    ident = null;
+                }
+
+                return (ident);
+            }
+        }
+
+        /**************************************************************
+         * 
+         * Decryption
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Decrypts (if necessary, managing any mirrors) and returns the pEp rating for this cryptable mail item.
+        /// The calculated rating will be returned but it is already set as the property value by this method.
+        /// If rating is ever undefined: it can be assumed an error occured.
+        /// </summary>
+        private ProcessingResult ProcessAndGetRating(string entryId)
+        {
+            ProcessingResult result = new ProcessingResult();
+
+            Log.Verbose("ProcessAndGetRating: Started.");
+
+            lock (mutexMailItem)
+            {
+                bool isDraft;
+                bool isPEPInternal = false;
+                bool isSecurelyStored = false;
+                bool isSubmitted;
+                bool fullCalculation = true;
+                bool preProcessingPropertySet = false;
+                bool saveInternalMailItem = false;
+                Outlook.MailItem mirrorMailItem = null;
+                PEPMessage message = null;
+                PEPMessage mirror = null;
+                pEpDecryptFlags decryptionFlags;
+                MsgProcessor msgProcessor = new MsgProcessor();
+                Globals.ReturnStatus sts1;
+                Globals.ReturnStatus status = Globals.ReturnStatus.Success;
+
+                // Reset status
+                this._LastProcessedStatus = Globals.ReturnStatus.Success;
+
+                // Log the download status which can influence later processing
+                try
+                {
+                    Log.Verbose("ProcessAndGetRating: DownloadState=" + this.wrappedMailItem.DownloadState.ToString());
+                }
+                catch { }
+
+                // Detect if the mail item is a draft
+                isDraft = this.wrappedMailItem.GetIsDraft();
+                isSubmitted = this.wrappedMailItem.GetIsSubmitted();
+                Outlook.OlAccountType accountType = this.wrappedMailItem.GetAccountType();
+
+                // Do not processes deleted messages on IMAP
+                if ((fullCalculation) &&
+                    (accountType == Outlook.OlAccountType.olImap) &&
+                    (MapiHelper.GetProperty(this.wrappedMailItem, MapiProperty.PidLidImapMarkedForDeletion, "0").ToString() == "1"))
+                {
+                    Log.Verbose("ProcessAndGetRating: Deleted IMAP message detected, skipping processing");
+                    result.Rating = pEpRating.pEpRatingUndefined;
+                    fullCalculation = false;
+                }
+
+                // Check if the mail item is a mirror and use stored rating
+                if ((fullCalculation) &&
+                    (this.wrappedMailItem.GetIsMirror()))
+                {
+                    // Get UI rating from mirror
+                    try
+                    {
+                        if (PEPMessage.Create(this.wrappedMailItem, out mirror) == Globals.ReturnStatus.Success)
+                        {
+                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
+                            this.Message = mirror;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
+                        result.Rating = mirror.Rating;
+                    }
+
+                    // If the value was undefined, don't use it. Recalculation is needed.
+                    if (result.Rating != pEpRating.pEpRatingUndefined)
+                    {
+                        Log.Verbose("ProcessAndGetRating: Mirror detected, using stored rating.");
+                        fullCalculation = false;
+                    }
+                }
+
+                /* Check if the mail item is a draft (if the Unsent flag is set)
+                 * If the message is a draft, the outgoing rating will be used, value is not stored.
+                 * This check is technically not required as the logic below will detect Outgoing messages and do the same.
+                 * However, it's potentially quicker (and more robust) to handle this special case.
+                 * Note: It's important that the message is not submitted (since it could already be encrypted).
+                 */
+                if ((fullCalculation) &&
+                    (isDraft) &&
+                    (isSubmitted == false))
+                {
+                    Log.Verbose("ProcessAndGetRating: Draft detected, using outgoing rating.");
+
+                    result.Rating = this.wrappedMailItem.GetOutgoingRating(true);
+                    fullCalculation = false;
+                }
+
+                // Check if untrusted server and search for mirror. Use mirror rating if available
+                isSecurelyStored = (this.wrappedMailItem.GetIsSecurelyStored() || this.IsSecureAttachedMail);
+                if (fullCalculation &&
+                    isSecurelyStored)
+                {
+                    // If internal mail item is attached mail, use message id for mirror lookup
+                    string messageId = null;
+                    if (this.IsSecureAttachedMail)
+                    {
+                        messageId = this.MessageId;
+                    }
+
+                    mirrorMailItem = this.wrappedMailItem.GetMirror(messageId);
+                    if ((mirrorMailItem != null) &&
+                        (PEPMessage.Create(mirrorMailItem, out mirror) == Globals.ReturnStatus.Success))
+                    {
+                        fullCalculation = false;
+                        this.Mirror = mirror;
+
+                        // Get UI rating from mirror
+                        try
+                        {
+                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
+                            result.Rating = mirror.Rating;
+                        }
+
+                        this.Mirror.Rating = result.Rating;
+                    }
+                }
+
+                // Full calculation if no special cases were found
+                if (fullCalculation)
+                {
+                    // Check if message has autoconsume header and set pEp internal category if necessary
+                    try
+                    {
+                        if (this.wrappedMailItem.GetIsAutoConsume())
+                        {
+                            isPEPInternal = true;
+
+                            /* Set the mail item as read and apply again the category to make sure it is really set. As those
+                             * two operations require the mail item to be saved afterwards, do NOT apply it to ActiveSync 
+                             * messages, as saving with ActiveSync accounts tends to fail and then leads to "Save message?" dialogs
+                             * popping up during shutdown of Outlook. (see OUT-216).
+                             */
+                            if (accountType != Outlook.OlAccountType.olEas)
+                            {
+                                Globals.ThisAddIn.CreatePEPCategories();
+
+                                // Only one category is needed to hide the MailItem -- delete any others
+                                this.wrappedMailItem.Categories = Globals.PEP_INTERNAL_CATEGORY_NAME;
+                                this.wrappedMailItem.UnRead = false;
+                                preProcessingPropertySet = true;
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Error("ProcessAndGetRating: Could not set pEp internal category, " + ex.ToString());
+                    }
+
+                    /* Apply a custom message class to secure mail items in secure stores (doesn't apply for pEp internal messages). This is needed for the
+                     * FormRegionPreviewUnencrypted to be shown in Outlook 2010 (technically, all versions require this according to the documentation).
+                     * See: https://msdn.microsoft.com/en-us/library/office/ff866019.aspx
+                     * In case of Outlook 2010, set message class for all messages in secure stores, as this version often downloads only mail headers in the first place
+                     * which then leads to the form region not being properly displayed at the first click (OUT-68).
+                     */
+                    if ((isPEPInternal == false) &&
+                         ((Globals.OutlookVersion == Globals.Version.Outlook2010) &&
+                          (this.wrappedMailItem.GetIsInSecureStore() || this.wrappedMailItem.GetNeverUnsecure())))
+                    {
+                        try
+                        {
+                            MapiHelper.SetProperty(this.wrappedMailItem, MapiProperty.PidTagMessageClass, MapiPropertyValue.PidTagMessageClassSecurePEP);
+                            preProcessingPropertySet = true;
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("ProcessAndGetRating: Could not set custom message class, " + ex.ToString());
+                        }
+                    }
+
+                    // Save any changes
+                    if (preProcessingPropertySet)
+                    {
+                        try
+                        {
+                            this.wrappedMailItem.Save();
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("ProcessAndGetRating: Could not save pre-processing properties, " + ex.ToString());
+                        }
+                    }
+
+                    // Process mail item
+                    sts1 = PEPMessage.Create(this.wrappedMailItem, out message);
+
+                    // If Key Import Wizard is open, add mail to list to process later
+                    if ((KeySyncWizard.Wizard?.IsVisible == true) &&
+                        (message.Direction == pEpMsgDirection.pEpDirIncoming) &&
+                        (message.To?.Count == 1) &&
+                        (message.From?.EqualsByAddress(message.To[0]) == true))
+                    {
+                        KeySyncWizard.Wizard?.AddToReceivedSyncMessages(message);
+                    }
+
+                    // Define decryption flags
+                    decryptionFlags = isSecurelyStored ? pEpDecryptFlags.pEpDecryptFlagUntrustedServer : pEpDecryptFlags.pEpDecryptFlagsNone;
+
+                    /* Check if the message is an attached disclaimer message.
+                     * The definition for such a message is that it's a secure attached
+                     * message with the same subject as the outer message.
+                     * See also comments in PEPAttachment.CheckIfAttachedMailAndAddToCache().
+                     */
+                    if ((message.Attachments?.Count == 1) &&
+                        (message.Attachments[0].AttachedDisclaimerMessage?.ShortMsg?.Equals(message.ShortMsg) == true))
+                    {
+                        var msg = message.Attachments[0].AttachedDisclaimerMessage.Copy();
+                        message.Attachments.Clear();
+                        for (int i = 0; i < msg.Attachments.Count; i++)
+                        {
+                            message.Attachments.Add(msg.Attachments[i]);
+                        }
+                    }
+
+                    // Process
+                    status = msgProcessor.ProcessMessage(ref message,
+                                                         sts1,
+                                                         this.wrappedMailItem.GetIsInSecureStore(),
+                                                         this.wrappedMailItem.GetIsInSentFolder(),
+                                                         isDraft,
+                                                         out mirror,
+                                                         out PEPMessage processedMessage,
+                                                         out pEpRating processedRating,
+                                                         ref decryptionFlags);
+
+                    if (status == Globals.ReturnStatus.Success)
+                    {
+                        // Handle the consumed flag marking for deletion
+                        if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagConsume))
+                        {
+                            // Delete the mail item from Outlook
+                            try
+                            {
+                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.wrappedMailItem.Subject + " received on " + this.wrappedMailItem.ReceivedTime.ToString());
+                            }
+                            catch { }
+                            this.wrappedMailItem.PermanentlyDelete();
+                            this.disposeAfterProcessing = true;
+
+                            Log.Verbose("ProcessAndGetRating: Processed message consumed");
+                        }
+                        else if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagIgnore))
+                        {
+                            try
+                            {
+                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.wrappedMailItem.Subject + " received on " + this.wrappedMailItem.ReceivedTime.ToString());
+                            }
+                            catch { }
+                            Log.Verbose("ProcessAndGetRating: Processed message ignored.");
+                        }
+                        else if ((Globals.ThisAddIn.OutlookOptions.ReadAsPlain) &&
+                                 (isSecurelyStored))
+                        {
+                            this.Mirror = mirror;
+                        }
+                        else
+                        {
+                            // Save processed message data to Outlook
+                            if (processedMessage != null)
+                            {
+
+                                // Set the mail item
+                                if (mirror != null)
+                                {
+                                    // Save mirror as property of this cryptable mail item
+                                    this.Mirror = mirror;
+                                    this.Mirror.Rating = processedRating;
+
+                                    if (mirrorMailItem == null)
+                                    {
+                                        // If internal mail item is attached mail, use message id for mirror creation
+                                        string messageId = null;
+                                        if (this.IsSecureAttachedMail)
+                                        {
+                                            messageId = this.MessageId;
+                                        }
+
+                                        mirrorMailItem = this.wrappedMailItem.CreateMirrorOMI(messageId);
+                                    }
+
+                                    // Apply message to mirror and save
+                                    processedMessage.ApplyTo(mirrorMailItem, true, true);
+
+                                    try
+                                    {
+                                        mirrorMailItem.Save();
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        Log.Error("ProcessAndGetRating: Error saving mirror item. " + ex.ToString());
+                                    }
+
+                                    // If needed, set SmartNoAttach MAPI property to hide the attachments icon
+                                    if ((accountType != Outlook.OlAccountType.olImap) &&
+                                        (processedMessage.Attachments?.Count == 0) &&
+                                        (this.wrappedMailItem.Attachments?.Count > 0))
+                                    {
+                                        // Note: The documented MAPI property PidLidSmartNoAttach (0x8514000B) doesn't work for some reason
+                                        result.PropertiesToSet.Add(MapiProperty.PidTagSmartNoAttach2, true);
+                                    }
+
+                                    /* If we have extra keys and are on an untrusted server, reencrypt message
+                                     * for myself and the extra keys.
+                                     */
+                                    if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagSrcModified))
+                                    {
+                                        if (message.ApplyTo(this.wrappedMailItem, false, false, true, false) == Globals.ReturnStatus.Success)
+                                        {
+                                            saveInternalMailItem = true;
+                                        }
+                                        else
+                                        {
+                                            Log.Error("ProcessAndGetRating: Error reencrypting with extra keys.");
+                                        }
+                                    }
+                                }
+                                else
+                                {
+                                    // Trusted server: apply message and save
+                                    processedMessage.ApplyTo(this.wrappedMailItem, true, false);
+                                    saveInternalMailItem = true;
+                                }
+                            }
+                            // If processed message is null (= didn't run through decryption (again)), update UI rating
+                            else
+                            {
+                                /* In rare circumstances (i.e. when a user makes a handshake using
+                                 * an FPP message) we can get here. In this case, we need to set the
+                                 * rating manually to reliable or higher (reevaluate).
+                                 */
+                                if ((string.IsNullOrEmpty(message.ForceProtectionId) == false) &&
+                                    (message.Rating == pEpRating.pEpRatingUndefined))
+                                {
+                                    message.Rating = processedRating;
+                                    processedRating = AdapterExtensions.ReevaluateFPPMessageRating(message);
+                                }
+                                else
+                                {
+                                    processedRating = AdapterExtensions.ReevaluateMessageRating(message, processedRating);
+                                }
+                            }
+                        }
+                    }
+
+                    // Remove the pEp Processing category if needed
+                    if (Globals.ThisAddIn.Settings.IsUXImprovementEnabled &&
+                        this.wrappedMailItem.RemovePEPProcessingCategory())
+                    {
+                        if (message?.Direction != null)
+                        {
+                            this.wrappedMailItem.UnRead = (message.Direction == pEpMsgDirection.pEpDirIncoming);
+                        }
+                        else
+                        {
+                            this.wrappedMailItem.UnRead = (this.wrappedMailItem.GetIsInSentFolder() == false);
+                        }
+                        saveInternalMailItem = true;
+                    }
+
+                    // Save internal mail item if necessary
+                    if (saveInternalMailItem)
+                    {
+                        bool saveError = false;
+                        try
+                        {
+                            this.wrappedMailItem.Save();
+                        }
+                        catch (Exception ex)
+                        {
+                            saveError = true;
+                            Log.Error("ProcessAndGetRating: Error saving internal mail item. " + ex.ToString());
+                        }
+
+                        // If an error occured during saving, try to forcefully save
+                        if (saveError)
+                        {
+                            try
+                            {
+                                int sts = Mapi.Save(this.wrappedMailItem, Mapi.SaveOption.KEEP_OPEN_READWRITE);
+                                Log.Verbose("ProcessAndGetRating: Saving using backup method. Return status is " + sts.ToString("X"));
+
+                                if (sts != (uint)Mapi.HResult.S_OK)
+                                {
+                                    sts = Mapi.Save(this.wrappedMailItem, Mapi.SaveOption.FORCE_SAVE);
+                                    Log.Verbose("ProcessAndGetRating: Saving with FORCE_SAVE flag returned " + sts.ToString("X"));
+                                }
+                            }
+                            catch (Exception ex)
+                            {
+                                Log.Error("ProcessAndGetRating: Error forcefully saving internal mail item. " + ex.ToString());
+                            }
+                        }
+                    }
+
+                    this.Message = processedMessage ?? message;
+                    this.Message.Rating = processedRating;
+                    result.Rating = processedRating;
+                }
+
+                // Save processing status
+                this._LastProcessedRating = result.Rating;
+                this._LastProcessedStatus = status;
+
+                // If it's an incoming message, do some caching (entry ids of drafts are empty)
+                if (string.IsNullOrEmpty(entryId) == false)
+                {
+                    // Save rating in db
+                    PEPDatabase.StoreOrUpdateRating(entryId, result.Rating);
+
+                    // Save message in cache
+                    if (isSecurelyStored)
+                    {
+                        if (Mirror != null)
+                        {
+                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Mirror, Rating = result.Rating });
+                        }
+                        else if ((Message != null) &&
+                                 (Message.IsSecure == false))
+                        {
+                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Message, Rating = result.Rating });
+                        }
+                    }
+                    else
+                    {
+                        PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = null, Rating = result.Rating });
+                    }
+                }
+
+                // Release objects
+                mirrorMailItem = null;
+
+                // Release the decryption lock
+                lock (mutexDecryptionList)
+                {
+                    try
+                    {
+                        if ((string.IsNullOrEmpty(entryId) == false) &&
+                            (decryptionList?.Count > 0))
+                        {
+                            decryptionList.Remove(entryId);
+                            Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
+                                        (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
+                        }
+                    }
+                    catch
+                    {
+                        Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
+                    }
+
+                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
+                }
+            }
+
+            Log.Verbose("ProcessAndGetRating: Completed. Result is " + Enum.GetName(typeof(pEpRating), result.Rating));
+
+            return result;
+        }
+
+        /// <summary>
+        /// Starts the processing of the mail item which can result in decryption or encryption of the message.
+        /// </summary>
+        /// <param name="disposeAfterComplete">Set to true in order to release/dispose the internal MailItem and this MailItemWrapper 
+        /// after processing is complete. This would be used for background processing where the reference is not maintained in the UI.
+        /// WARNING: do not set to true if you will use this MailItem or MailItemWrapper later!</param>
+        /// <returns>True if the processing started successfully, otherwise false if it is already busy.</returns>
+        public async void StartProcessing(bool isDraft, bool disposeAfterComplete = false)
+        {
+            if (this.processor.IsBusy == false)
+            {
+                string entryId = null;
+                this.disposeAfterProcessing = disposeAfterComplete;
+
+                bool process = await Task.Run(() =>
+                {
+                    int sleepTime = 1000; // 1 second in milliseconds
+                    int curWaitTime = 0;
+                    int maxWaitTime = 60000; // 1 minute in milliseconds
+                    bool isAlreadyBeingDecrypted = false;
+                    bool isAutoConsume = false;
+
+                    lock (mutexMailItem)
+                    {
+                        /* Explicitly add try/catch block to catch error getting EntryID.
+                         * This should theoretically never happen, but was seen in practice.
+                         */
+                        try
+                        {
+                            entryId = this.wrappedMailItem.EntryID;
+                            isAutoConsume = this.wrappedMailItem.GetIsAutoConsume();
+                        }
+                        catch
+                        {
+                            Log.Error("ProcessAndGetRating: internalMailItem is invalid or EntryID could not get retrieved");
+                            this._LastProcessedRating = pEpRating.pEpRatingUndefined;
+                            this._LastProcessedStatus = Globals.ReturnStatus.Failure;
+                            return false;
+                        }
+                    }
+
+                    // Make sure this mail item is not already being decrypted
+                    if (string.IsNullOrEmpty(entryId) == false)
+                    {
+                        do
+                        {
+                            /* Check if the EntryID is already in the decrypting list
+                             * If so, it is being decrypted already and we must wait
+                             * If it isn't already being decrypted, then add it to the decryption list
+                             */
+                            lock (mutexDecryptionList)
+                            {
+                                if (decryptionList.ContainsKey(entryId))
+                                {
+                                    isAlreadyBeingDecrypted = true;
+                                }
+                                else
+                                {
+                                    isAlreadyBeingDecrypted = false;
+
+                                    /* Add the entryID to the decryption list and we can start decryption
+                                     * It is important to do this all under the same lock
+                                     * 
+                                     * Note: It’s known the EntryID is not guaranteed to be unique for a given MailItem across different stores.
+                                     * However, only the EntryID is used in the decryption list.
+                                     * This is not an issue as worse-case is simply waiting for a different MailItem with the same EntryID to finish.
+                                     */
+                                    decryptionList.Add(entryId, "");
+                                    Log.Verbose("ProcessAndGetRating: Added EntryID to decryption list. " + entryId);
+                                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
+                                    break;
+                                }
+                            }
+
+                            // Wait for the other thread to finish
+                            if (isAlreadyBeingDecrypted)
+                            {
+                                // Do not process multiple times if it is an automatic message
+                                if (isAutoConsume)
+                                {
+                                    curWaitTime = maxWaitTime + 1;
+                                    Log.Verbose("ProcessAndGetRating: Setting timeout for AutoConsume message.");
+                                }
+                                else
+                                {
+                                    Log.Verbose("ProcessAndGetRating: Waiting for other decryption thread to finish. " + entryId);
+                                    Thread.Sleep(sleepTime);
+                                    curWaitTime += sleepTime;
+                                }
+                            }
+                        }
+                        while ((isAlreadyBeingDecrypted) && (curWaitTime < maxWaitTime));
+                    }
+                    else
+                    {
+                        // Log the issue unless the MailItem is an unsaved draft message
+                        if (isDraft == false)
+                        {
+                            Log.Warning("ProcessAndGetRating: EntryID does not exist, unable to lock during decryption.");
+                        }
+                        else
+                        {
+                            Log.Verbose("ProcessAndGetRating: Could not add EntryID to decryption list lock because message is an unsaved draft.");
+                        }
+                    }
+
+                    // Exit if timeout occured
+                    if ((isAlreadyBeingDecrypted) ||
+                        (curWaitTime >= maxWaitTime))
+                    {
+                        Log.Error("ProcessAndGetRating: Exited by timeout. " + (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
+
+                        // Save processing status
+                        this._LastProcessedRating = pEpRating.pEpRatingCannotDecrypt;
+                        this._LastProcessedStatus = Globals.ReturnStatus.Failure;
+
+                        // Remove entryId from decryption list
+                        lock (mutexDecryptionList)
+                        {
+                            try
+                            {
+                                decryptionList.Remove(entryId);
+                                Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
+                                            (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
+                            }
+                            catch
+                            {
+                                Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
+                            }
+
+                            Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
+                        }
+
+                        return false;
+                    }
+
+                    return true;
+                });
+
+                if (process)
+                {
+                    this.processor.RunWorkerAsync(entryId);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Event handler for when the processor background worker is doing work.
+        /// </summary>
+        private void Processor_DoWork(object sender, DoWorkEventArgs e)
+        {
+            e.Result = this.ProcessAndGetRating(e.Argument as string);
+            return;
+        }
+
+        /// <summary>
+        /// Event handler for when the processor background worker is completed.
+        /// </summary>
+        private void Processor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            MsgProcessor.ProcessingCompletedEventArgs args;
+
+            // Decrement decryption counter after decryption has finished (if necessary)
+            if (this.decrementCounter)
+            {
+                ThisAddIn.DecryptionStack.DecrementDecryptionCounter();
+            }
+
+            // Catch any errors that occured during processing
+            if (e.Error != null)
+            {
+                Log.Error("Processor_RunWorkerCompleted: Error during processing of mail item. " + e.Error.ToString());
+
+                if (this.disposeAfterProcessing)
+                {
+                    this.Dispose(false);
+
+                    // Must be called last!
+                    this.DisposeInternalMailItem();
+                }
+
+                return;
+            }
+
+            // Get processing result
+            ProcessingResult result = e.Result as ProcessingResult;
+
+            // Dispose if necessary
+            if (this.disposeAfterProcessing)
+            {
+                /* If there are MAPI properties to set, we have to marshal
+                 * this call to the main thread. If not, we can just dispose it
+                 * on the current one.
+                 */
+                if (result?.PropertiesToSet?.Count > 0)
+                {
+                    KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
+                    {
+                        this.wrappedMailItem?.SetMAPIProperties(result.PropertiesToSet);
+
+                        this.Dispose(false);
+
+                        // Must be called last!
+                        this.DisposeInternalMailItem();
+                    }));
+                }
+                else
+                {
+                    this.Dispose(false);
+
+                    // Must be called last!
+                    this.DisposeInternalMailItem();
+                }
+            }
+            else
+            {
+                // Raise complete event (only if dispose after decryption is not true since .this reference is returned)
+                args = new MsgProcessor.ProcessingCompletedEventArgs();
+
+                // Check for errors during processing but invoke anyhow to complete process (needed to look up mirror).
+                if (e.Error == null)
+                {
+                    args.ProcessedRating = result.Rating;
+                    args.PropertiesToSet = result.PropertiesToSet;
+                }
+                else
+                {
+                    args.ProcessedRating = pEpRating.pEpRatingUndefined;
+                }
+
+                this.ProcessingCompleted?.Invoke(this, args);
+            }
+        }
+
+        /**************************************************************
+         * 
+         * Mirror Locator
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Starts the process to locate the mirror of the mail item.
+        /// </summary>
+        public void StartGetMirror(string messageId = null)
+        {
+            if (this.mirrorLocator.IsBusy == false)
+            {
+                this.mirrorLocator.RunWorkerAsync(messageId);
+            }
+
+            return;
+        }
+
+        /// <summary>
+        /// Event handler for when the mirror locator background worker is doing work.
+        /// </summary>
+        private void MirrorLocator_DoWork(object sender, DoWorkEventArgs e)
+        {
+            PEPMessage mirror = null;
+            Outlook.MailItem omi = null;
+            e.Result = null;
+            Globals.ReturnStatus sts;
+
+            Log.Verbose("MirrorLocator_DoWork: Started");
+
+            try
+            {
+                if (this.Mirror != null)
+                {
+                    // If we already have a mirror, use it
+                    e.Result = this.Mirror;
+                }
+                else
+                {
+                    // If no stored mirror is there, look it up
+                    lock (mutexMailItem)
+                    {
+                        string id = e.Argument as string;
+                        omi = this.wrappedMailItem.GetMirror(id);
+
+                        if (omi != null)
+                        {
+                            Log.Verbose("MirrorLocator_DoWork: Mirror found");
+
+                            sts = PEPMessage.Create(omi, out mirror);
+                        }
+                    }
+
+                    e.Result = mirror;
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.Error("MirrorLocator_DoWork: Failed to find mirror OMI, " + ex.ToString());
+            }
+            finally
+            {
+                omi = null;
+            }
+
+            Log.Verbose("MirrorLocator_DoWork: Completed");
+        }
+
+        /// <summary>
+        /// Event handler for when the mirror locator background worker is completed.
+        /// </summary>
+        private void MirrorLocator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            this.GetMirrorCompleted?.Invoke(this, new GetMirrorCompletedEventArgs(e.Result == null ? null : (PEPMessage)e.Result));
+            return;
+        }
+
+        /**************************************************************
+         * 
+         * Methods
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Releases all resources and disconnects internal events.
+        /// The internal mail item will NOT be released -- this is managed externally.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            // Note: GC.SuppressFinalize(this); is not called because that just seems bad
+            return;
+        }
+
+        /// <summary>
+        /// Releases the internal Outlook.MailItem wrapped by this MailItemWrapper.
+        /// In general, this shouldn't be used as the MailItems are managed externally.
+        /// However, there are some cases where the MailItem needs to be disposed and the MailItemWrapper is the only
+        /// object that maintains the reference.
+        /// </summary>
+        public void DisposeInternalMailItem()
+        {
+            if (this.wrappedMailItem != null)
+            {
+                // Marshal.ReleaseComObject(this.internalMailItem);
+                this.wrappedMailItem = null;
+            }
+
+            return;
+        }
+
+        /// <summary>
+        /// Releases resources and disconnects internal events.
+        /// This exists to make code-analysis not throw old warnings.
+        /// </summary>
+        /// <param name="disposing">True to clean up native and managed resources. 
+        /// False to clean up only native resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            // Free managed resources
+            if (disposing)
+            {
+                // Disconnect mail item events
+                this.ConnectInternalMailItemEvents(false);
+
+                /* The BackgroundWorker class doesn't actually implement any functionality in Dispose.
+                 * It's simply inherited from the base implementation.
+                 * Just to make this clear (especially for code analysis) it is called and documented here.
+                 */
+                if (this.processor != null)
+                {
+                    this.processor.RunWorkerCompleted -= Processor_RunWorkerCompleted;
+                    this.processor.DoWork -= Processor_DoWork;
+                    this.processor.Dispose();
+                }
+                if (this.mirrorLocator != null)
+                {
+                    this.mirrorLocator.RunWorkerCompleted -= MirrorLocator_RunWorkerCompleted;
+                    this.mirrorLocator.DoWork -= MirrorLocator_DoWork;
+                    this.mirrorLocator.Dispose();
+                }
+            }
+
+            this.wrappedMailItem = null;
+        }
+
+        /// <summary>
+        /// Attempts to resolve all the Recipient objects in the Recipients collection of
+        /// the internal mail item against the Address Book (similar to 'Check Names').
+        /// This will first save the mail item (if it's not a draft), then forward the call to Recipients.ResolveAll().
+        /// See: https://msdn.microsoft.com/en-us/library/office/microsoft.office.interop.outlook.recipients.resolveall
+        /// </summary>
+        public void ResolveAllRecipients()
+        {
+            lock (mutexMailItem)
+            {
+                try
+                {
+                    /* Calling Save() for drafts might cause a crash, as this then interferes
+                     * with the protected storing of drafts for untrusted servers.
+                     */
+                    if (this.wrappedMailItem.GetIsDraft() == false)
+                    {
+                        this.wrappedMailItem.Save();
+                    }
+                    bool result = this.wrappedMailItem.Recipients.ResolveAll();
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("ResolveAllRecipients: exception " + ex.ToString());
+                }
+            }
+
+            return;
+        }
+
+        /// <summary>
+        /// Checks if the original item was encrypted and sets the user property to the
+        /// reply/forward item if needed.
+        /// This method evokes the OriginallyEncryptedStatusUpdated because it is possible
+        /// that the FormRegionPrivacyStatus has already been initialized when this method
+        /// is run. However, it might be necessary to check if the original item was encrypted
+        /// in order to decide whether to encrypt the reply/forward, so we need to update its
+        /// status.
+        /// </summary>
+        /// <param name="replyItem">The reply/forward item</param>
+        private void SetOriginallyEncryptedStatus(Outlook.MailItem replyItem)
+        {
+            if (this._LastProcessedRating >= pEpRating.pEpRatingUnreliable)
+            {
+                replyItem?.SetOriginallyEncryptedStatus(this._LastProcessedRating);
+
+                OriginallyEncryptedStatusUpdated?.Invoke(this, new EventArgs());
+            }
+        }
+
+        /// <summary>
+        /// Displays the unencrypted mirror mail item (if it exists) associated with the wrapped mail item.
+        /// </summary>
+        /// <returns>True if successful, otherwise false.</returns>
+        public bool DisplayMirror()
+        {
+            if (this.processor.IsBusy ||
+                this.mirrorLocator.IsBusy)
+            {
+                // Don't try to locate the mirror if it's being used
+                return (false);
+            }
+            else
+            {
+                Outlook.MailItem omi = this.wrappedMailItem.GetMirror();
+
+                if (omi == null)
+                {
+                    return (false);
+                }
+                else
+                {
+                    omi.Display();
+                }
+            }
+
+            return true;
+        }
+
+        /**************************************************************
+         * 
+         * Event Methods
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Raises the property change event, if possible, with the given arguments.
+        /// </summary>
+        /// <param name="propertyName">The name of the property that was changed.</param>
+        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
+        {
+            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+
+        /// <summary>
+        /// Dis/connects all necessary events to/from the internal mail item.
+        /// This will then expose these events through the cryptable mail item directly.
+        /// </summary>
+        /// <param name="connect">Whether to connect or disconnect events.</param>
+        private void ConnectInternalMailItemEvents(bool connect)
+        {
+            if (this.wrappedMailItem != null)
+            {
+                /* OUT-285: This should probably never fail, but during dis/connection
+                 * of an account, this method raised an InvalidCastException, so we will 
+                 * catch any error here anyway.
+                 */
+                try
+                {
+                    // Connect or disconnect events
+                    if (connect)
+                    {
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).BeforeAttachmentPreview += MailItem_BeforeAttachmentPreview;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Close += MailItem_Close;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Forward += MailItem_Forward;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Open += MailItem_Open;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).PropertyChange += MailItem_PropertyChange;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Reply += MailItem_Reply;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).ReplyAll += MailItem_ReplyAll;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Send += MailItem_Send;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Write += MailItem_Write;
+                    }
+                    else
+                    {
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).BeforeAttachmentPreview -= MailItem_BeforeAttachmentPreview;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Close -= MailItem_Close;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Forward -= MailItem_Forward;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Open -= MailItem_Open;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).PropertyChange -= MailItem_PropertyChange;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Reply -= MailItem_Reply;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).ReplyAll -= MailItem_ReplyAll;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Send -= MailItem_Send;
+                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Write -= MailItem_Write;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("ConnectInternalMailItemEvents: Error occured. " + ex.ToString());
+                }
+            }
+
+            return;
+        }
+
+        /**************************************************************
+         * 
+         * Sub-classes
+         * 
+         *************************************************************/
+
+        /// <summary>
+        /// Class used to store the arguments in the GetMirrorCompleted event.
+        /// </summary>
+        internal class GetMirrorCompletedEventArgs : EventArgs
+        {
+            /// <summary>
+            /// The located mirror after the get mirror process is complete.
+            /// </summary>
+            public PEPMessage Mirror = null;
+
+            /// <summary>
+            /// Constructs a new GetMirrorCompletedEventArgs with the given arguments.
+            /// </summary>
+            /// <param name="mirror">The located mirror after the get mirror process completes.</param>
+            public GetMirrorCompletedEventArgs(PEPMessage mirror)
+            {
+                this.Mirror = mirror;
+            }
+        }
+
+        /// <summary>
+        /// Class used to store an entry in the encrypted conversation cache.
+        /// This will identify the original parent encrypted mail item.
+        /// </summary>
+        private class OriginalMailItem
+        {
+            public string ConversationId { get; set; }
+            public string ConversationIndex { get; set; }
+            public string ConversationTopic { get; set; }
+            public string EntryId { get; set; }
+            public bool IsEncrypted { get; set; }
+
+            public OriginalMailItem()
+            {
+                this.ConversationId = null;
+                this.ConversationIndex = null;
+                this.ConversationTopic = null;
+                this.EntryId = null;
+                this.IsEncrypted = false;
+            }
+        }
+
+        /// <summary>
+        /// Class used to store a processing result.
+        /// </summary>
+        internal class ProcessingResult
+        {
+            public pEpRating Rating { get; set; } = pEpRating.pEpRatingUndefined;
+            public Dictionary<MapiProperty.MapiProp, object> PropertiesToSet { get; set; } = new Dictionary<MapiProperty.MapiProp, object>();
+        }
+    }
+}
--- a/Wrappers/WatchedExplorer.cs	Wed Mar 13 13:50:02 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-using System;
-using System.Linq;
-using System.Xml;
-using Outlook = Microsoft.Office.Interop.Outlook;
-
-namespace pEp
-{
-    /// <summary>
-    /// Stores an Outlook Explorer with connected events.
-    /// </summary>
-    public class WatchedExplorer : WatchedWindow
-    {
-        private string                  lastProcessedEntryId    = null;
-        private CryptableMailItem       inlineResponseItem      = null;
-
-        /**************************************************************
-         * 
-         * Constructors/Destructors
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Primary constructor.
-        /// </summary>
-        /// <param name="explorer">The explorer to watch.</param>
-        public WatchedExplorer(Outlook.Explorer explorer)
-        {
-            this.Explorer = explorer;
-
-            if (this.Explorer != null)
-            {
-                this.ConnectWatchedExplorerEvents(true);
-            }
-        }
-
-        #region Properties
-
-        /// <summary>
-        /// Gets the Explorer that is wrapped by this WatchedExplorer.
-        /// </summary>
-        public Outlook.Explorer Explorer { get; private set; } = null;
-
-        /// <summary>
-        /// Gets the Explorer that is wrapped by this WatchedExplorer.
-        /// </summary>
-        public override dynamic Window
-        {
-            get { return this.Explorer; }
-        }
-
-        /// <summary>
-        /// Gets the window type of this window.
-        /// </summary>
-        public override WindowType Type
-        {
-            get { return WindowType.Explorer; }
-        }
-
-        #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)
-            {
-                // Disconnect all events
-                this.ConnectWatchedExplorerEvents(false);
-
-                // Disconnect cryptable mail item
-                if (this.inlineResponseItem != null)
-                {
-                    this.inlineResponseItem.Dispose();
-                    this.inlineResponseItem = null;
-                }
-
-                // Set Outlook objects to null
-                this.Explorer = null;
-
-                // Dispose base class
-                base.Dispose(disposing);
-            }
-        }
-
-        /// <summary>
-        /// Connects the events for this watched explorer.
-        /// <param name="connect">Whether to connect or disconnect the events.</param>
-        /// </summary>
-        private void ConnectWatchedExplorerEvents(bool connect)
-        {
-            try
-            {
-                if (connect)
-                {
-                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close += Explorer_Close;
-                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch += Explorer_FolderSwitch;
-                    ((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).FolderSwitch -= Explorer_FolderSwitch;
-                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose -= Explorer_InlineResponseClose;
-                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange -= Explorer_SelectionChange;
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
-            }
-        }
-        #endregion
-
-        #region Event Handling
-        /**************************************************************
-         * 
-         * Event Handling
-         * 
-         *************************************************************/
-
-        /// <summary>
-        /// Event handler for when a watched explorer is being closed.
-        /// </summary>
-        private void Explorer_Close()
-        {
-            Globals.ThisAddIn.RemoveFromWatchedExplorers(this);
-            this.Dispose();
-        }
-
-        /// <summary>
-        /// Event handler for when a different folder is being selected.
-        /// </summary>
-        private void Explorer_FolderSwitch()
-        {
-            Outlook.Folder folder = null;
-            Outlook.TableView customView = null;
-            Outlook.View view = null;
-            Outlook.Views views = null;
-
-            try
-            {
-                folder = this.Explorer?.CurrentFolder as Outlook.Folder;
-
-                // If the "Last Used" contacts folder is selected, make sure the correct view is applied
-                if ((folder?.DefaultMessageClass?.Equals(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Contact) == true) &&
-                    (folder?.Name?.Equals(Properties.Resources.LastUsedFolderName) == true))
-                {
-                    view = this.Explorer.CurrentView;
-
-                    // If the current view isn't the custom one, create it if necessary
-                    if (view?.Name?.Equals(Properties.Resources.LastUsedFolderName) != true)
-                    {
-                        views = this.Explorer.CurrentFolder.Views as Outlook.Views;
-
-                        try
-                        {
-                            customView = views[Properties.Resources.LastUsedFolderName] as Outlook.TableView;
-                        }
-                        catch (Exception ex)
-                        {
-                            customView = null;
-                            Log.Info("Explorer_SelectionChange: Error getting Last Used folder view. " + ex.ToString());
-                        }
-
-                        /* If the custom view doesn't exist, create and apply it.
-                         * If it already exists, don't apply it.
-                         * Caveat: If the creation of the view went wrong at some point, it will never be set correctly. The alternative
-                         *         here would be to set it each time it's not set. This is another problem, however, as we don't know if
-                         *         the view of this folder is not the custom one because it has never been set correctly or if the user 
-                         *         selects another one. So, in the latter case, we would basically override a user decision.
-                         * Note: This whole procedure is a workaround because we can only set the Explorer's current view and not the folder's
-                         *       current view directly.
-                         */                           
-                        if (customView == null)
-                        {
-                            customView = views.Add(Properties.Resources.LastUsedFolderName, Outlook.OlViewType.olTableView, Outlook.OlViewSaveOption.olViewSaveOptionThisFolderEveryone) as Outlook.TableView;
-                            XmlDocument xmlDoc = new XmlDocument();
-                            xmlDoc.LoadXml(customView.XML);
-                            XmlNodeList childNodes = xmlDoc.LastChild.ChildNodes;
-
-                            // Create and/or set up Order By property
-                            XmlNode orderByNode = childNodes.OfType<XmlNode>().First(a => (a.Name?.Equals("orderby", StringComparison.OrdinalIgnoreCase) == true));
-                            if (orderByNode == null)
-                            {
-                                orderByNode = xmlDoc.CreateNode(XmlNodeType.Element, "orderby", string.Empty);
-                                xmlDoc.LastChild.AppendChild(orderByNode);
-                            }
-                            orderByNode.InnerXml = "<order><heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><sort>desc</sort></order>";
-
-                            // Create and/or set up Modified column
-                            XmlNode modifiedNode = childNodes.OfType<XmlNode>().FirstOrDefault(a => (a.ChildNodes.OfType<XmlNode>().FirstOrDefault(b => (b.Value?.Equals("Modified", StringComparison.OrdinalIgnoreCase) == true)) != null));
-
-                            if (modifiedNode == null)
-                            {
-                                modifiedNode = xmlDoc.CreateNode(XmlNodeType.Element, "column", string.Empty);
-
-                                // Get first column
-                                XmlNode fullNameColumn = null;
-                                foreach (var node in childNodes)
-                                {
-                                    if (((node as XmlNode)?.Name?.Equals("column", StringComparison.OrdinalIgnoreCase) == true) &&
-                                        ((node as XmlNode)?.FirstChild?.InnerText?.Equals("Full Name", StringComparison.OrdinalIgnoreCase) == true))
-                                    {
-                                        fullNameColumn = node as XmlNode;
-                                        break;
-                                    }
-                                }
-
-                                // If not found, just insert after the 4th column
-                                if (fullNameColumn == null)
-                                {
-                                    fullNameColumn = childNodes[4];
-                                }
-
-                                if (fullNameColumn != null)
-                                {
-                                    xmlDoc.LastChild.InsertAfter(modifiedNode, fullNameColumn);
-                                }
-                            }
-                            modifiedNode.InnerXml = "<heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><width>50</width><style>padding-left:3px;;text-align:left</style><editable>0</editable><format>M/d/yyyy||h:mm tt</format><displayformat>2</displayformat>";
-
-                            // Set modified XML
-                            customView.XML = xmlDoc.OuterXml;
-                            customView.Save();
-
-                            // Apply as current view
-                            this.Explorer.CurrentView = customView;
-                        }
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.Error("Explorer_FolderSwitch: Error setting Last Used folder view. " + ex.ToString());
-            }
-            finally
-            {
-                customView = null;
-                folder = null;
-                view = null;
-                views = null;
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when an inline response is being closed.
-        /// </summary>
-        private void Explorer_InlineResponseClose()
-        {
-            Outlook.MailItem omi = null;
-
-            /* Create a new CryptableMailItem. This is needed so that its
-             * MailItem_Write event gets called and the message will get saved
-             * 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;
-
-                if (omi != null)
-                {
-                    this.inlineResponseItem = new CryptableMailItem(omi, null, false)
-                    {
-                        IsInlineResponse = true
-                    };
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.Error("WatchedExplorer_InlineResponseClose: Error setting new inline response item. " + ex.ToString());
-            }
-            finally
-            {
-                omi = null;
-            }
-        }
-
-        /// <summary>
-        /// Event handler for when the currently selected item in the explorer changes.
-        /// </summary>
-        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. Note: in Outlook 2010, there is no inline response.
-                         * IMPORTANT: Never call Explorer.ActiveInlineResponse on Outlook 2010
-                         *            as this might lead to a crash of Outlook (even inside a
-                         *            try/catch block)
-                         */
-                        bool isInlineResponse = false;
-                        if (Globals.OutlookVersion != Globals.Version.Outlook2010)
-                        {
-                            Outlook.MailItem inlineResponse = null;
-                            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.OrdinalIgnoreCase) == 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.InitializeWindow(isInlineResponse);
-                    }                    
-                    else
-                    {
-                        Log.Error("Explorer_SelectionChange: Error getting current selection.");
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                Log.Error("Explorer_SelectionChange: Error occured: " + ex?.ToString());
-            }
-            finally
-            {
-                selection = null;
-            }
-        }
-        #endregion
-    }
-}
--- a/Wrappers/WatchedInspector.cs	Wed Mar 13 13:50:02 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-using System;
-using Outlook = Microsoft.Office.Interop.Outlook;
-
-namespace pEp
-{
-    /// <summary>
-    /// Stores an Outlook Explorer with connected events.
-    /// </summary>
-    public class WatchedInspector : WatchedWindow
-    {
-
-        /**************************************************************
-         * 
-         * 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.InitializeWindow();
-                }
-                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; private set; } = null;
-
-        /// <summary>
-        /// Gets the Inspector that is wrapped by this WatchedInspector.
-        /// </summary>
-        public override dynamic Window
-        {
-            get { return this.Inspector; }
-        }
-
-        /// <summary>
-        /// Gets the window type of this window.
-        /// </summary>
-        public override WindowType Type
-        {
-            get { return WindowType.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)
-            {
-                // Disconnect all events
-                this.DisconnectWatchedInspectorEvents();
-
-                // Set Outlook objects to null
-                this.Inspector = null;
-
-                // Dispose base class
-                base.Dispose(disposing);
-            }
-        }
-
-        /// <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)
-        {
-            Log.Error("Inspector_ProcessingCompleted: Not implemented.");
-        }
-
-        #endregion
-    }
-}
--- a/Wrappers/WatchedWindow.cs	Wed Mar 13 13:50:02 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1594 +0,0 @@
-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;
-
-        public enum WindowType
-        {
-            Undefined,
-            Inspector,
-            Explorer
-        }
-
-        #region Properties
-
-        /// <summary>
-        /// The mail item that is connected to this Inspector/Explorer window.
-        /// </summary>
-        public Outlook.MailItem CurrentMailItem { get; set; } = null;
-
-        /// <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>
-        /// The privacy state of this form region.
-        /// </summary>
-        internal PrivacyState PrivacyState { get; private set; } = new PrivacyState();
-
-        /// <summary>
-        /// Gets the rating of this message.
-        /// </summary>
-        public pEpRating Rating { get; private set; } = pEpRating.pEpRatingUndefined;
-
-        /// <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;
-            this.UpdatePrivacyStateAndUI();
-        }
-
-        /// <summary>
-        /// The timer that schedules the updates of this window.
-        /// </summary>
-        public System.Windows.Forms.Timer TimerRefresh { get; set; } = new System.Windows.Forms.Timer();
-
-        /// <summary>
-        /// Gets the associated Explorer/Inspector window. To be overwritten in child class.
-        /// </summary>
-        public abstract dynamic Window { get; }
-
-        /// <summary>
-        /// Gets the window type of this window. To be overwritten in child class.
-        /// </summary>
-        public abstract WindowType Type { get; }
-
-        #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)
-            {
-                // 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);
-
-                // Set Outlook objects to null
-                this.CurrentMailItem = null;
-
-                // Dispose of timer
-                if (this.TimerRefresh != null)
-                {
-                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
-                    this.TimerRefresh.Dispose();
-                    this.TimerRefresh = 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, true) == Globals.ReturnStatus.Success)
-                    {
-                        // 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
-                    {
-                        Log.Error("BuildAndShowManager: Error creating PEPMessage from draft.");
-                        message = null;
-                    }
-                }
-                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();
-                                        pEpDecryptFlags flags = pEpDecryptFlags.pEpDecryptFlagsNone;
-                                        pEpRating rating = msgProcessor.Decrypt(ref message, out PEPMessage decryptedMsg, out string[] 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("BuildAndShowManager: 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>
-        /// Initializes the watched explorer or inspector window.
-        /// </summary>
-        /// <param name="isInlineResponse">Whether this window is an inline response.</param>
-        protected void InitializeWindow(bool isInlineResponse = false)
-        {
-            bool enableFormRegion = false;
-            bool cancelOpenEvent = false;
-            bool isSecureAttachedMail = false;
-            string messageId = null;
-            PEPCache.CacheItem cacheItem = 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)
-                {
-                    if (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 item from cache
-                    cacheItem = PEPCache.GetItemFromCache(this.CurrentMailItem.EntryID);
-
-                    if (cacheItem != null)
-                    {
-                        // Set rating from cache
-                        provisionalRating = cacheItem?.Rating ?? pEpRating.pEpRatingUndefined;
-                    }
-                    else
-                    {
-                        // 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("InitializeWindow: Provisional rating {0} shown.", Enum.GetName(typeof(pEpRating), provisionalRating));
-                }
-
-                // Do not process S/MIME messages
-                if (this.CurrentMailItem.GetIsSMIMEEnabled())
-                {
-                    Log.Verbose("InitializeWindow: 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("InitializeWindow: 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;
-
-                            // 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 pEpMessage) == Globals.ReturnStatus.Success) &&
-                                    (pEpMessage.IsSecure))
-                                {
-                                    MsgProcessor msgProcessor = new MsgProcessor();
-                                    if (msgProcessor.Decrypt(pEpMessage, out PEPMessage decryptedMessage))
-                                    {
-                                        isSecureAttachedMail = true;
-                                        mirror = this.CurrentMailItem.CreateMirrorOMI(messageId);
-                                        decryptedMessage.ApplyTo(mirror, true, false);
-                                        mirror?.Save();
-                                    }
-                                    else
-                                    {
-                                        Log.Error("InitializeWindow: 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("InitializeWindow: Error checking for attached mail. " + ex.ToString());
-                    }
-                }
-
-                // Check for item from cache and show it if possible
-                if ((this.IsDraft == false) &&
-                    (cacheItem?.Mirror != null) &&
-                    (this.CurrentMailItem.GetIsInSecureStore()))
-                {
-                    WindowFormRegionCollection formRegions = null;
-                    try
-                    {
-                        formRegions = Globals.FormRegions[this.Window];
-                    }
-                    catch (Exception ex)
-                    {
-                        Log.Error("InitializeWindow: Error getting form region collection. " + ex.ToString());
-                    }
-
-                    this.GetFormRegionPreviewUnencrypted()?.DisplayState?.SetMessage(cacheItem.Mirror);
-                }
-
-                this.cryptableMailItem = new CryptableMailItem(this.CurrentMailItem, provisionalRating)
-                {
-                    // Set inline response property
-                    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("BuildAndShowManager: 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 ex)
-            {
-                Log.Error("BuildAndShowManager: Error. " + ex.ToString());
-            }
-        }
-
-        /// <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.IsDraft);
-                this.processingOngoing = true;
-
-                // If we have a draft message, fetch directly a preview outgoing rating
-                if (this.IsDraft)
-                {
-                    pEpRating rating = this.GetOutgoingRatingPreview();
-
-                    if (rating != pEpRating.pEpRatingUndefined)
-                    {
-                        this.SetRating(rating);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets a preview of the outgoing rating which is faster than the full version.
-        /// Caveat: might show a wrong rating in case of missing keys.
-        /// </summary>
-        /// <returns>A preview of the outgoing rating.</returns>
-        private pEpRating GetOutgoingRatingPreview()
-        {
-            pEpRating rating = pEpRating.pEpRatingUndefined;
-
-            try
-            {
-                rating = this.CurrentMailItem?.GetOutgoingRating(false, true) ?? pEpRating.pEpRatingUndefined;
-            }
-            catch (Exception ex)
-            {
-                rating = pEpRating.pEpRatingUndefined;
-                Log.Error("ImmediateRatingAndUIUpdate: Error getting outgoing preview rating. " + ex.ToString());
-            }
-
-            return rating;
-        }
-
-        /// <summary>
-        /// Updates the privacy state and the UI (ribbon and form region).
-        /// </summary>
-        public void UpdatePrivacyStateAndUI()
-        {
-            try
-            {
-                this.PrivacyState = new PrivacyState(this.Rating,
-                                                     this.ForceProtection,
-                                                     this.ForceUnencrypted);
-                RibbonCustomizations.Invalidate();
-                this.GetFormRegionPrivacyStatus()?.UpdateFormRegion(this.PrivacyState);
-            }
-            catch (Exception ex)
-            {
-                Log.Error("UpdateUI: Error occured. " + ex.ToString());
-            }
-        }
-
-        /// <summary>
-        /// Gathers all form regions for this WatchedWindow.
-        /// </summary>
-        /// <returns>The gathered form regions.</returns>
-        internal WindowFormRegionCollection GetFormRegions()
-        {
-            /* We have to find out here if the window is an explorer or an inspector.
-             * Calling Globals.FormRegions[] with an ambiguous window type leads to a crash.
-             */
-            Outlook.Explorer explorer;
-            Outlook.Inspector inspector;
-            WindowFormRegionCollection formRegions = null;
-            try
-            {
-                if (this.Window != null)
-                {
-                    if (this.Type == WindowType.Explorer)
-                    {
-                        explorer = this.Window as Outlook.Explorer;
-                        formRegions = Globals.FormRegions[explorer];
-                    }
-                    else if (this.Type == WindowType.Inspector)
-                    {
-                        inspector = this.Window as Outlook.Inspector;
-                        formRegions = Globals.FormRegions[inspector];
-                    }
-                }
-                else
-                {
-                    Log.Warning("GetFormRegions: Could not get form regions. Current window is null.");
-                }
-            }
-            catch (Exception ex)
-            {
-                formRegions = null;
-                Log.Error("GetFormRegions: Error getting form regions collection. " + ex.ToString());
-            }
-            finally
-            {
-                explorer = null;
-                inspector = null;
-            }
-
-            return formRegions;
-        }
-
-        /// <summary>
-        /// Gets the FormRegionPrivacyStatus of this WatchedWindow (if available).
-        /// </summary>
-        /// <returns>The FormRegionPrivacyStatus of this window or null.</returns>
-        internal FormRegionPrivacyStatus GetFormRegionPrivacyStatus()
-        {
-            return this.GetFormRegions()?.FormRegionPrivacyStatus;
-        }
-
-        /// <summary>
-        /// Gets the FormRegionPreviewUnencrypted of this WatchedWindow (if available).
-        /// </summary>
-        /// <returns>The FormRegionPreviewUnencrypted of this window or null.</returns>
-        internal FormRegionPreviewUnencrypted GetFormRegionPreviewUnencrypted()
-        {
-            return this.GetFormRegions()?.FormRegionPreviewUnencrypted;
-        }
-
-        /// <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)
-        {
-            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.
-                     */
-                    if (this.IsDraft)
-                    {
-                        try
-                        {
-                            sendingAccount = this.CurrentMailItem.SendUsingAccount;
-                            if (sendingAccount == null)
-                            {
-                                ns = Globals.ThisAddIn.Application.Session;
-                                currUser = ns.CurrentUser;
-                                sts = PEPIdentity.Create(currUser, out PEPIdentity 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, Globals.ThisAddIn.Settings.HideInternalMessages);
-                            }
-                        }
-                        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
-                if (this.TimerRefresh != null)
-                {
-                    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
-         * 
-         *************************************************************/
-
-        /// <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("MailItem_ProcessingComplete: 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("MailItem_ProcessingComplete: 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)
-                    {
-                        // If the message was forcefully protected, there is no mirror and we show the actual message
-                        if ((e.Mirror == null) &&
-                            (this.CurrentMailItem?.GetIsForcefullyProtected() == true))
-                        {
-                            if (PEPMessage.Create(this.CurrentMailItem, out PEPMessage 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
-                        {
-                            FormRegionPreviewUnencrypted formRegionPreviewUnencrypted = this.GetFormRegionPreviewUnencrypted();
-
-                            // If we have a FormRegionPreviewUnencrypted and it's visible, show preview
-                            if (formRegionPreviewUnencrypted?.Visible == true)
-                            {
-                                formRegionPreviewUnencrypted.DisplayState.OriginalEntryId = this.CurrentMailItem?.EntryID;
-                                formRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
-
-                                Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
-                            }
-                            else
-                            {
-                                Log.Error("MailItem_GetMirrorComplete: FormRegionPreviewUnencrypted is null or invisible.");
-                            }
-                        }
-
-                        // 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(this.IsDraft);
-            }
-        }
-
-        /// <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)
-        {
-            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
-                    cancel = this.cryptableMailItem.DisplayMirror();
-                }
-            }
-        }
-
-        /// <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))
-                {
-                    /* If the mail item is still being processed, this means that the message might go out with
-                     * a different rating than the one that was shown in the UI when sending was initiated.
-                     * As a trade-off between security and user experience, we make at least sure that the
-                     * current outgoing rating preview (which is only wrong under rare circumstances) is not
-                     * smaller than the one shown in the UI. If this is the case, just abort sending.
-                     */
-                    pEpRating outgoingPreviewRating = this.GetOutgoingRatingPreview();
-                    if (this.Rating != outgoingPreviewRating)
-                    {
-                        if (this.Rating > outgoingPreviewRating)
-                        {
-                            Log.Verbose("MailItem_Send: Mail item still being processed.");
-                            cancel = true;
-                            return;
-                        }
-
-                        this.SetRating(outgoingPreviewRating);
-                    }
-                }
-
-                // 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)
-                {
-                    if ((this.Type == WindowType.Inspector) &&
-                        (this.cryptableMailItem.IsInlineResponse == false) &&
-                        (this.CurrentMailItem.GetProcessingState() == null))
-                    {                        
-                        IntPtr hWnd = NativeMethods.GetActiveWindow();    
-                        NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_BOTTOM, 0, 0, 0, 0, NativeMethods.SetWindowPosFlags.DoNotActivate |
-                                                                                                NativeMethods.SetWindowPosFlags.IgnoreMove |
-                                                                                                NativeMethods.SetWindowPosFlags.DoNotReposition |
-                                                                                                NativeMethods.SetWindowPosFlags.IgnoreResize |
-                                                                                                NativeMethods.SetWindowPosFlags.HideWindow);
-                        this.CurrentMailItem.SetProcessingState(MailItemExtensions.ProcessingState.ProcessInBackground);
-                        Log.Verbose("MailItem_Send: Inspector window closed.");
-                    }
-
-                    // 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);
-                    }
-
-                    // Reset pEp options
-                    this.ForceProtection = false;
-                    this.DisableForceProtection = false;
-                    this.ForceUnencrypted = false;
-                    this.NeverUnsecure = false;
-
-                    // 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
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wrappers/WindowBaseWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
@@ -0,0 +1,1592 @@
+using pEp.UI;
+using pEp.Wrappers;
+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 WindowBaseWrapper : IDisposable
+    {
+        private bool                            displayMirrorRequested      = false;
+        private HandshakeDialog                 handshakeDialog             = null;
+        private bool                            isEnabled                   = true;
+        private bool                            isStarted                   = false;
+        private const int                       maxRepeatCount              = 5;
+        private bool                            processingOngoing           = false;
+        private bool                            refreshOngoing              = false;
+        private bool                            repeatProcessing            = false;
+        private int                             repeatCounter               = 0;
+        private MailItemWrapper                 wrappedMailItem             = null;
+
+        public enum WindowType
+        {
+            Undefined,
+            Inspector,
+            Explorer
+        }
+
+        #region Properties
+
+        /// <summary>
+        /// The mail item that is connected to this Inspector/Explorer window.
+        /// </summary>
+        public Outlook.MailItem CurrentMailItem { get; set; } = null;
+
+        /// <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 whether the wrapped mail item is a draft.
+        /// </summary>
+        public bool IsDraft { get => (this.wrappedMailItem?.IsDraft == true); }
+
+        /// <summary>
+        /// Gets or sets whether to always store this message as if on an untrusted server.
+        /// </summary>
+        public bool NeverUnsecure { get; set; } = false;
+
+        /// <summary>
+        /// The privacy state of this form region.
+        /// </summary>
+        internal PrivacyState PrivacyState { get; private set; } = new PrivacyState();
+
+        /// <summary>
+        /// Gets the rating of this message.
+        /// </summary>
+        public pEpRating Rating { get; private set; } = pEpRating.pEpRatingUndefined;
+
+        /// <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;
+            this.UpdatePrivacyStateAndUI();
+        }
+
+        /// <summary>
+        /// The timer that schedules the updates of this window.
+        /// </summary>
+        public System.Windows.Forms.Timer TimerRefresh { get; set; } = new System.Windows.Forms.Timer();
+
+        /// <summary>
+        /// Gets the associated Explorer/Inspector window. To be overwritten in child class.
+        /// </summary>
+        public abstract dynamic Window { get; }
+
+        /// <summary>
+        /// Gets the window type of this window. To be overwritten in child class.
+        /// </summary>
+        public abstract WindowType Type { get; }
+
+        #endregion
+
+        #region Constructors / Destructors
+
+        /// <summary>
+        /// Destructor.
+        /// </summary>
+        ~WindowBaseWrapper()
+        {
+            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)
+            {
+                // Disconnect cryptable mail item
+                if (this.wrappedMailItem != null)
+                {
+                    try
+                    {
+                        this.wrappedMailItem.PropertyChanged -= MailItem_PropertyChanged;
+                        this.wrappedMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
+                        this.wrappedMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
+                        this.wrappedMailItem.Open -= MailItem_Open;
+                        this.wrappedMailItem.Send -= MailItem_Send;
+                        this.wrappedMailItem.OriginallyEncryptedStatusUpdated -= MailItemWrapper_OriginallyEncryptedStatusUpdated;
+                    }
+                    catch { }
+
+                    this.wrappedMailItem.Dispose();
+                    this.wrappedMailItem = null;
+                }
+
+                // Disconnect other
+                this.SetIsEnabled(false);
+
+                // Set Outlook objects to null
+                this.CurrentMailItem = null;
+
+                // Dispose of timer
+                if (this.TimerRefresh != null)
+                {
+                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
+                    this.TimerRefresh.Dispose();
+                    this.TimerRefresh = 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.wrappedMailItem?.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, true) == Globals.ReturnStatus.Success)
+                    {
+                        // 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
+                    {
+                        Log.Error("BuildAndShowManager: Error creating PEPMessage from draft.");
+                        message = null;
+                    }
+                }
+                else
+                {
+                    // Else, use either the cryptable mail item's associated mirror or message
+                    message = this.wrappedMailItem?.Mirror ?? this.wrappedMailItem?.Message;
+                    Log.Verbose(string.Format("BuildAndShowManager: Message {0} retrieved from wrappedMailItem", ((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();
+                                        pEpDecryptFlags flags = pEpDecryptFlags.pEpDecryptFlagsNone;
+                                        pEpRating rating = msgProcessor.Decrypt(ref message, out PEPMessage decryptedMsg, out string[] 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("BuildAndShowManager: 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>
+        /// Initializes the watched explorer or inspector window.
+        /// </summary>
+        /// <param name="isInlineResponse">Whether this window is an inline response.</param>
+        protected void InitializeWindow(bool isInlineResponse = false)
+        {
+            bool enableFormRegion = false;
+            bool cancelOpenEvent = false;
+            bool isSecureAttachedMail = false;
+            string messageId = null;
+            PEPCache.CacheItem cacheItem = null;
+
+            try
+            {
+                /* 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)
+                {
+                    if (this.CurrentMailItem?.Recipients?.Count > 0)
+                    {
+                        string originalRatingString = this.CurrentMailItem.GetUserProperty(MailItemWrapper.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 item from cache
+                    cacheItem = PEPCache.GetItemFromCache(this.CurrentMailItem.EntryID);
+
+                    if (cacheItem != null)
+                    {
+                        // Set rating from cache
+                        provisionalRating = cacheItem?.Rating ?? pEpRating.pEpRatingUndefined;
+                    }
+                    else
+                    {
+                        // 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("InitializeWindow: Provisional rating {0} shown.", Enum.GetName(typeof(pEpRating), provisionalRating));
+                }
+
+                // Do not process S/MIME messages
+                if (this.CurrentMailItem.GetIsSMIMEEnabled())
+                {
+                    Log.Verbose("InitializeWindow: 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("InitializeWindow: 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;
+
+                            // 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 pEpMessage) == Globals.ReturnStatus.Success) &&
+                                    (pEpMessage.IsSecure))
+                                {
+                                    MsgProcessor msgProcessor = new MsgProcessor();
+                                    if (msgProcessor.Decrypt(pEpMessage, out PEPMessage decryptedMessage))
+                                    {
+                                        isSecureAttachedMail = true;
+                                        mirror = this.CurrentMailItem.CreateMirrorOMI(messageId);
+                                        decryptedMessage.ApplyTo(mirror, true, false);
+                                        mirror?.Save();
+                                    }
+                                    else
+                                    {
+                                        Log.Error("InitializeWindow: Decryption of attached mail was not successful.");
+                                    }
+                                }
+                            }
+
+                            // Check if attachment is being opened or if only the preview is needed
+                            if (MailItemWrapper.PreviewAttachedMailId?.Equals(messageId) != true)
+                            {
+                                // Display mirror and cancel opening of original
+                                cancelOpenEvent = true;
+                                mirror?.Display();
+                            }
+
+                            // Not needed anymore after this point
+                            MailItemWrapper.PreviewAttachedMailId = null;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        messageId = null;
+                        Log.Error("InitializeWindow: Error checking for attached mail. " + ex.ToString());
+                    }
+                }
+
+                // Check for item from cache and show it if possible
+                if ((this.IsDraft == false) &&
+                    (cacheItem?.Mirror != null) &&
+                    (this.CurrentMailItem.GetIsInSecureStore()))
+                {
+                    WindowFormRegionCollection formRegions = null;
+                    try
+                    {
+                        formRegions = Globals.FormRegions[this.Window];
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.Error("InitializeWindow: Error getting form region collection. " + ex.ToString());
+                    }
+
+                    this.GetFormRegionPreviewUnencrypted()?.DisplayState?.SetMessage(cacheItem.Mirror);
+                }
+
+                this.wrappedMailItem = new MailItemWrapper(this.CurrentMailItem, provisionalRating)
+                {
+                    // Set inline response property
+                    IsInlineResponse = isInlineResponse
+                };
+
+                // Set properties for encrypted attached mail
+                if (isSecureAttachedMail)
+                {
+                    this.wrappedMailItem.MessageId = messageId;
+                    this.wrappedMailItem.IsSecureAttachedMail = true;
+                }
+
+                // Connect cryptable mail item events
+                if (this.wrappedMailItem != null)
+                {
+                    // If we don't open the original, set property and return
+                    if (cancelOpenEvent)
+                    {
+                        this.wrappedMailItem.Open += MailItem_Open;
+                        this.wrappedMailItem.CancelOpen = true;
+                        return;
+                    }
+                    else
+                    {
+                        try
+                        {
+                            this.wrappedMailItem.PropertyChanged += MailItem_PropertyChanged;
+                            this.wrappedMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
+                            this.wrappedMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
+                            this.wrappedMailItem.Send += MailItem_Send;
+
+                            if (this.wrappedMailItem.IsSecurelyStored)
+                            {
+                                this.wrappedMailItem.Open += MailItem_Open;
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Log.Error("BuildAndShowManager: 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 MailItemWrapper.MailItem_Reply
+                             *                          or MailItemWrapper.MailItem_Forward.
+                             */
+                            if (this.IsDraft)
+                            {
+                                enableFormRegion = true;
+                                this.wrappedMailItem.OriginallyEncryptedStatusUpdated += MailItemWrapper_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 ex)
+            {
+                Log.Error("BuildAndShowManager: Error. " + ex.ToString());
+            }
+        }
+
+        /// <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.wrappedMailItem != null))
+            {
+                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
+
+                // Start the rating calculation/decryption process
+                this.wrappedMailItem.StartProcessing(this.IsDraft);
+                this.processingOngoing = true;
+
+                // If we have a draft message, fetch directly a preview outgoing rating
+                if (this.IsDraft)
+                {
+                    pEpRating rating = this.GetOutgoingRatingPreview();
+
+                    if (rating != pEpRating.pEpRatingUndefined)
+                    {
+                        this.SetRating(rating);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a preview of the outgoing rating which is faster than the full version.
+        /// Caveat: might show a wrong rating in case of missing keys.
+        /// </summary>
+        /// <returns>A preview of the outgoing rating.</returns>
+        private pEpRating GetOutgoingRatingPreview()
+        {
+            pEpRating rating = pEpRating.pEpRatingUndefined;
+
+            try
+            {
+                rating = this.CurrentMailItem?.GetOutgoingRating(false, true) ?? pEpRating.pEpRatingUndefined;
+            }
+            catch (Exception ex)
+            {
+                rating = pEpRating.pEpRatingUndefined;
+                Log.Error("ImmediateRatingAndUIUpdate: Error getting outgoing preview rating. " + ex.ToString());
+            }
+
+            return rating;
+        }
+
+        /// <summary>
+        /// Updates the privacy state and the UI (ribbon and form region).
+        /// </summary>
+        public void UpdatePrivacyStateAndUI()
+        {
+            try
+            {
+                this.PrivacyState = new PrivacyState(this.Rating,
+                                                     this.ForceProtection,
+                                                     this.ForceUnencrypted);
+                RibbonCustomizations.Invalidate();
+                this.GetFormRegionPrivacyStatus()?.UpdateFormRegion(this.PrivacyState);
+            }
+            catch (Exception ex)
+            {
+                Log.Error("UpdateUI: Error occured. " + ex.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Gathers all form regions for this WatchedWindow.
+        /// </summary>
+        /// <returns>The gathered form regions.</returns>
+        internal WindowFormRegionCollection GetFormRegions()
+        {
+            /* We have to find out here if the window is an explorer or an inspector.
+             * Calling Globals.FormRegions[] with an ambiguous window type leads to a crash.
+             */
+            Outlook.Explorer explorer;
+            Outlook.Inspector inspector;
+            WindowFormRegionCollection formRegions = null;
+            try
+            {
+                if (this.Window != null)
+                {
+                    if (this.Type == WindowType.Explorer)
+                    {
+                        explorer = this.Window as Outlook.Explorer;
+                        formRegions = Globals.FormRegions[explorer];
+                    }
+                    else if (this.Type == WindowType.Inspector)
+                    {
+                        inspector = this.Window as Outlook.Inspector;
+                        formRegions = Globals.FormRegions[inspector];
+                    }
+                }
+                else
+                {
+                    Log.Warning("GetFormRegions: Could not get form regions. Current window is null.");
+                }
+            }
+            catch (Exception ex)
+            {
+                formRegions = null;
+                Log.Error("GetFormRegions: Error getting form regions collection. " + ex.ToString());
+            }
+            finally
+            {
+                explorer = null;
+                inspector = null;
+            }
+
+            return formRegions;
+        }
+
+        /// <summary>
+        /// Gets the FormRegionPrivacyStatus of this WatchedWindow (if available).
+        /// </summary>
+        /// <returns>The FormRegionPrivacyStatus of this window or null.</returns>
+        internal FormRegionPrivacyStatus GetFormRegionPrivacyStatus()
+        {
+            return this.GetFormRegions()?.FormRegionPrivacyStatus;
+        }
+
+        /// <summary>
+        /// Gets the FormRegionPreviewUnencrypted of this WatchedWindow (if available).
+        /// </summary>
+        /// <returns>The FormRegionPreviewUnencrypted of this window or null.</returns>
+        internal FormRegionPreviewUnencrypted GetFormRegionPreviewUnencrypted()
+        {
+            return this.GetFormRegions()?.FormRegionPreviewUnencrypted;
+        }
+
+        /// <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)
+        {
+            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.
+                     */
+                    if (this.IsDraft)
+                    {
+                        try
+                        {
+                            sendingAccount = this.CurrentMailItem.SendUsingAccount;
+                            if (sendingAccount == null)
+                            {
+                                ns = Globals.ThisAddIn.Application.Session;
+                                currUser = ns.CurrentUser;
+                                sts = PEPIdentity.Create(currUser, out PEPIdentity 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, Globals.ThisAddIn.Settings.HideInternalMessages);
+                            }
+                        }
+                        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
+                if (this.TimerRefresh != null)
+                {
+                    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.wrappedMailItem != 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.wrappedMailItem.PropertyChanged -= MailItem_PropertyChanged;
+                    this.wrappedMailItem.ResolveAllRecipients();
+                    this.wrappedMailItem.PropertyChanged += MailItem_PropertyChanged;
+                }
+                catch (Exception ex)
+                {
+                    Log.Error("Error resolving recipients. " + ex.ToString());
+                }
+            }
+        }
+        #endregion
+
+        #region Event Handling
+        /**************************************************************
+         * 
+         * Event Handling
+         * 
+         *************************************************************/
+
+        /// <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.wrappedMailItem.IsSecurelyStored || this.wrappedMailItem.IsSecureAttachedMail)
+                                {
+                                    Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
+                                    this.wrappedMailItem.StartGetMirror(this.wrappedMailItem.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("MailItem_ProcessingComplete: 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("MailItem_ProcessingComplete: 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, MailItemWrapper.GetMirrorCompletedEventArgs e)
+        {
+            try
+            {
+                // Marshal code back to UI thread as necessary
+                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
+                {
+                    if (this.isEnabled)
+                    {
+                        // If the message was forcefully protected, there is no mirror and we show the actual message
+                        if ((e.Mirror == null) &&
+                            (this.CurrentMailItem?.GetIsForcefullyProtected() == true))
+                        {
+                            if (PEPMessage.Create(this.CurrentMailItem, out PEPMessage mirror) == Globals.ReturnStatus.Success)
+                            {
+                                e.Mirror = mirror;
+                            }
+                        }
+
+                        if ((e.Mirror == null) &&
+                            (this.wrappedMailItem.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.wrappedMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
+                        {
+                            this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
+                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
+                        }
+                        else
+                        {
+                            FormRegionPreviewUnencrypted formRegionPreviewUnencrypted = this.GetFormRegionPreviewUnencrypted();
+
+                            // If we have a FormRegionPreviewUnencrypted and it's visible, show preview
+                            if (formRegionPreviewUnencrypted?.Visible == true)
+                            {
+                                formRegionPreviewUnencrypted.DisplayState.OriginalEntryId = this.CurrentMailItem?.EntryID;
+                                formRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
+
+                                Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
+                            }
+                            else
+                            {
+                                Log.Error("MailItem_GetMirrorComplete: FormRegionPreviewUnencrypted is null or invisible.");
+                            }
+                        }
+
+                        // Display the mirror if necessary
+                        if ((this.wrappedMailItem != null) &&
+                            (this.displayMirrorRequested))
+                        {
+                            this.wrappedMailItem.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 MailItemWrapper_OriginallyEncryptedStatusUpdated(object sender, EventArgs e)
+        {
+            // Process the mail item now that the cache is updated
+            if (this.wrappedMailItem.IsOriginallyEncrypted)
+            {
+                this.wrappedMailItem.StartProcessing(this.IsDraft);
+            }
+        }
+
+        /// <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)
+        {
+            if ((this.isEnabled) &&
+                (this.wrappedMailItem != null))
+            {
+                // If cryptable mail item is not to be opened, cancel opening
+                if (this.wrappedMailItem.CancelOpen)
+                {
+                    cancel = true;
+                }
+                else if ((this.wrappedMailItem.IsSecurelyStored) &&
+                         (this.wrappedMailItem.IsIncoming || this.wrappedMailItem.IsOriginallyEncrypted || !this.wrappedMailItem.IsDraft))
+                {
+                    // Try to open the mirror
+                    cancel = this.wrappedMailItem.DisplayMirror();
+                }
+            }
+        }
+
+        /// <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.wrappedMailItem.IsBeingProcessed) ||
+                    (this.processingOngoing))
+                {
+                    /* If the mail item is still being processed, this means that the message might go out with
+                     * a different rating than the one that was shown in the UI when sending was initiated.
+                     * As a trade-off between security and user experience, we make at least sure that the
+                     * current outgoing rating preview (which is only wrong under rare circumstances) is not
+                     * smaller than the one shown in the UI. If this is the case, just abort sending.
+                     */
+                    pEpRating outgoingPreviewRating = this.GetOutgoingRatingPreview();
+                    if (this.Rating != outgoingPreviewRating)
+                    {
+                        if (this.Rating > outgoingPreviewRating)
+                        {
+                            Log.Verbose("MailItem_Send: Mail item still being processed.");
+                            cancel = true;
+                            return;
+                        }
+
+                        this.SetRating(outgoingPreviewRating);
+                    }
+                }
+
+                // Show warning message if needed
+                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
+                    (this.Rating < pEpRating.pEpRatingUnreliable) &&
+                    (this.wrappedMailItem.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)
+                {
+                    if ((this.Type == WindowType.Inspector) &&
+                        (this.wrappedMailItem.IsInlineResponse == false) &&
+                        (this.CurrentMailItem.GetProcessingState() == null))
+                    {                        
+                        IntPtr hWnd = NativeMethods.GetActiveWindow();    
+                        NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_BOTTOM, 0, 0, 0, 0, NativeMethods.SetWindowPosFlags.DoNotActivate |
+                                                                                                NativeMethods.SetWindowPosFlags.IgnoreMove |
+                                                                                                NativeMethods.SetWindowPosFlags.DoNotReposition |
+                                                                                                NativeMethods.SetWindowPosFlags.IgnoreResize |
+                                                                                                NativeMethods.SetWindowPosFlags.HideWindow);
+                        this.CurrentMailItem.SetProcessingState(MailItemExtensions.ProcessingState.ProcessInBackground);
+                        Log.Verbose("MailItem_Send: Inspector window closed.");
+                    }
+
+                    // 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);
+                    }
+
+                    // Reset pEp options
+                    this.ForceProtection = false;
+                    this.DisableForceProtection = false;
+                    this.ForceUnencrypted = false;
+                    this.NeverUnsecure = false;
+
+                    // 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 MailItemWrapper.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.wrappedMailItem != null) &&
+                    (this.wrappedMailItem.IsBeingProcessed == false))
+                {
+                    // Attempt to get the download state
+                    try
+                    {
+                        dlState = this.wrappedMailItem.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.MailItemWrapper.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;
+                }
+
+