OUT-78: Renaming and optimization OUT-78
authorThomas
Thu, 14 Mar 2019 15:36:43 +0100
branchOUT-78
changeset 25994a54e3221729
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
     1.1 --- a/CryptableMailItem.cs	Wed Mar 13 13:50:02 2019 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,2045 +0,0 @@
     1.4 -using MimeKit;
     1.5 -using pEp.UI;
     1.6 -using pEpCOMServerAdapterLib;
     1.7 -using System;
     1.8 -using System.Collections.Generic;
     1.9 -using System.ComponentModel;
    1.10 -using System.IO;
    1.11 -using System.Runtime.InteropServices;
    1.12 -using System.Threading;
    1.13 -using System.Threading.Tasks;
    1.14 -using Outlook = Microsoft.Office.Interop.Outlook;
    1.15 -
    1.16 -namespace pEp
    1.17 -{
    1.18 -    /// <summary>
    1.19 -    /// Wrapper for the Outlook MailItem supporting encryption.
    1.20 -    /// </summary>
    1.21 -    internal class CryptableMailItem : INotifyPropertyChanged,
    1.22 -                                       IDisposable
    1.23 -    {
    1.24 -        public const string USER_PROPERTY_KEY_FORCE_UNENCRYPTED         = "sendUnencrypted";
    1.25 -        public const string USER_PROPERTY_KEY_ENABLE_PROTECTION         = "enableProtection";
    1.26 -        public const string USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED   = "isOriginallyEncrypted";
    1.27 -        public const string USER_PROPERTY_KEY_ORIGINAL_RATING           = "originalRating";
    1.28 -
    1.29 -        public delegate void StdMailEventHandler(ref bool cancel);
    1.30 -        public delegate void RespondMailEventHandler(object item, ref bool cancel);
    1.31 -        public delegate void GenericHandler(object sender, EventArgs e);
    1.32 -        public delegate void ProcessingCompletedHandler(object sender, MsgProcessor.ProcessingCompletedEventArgs e);
    1.33 -        public delegate void GetMirrorCompletedHandler(object sender, GetMirrorCompletedEventArgs e);
    1.34 -
    1.35 -        /// <summary>
    1.36 -        /// Event when the internal mail item before delete event occurs.
    1.37 -        /// </summary>
    1.38 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.39 -        public event StdMailEventHandler BeforeDelete;
    1.40 -
    1.41 -        /// <summary>
    1.42 -        /// Event when the internal mail item forward event occurs.
    1.43 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
    1.44 -        /// Do not try to modify the item directly
    1.45 -        /// </summary>
    1.46 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.47 -        public event RespondMailEventHandler Forward;
    1.48 -
    1.49 -        /// <summary>
    1.50 -        /// Event when the internal mail item open event occurs.
    1.51 -        /// </summary>
    1.52 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.53 -        public event StdMailEventHandler Open;
    1.54 -
    1.55 -        /// <summary>
    1.56 -        /// Event when the internal mail item reply event occurs.
    1.57 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
    1.58 -        /// Do not try to modify the item directly
    1.59 -        /// </summary>
    1.60 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.61 -        public event RespondMailEventHandler Reply;
    1.62 -
    1.63 -        /// <summary>
    1.64 -        /// Event when the internal mail item reply to all event occurs.
    1.65 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
    1.66 -        /// Do not try to modify the item directly
    1.67 -        /// </summary>
    1.68 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.69 -        public event RespondMailEventHandler ReplyAll;
    1.70 -
    1.71 -        /// <summary>
    1.72 -        /// Event when the internal mail item send event occurs.
    1.73 -        /// </summary>
    1.74 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.75 -        public event StdMailEventHandler Send;
    1.76 -
    1.77 -        /// <summary>
    1.78 -        /// Event when the internal mail item write event occurs.
    1.79 -        /// </summary>
    1.80 -        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
    1.81 -        public event StdMailEventHandler Write;
    1.82 -
    1.83 -        /// <summary>
    1.84 -        /// Event when either a cryptable mail item property change occurs, or
    1.85 -        /// when the internal mail item property change event occurs.
    1.86 -        /// </summary>
    1.87 -        public event PropertyChangedEventHandler PropertyChanged;
    1.88 -
    1.89 -        /// <summary>
    1.90 -        /// Event when processing of this cryptable mail item is completed.
    1.91 -        /// WARNING: The calling thread is a background worker.
    1.92 -        /// </summary>
    1.93 -        public event ProcessingCompletedHandler ProcessingCompleted;
    1.94 -
    1.95 -        /// <summary>
    1.96 -        /// Event when the get mirror search is completed.
    1.97 -        /// WARNING: The calling thread is a background worker.
    1.98 -        /// </summary>
    1.99 -        public event GetMirrorCompletedHandler GetMirrorCompleted;
   1.100 -
   1.101 -        public delegate void OriginallyEncryptedStatusUpdateHandler(object sender, EventArgs e);
   1.102 -        public event OriginallyEncryptedStatusUpdateHandler OriginallyEncryptedStatusUpdated;
   1.103 -
   1.104 -        private pEpRating            _LastProcessedRating;
   1.105 -        private Globals.ReturnStatus _LastProcessedStatus;
   1.106 -
   1.107 -        private bool                              disposeAfterProcessing;
   1.108 -        private bool                              decrementCounter;
   1.109 -        private Outlook.MailItem                  internalMailItem;
   1.110 -        private BackgroundWorker                  mirrorLocator;
   1.111 -        private BackgroundWorker                  processor;
   1.112 -
   1.113 -        private string                            draftEntryId          = null;
   1.114 -        private string                            draftFileName         = null;
   1.115 -        private object                            mutexMailItem         = new object();
   1.116 -        private static object                     mutexConversation     = new object();
   1.117 -        private static object                     mutexDecryptionList   = new object();
   1.118 -        private static List<OriginalMailItem>     conversationCache     = new List<OriginalMailItem>();
   1.119 -        private static Dictionary<string, string> decryptionList        = new Dictionary<string, string>();
   1.120 -
   1.121 -        /// <summary>
   1.122 -        /// Stores the message id of an attached mail item if it is loaded into the preview.
   1.123 -        /// See comments below in MailItem_BeforeAttachmentPreview event handler.
   1.124 -        /// </summary>
   1.125 -        public static string PreviewAttachedMailId = null;
   1.126 -
   1.127 -        /// <summary>
   1.128 -        /// Whether to cancel the opening event of the internal mail item. Default is false.
   1.129 -        /// </summary>
   1.130 -        public bool CancelOpen { get; set; } = false;
   1.131 -
   1.132 -        /// <summary>
   1.133 -        /// The messageId of the internal mail item. Only needed for special cases like attached mails.
   1.134 -        /// </summary>
   1.135 -        public string MessageId { get; set; } = null;
   1.136 -
   1.137 -        /// <summary>
   1.138 -        /// Whether the internal mail item is an inline response
   1.139 -        /// </summary>
   1.140 -        public bool IsInlineResponse { get; set; } = false;
   1.141 -
   1.142 -        /// <summary>
   1.143 -        /// Whether the internal mail item is an attached mail.
   1.144 -        /// </summary>
   1.145 -        public bool IsSecureAttachedMail { get; set; } = false;
   1.146 -
   1.147 -        /// <summary>
   1.148 -        /// The mirror of the internal mail item stored as PEPMessage.
   1.149 -        /// </summary>
   1.150 -        public PEPMessage Mirror { get; set; } = null;
   1.151 -
   1.152 -        /// <summary>
   1.153 -        /// The PEPMessage of this mail item.
   1.154 -        /// </summary>
   1.155 -        public PEPMessage Message { get; set; } = null;
   1.156 -
   1.157 -        /**************************************************************
   1.158 -         * 
   1.159 -         * Constructors/Destructors
   1.160 -         * 
   1.161 -         *************************************************************/
   1.162 -
   1.163 -        /// <summary>
   1.164 -        /// Primary constructor creating the cryptable mail item from an existing outlook mail item.
   1.165 -        /// </summary>
   1.166 -        /// <param name="mailItem">The mail item to wrap and make cryptable.</param>
   1.167 -        /// <param name="defaultRating">The default rating for this cryptable mail item.</param>
   1.168 -        /// <param name="decrementCounter">Whether or not to decrement the decryption counter after processing.</param>
   1.169 -        public CryptableMailItem(Outlook.MailItem mailItem,
   1.170 -                                 pEpRating? defaultRating = null,
   1.171 -                                 bool decrementCounter = false)
   1.172 -        {
   1.173 -            this.internalMailItem = mailItem;
   1.174 -            this.ConnectInternalMailItemEvents(true);
   1.175 -
   1.176 -            this.disposeAfterProcessing = false;
   1.177 -            this.decrementCounter = decrementCounter;
   1.178 -            this._LastProcessedRating = defaultRating ?? pEpRating.pEpRatingUndefined;
   1.179 -            this._LastProcessedStatus = Globals.ReturnStatus.Success;
   1.180 -
   1.181 -            // Setup the message processor background worker
   1.182 -            this.processor = new BackgroundWorker
   1.183 -            {
   1.184 -                WorkerSupportsCancellation = false,
   1.185 -            };
   1.186 -            this.processor.RunWorkerCompleted += Processor_RunWorkerCompleted;
   1.187 -            this.processor.DoWork += Processor_DoWork;
   1.188 -
   1.189 -            // Setup the mirror locator background worker
   1.190 -            this.mirrorLocator = new BackgroundWorker
   1.191 -            {
   1.192 -                WorkerSupportsCancellation = false
   1.193 -            };
   1.194 -            this.mirrorLocator.RunWorkerCompleted += MirrorLocator_RunWorkerCompleted;
   1.195 -            this.mirrorLocator.DoWork += MirrorLocator_DoWork;
   1.196 -        }
   1.197 -
   1.198 -        /// <summary>
   1.199 -        /// Destructor.
   1.200 -        /// </summary>
   1.201 -        ~CryptableMailItem()
   1.202 -        {
   1.203 -            // This should have been called in code before garbage collection, but call it just in case
   1.204 -            this.Dispose(true);
   1.205 -        }
   1.206 -
   1.207 -        /**************************************************************
   1.208 -         * 
   1.209 -         * Event Handling
   1.210 -         * 
   1.211 -         *************************************************************/
   1.212 -
   1.213 -        /// <summary>
   1.214 -        /// Event hander for when an attachment is previewed. Occurs before the preview occurs
   1.215 -        /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.beforeattachmentpreview.aspx
   1.216 -        /// </summary>
   1.217 -        /// <param name="attachment">The attachment that is about to be previewed.</param>
   1.218 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.219 -        /// If the event procedure sets this argument to True, the operation is not completed
   1.220 -        /// and the attachment is not previewed.</param>
   1.221 -        private void MailItem_BeforeAttachmentPreview(Outlook.Attachment attachment, ref bool cancel)
   1.222 -        {
   1.223 -            /* Check if the attachment to be previewed is a mail item and store its messageId in the 
   1.224 -             * static PreviewAttachedMailId property. This is a somewhat clumsy workaround, but is needed
   1.225 -             * because we need to know upon processing of the mail item whether it is an attached mail
   1.226 -             * and whether it is opened (a) or previewed (b).
   1.227 -             *      => a. Cancel opening and open mirror
   1.228 -             *      => b. Display mirror in preview window
   1.229 -             * As all methods to store the relevant information directly in the attached mail failed, we 
   1.230 -             * set the messageId during this event and query it in FormRegionPrivacyStatus_FormRegionShowing.
   1.231 -             */
   1.232 -            try
   1.233 -            {
   1.234 -                PEPAttachment attach = new PEPAttachment(attachment);
   1.235 -
   1.236 -                // Exclude based on file name and/or MIME type (for performance)
   1.237 -                if ((attach.Data != null) &&
   1.238 -                    ((Path.GetExtension(attach.FileName)?.Equals(".eml") == true) ||
   1.239 -                     (Path.GetExtension(attach.FileName)?.Equals(".msg") == true) ||
   1.240 -                     (attach.MimeType?.Equals("text/rfc822") == true)))
   1.241 -                {
   1.242 -                    // Try to convert attachment into MIME message
   1.243 -                    MimeMessage message;
   1.244 -                    MemoryStream memoryStream;
   1.245 -                    using (memoryStream = new MemoryStream(attach.Data))
   1.246 -                    {
   1.247 -                        message = MimeMessage.Load(memoryStream);
   1.248 -                    }
   1.249 -
   1.250 -                    // If conversion was successful, attachment is mail
   1.251 -                    if (message != null)
   1.252 -                    {
   1.253 -                        string messageId = null;
   1.254 -
   1.255 -                        // Retrieve the mail's messageId
   1.256 -                        if (message?.Headers?.Contains(HeaderId.MessageId) == true)
   1.257 -                        {
   1.258 -                            messageId = message.Headers?[HeaderId.MessageId];
   1.259 -                        }
   1.260 -
   1.261 -                        // Save messageId
   1.262 -                        if (string.IsNullOrEmpty(messageId) == false)
   1.263 -                        {
   1.264 -                            CryptableMailItem.PreviewAttachedMailId = messageId;
   1.265 -                        }
   1.266 -                    }
   1.267 -                }
   1.268 -            }
   1.269 -            catch (Exception ex)
   1.270 -            {
   1.271 -                CryptableMailItem.PreviewAttachedMailId = null;
   1.272 -                Log.Error("MailItem_BeforeAttachmentPreview: Error determining if attachment is mail. " + ex.ToString());
   1.273 -            }
   1.274 -        }
   1.275 -
   1.276 -        /// <summary>
   1.277 -        /// Event hander for when the internal mail item is deleted.
   1.278 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff861266.aspx
   1.279 -        /// </summary>
   1.280 -        /// <param name="item">The item being deleted.</param>
   1.281 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.282 -        /// If the event procedure sets this argument to True, the operation is not completed
   1.283 -        /// and the item is not deleted.</param>
   1.284 -        private void MailItem_BeforeDelete(object item, ref bool cancel)
   1.285 -        {
   1.286 -            this.BeforeDelete?.Invoke(ref cancel);
   1.287 -            return;
   1.288 -        }
   1.289 -
   1.290 -        /// <summary>
   1.291 -        /// Event handler for when the internal mail item is forwarded.
   1.292 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   1.293 -        /// Do not try to modify the item directly
   1.294 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff862702.aspx
   1.295 -        /// </summary>
   1.296 -        /// <param name="item">The new item being forwarded.</param>
   1.297 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs.
   1.298 -        /// If the event procedure sets this argument to True, the forward operation is not completed 
   1.299 -        /// and the new item is not displayed.</param>
   1.300 -        private void MailItem_Forward(object item, ref bool cancel)
   1.301 -        {
   1.302 -            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
   1.303 -
   1.304 -            this.Forward?.Invoke(item, ref cancel);
   1.305 -            return;
   1.306 -        }
   1.307 -
   1.308 -        /// <summary>
   1.309 -        /// Event handler for when the internal mail item is being opened in an inspector.
   1.310 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
   1.311 -        /// </summary>
   1.312 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.313 -        /// If the event procedure sets this argument to True, the open operation is not completed 
   1.314 -        /// and the inspector is not displayed.</param>
   1.315 -        private void MailItem_Open(ref bool cancel)
   1.316 -        {
   1.317 -            cancel = this.CancelOpen;
   1.318 -
   1.319 -            this.Open?.Invoke(ref cancel);
   1.320 -            return;
   1.321 -        }
   1.322 -
   1.323 -        /// <summary>
   1.324 -        /// Event handler for when the internal mail item property is changed.
   1.325 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
   1.326 -        /// </summary>
   1.327 -        /// <param name="propertyName">The name of the property that was changed.</param>
   1.328 -        private void MailItem_PropertyChange(string propertyName)
   1.329 -        {
   1.330 -            this.RaisePropertyChangedEvent(propertyName);
   1.331 -            return;
   1.332 -        }
   1.333 -
   1.334 -        /// <summary>
   1.335 -        /// Event handler for when the internal mail item is replied to.
   1.336 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   1.337 -        /// Do not try to modify the item directly
   1.338 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
   1.339 -        /// </summary>
   1.340 -        /// <param name="item">The new item being sent in response to the original message.</param>
   1.341 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.342 -        /// If the event procedure sets this argument to True, the reply operation is not completed 
   1.343 -        /// and the new item is not displayed.</param>
   1.344 -        private void MailItem_Reply(object item, ref bool cancel)
   1.345 -        {
   1.346 -            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
   1.347 -
   1.348 -            this.Reply?.Invoke(item, ref cancel);
   1.349 -            return;
   1.350 -        }
   1.351 -
   1.352 -        /// <summary>
   1.353 -        /// Event handler for when the internal mail item is replied to all recipients.
   1.354 -        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   1.355 -        /// Do not try to modify the item directly
   1.356 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
   1.357 -        /// </summary>
   1.358 -        /// <param name="item">The new item being sent in response to the original message.</param>
   1.359 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.360 -        /// If the event procedure sets this argument to True, the reply operation is not completed 
   1.361 -        /// and the new item is not displayed.</param>
   1.362 -        private void MailItem_ReplyAll(object item, ref bool cancel)
   1.363 -        {
   1.364 -            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
   1.365 -
   1.366 -            this.ReplyAll?.Invoke(item, ref cancel);
   1.367 -            return;
   1.368 -        }
   1.369 -
   1.370 -        /// <summary>
   1.371 -        /// Event handler for when the internal mail item is sent.
   1.372 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
   1.373 -        /// </summary>
   1.374 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.375 -        /// If the event procedure sets this argument to True, the send operation is not completed 
   1.376 -        /// and the inspector is left open.</param>
   1.377 -        private void MailItem_Send(ref bool cancel)
   1.378 -        {
   1.379 -            try
   1.380 -            {
   1.381 -                this.Send?.Invoke(ref cancel);
   1.382 -            }
   1.383 -            catch (Exception)
   1.384 -            {
   1.385 -                throw;
   1.386 -            }
   1.387 -
   1.388 -            this.HasBeenSent = true;
   1.389 -
   1.390 -            return;
   1.391 -        }
   1.392 -
   1.393 -        /// <summary>
   1.394 -        /// Event handler for when the internal mail item is written (Save, SaveAs, etc...)
   1.395 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff868664.aspx
   1.396 -        /// </summary>
   1.397 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
   1.398 -        /// If the event procedure sets this argument to True, the save operation is not completed.
   1.399 -        /// </param>
   1.400 -        private void MailItem_Write(ref bool cancel)
   1.401 -        {
   1.402 -#if !READER_RELEASE_MODE
   1.403 -            /* Save drafts for untrusted servers in a secure location.
   1.404 -             * First we try to save it to a custom drafts folder in the pEp store
   1.405 -             * and make this store visible in the favorites.
   1.406 -             * If this fails, as a fallback solution, we offer to save as a message file.
   1.407 -             * Note: Inline responses need to be processed differently.
   1.408 -             */
   1.409 -            if ((this.HasBeenSent == false) &&
   1.410 -                (this.IsPEPMessage == false) &&
   1.411 -                (this.internalMailItem.GetIsDraft()) &&
   1.412 -                ((this.internalMailItem.GetIsInSecureStore() || this.internalMailItem.GetNeverUnsecure())))
   1.413 -            {
   1.414 -                bool useFallback = false;
   1.415 -                Outlook.Folder parentFolder = null;
   1.416 -                Outlook.Folder pEpDraftsFolder = null;
   1.417 -                Outlook.Inspector currentInspector = null;
   1.418 -                Outlook.Inspector newInspector = null;
   1.419 -                Outlook.MailItem omi = null;
   1.420 -
   1.421 -                Outlook.Application app = null;
   1.422 -                Outlook.Explorer activeExplorer = null;
   1.423 -                Outlook.NavigationPane navPane = null;
   1.424 -                Outlook.NavigationModules navModules = null;
   1.425 -                Outlook.MailModule mailModule = null;
   1.426 -                Outlook.NavigationGroups navGroups = null;
   1.427 -                Outlook.NavigationGroup navGroup = null;
   1.428 -                Outlook.NavigationFolders navFolders = null;
   1.429 -
   1.430 -                try
   1.431 -                {
   1.432 -                    // Get the pEp drafts folder and the current mail item's folder
   1.433 -                    pEpDraftsFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
   1.434 -
   1.435 -                    // Get the caret position to later set it again
   1.436 -                    bool caretPositionRetrieved = false;
   1.437 -                    NativeMethods.Point caretPosition = new NativeMethods.Point(-1,-1);
   1.438 -                    IntPtr inspectorHandle = IntPtr.Zero;
   1.439 -
   1.440 -                    try
   1.441 -                    {
   1.442 -                        // First, get the current process to retrieve a handle to the caret's window
   1.443 -                        uint currentThreadId = NativeMethods.GetCurrentThreadId();
   1.444 -                        NativeMethods.GuiThreadInfo guiThreadInfo = new NativeMethods.GuiThreadInfo();
   1.445 -                        guiThreadInfo.size = Marshal.SizeOf(guiThreadInfo);
   1.446 -
   1.447 -                        if (NativeMethods.GetGUIThreadInfo(currentThreadId, ref guiThreadInfo))
   1.448 -                        {
   1.449 -                            inspectorHandle = guiThreadInfo.hwndCaret;
   1.450 -
   1.451 -                            // Get caret position and convert to screen coordinates
   1.452 -                            if (NativeMethods.GetCaretPos(out caretPosition) &&
   1.453 -                                NativeMethods.ClientToScreen(inspectorHandle, ref caretPosition))
   1.454 -                            {
   1.455 -                                caretPositionRetrieved = true;
   1.456 -                            }
   1.457 -                            else
   1.458 -                            {
   1.459 -                                int error = Marshal.GetLastWin32Error();
   1.460 -                                Log.Error("MailItem_Write: Error getting caret position. Last Win32 error: " + error.ToString("X"));
   1.461 -                            }
   1.462 -                        }
   1.463 -                        else
   1.464 -                        {
   1.465 -                            int error = Marshal.GetLastWin32Error();
   1.466 -                            Log.Error("MailItem_Write: Error getting inspector Handle. Last Win32 error: " + error.ToString("X"));
   1.467 -                        }
   1.468 -                    }
   1.469 -                    catch (Exception ex)
   1.470 -                    {
   1.471 -                        Log.Error("MailItem_Write: Error getting caret position. " + ex.ToString());
   1.472 -                    }
   1.473 -
   1.474 -                    /* Inline responses need a special treatment.
   1.475 -                     * We cannot just intercept the Write event and check, if the item
   1.476 -                     * is in the pEp folder, as it gets synced to the server anyhow if we
   1.477 -                     * don't cancel the event.
   1.478 -                     * So, we look up if the mail item is already present in pEp drafts and overwrite it 
   1.479 -                     * with the current state if possible. If the item isn't there yet, create new item, 
   1.480 -                     * move to pEp drafts folder and save current state.
   1.481 -                     */
   1.482 -                    if (this.IsInlineResponse)
   1.483 -                    {
   1.484 -                        Outlook.Items items = null;
   1.485 -                        Outlook.MailItem draft = null;
   1.486 -
   1.487 -                        try
   1.488 -                        {
   1.489 -                            // Always cancel
   1.490 -                            cancel = true;
   1.491 -
   1.492 -                            // Try to find the draft (if existing)
   1.493 -                            if (string.IsNullOrEmpty(this.draftEntryId) == false)
   1.494 -                            {
   1.495 -                                // Get all items in the pEp drafts folder with the same subject as the current draft
   1.496 -                                items = pEpDraftsFolder?.Items?.Restrict(string.Format("[Subject] = '{0}'", this.internalMailItem?.Subject));
   1.497 -
   1.498 -                                for (int i = 1; i <= items?.Count; i++)
   1.499 -                                {
   1.500 -                                    draft = items[i] as Outlook.MailItem;
   1.501 -
   1.502 -                                    if (draftEntryId.Equals(draft?.EntryID) == true)
   1.503 -                                    {
   1.504 -                                        // Draft found. Just break and continue.
   1.505 -                                        break;
   1.506 -                                    }
   1.507 -
   1.508 -                                    draft = null;
   1.509 -                                }
   1.510 -
   1.511 -                                items = null;
   1.512 -                            }
   1.513 -
   1.514 -                            if (PEPMessage.Create(this.internalMailItem, out PEPMessage createdMessage) == Globals.ReturnStatus.Success)
   1.515 -                            {
   1.516 -                                if (draft == null)
   1.517 -                                {
   1.518 -                                    draft = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
   1.519 -                                    createdMessage.ApplyTo(draft, true, true);
   1.520 -                                    draft = draft.Move(pEpDraftsFolder);
   1.521 -                                    draft.Save();
   1.522 -                                    this.draftEntryId = draft.EntryID;
   1.523 -                                }
   1.524 -                                else
   1.525 -                                {
   1.526 -                                    createdMessage.ApplyTo(draft, true, true);
   1.527 -                                    draft.Save();
   1.528 -                                }
   1.529 -                            }
   1.530 -                            else
   1.531 -                            {
   1.532 -                                Log.Error("MailItem_Write: Error creating PEPMessage.");
   1.533 -                            }
   1.534 -                        }
   1.535 -                        catch (Exception ex)
   1.536 -                        {
   1.537 -                            Log.Error("MailItem_Write: Error saving inline item. " + ex.ToString());
   1.538 -                        }
   1.539 -                        finally
   1.540 -                        {
   1.541 -                            items = null;
   1.542 -                            omi = null;
   1.543 -                        }
   1.544 -                    }
   1.545 -                    else
   1.546 -                    {
   1.547 -                        // Get the mail item's parent folder
   1.548 -                        parentFolder = this.internalMailItem.Parent as Outlook.Folder;
   1.549 -
   1.550 -                        // Save to pEp folder if not already there
   1.551 -                        if (pEpDraftsFolder?.FullFolderPath?.Equals(parentFolder?.FullFolderPath) == false)
   1.552 -                        {
   1.553 -                            currentInspector = this.internalMailItem.GetInspector;
   1.554 -                            omi = this.internalMailItem.Copy();
   1.555 -                            omi = omi.Move(pEpDraftsFolder);
   1.556 -
   1.557 -                            if (currentInspector != null)
   1.558 -                            {
   1.559 -                                Outlook.OlWindowState windowState = currentInspector.WindowState;
   1.560 -                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
   1.561 -
   1.562 -                                if (windowState == Outlook.OlWindowState.olNormalWindow)
   1.563 -                                {
   1.564 -                                    newInspector.Left = currentInspector.Left;
   1.565 -                                    newInspector.Top = currentInspector.Top;
   1.566 -                                    newInspector.Width = currentInspector.Width;
   1.567 -                                    newInspector.Height = currentInspector.Height;
   1.568 -                                }
   1.569 -
   1.570 -                                /* In some circumstances (e.g. ForceProtection on Exchange), the Sender information 
   1.571 -                                 * may be missing. If this is the case, try to add it from the internal mail item.
   1.572 -                                 */
   1.573 -                                try
   1.574 -                                {
   1.575 -                                    // Check if there really is no useful Sender information
   1.576 -                                    if ((omi != null) &&
   1.577 -                                        (omi.Sender == null) &&
   1.578 -                                        (string.IsNullOrEmpty(omi.SenderEmailAddress)) &&
   1.579 -                                        (omi.SendUsingAccount == null))
   1.580 -                                    {
   1.581 -                                        // Try to add SendUsingAccount
   1.582 -                                        if (this.internalMailItem.SendUsingAccount != null)
   1.583 -                                        {
   1.584 -                                            omi.SendUsingAccount = this.internalMailItem.SendUsingAccount;
   1.585 -                                        }
   1.586 -
   1.587 -                                        // Try to add the Sender directly
   1.588 -                                        if (this.internalMailItem.Sender != null)
   1.589 -                                        {
   1.590 -                                            omi.Sender = this.internalMailItem.Sender;
   1.591 -                                        }
   1.592 -                                    }
   1.593 -                                }
   1.594 -                                catch (Exception ex)
   1.595 -                                {
   1.596 -                                    Log.Error("MailItem_Write: Error determining/setting sender information of new Inspector. " + ex.ToString());
   1.597 -                                }
   1.598 -
   1.599 -                                newInspector.Display();
   1.600 -                                newInspector.WindowState = windowState;
   1.601 -                                currentInspector.Close(Outlook.OlInspectorClose.olDiscard);
   1.602 -
   1.603 -                                // Set caret position again to where it was before
   1.604 -                                if (caretPositionRetrieved)
   1.605 -                                {
   1.606 -                                    try
   1.607 -                                    {
   1.608 -                                        // Set cursor to the caret's previous position
   1.609 -                                        NativeMethods.SetCursorPos(caretPosition.X, caretPosition.Y);
   1.610 -
   1.611 -                                        // Send mouse click event (mouse down and mouse up)
   1.612 -                                        NativeMethods.Input[] inputs = new NativeMethods.Input[1];
   1.613 -                                        inputs[0].Type = (int)NativeMethods.InputType.InputMouse;
   1.614 -                                        inputs[0].Mi.Flags = (int)NativeMethods.MouseEvents.MouseEventFLeftDown | (int)NativeMethods.MouseEvents.MouseEventFLeftUp;
   1.615 -
   1.616 -                                        if (NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])) == 0)
   1.617 -                                        {
   1.618 -                                            int error = Marshal.GetLastWin32Error();
   1.619 -                                            Log.Error("MailItem_Write: Error setting caret to original position. Win32 error " + error.ToString("X"));
   1.620 -                                        }
   1.621 -                                    }
   1.622 -                                    catch (Exception ex)
   1.623 -                                    {
   1.624 -                                        Log.Error("MailItem_Write: Error setting caret to original position. " + ex.ToString());
   1.625 -                                    }
   1.626 -                                }
   1.627 -                            }
   1.628 -                            else
   1.629 -                            {
   1.630 -                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
   1.631 -                                newInspector.Display();
   1.632 -                            }
   1.633 -
   1.634 -                            cancel = true;
   1.635 -                        }
   1.636 -                    }
   1.637 -
   1.638 -                    /* Add the pEp drafts folder to favorites.
   1.639 -                     * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
   1.640 -                     * To make this more secure, we only proceed if the pEp store is already visible at this point.
   1.641 -                     * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
   1.642 -                     * to the favorites next time.
   1.643 -                     */
   1.644 -                    if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
   1.645 -                    {
   1.646 -                        // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
   1.647 -                        app = Globals.ThisAddIn?.Application;
   1.648 -                        activeExplorer = app?.ActiveExplorer();
   1.649 -                        navPane = activeExplorer?.NavigationPane;
   1.650 -                        navModules = navPane?.Modules;
   1.651 -                        mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
   1.652 -                        navGroups = mailModule?.NavigationGroups;
   1.653 -                        navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
   1.654 -                        navFolders = navGroup?.NavigationFolders;
   1.655 -
   1.656 -                        /* Check, if pEp drafts folder is already in favorites
   1.657 -                         * WARNING: If for whatever reason, the pEp store is not visible
   1.658 -                         * at this point, the Add() method crashes Outlook!
   1.659 -                         */
   1.660 -                        if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
   1.661 -                        {
   1.662 -                            if (navFolders != null)
   1.663 -                            {
   1.664 -                                navFolders.Add(pEpDraftsFolder);
   1.665 -                            }
   1.666 -                            else
   1.667 -                            {
   1.668 -                                Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
   1.669 -                            }
   1.670 -                        }
   1.671 -                    }
   1.672 -                    else
   1.673 -                    {
   1.674 -                        Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
   1.675 -                    }
   1.676 -                }
   1.677 -                catch (Exception ex)
   1.678 -                {
   1.679 -                    Log.Error("MailItem_Write: Error while saving to pEp Drafts folder. " + ex.ToString());
   1.680 -                    useFallback = true;
   1.681 -                }
   1.682 -                finally
   1.683 -                {
   1.684 -                    currentInspector = null;
   1.685 -                    parentFolder = null;
   1.686 -                    pEpDraftsFolder = null;
   1.687 -                    omi = null;
   1.688 -
   1.689 -                    app = null;
   1.690 -                    activeExplorer = null;
   1.691 -                    navPane = null;
   1.692 -                    navModules = null;
   1.693 -                    mailModule = null;
   1.694 -                    navGroups = null;
   1.695 -                    navGroup = null;
   1.696 -                    navFolders = null;
   1.697 -                }
   1.698 -
   1.699 -                if (useFallback)
   1.700 -                {
   1.701 -                    Log.Verbose("MailItem_Write: pEp folder could not be found or created. Trying fallback");
   1.702 -
   1.703 -                    // Fallback solution
   1.704 -                    if (draftFileName == null)
   1.705 -                    {
   1.706 -                        var result = System.Windows.MessageBox.Show(Properties.Resources.DraftProtection_Warning, Properties.Resources.DraftProtection_Title, System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Exclamation);
   1.707 -                        if (result == System.Windows.MessageBoxResult.Yes)
   1.708 -                        {
   1.709 -                            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
   1.710 -                            {
   1.711 -                                Filter = Properties.Resources.DraftProtection_MSG_Format + " (*.msg)|*.msg",
   1.712 -                                FilterIndex = 1
   1.713 -                            };
   1.714 -                            if (string.IsNullOrEmpty(this.internalMailItem.Subject) == false)
   1.715 -                                sfd.FileName = this.internalMailItem.Subject;
   1.716 -                            var r = sfd.ShowDialog();
   1.717 -                            if (r == System.Windows.Forms.DialogResult.OK)
   1.718 -                            {
   1.719 -                                draftFileName = sfd.FileName;
   1.720 -                                this.internalMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
   1.721 -                            }
   1.722 -                        }
   1.723 -
   1.724 -                        cancel = true;
   1.725 -                    }
   1.726 -                    else
   1.727 -                    {
   1.728 -                        this.internalMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
   1.729 -                        cancel = true;
   1.730 -                    }
   1.731 -                }
   1.732 -            }
   1.733 -#endif
   1.734 -            this.Write?.Invoke(ref cancel);
   1.735 -            return;
   1.736 -        }
   1.737 -
   1.738 -        /**************************************************************
   1.739 -         * 
   1.740 -         * Property Accessors
   1.741 -         * 
   1.742 -         *************************************************************/
   1.743 -
   1.744 -        /// <summary>
   1.745 -        /// Returns a constant that belongs to the OlDownloadState enumeration indicating the download state of the item.
   1.746 -        /// This forwards the call to the internal mail item.
   1.747 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff866978.aspx
   1.748 -        /// </summary>
   1.749 -        public Outlook.OlDownloadState DownloadState
   1.750 -        {
   1.751 -            get
   1.752 -            {
   1.753 -                lock (mutexMailItem)
   1.754 -                {
   1.755 -                    return (this.internalMailItem.DownloadState);
   1.756 -                }
   1.757 -            }
   1.758 -        }
   1.759 -
   1.760 -        /// <summary>
   1.761 -        /// Gets or sets the cryptable mail item enable proctection status.
   1.762 -        /// This information is stored as a user property of the wrapped mail item.
   1.763 -        /// Warning: This will call .Save() on the MailItem.
   1.764 -        /// </summary>
   1.765 -        public bool EnableProtection
   1.766 -        {
   1.767 -            get
   1.768 -            {
   1.769 -                object propValue;
   1.770 -
   1.771 -                lock (mutexMailItem)
   1.772 -                {
   1.773 -                    // Return status can be ignored here, using the auto default value is good enough
   1.774 -                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, out propValue);
   1.775 -                }
   1.776 -
   1.777 -                return ((bool)propValue);
   1.778 -            }
   1.779 -            set
   1.780 -            {
   1.781 -                lock (mutexMailItem)
   1.782 -                {
   1.783 -                    // Return status can be ignored
   1.784 -                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, value);
   1.785 -                    this.internalMailItem.Save();
   1.786 -                }
   1.787 -
   1.788 -                this.RaisePropertyChangedEvent(nameof(this.EnableProtection));
   1.789 -            }
   1.790 -        }
   1.791 -
   1.792 -        /// <summary>
   1.793 -        /// Gets or sets the cryptable mail item force unencrypted status.
   1.794 -        /// This information is stored as a user property of the wrapped mail item.
   1.795 -        /// Warning: This will call .Save() on the MailItem.
   1.796 -        /// </summary>
   1.797 -        public bool ForceUnencrypted
   1.798 -        {
   1.799 -            get
   1.800 -            {
   1.801 -                object propValue;
   1.802 -
   1.803 -                lock (mutexMailItem)
   1.804 -                {
   1.805 -                    // Return status can be ignored here, using the auto default value is good enough
   1.806 -                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, out propValue);
   1.807 -                }
   1.808 -
   1.809 -                return ((bool)propValue);
   1.810 -            }
   1.811 -            set
   1.812 -            {
   1.813 -                lock (mutexMailItem)
   1.814 -                {
   1.815 -                    // Return status can be ignored
   1.816 -                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, value);
   1.817 -                    this.internalMailItem.Save();
   1.818 -                }
   1.819 -
   1.820 -                this.RaisePropertyChangedEvent(nameof(this.ForceUnencrypted));
   1.821 -            }
   1.822 -        }
   1.823 -
   1.824 -        /// <summary>
   1.825 -        /// Gets or sets whether this cryptable mail item has already been sent.
   1.826 -        /// </summary>
   1.827 -        public bool HasBeenSent { get; set; } = false;
   1.828 -
   1.829 -        /// <summary>
   1.830 -        /// Gets whether this cryptable mail item is currently being processed.
   1.831 -        /// </summary>
   1.832 -        public bool IsBeingProcessed
   1.833 -        {
   1.834 -            get
   1.835 -            {
   1.836 -                return (this.processor.IsBusy);
   1.837 -            }
   1.838 -        }
   1.839 -
   1.840 -        /// <summary>
   1.841 -        /// Gets whether the cryptable mail item is marked as a draft (unsent).
   1.842 -        /// </summary>
   1.843 -        public bool IsDraft
   1.844 -        {
   1.845 -            get
   1.846 -            {
   1.847 -                lock (mutexMailItem)
   1.848 -                {
   1.849 -                    return (this.internalMailItem.GetIsDraft());
   1.850 -                }
   1.851 -            }
   1.852 -        }
   1.853 -
   1.854 -        /// <summary>
   1.855 -        /// Gets whether the cryptable mail item is marked as incoming (received mail, not sent).
   1.856 -        /// </summary>
   1.857 -        public bool IsIncoming
   1.858 -        {
   1.859 -            get
   1.860 -            {
   1.861 -                lock (mutexMailItem)
   1.862 -                {
   1.863 -                    return (this.internalMailItem.GetIsIncoming());
   1.864 -                }
   1.865 -            }
   1.866 -        }
   1.867 -
   1.868 -        /// <summary>
   1.869 -        /// Gets whether the wrapped mail item was marked as being originally encrypted.
   1.870 -        /// This should have been set by calling SetIsOriginallyEncryptedByCache() during the 
   1.871 -        /// EncryptedConversationCacheUpdated event.
   1.872 -        /// False is returned if the property is either false or null (doesn't exist).
   1.873 -        /// </summary>
   1.874 -        public bool IsOriginallyEncrypted
   1.875 -        {
   1.876 -            get
   1.877 -            {
   1.878 -                bool isOriginallyEncrypted = false;
   1.879 -                lock (mutexMailItem)
   1.880 -                {
   1.881 -                    try
   1.882 -                    {
   1.883 -                        isOriginallyEncrypted = ((this.internalMailItem.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED) as bool?) == true);
   1.884 -                    }
   1.885 -                    catch (Exception ex)
   1.886 -                    {
   1.887 -                        Log.Error("IsOriginallyEncrypted: Error occured. " + ex.ToString());
   1.888 -                    }
   1.889 -                }
   1.890 -
   1.891 -                return isOriginallyEncrypted;
   1.892 -            }
   1.893 -        }
   1.894 -
   1.895 -        /// <summary>
   1.896 -        /// Determines whether a cryptable mail item has been processed through pEp. This is done by checking if a pEp protocol
   1.897 -        /// version is available for the item.
   1.898 -        /// </summary>
   1.899 -        protected bool IsPEPMessage
   1.900 -        {
   1.901 -            get
   1.902 -            {
   1.903 -                MailItemExtensions.GetPEPProperty(internalMailItem, MailItemExtensions.PEPProperty.PEPProtocolVersion, out object version);
   1.904 -                return version != null;
   1.905 -            }
   1.906 -        }
   1.907 -
   1.908 -        /// <summary>
   1.909 -        /// Gets if the given Outlook mail item should be securely stored (use a mirror).
   1.910 -        /// </summary>
   1.911 -        public bool IsSecurelyStored
   1.912 -        {
   1.913 -            get
   1.914 -            {
   1.915 -                lock (mutexMailItem)
   1.916 -                {
   1.917 -                    return (this.internalMailItem.GetIsSecurelyStored());
   1.918 -                }
   1.919 -            }
   1.920 -        }
   1.921 -
   1.922 -        /// <summary>
   1.923 -        /// Gets or sets whether this cryptable mail item is marked to never be unsecure (always encrypted).
   1.924 -        /// This information is stored as a MAPI property of the wrapped mail item.
   1.925 -        /// Warning: This will call .Save() on the MailItem.
   1.926 -        /// </summary>
   1.927 -        public bool NeverUnsecure
   1.928 -        {
   1.929 -            get
   1.930 -            {
   1.931 -                object propValue;
   1.932 -
   1.933 -                lock (mutexMailItem)
   1.934 -                {
   1.935 -                    // Return status can be ignored here, using the auto default value is good enough
   1.936 -                    this.internalMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, out propValue);
   1.937 -                }
   1.938 -
   1.939 -                return ((bool)propValue);
   1.940 -            }
   1.941 -            set
   1.942 -            {
   1.943 -                lock (mutexMailItem)
   1.944 -                {
   1.945 -                    // Return status can be ignored
   1.946 -                    this.internalMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, value);
   1.947 -                    this.internalMailItem.Save();
   1.948 -                }
   1.949 -
   1.950 -                this.RaisePropertyChangedEvent(nameof(this.NeverUnsecure));
   1.951 -            }
   1.952 -        }
   1.953 -
   1.954 -        /// <summary>
   1.955 -        /// Gets the status after the last message processing.
   1.956 -        /// This should be used to determine if a failure occured.
   1.957 -        /// Success is the default if no processing has been completed.
   1.958 -        /// </summary>
   1.959 -        public Globals.ReturnStatus LastProcessedStatus
   1.960 -        {
   1.961 -            get { return (this._LastProcessedStatus); }
   1.962 -        }
   1.963 -
   1.964 -        /// <summary>
   1.965 -        /// Gets the personal identity using the internal mail item.
   1.966 -        /// Warning: This can return null.
   1.967 -        /// </summary>
   1.968 -        public PEPIdentity Myself
   1.969 -        {
   1.970 -            get
   1.971 -            {
   1.972 -                PEPIdentity ident = null;
   1.973 -                Globals.ReturnStatus sts;
   1.974 -
   1.975 -                lock (mutexMailItem)
   1.976 -                {
   1.977 -                    sts = PEPIdentity.GetOwnIdentity(this.internalMailItem, out ident);
   1.978 -                }
   1.979 -
   1.980 -                if (sts != Globals.ReturnStatus.Success)
   1.981 -                {
   1.982 -                    ident = null;
   1.983 -                }
   1.984 -
   1.985 -                return (ident);
   1.986 -            }
   1.987 -        }
   1.988 -
   1.989 -        /**************************************************************
   1.990 -         * 
   1.991 -         * Decryption
   1.992 -         * 
   1.993 -         *************************************************************/
   1.994 -
   1.995 -        /// <summary>
   1.996 -        /// Decrypts (if necessary, managing any mirrors) and returns the pEp rating for this cryptable mail item.
   1.997 -        /// The calculated rating will be returned but it is already set as the property value by this method.
   1.998 -        /// If rating is ever undefined: it can be assumed an error occured.
   1.999 -        /// </summary>
  1.1000 -        private ProcessingResult ProcessAndGetRating(string entryId)
  1.1001 -        {
  1.1002 -            ProcessingResult result = new ProcessingResult();
  1.1003 -
  1.1004 -            Log.Verbose("ProcessAndGetRating: Started.");
  1.1005 -
  1.1006 -            lock (mutexMailItem)
  1.1007 -            {
  1.1008 -                bool isDraft;
  1.1009 -                bool isPEPInternal = false;
  1.1010 -                bool isSecurelyStored = false;
  1.1011 -                bool isSubmitted;
  1.1012 -                bool fullCalculation = true;
  1.1013 -                bool preProcessingPropertySet = false;
  1.1014 -                bool saveInternalMailItem = false;
  1.1015 -                Outlook.MailItem mirrorMailItem = null;
  1.1016 -                PEPMessage message = null;
  1.1017 -                PEPMessage mirror = null;
  1.1018 -                pEpDecryptFlags decryptionFlags;
  1.1019 -                MsgProcessor msgProcessor = new MsgProcessor();
  1.1020 -                Globals.ReturnStatus sts1;
  1.1021 -                Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  1.1022 -
  1.1023 -                // Reset status
  1.1024 -                this._LastProcessedStatus = Globals.ReturnStatus.Success;
  1.1025 -
  1.1026 -                // Log the download status which can influence later processing
  1.1027 -                try
  1.1028 -                {
  1.1029 -                    Log.Verbose("ProcessAndGetRating: DownloadState=" + this.internalMailItem.DownloadState.ToString());
  1.1030 -                }
  1.1031 -                catch { }
  1.1032 -
  1.1033 -                // Detect if the mail item is a draft
  1.1034 -                isDraft = this.internalMailItem.GetIsDraft();
  1.1035 -                isSubmitted = this.internalMailItem.GetIsSubmitted();
  1.1036 -                Outlook.OlAccountType accountType = this.internalMailItem.GetAccountType();
  1.1037 -
  1.1038 -                // Do not processes deleted messages on IMAP
  1.1039 -                if ((fullCalculation) &&
  1.1040 -                    (accountType == Outlook.OlAccountType.olImap) &&
  1.1041 -                    (MapiHelper.GetProperty(this.internalMailItem, MapiProperty.PidLidImapMarkedForDeletion, "0").ToString() == "1"))
  1.1042 -                {
  1.1043 -                    Log.Verbose("ProcessAndGetRating: Deleted IMAP message detected, skipping processing");
  1.1044 -                    result.Rating = pEpRating.pEpRatingUndefined;
  1.1045 -                    fullCalculation = false;
  1.1046 -                }
  1.1047 -
  1.1048 -                // Check if the mail item is a mirror and use stored rating
  1.1049 -                if ((fullCalculation) &&
  1.1050 -                    (this.internalMailItem.GetIsMirror()))
  1.1051 -                {
  1.1052 -                    // Get UI rating from mirror
  1.1053 -                    try
  1.1054 -                    {
  1.1055 -                        if (PEPMessage.Create(this.internalMailItem, out mirror) == Globals.ReturnStatus.Success)
  1.1056 -                        {
  1.1057 -                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
  1.1058 -                            this.Message = mirror;
  1.1059 -                        }
  1.1060 -                    }
  1.1061 -                    catch (Exception ex)
  1.1062 -                    {
  1.1063 -                        Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
  1.1064 -                        result.Rating = mirror.Rating;
  1.1065 -                    }
  1.1066 -
  1.1067 -                    // If the value was undefined, don't use it. Recalculation is needed.
  1.1068 -                    if (result.Rating != pEpRating.pEpRatingUndefined)
  1.1069 -                    {
  1.1070 -                        Log.Verbose("ProcessAndGetRating: Mirror detected, using stored rating.");
  1.1071 -                        fullCalculation = false;
  1.1072 -                    }
  1.1073 -                }
  1.1074 -
  1.1075 -                /* Check if the mail item is a draft (if the Unsent flag is set)
  1.1076 -                 * If the message is a draft, the outgoing rating will be used, value is not stored.
  1.1077 -                 * This check is technically not required as the logic below will detect Outgoing messages and do the same.
  1.1078 -                 * However, it's potentially quicker (and more robust) to handle this special case.
  1.1079 -                 * Note: It's important that the message is not submitted (since it could already be encrypted).
  1.1080 -                 */
  1.1081 -                if ((fullCalculation) &&
  1.1082 -                    (isDraft) &&
  1.1083 -                    (isSubmitted == false))
  1.1084 -                {
  1.1085 -                    Log.Verbose("ProcessAndGetRating: Draft detected, using outgoing rating.");
  1.1086 -
  1.1087 -                    result.Rating = this.internalMailItem.GetOutgoingRating(true);
  1.1088 -                    fullCalculation = false;
  1.1089 -                }
  1.1090 -
  1.1091 -                // Check if untrusted server and search for mirror. Use mirror rating if available
  1.1092 -                isSecurelyStored = (this.internalMailItem.GetIsSecurelyStored() || this.IsSecureAttachedMail);
  1.1093 -                if (fullCalculation &&
  1.1094 -                    isSecurelyStored)
  1.1095 -                {
  1.1096 -                    // If internal mail item is attached mail, use message id for mirror lookup
  1.1097 -                    string messageId = null;
  1.1098 -                    if (this.IsSecureAttachedMail)
  1.1099 -                    {
  1.1100 -                        messageId = this.MessageId;
  1.1101 -                    }
  1.1102 -
  1.1103 -                    mirrorMailItem = this.internalMailItem.GetMirror(messageId);
  1.1104 -                    if ((mirrorMailItem != null) &&
  1.1105 -                        (PEPMessage.Create(mirrorMailItem, out mirror) == Globals.ReturnStatus.Success))
  1.1106 -                    {
  1.1107 -                        fullCalculation = false;
  1.1108 -                        this.Mirror = mirror;
  1.1109 -
  1.1110 -                        // Get UI rating from mirror
  1.1111 -                        try
  1.1112 -                        {
  1.1113 -                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
  1.1114 -                        }
  1.1115 -                        catch (Exception ex)
  1.1116 -                        {
  1.1117 -                            Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
  1.1118 -                            result.Rating = mirror.Rating;
  1.1119 -                        }
  1.1120 -
  1.1121 -                        this.Mirror.Rating = result.Rating;
  1.1122 -                    }
  1.1123 -                }
  1.1124 -
  1.1125 -                // Full calculation if no special cases were found
  1.1126 -                if (fullCalculation)
  1.1127 -                {
  1.1128 -                    // Check if message has autoconsume header and set pEp internal category if necessary
  1.1129 -                    try
  1.1130 -                    {
  1.1131 -                        if (this.internalMailItem.GetIsAutoConsume())
  1.1132 -                        {
  1.1133 -                            isPEPInternal = true;
  1.1134 -
  1.1135 -                            /* Set the mail item as read and apply again the category to make sure it is really set. As those
  1.1136 -                             * two operations require the mail item to be saved afterwards, do NOT apply it to ActiveSync 
  1.1137 -                             * messages, as saving with ActiveSync accounts tends to fail and then leads to "Save message?" dialogs
  1.1138 -                             * popping up during shutdown of Outlook. (see OUT-216).
  1.1139 -                             */
  1.1140 -                            if (accountType != Outlook.OlAccountType.olEas)
  1.1141 -                            {
  1.1142 -                                Globals.ThisAddIn.CreatePEPCategories();
  1.1143 -
  1.1144 -                                // Only one category is needed to hide the MailItem -- delete any others
  1.1145 -                                this.internalMailItem.Categories = Globals.PEP_INTERNAL_CATEGORY_NAME;
  1.1146 -                                this.internalMailItem.UnRead = false;
  1.1147 -                                preProcessingPropertySet = true;
  1.1148 -                            }
  1.1149 -                        }
  1.1150 -                    }
  1.1151 -                    catch (Exception ex)
  1.1152 -                    {
  1.1153 -                        Log.Error("ProcessAndGetRating: Could not set pEp internal category, " + ex.ToString());
  1.1154 -                    }
  1.1155 -
  1.1156 -                    /* Apply a custom message class to secure mail items in secure stores (doesn't apply for pEp internal messages). This is needed for the
  1.1157 -                     * FormRegionPreviewUnencrypted to be shown in Outlook 2010 (technically, all versions require this according to the documentation).
  1.1158 -                     * See: https://msdn.microsoft.com/en-us/library/office/ff866019.aspx
  1.1159 -                     * 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
  1.1160 -                     * which then leads to the form region not being properly displayed at the first click (OUT-68).
  1.1161 -                     */
  1.1162 -                    if ((isPEPInternal == false) &&
  1.1163 -                         ((Globals.OutlookVersion == Globals.Version.Outlook2010) &&
  1.1164 -                          (this.internalMailItem.GetIsInSecureStore() || this.internalMailItem.GetNeverUnsecure())))
  1.1165 -                    {
  1.1166 -                        try
  1.1167 -                        {
  1.1168 -                            MapiHelper.SetProperty(this.internalMailItem, MapiProperty.PidTagMessageClass, MapiPropertyValue.PidTagMessageClassSecurePEP);
  1.1169 -                            preProcessingPropertySet = true;
  1.1170 -                        }
  1.1171 -                        catch (Exception ex)
  1.1172 -                        {
  1.1173 -                            Log.Error("ProcessAndGetRating: Could not set custom message class, " + ex.ToString());
  1.1174 -                        }
  1.1175 -                    }
  1.1176 -
  1.1177 -                    // Save any changes
  1.1178 -                    if (preProcessingPropertySet)
  1.1179 -                    {
  1.1180 -                        try
  1.1181 -                        {
  1.1182 -                            this.internalMailItem.Save();
  1.1183 -                        }
  1.1184 -                        catch (Exception ex)
  1.1185 -                        {
  1.1186 -                            Log.Error("ProcessAndGetRating: Could not save pre-processing properties, " + ex.ToString());
  1.1187 -                        }
  1.1188 -                    }
  1.1189 -
  1.1190 -                    // Process mail item
  1.1191 -                    sts1 = PEPMessage.Create(this.internalMailItem, out message);
  1.1192 -
  1.1193 -                    // If Key Import Wizard is open, add mail to list to process later
  1.1194 -                    if ((KeySyncWizard.Wizard?.IsVisible == true) &&
  1.1195 -                        (message.Direction == pEpMsgDirection.pEpDirIncoming) &&
  1.1196 -                        (message.To?.Count == 1) &&
  1.1197 -                        (message.From?.EqualsByAddress(message.To[0]) == true))
  1.1198 -                    {
  1.1199 -                        KeySyncWizard.Wizard?.AddToReceivedSyncMessages(message);
  1.1200 -                    }
  1.1201 -
  1.1202 -                    // Define decryption flags
  1.1203 -                    decryptionFlags = isSecurelyStored ? pEpDecryptFlags.pEpDecryptFlagUntrustedServer : pEpDecryptFlags.pEpDecryptFlagsNone;
  1.1204 -
  1.1205 -                    /* Check if the message is an attached disclaimer message.
  1.1206 -                     * The definition for such a message is that it's a secure attached
  1.1207 -                     * message with the same subject as the outer message.
  1.1208 -                     * See also comments in PEPAttachment.CheckIfAttachedMailAndAddToCache().
  1.1209 -                     */
  1.1210 -                    if ((message.Attachments?.Count == 1) &&
  1.1211 -                        (message.Attachments[0].AttachedDisclaimerMessage?.ShortMsg?.Equals(message.ShortMsg) == true))
  1.1212 -                    {
  1.1213 -                        var msg = message.Attachments[0].AttachedDisclaimerMessage.Copy();
  1.1214 -                        message.Attachments.Clear();
  1.1215 -                        for (int i = 0; i < msg.Attachments.Count; i++)
  1.1216 -                        {
  1.1217 -                            message.Attachments.Add(msg.Attachments[i]);
  1.1218 -                        }
  1.1219 -                    }
  1.1220 -
  1.1221 -                    // Process
  1.1222 -                    status = msgProcessor.ProcessMessage(ref message,
  1.1223 -                                                         sts1,
  1.1224 -                                                         this.internalMailItem.GetIsInSecureStore(),
  1.1225 -                                                         this.internalMailItem.GetIsInSentFolder(),
  1.1226 -                                                         isDraft,
  1.1227 -                                                         out mirror,
  1.1228 -                                                         out PEPMessage processedMessage,
  1.1229 -                                                         out pEpRating processedRating,
  1.1230 -                                                         ref decryptionFlags);
  1.1231 -
  1.1232 -                    if (status == Globals.ReturnStatus.Success)
  1.1233 -                    {
  1.1234 -                        // Handle the consumed flag marking for deletion
  1.1235 -                        if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagConsume))
  1.1236 -                        {
  1.1237 -                            // Delete the mail item from Outlook
  1.1238 -                            try
  1.1239 -                            {
  1.1240 -                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.internalMailItem.Subject + " received on " + this.internalMailItem.ReceivedTime.ToString());
  1.1241 -                            }
  1.1242 -                            catch { }
  1.1243 -                            this.internalMailItem.PermanentlyDelete();
  1.1244 -                            this.disposeAfterProcessing = true;
  1.1245 -
  1.1246 -                            Log.Verbose("ProcessAndGetRating: Processed message consumed");
  1.1247 -                        }
  1.1248 -                        else if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagIgnore))
  1.1249 -                        {
  1.1250 -                            try
  1.1251 -                            {
  1.1252 -                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.internalMailItem.Subject + " received on " + this.internalMailItem.ReceivedTime.ToString());
  1.1253 -                            }
  1.1254 -                            catch { }
  1.1255 -                            Log.Verbose("ProcessAndGetRating: Processed message ignored.");
  1.1256 -                        }
  1.1257 -                        else if ((Globals.ThisAddIn.OutlookOptions.ReadAsPlain) &&
  1.1258 -                                 (isSecurelyStored))
  1.1259 -                        {
  1.1260 -                            this.Mirror = mirror;
  1.1261 -                        }
  1.1262 -                        else
  1.1263 -                        {
  1.1264 -                            // Save processed message data to Outlook
  1.1265 -                            if (processedMessage != null)
  1.1266 -                            {
  1.1267 -
  1.1268 -                                // Set the mail item
  1.1269 -                                if (mirror != null)
  1.1270 -                                {
  1.1271 -                                    // Save mirror as property of this cryptable mail item
  1.1272 -                                    this.Mirror = mirror;
  1.1273 -                                    this.Mirror.Rating = processedRating;
  1.1274 -
  1.1275 -                                    if (mirrorMailItem == null)
  1.1276 -                                    {
  1.1277 -                                        // If internal mail item is attached mail, use message id for mirror creation
  1.1278 -                                        string messageId = null;
  1.1279 -                                        if (this.IsSecureAttachedMail)
  1.1280 -                                        {
  1.1281 -                                            messageId = this.MessageId;
  1.1282 -                                        }
  1.1283 -
  1.1284 -                                        mirrorMailItem = this.internalMailItem.CreateMirrorOMI(messageId);
  1.1285 -                                    }
  1.1286 -
  1.1287 -                                    // Apply message to mirror and save
  1.1288 -                                    processedMessage.ApplyTo(mirrorMailItem, true, true);
  1.1289 -
  1.1290 -                                    try
  1.1291 -                                    {
  1.1292 -                                        mirrorMailItem.Save();
  1.1293 -                                    }
  1.1294 -                                    catch (Exception ex)
  1.1295 -                                    {
  1.1296 -                                        Log.Error("ProcessAndGetRating: Error saving mirror item. " + ex.ToString());
  1.1297 -                                    }
  1.1298 -
  1.1299 -                                    // If needed, set SmartNoAttach MAPI property to hide the attachments icon
  1.1300 -                                    if ((accountType != Outlook.OlAccountType.olImap) &&
  1.1301 -                                        (processedMessage.Attachments?.Count == 0) &&
  1.1302 -                                        (this.internalMailItem.Attachments?.Count > 0))
  1.1303 -                                    {
  1.1304 -                                        // Note: The documented MAPI property PidLidSmartNoAttach (0x8514000B) doesn't work for some reason
  1.1305 -                                        result.PropertiesToSet.Add(MapiProperty.PidTagSmartNoAttach2, true);
  1.1306 -                                    }
  1.1307 -
  1.1308 -                                    /* If we have extra keys and are on an untrusted server, reencrypt message
  1.1309 -                                     * for myself and the extra keys.
  1.1310 -                                     */
  1.1311 -                                    if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagSrcModified))
  1.1312 -                                    {
  1.1313 -                                        if (message.ApplyTo(this.internalMailItem, false, false, true, false) == Globals.ReturnStatus.Success)
  1.1314 -                                        {
  1.1315 -                                            saveInternalMailItem = true;
  1.1316 -                                        }
  1.1317 -                                        else
  1.1318 -                                        {
  1.1319 -                                            Log.Error("ProcessAndGetRating: Error reencrypting with extra keys.");
  1.1320 -                                        }
  1.1321 -                                    }
  1.1322 -                                }
  1.1323 -                                else
  1.1324 -                                {
  1.1325 -                                    // Trusted server: apply message and save
  1.1326 -                                    processedMessage.ApplyTo(this.internalMailItem, true, false);
  1.1327 -                                    saveInternalMailItem = true;
  1.1328 -                                }
  1.1329 -                            }
  1.1330 -                            // If processed message is null (= didn't run through decryption (again)), update UI rating
  1.1331 -                            else
  1.1332 -                            {
  1.1333 -                                /* In rare circumstances (i.e. when a user makes a handshake using
  1.1334 -                                 * an FPP message) we can get here. In this case, we need to set the
  1.1335 -                                 * rating manually to reliable or higher (reevaluate).
  1.1336 -                                 */
  1.1337 -                                if ((string.IsNullOrEmpty(message.ForceProtectionId) == false) &&
  1.1338 -                                    (message.Rating == pEpRating.pEpRatingUndefined))
  1.1339 -                                {
  1.1340 -                                    message.Rating = processedRating;
  1.1341 -                                    processedRating = AdapterExtensions.ReevaluateFPPMessageRating(message);
  1.1342 -                                }
  1.1343 -                                else
  1.1344 -                                {
  1.1345 -                                    processedRating = AdapterExtensions.ReevaluateMessageRating(message, processedRating);
  1.1346 -                                }
  1.1347 -                            }
  1.1348 -                        }
  1.1349 -                    }
  1.1350 -
  1.1351 -                    // Remove the pEp Processing category if needed
  1.1352 -                    if (Globals.ThisAddIn.Settings.IsUXImprovementEnabled &&
  1.1353 -                        this.internalMailItem.RemovePEPProcessingCategory())
  1.1354 -                    {
  1.1355 -                        if (message?.Direction != null)
  1.1356 -                        {
  1.1357 -                            this.internalMailItem.UnRead = (message.Direction == pEpMsgDirection.pEpDirIncoming);
  1.1358 -                        }
  1.1359 -                        else
  1.1360 -                        {
  1.1361 -                            this.internalMailItem.UnRead = (this.internalMailItem.GetIsInSentFolder() == false);
  1.1362 -                        }
  1.1363 -                        saveInternalMailItem = true;
  1.1364 -                    }
  1.1365 -
  1.1366 -                    // Save internal mail item if necessary
  1.1367 -                    if (saveInternalMailItem)
  1.1368 -                    {
  1.1369 -                        bool saveError = false;
  1.1370 -                        try
  1.1371 -                        {
  1.1372 -                            this.internalMailItem.Save();
  1.1373 -                        }
  1.1374 -                        catch (Exception ex)
  1.1375 -                        {
  1.1376 -                            saveError = true;
  1.1377 -                            Log.Error("ProcessAndGetRating: Error saving internal mail item. " + ex.ToString());
  1.1378 -                        }
  1.1379 -
  1.1380 -                        // If an error occured during saving, try to forcefully save
  1.1381 -                        if (saveError)
  1.1382 -                        {
  1.1383 -                            try
  1.1384 -                            {
  1.1385 -                                int sts = Mapi.Save(this.internalMailItem, Mapi.SaveOption.KEEP_OPEN_READWRITE);
  1.1386 -                                Log.Verbose("ProcessAndGetRating: Saving using backup method. Return status is " + sts.ToString("X"));
  1.1387 -
  1.1388 -                                if (sts != (uint)Mapi.HResult.S_OK)
  1.1389 -                                {
  1.1390 -                                    sts = Mapi.Save(this.internalMailItem, Mapi.SaveOption.FORCE_SAVE);
  1.1391 -                                    Log.Verbose("ProcessAndGetRating: Saving with FORCE_SAVE flag returned " + sts.ToString("X"));
  1.1392 -                                }
  1.1393 -                            }
  1.1394 -                            catch (Exception ex)
  1.1395 -                            {
  1.1396 -                                Log.Error("ProcessAndGetRating: Error forcefully saving internal mail item. " + ex.ToString());
  1.1397 -                            }
  1.1398 -                        }
  1.1399 -                    }
  1.1400 -
  1.1401 -                    this.Message = processedMessage ?? message;
  1.1402 -                    this.Message.Rating = processedRating;
  1.1403 -                    result.Rating = processedRating;
  1.1404 -                }
  1.1405 -
  1.1406 -                // Save processing status
  1.1407 -                this._LastProcessedRating = result.Rating;
  1.1408 -                this._LastProcessedStatus = status;
  1.1409 -
  1.1410 -                // If it's an incoming message, do some caching (entry ids of drafts are empty)
  1.1411 -                if (string.IsNullOrEmpty(entryId) == false)
  1.1412 -                {
  1.1413 -                    // Save rating in db
  1.1414 -                    PEPDatabase.StoreOrUpdateRating(entryId, result.Rating);
  1.1415 -
  1.1416 -                    // Save message in cache
  1.1417 -                    if (isSecurelyStored)
  1.1418 -                    {
  1.1419 -                        if (Mirror != null)
  1.1420 -                        {
  1.1421 -                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Mirror, Rating = result.Rating });
  1.1422 -                        }
  1.1423 -                        else if ((Message != null) &&
  1.1424 -                                 (Message.IsSecure == false))
  1.1425 -                        {
  1.1426 -                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Message, Rating = result.Rating });
  1.1427 -                        }
  1.1428 -                    }
  1.1429 -                    else
  1.1430 -                    {
  1.1431 -                        PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = null, Rating = result.Rating });
  1.1432 -                    }
  1.1433 -                }
  1.1434 -
  1.1435 -                // Release objects
  1.1436 -                mirrorMailItem = null;
  1.1437 -
  1.1438 -                // Release the decryption lock
  1.1439 -                lock (mutexDecryptionList)
  1.1440 -                {
  1.1441 -                    try
  1.1442 -                    {
  1.1443 -                        if ((string.IsNullOrEmpty(entryId) == false) &&
  1.1444 -                            (decryptionList?.Count > 0))
  1.1445 -                        {
  1.1446 -                            decryptionList.Remove(entryId);
  1.1447 -                            Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
  1.1448 -                                        (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
  1.1449 -                        }
  1.1450 -                    }
  1.1451 -                    catch
  1.1452 -                    {
  1.1453 -                        Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
  1.1454 -                    }
  1.1455 -
  1.1456 -                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
  1.1457 -                }
  1.1458 -            }
  1.1459 -
  1.1460 -            Log.Verbose("ProcessAndGetRating: Completed. Result is " + Enum.GetName(typeof(pEpRating), result.Rating));
  1.1461 -
  1.1462 -            return result;
  1.1463 -        }
  1.1464 -
  1.1465 -        /// <summary>
  1.1466 -        /// Starts the processing of the mail item which can result in decryption or encryption of the message.
  1.1467 -        /// </summary>
  1.1468 -        /// <param name="disposeAfterComplete">Set to true in order to release/dispose the internal MailItem and this CryptableMailItem 
  1.1469 -        /// after processing is complete. This would be used for background processing where the reference is not maintained in the UI.
  1.1470 -        /// WARNING: do not set to true if you will use this MailItem or CryptableMailItem later!</param>
  1.1471 -        /// <returns>True if the processing started successfully, otherwise false if it is already busy.</returns>
  1.1472 -        public async void StartProcessing(bool isDraft, bool disposeAfterComplete = false)
  1.1473 -        {
  1.1474 -            if (this.processor.IsBusy == false)
  1.1475 -            {
  1.1476 -                string entryId = null;
  1.1477 -                this.disposeAfterProcessing = disposeAfterComplete;
  1.1478 -
  1.1479 -                bool process = await Task.Run(() =>
  1.1480 -                {
  1.1481 -                    int sleepTime = 1000; // 1 second in milliseconds
  1.1482 -                    int curWaitTime = 0;
  1.1483 -                    int maxWaitTime = 60000; // 1 minute in milliseconds
  1.1484 -                    bool isAlreadyBeingDecrypted = false;
  1.1485 -                    bool isAutoConsume = false;
  1.1486 -
  1.1487 -                    lock (mutexMailItem)
  1.1488 -                    {
  1.1489 -                        /* Explicitly add try/catch block to catch error getting EntryID.
  1.1490 -                         * This should theoretically never happen, but was seen in practice.
  1.1491 -                         */
  1.1492 -                        try
  1.1493 -                        {
  1.1494 -                            entryId = this.internalMailItem.EntryID;
  1.1495 -                            isAutoConsume = this.internalMailItem.GetIsAutoConsume();
  1.1496 -                        }
  1.1497 -                        catch
  1.1498 -                        {
  1.1499 -                            Log.Error("ProcessAndGetRating: internalMailItem is invalid or EntryID could not get retrieved");
  1.1500 -                            this._LastProcessedRating = pEpRating.pEpRatingUndefined;
  1.1501 -                            this._LastProcessedStatus = Globals.ReturnStatus.Failure;
  1.1502 -                            return false;
  1.1503 -                        }
  1.1504 -                    }
  1.1505 -
  1.1506 -                    // Make sure this mail item is not already being decrypted
  1.1507 -                    if (string.IsNullOrEmpty(entryId) == false)
  1.1508 -                    {
  1.1509 -                        do
  1.1510 -                        {
  1.1511 -                            /* Check if the EntryID is already in the decrypting list
  1.1512 -                             * If so, it is being decrypted already and we must wait
  1.1513 -                             * If it isn't already being decrypted, then add it to the decryption list
  1.1514 -                             */
  1.1515 -                            lock (mutexDecryptionList)
  1.1516 -                            {
  1.1517 -                                if (decryptionList.ContainsKey(entryId))
  1.1518 -                                {
  1.1519 -                                    isAlreadyBeingDecrypted = true;
  1.1520 -                                }
  1.1521 -                                else
  1.1522 -                                {
  1.1523 -                                    isAlreadyBeingDecrypted = false;
  1.1524 -
  1.1525 -                                    /* Add the entryID to the decryption list and we can start decryption
  1.1526 -                                     * It is important to do this all under the same lock
  1.1527 -                                     * 
  1.1528 -                                     * Note: It’s known the EntryID is not guaranteed to be unique for a given MailItem across different stores.
  1.1529 -                                     * However, only the EntryID is used in the decryption list.
  1.1530 -                                     * This is not an issue as worse-case is simply waiting for a different MailItem with the same EntryID to finish.
  1.1531 -                                     */
  1.1532 -                                    decryptionList.Add(entryId, "");
  1.1533 -                                    Log.Verbose("ProcessAndGetRating: Added EntryID to decryption list. " + entryId);
  1.1534 -                                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
  1.1535 -                                    break;
  1.1536 -                                }
  1.1537 -                            }
  1.1538 -
  1.1539 -                            // Wait for the other thread to finish
  1.1540 -                            if (isAlreadyBeingDecrypted)
  1.1541 -                            {
  1.1542 -                                // Do not process multiple times if it is an automatic message
  1.1543 -                                if (isAutoConsume)
  1.1544 -                                {
  1.1545 -                                    curWaitTime = maxWaitTime + 1;
  1.1546 -                                    Log.Verbose("ProcessAndGetRating: Setting timeout for AutoConsume message.");
  1.1547 -                                }
  1.1548 -                                else
  1.1549 -                                {
  1.1550 -                                    Log.Verbose("ProcessAndGetRating: Waiting for other decryption thread to finish. " + entryId);
  1.1551 -                                    Thread.Sleep(sleepTime);
  1.1552 -                                    curWaitTime += sleepTime;
  1.1553 -                                }
  1.1554 -                            }
  1.1555 -                        }
  1.1556 -                        while ((isAlreadyBeingDecrypted) && (curWaitTime < maxWaitTime));
  1.1557 -                    }
  1.1558 -                    else
  1.1559 -                    {
  1.1560 -                        // Log the issue unless the MailItem is an unsaved draft message
  1.1561 -                        if (isDraft == false)
  1.1562 -                        {
  1.1563 -                            Log.Warning("ProcessAndGetRating: EntryID does not exist, unable to lock during decryption.");
  1.1564 -                        }
  1.1565 -                        else
  1.1566 -                        {
  1.1567 -                            Log.Verbose("ProcessAndGetRating: Could not add EntryID to decryption list lock because message is an unsaved draft.");
  1.1568 -                        }
  1.1569 -                    }
  1.1570 -
  1.1571 -                    // Exit if timeout occured
  1.1572 -                    if ((isAlreadyBeingDecrypted) ||
  1.1573 -                        (curWaitTime >= maxWaitTime))
  1.1574 -                    {
  1.1575 -                        Log.Error("ProcessAndGetRating: Exited by timeout. " + (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
  1.1576 -
  1.1577 -                        // Save processing status
  1.1578 -                        this._LastProcessedRating = pEpRating.pEpRatingCannotDecrypt;
  1.1579 -                        this._LastProcessedStatus = Globals.ReturnStatus.Failure;
  1.1580 -
  1.1581 -                        // Remove entryId from decryption list
  1.1582 -                        lock (mutexDecryptionList)
  1.1583 -                        {
  1.1584 -                            try
  1.1585 -                            {
  1.1586 -                                decryptionList.Remove(entryId);
  1.1587 -                                Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
  1.1588 -                                            (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
  1.1589 -                            }
  1.1590 -                            catch
  1.1591 -                            {
  1.1592 -                                Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
  1.1593 -                            }
  1.1594 -
  1.1595 -                            Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
  1.1596 -                        }
  1.1597 -
  1.1598 -                        return false;
  1.1599 -                    }
  1.1600 -
  1.1601 -                    return true;
  1.1602 -                });
  1.1603 -
  1.1604 -                if (process)
  1.1605 -                {
  1.1606 -                    this.processor.RunWorkerAsync(entryId);
  1.1607 -                }
  1.1608 -            }
  1.1609 -        }
  1.1610 -
  1.1611 -        /// <summary>
  1.1612 -        /// Event handler for when the processor background worker is doing work.
  1.1613 -        /// </summary>
  1.1614 -        private void Processor_DoWork(object sender, DoWorkEventArgs e)
  1.1615 -        {
  1.1616 -            e.Result = this.ProcessAndGetRating(e.Argument as string);
  1.1617 -            return;
  1.1618 -        }
  1.1619 -
  1.1620 -        /// <summary>
  1.1621 -        /// Event handler for when the processor background worker is completed.
  1.1622 -        /// </summary>
  1.1623 -        private void Processor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  1.1624 -        {
  1.1625 -            MsgProcessor.ProcessingCompletedEventArgs args;
  1.1626 -
  1.1627 -            // Decrement decryption counter after decryption has finished (if necessary)
  1.1628 -            if (this.decrementCounter)
  1.1629 -            {
  1.1630 -                ThisAddIn.DecryptionStack.DecrementDecryptionCounter();
  1.1631 -            }
  1.1632 -
  1.1633 -            // Catch any errors that occured during processing
  1.1634 -            if (e.Error != null)
  1.1635 -            {
  1.1636 -                Log.Error("Processor_RunWorkerCompleted: Error during processing of mail item. " + e.Error.ToString());
  1.1637 -
  1.1638 -                if (this.disposeAfterProcessing)
  1.1639 -                {
  1.1640 -                    this.Dispose(false);
  1.1641 -
  1.1642 -                    // Must be called last!
  1.1643 -                    this.DisposeInternalMailItem();
  1.1644 -                }
  1.1645 -
  1.1646 -                return;
  1.1647 -            }
  1.1648 -
  1.1649 -            // Get processing result
  1.1650 -            ProcessingResult result = e.Result as ProcessingResult;
  1.1651 -
  1.1652 -            // Dispose if necessary
  1.1653 -            if (this.disposeAfterProcessing)
  1.1654 -            {
  1.1655 -                /* If there are MAPI properties to set, we have to marshal
  1.1656 -                 * this call to the main thread. If not, we can just dispose it
  1.1657 -                 * on the current one.
  1.1658 -                 */
  1.1659 -                if (result?.PropertiesToSet?.Count > 0)
  1.1660 -                {
  1.1661 -                    KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
  1.1662 -                    {
  1.1663 -                        this.internalMailItem?.SetMAPIProperties(result.PropertiesToSet);
  1.1664 -
  1.1665 -                        this.Dispose(false);
  1.1666 -
  1.1667 -                        // Must be called last!
  1.1668 -                        this.DisposeInternalMailItem();
  1.1669 -                    }));
  1.1670 -                }
  1.1671 -                else
  1.1672 -                {
  1.1673 -                    this.Dispose(false);
  1.1674 -
  1.1675 -                    // Must be called last!
  1.1676 -                    this.DisposeInternalMailItem();
  1.1677 -                }
  1.1678 -            }
  1.1679 -            else
  1.1680 -            {
  1.1681 -                // Raise complete event (only if dispose after decryption is not true since .this reference is returned)
  1.1682 -                args = new MsgProcessor.ProcessingCompletedEventArgs();
  1.1683 -
  1.1684 -                // Check for errors during processing but invoke anyhow to complete process (needed to look up mirror).
  1.1685 -                if (e.Error == null)
  1.1686 -                {
  1.1687 -                    args.ProcessedRating = result.Rating;
  1.1688 -                    args.PropertiesToSet = result.PropertiesToSet;
  1.1689 -                }
  1.1690 -                else
  1.1691 -                {
  1.1692 -                    args.ProcessedRating = pEpRating.pEpRatingUndefined;
  1.1693 -                }
  1.1694 -
  1.1695 -                this.ProcessingCompleted?.Invoke(this, args);
  1.1696 -            }
  1.1697 -        }
  1.1698 -
  1.1699 -        /**************************************************************
  1.1700 -         * 
  1.1701 -         * Mirror Locator
  1.1702 -         * 
  1.1703 -         *************************************************************/
  1.1704 -
  1.1705 -        /// <summary>
  1.1706 -        /// Starts the process to locate the mirror of the mail item.
  1.1707 -        /// </summary>
  1.1708 -        public void StartGetMirror(string messageId = null)
  1.1709 -        {
  1.1710 -            if (this.mirrorLocator.IsBusy == false)
  1.1711 -            {
  1.1712 -                this.mirrorLocator.RunWorkerAsync(messageId);
  1.1713 -            }
  1.1714 -
  1.1715 -            return;
  1.1716 -        }
  1.1717 -
  1.1718 -        /// <summary>
  1.1719 -        /// Event handler for when the mirror locator background worker is doing work.
  1.1720 -        /// </summary>
  1.1721 -        private void MirrorLocator_DoWork(object sender, DoWorkEventArgs e)
  1.1722 -        {
  1.1723 -            PEPMessage mirror = null;
  1.1724 -            Outlook.MailItem omi = null;
  1.1725 -            e.Result = null;
  1.1726 -            Globals.ReturnStatus sts;
  1.1727 -
  1.1728 -            Log.Verbose("MirrorLocator_DoWork: Started");
  1.1729 -
  1.1730 -            try
  1.1731 -            {
  1.1732 -                if (this.Mirror != null)
  1.1733 -                {
  1.1734 -                    // If we already have a mirror, use it
  1.1735 -                    e.Result = this.Mirror;
  1.1736 -                }
  1.1737 -                else
  1.1738 -                {
  1.1739 -                    // If no stored mirror is there, look it up
  1.1740 -                    lock (mutexMailItem)
  1.1741 -                    {
  1.1742 -                        string id = e.Argument as string;
  1.1743 -                        omi = this.internalMailItem.GetMirror(id);
  1.1744 -
  1.1745 -                        if (omi != null)
  1.1746 -                        {
  1.1747 -                            Log.Verbose("MirrorLocator_DoWork: Mirror found");
  1.1748 -
  1.1749 -                            sts = PEPMessage.Create(omi, out mirror);
  1.1750 -                        }
  1.1751 -                    }
  1.1752 -
  1.1753 -                    e.Result = mirror;
  1.1754 -                }
  1.1755 -            }
  1.1756 -            catch (Exception ex)
  1.1757 -            {
  1.1758 -                Log.Error("MirrorLocator_DoWork: Failed to find mirror OMI, " + ex.ToString());
  1.1759 -            }
  1.1760 -            finally
  1.1761 -            {
  1.1762 -                omi = null;
  1.1763 -            }
  1.1764 -
  1.1765 -            Log.Verbose("MirrorLocator_DoWork: Completed");
  1.1766 -        }
  1.1767 -
  1.1768 -        /// <summary>
  1.1769 -        /// Event handler for when the mirror locator background worker is completed.
  1.1770 -        /// </summary>
  1.1771 -        private void MirrorLocator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  1.1772 -        {
  1.1773 -            this.GetMirrorCompleted?.Invoke(this, new GetMirrorCompletedEventArgs(e.Result == null ? null : (PEPMessage)e.Result));
  1.1774 -            return;
  1.1775 -        }
  1.1776 -
  1.1777 -        /**************************************************************
  1.1778 -         * 
  1.1779 -         * Methods
  1.1780 -         * 
  1.1781 -         *************************************************************/
  1.1782 -
  1.1783 -        /// <summary>
  1.1784 -        /// Releases all resources and disconnects internal events.
  1.1785 -        /// The internal mail item will NOT be released -- this is managed externally.
  1.1786 -        /// </summary>
  1.1787 -        public void Dispose()
  1.1788 -        {
  1.1789 -            this.Dispose(true);
  1.1790 -            // Note: GC.SuppressFinalize(this); is not called because that just seems bad
  1.1791 -            return;
  1.1792 -        }
  1.1793 -
  1.1794 -        /// <summary>
  1.1795 -        /// Releases the internal Outlook.MailItem wrapped by this CryptableMailItem.
  1.1796 -        /// In general, this shouldn't be used as the MailItems are managed externally.
  1.1797 -        /// However, there are some cases where the MailItem needs to be disposed and the CryptableMailItem is the only
  1.1798 -        /// object that maintains the reference.
  1.1799 -        /// </summary>
  1.1800 -        public void DisposeInternalMailItem()
  1.1801 -        {
  1.1802 -            if (this.internalMailItem != null)
  1.1803 -            {
  1.1804 -                // Marshal.ReleaseComObject(this.internalMailItem);
  1.1805 -                this.internalMailItem = null;
  1.1806 -            }
  1.1807 -
  1.1808 -            return;
  1.1809 -        }
  1.1810 -
  1.1811 -        /// <summary>
  1.1812 -        /// Releases resources and disconnects internal events.
  1.1813 -        /// This exists to make code-analysis not throw old warnings.
  1.1814 -        /// </summary>
  1.1815 -        /// <param name="disposing">True to clean up native and managed resources. 
  1.1816 -        /// False to clean up only native resources.</param>
  1.1817 -        protected virtual void Dispose(bool disposing)
  1.1818 -        {
  1.1819 -            // Free managed resources
  1.1820 -            if (disposing)
  1.1821 -            {
  1.1822 -                // Disconnect mail item events
  1.1823 -                this.ConnectInternalMailItemEvents(false);
  1.1824 -
  1.1825 -                /* The BackgroundWorker class doesn't actually implement any functionality in Dispose.
  1.1826 -                 * It's simply inherited from the base implementation.
  1.1827 -                 * Just to make this clear (especially for code analysis) it is called and documented here.
  1.1828 -                 */
  1.1829 -                if (this.processor != null)
  1.1830 -                {
  1.1831 -                    this.processor.RunWorkerCompleted -= Processor_RunWorkerCompleted;
  1.1832 -                    this.processor.DoWork -= Processor_DoWork;
  1.1833 -                    this.processor.Dispose();
  1.1834 -                }
  1.1835 -                if (this.mirrorLocator != null)
  1.1836 -                {
  1.1837 -                    this.mirrorLocator.RunWorkerCompleted -= MirrorLocator_RunWorkerCompleted;
  1.1838 -                    this.mirrorLocator.DoWork -= MirrorLocator_DoWork;
  1.1839 -                    this.mirrorLocator.Dispose();
  1.1840 -                }
  1.1841 -            }
  1.1842 -
  1.1843 -            this.internalMailItem = null;
  1.1844 -        }
  1.1845 -
  1.1846 -        /// <summary>
  1.1847 -        /// Attempts to resolve all the Recipient objects in the Recipients collection of
  1.1848 -        /// the internal mail item against the Address Book (similar to 'Check Names').
  1.1849 -        /// This will first save the mail item (if it's not a draft), then forward the call to Recipients.ResolveAll().
  1.1850 -        /// See: https://msdn.microsoft.com/en-us/library/office/microsoft.office.interop.outlook.recipients.resolveall
  1.1851 -        /// </summary>
  1.1852 -        public void ResolveAllRecipients()
  1.1853 -        {
  1.1854 -            lock (mutexMailItem)
  1.1855 -            {
  1.1856 -                try
  1.1857 -                {
  1.1858 -                    /* Calling Save() for drafts might cause a crash, as this then interferes
  1.1859 -                     * with the protected storing of drafts for untrusted servers.
  1.1860 -                     */
  1.1861 -                    if (this.internalMailItem.GetIsDraft() == false)
  1.1862 -                    {
  1.1863 -                        this.internalMailItem.Save();
  1.1864 -                    }
  1.1865 -                    bool result = this.internalMailItem.Recipients.ResolveAll();
  1.1866 -                }
  1.1867 -                catch (Exception ex)
  1.1868 -                {
  1.1869 -                    Log.Error("ResolveAllRecipients: exception " + ex.ToString());
  1.1870 -                }
  1.1871 -            }
  1.1872 -
  1.1873 -            return;
  1.1874 -        }
  1.1875 -
  1.1876 -        /// <summary>
  1.1877 -        /// Checks if the original item was encrypted and sets the user property to the
  1.1878 -        /// reply/forward item if needed.
  1.1879 -        /// This method evokes the OriginallyEncryptedStatusUpdated because it is possible
  1.1880 -        /// that the FormRegionPrivacyStatus has already been initialized when this method
  1.1881 -        /// is run. However, it might be necessary to check if the original item was encrypted
  1.1882 -        /// in order to decide whether to encrypt the reply/forward, so we need to update its
  1.1883 -        /// status.
  1.1884 -        /// </summary>
  1.1885 -        /// <param name="replyItem">The reply/forward item</param>
  1.1886 -        private void SetOriginallyEncryptedStatus(Outlook.MailItem replyItem)
  1.1887 -        {
  1.1888 -            if (this._LastProcessedRating >= pEpRating.pEpRatingUnreliable)
  1.1889 -            {
  1.1890 -                replyItem?.SetOriginallyEncryptedStatus(this._LastProcessedRating);
  1.1891 -
  1.1892 -                OriginallyEncryptedStatusUpdated?.Invoke(this, new EventArgs());
  1.1893 -            }
  1.1894 -        }
  1.1895 -
  1.1896 -        /// <summary>
  1.1897 -        /// Displays the unencrypted mirror mail item (if it exists) associated with the wrapped mail item.
  1.1898 -        /// </summary>
  1.1899 -        /// <returns>True if successful, otherwise false.</returns>
  1.1900 -        public bool DisplayMirror()
  1.1901 -        {
  1.1902 -            if (this.processor.IsBusy ||
  1.1903 -                this.mirrorLocator.IsBusy)
  1.1904 -            {
  1.1905 -                // Don't try to locate the mirror if it's being used
  1.1906 -                return (false);
  1.1907 -            }
  1.1908 -            else
  1.1909 -            {
  1.1910 -                Outlook.MailItem omi = this.internalMailItem.GetMirror();
  1.1911 -
  1.1912 -                if (omi == null)
  1.1913 -                {
  1.1914 -                    return (false);
  1.1915 -                }
  1.1916 -                else
  1.1917 -                {
  1.1918 -                    omi.Display();
  1.1919 -                }
  1.1920 -            }
  1.1921 -
  1.1922 -            return true;
  1.1923 -        }
  1.1924 -
  1.1925 -        /**************************************************************
  1.1926 -         * 
  1.1927 -         * Event Methods
  1.1928 -         * 
  1.1929 -         *************************************************************/
  1.1930 -
  1.1931 -        /// <summary>
  1.1932 -        /// Raises the property change event, if possible, with the given arguments.
  1.1933 -        /// </summary>
  1.1934 -        /// <param name="propertyName">The name of the property that was changed.</param>
  1.1935 -        private void RaisePropertyChangedEvent(string propertyName)
  1.1936 -        {
  1.1937 -            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  1.1938 -            return;
  1.1939 -        }
  1.1940 -
  1.1941 -        /// <summary>
  1.1942 -        /// Dis/connects all necessary events to/from the internal mail item.
  1.1943 -        /// This will then expose these events through the cryptable mail item directly.
  1.1944 -        /// </summary>
  1.1945 -        /// <param name="connect">Whether to connect or disconnect events.</param>
  1.1946 -        private void ConnectInternalMailItemEvents(bool connect)
  1.1947 -        {
  1.1948 -            if (this.internalMailItem != null)
  1.1949 -            {
  1.1950 -                /* OUT-285: This should probably never fail, but during dis/connection
  1.1951 -                 * of an account, this method raised an InvalidCastException, so we will 
  1.1952 -                 * catch any error here anyway.
  1.1953 -                 */
  1.1954 -                try
  1.1955 -                {
  1.1956 -                    // Connect or disconnect events
  1.1957 -                    if (connect)
  1.1958 -                    {
  1.1959 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeAttachmentPreview += MailItem_BeforeAttachmentPreview;
  1.1960 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeDelete += MailItem_BeforeDelete;
  1.1961 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Forward += MailItem_Forward;
  1.1962 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Open += MailItem_Open;
  1.1963 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).PropertyChange += MailItem_PropertyChange;
  1.1964 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Reply += MailItem_Reply;
  1.1965 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).ReplyAll += MailItem_ReplyAll;
  1.1966 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Send += MailItem_Send;
  1.1967 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Write += MailItem_Write;
  1.1968 -                    }
  1.1969 -                    else
  1.1970 -                    {
  1.1971 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeAttachmentPreview -= MailItem_BeforeAttachmentPreview;
  1.1972 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).BeforeDelete -= MailItem_BeforeDelete;
  1.1973 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Forward -= MailItem_Forward;
  1.1974 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Open -= MailItem_Open;
  1.1975 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).PropertyChange -= MailItem_PropertyChange;
  1.1976 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Reply -= MailItem_Reply;
  1.1977 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).ReplyAll -= MailItem_ReplyAll;
  1.1978 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Send -= MailItem_Send;
  1.1979 -                        ((Outlook.ItemEvents_10_Event)this.internalMailItem).Write -= MailItem_Write;
  1.1980 -                    }
  1.1981 -                }
  1.1982 -                catch (Exception ex)
  1.1983 -                {
  1.1984 -                    Log.Error("ConnectInternalMailItemEvents: Error occured. " + ex.ToString());
  1.1985 -                }
  1.1986 -            }
  1.1987 -
  1.1988 -            return;
  1.1989 -        }
  1.1990 -
  1.1991 -        /**************************************************************
  1.1992 -         * 
  1.1993 -         * Sub-classes
  1.1994 -         * 
  1.1995 -         *************************************************************/
  1.1996 -
  1.1997 -        /// <summary>
  1.1998 -        /// Class used to store the arguments in the GetMirrorCompleted event.
  1.1999 -        /// </summary>
  1.2000 -        internal class GetMirrorCompletedEventArgs : EventArgs
  1.2001 -        {
  1.2002 -            /// <summary>
  1.2003 -            /// The located mirror after the get mirror process is complete.
  1.2004 -            /// </summary>
  1.2005 -            public PEPMessage Mirror = null;
  1.2006 -
  1.2007 -            /// <summary>
  1.2008 -            /// Constructs a new GetMirrorCompletedEventArgs with the given arguments.
  1.2009 -            /// </summary>
  1.2010 -            /// <param name="mirror">The located mirror after the get mirror process completes.</param>
  1.2011 -            public GetMirrorCompletedEventArgs(PEPMessage mirror)
  1.2012 -            {
  1.2013 -                this.Mirror = mirror;
  1.2014 -            }
  1.2015 -        }
  1.2016 -
  1.2017 -        /// <summary>
  1.2018 -        /// Class used to store an entry in the encrypted conversation cache.
  1.2019 -        /// This will identify the original parent encrypted mail item.
  1.2020 -        /// </summary>
  1.2021 -        private class OriginalMailItem
  1.2022 -        {
  1.2023 -            public string ConversationId { get; set; }
  1.2024 -            public string ConversationIndex { get; set; }
  1.2025 -            public string ConversationTopic { get; set; }
  1.2026 -            public string EntryId { get; set; }
  1.2027 -            public bool IsEncrypted { get; set; }
  1.2028 -
  1.2029 -            public OriginalMailItem()
  1.2030 -            {
  1.2031 -                this.ConversationId = null;
  1.2032 -                this.ConversationIndex = null;
  1.2033 -                this.ConversationTopic = null;
  1.2034 -                this.EntryId = null;
  1.2035 -                this.IsEncrypted = false;
  1.2036 -            }
  1.2037 -        }
  1.2038 -
  1.2039 -        /// <summary>
  1.2040 -        /// Class used to store a processing result.
  1.2041 -        /// </summary>
  1.2042 -        internal class ProcessingResult
  1.2043 -        {
  1.2044 -            public pEpRating Rating { get; set; } = pEpRating.pEpRatingUndefined;
  1.2045 -            public Dictionary<MapiProperty.MapiProp, object> PropertiesToSet { get; set; } = new Dictionary<MapiProperty.MapiProp, object>();
  1.2046 -        }
  1.2047 -    }
  1.2048 -}
     2.1 --- a/DecryptionStack.cs	Wed Mar 13 13:50:02 2019 +0100
     2.2 +++ b/DecryptionStack.cs	Thu Mar 14 15:36:43 2019 +0100
     2.3 @@ -1,4 +1,5 @@
     2.4 -using System;
     2.5 +using pEp.Wrappers;
     2.6 +using System;
     2.7  using System.Collections.Generic;
     2.8  using Outlook = Microsoft.Office.Interop.Outlook;
     2.9  
    2.10 @@ -219,7 +220,7 @@
    2.11          {
    2.12              Outlook.MailItem omi = null;
    2.13              Outlook.MailItem omiCopy = null;
    2.14 -            CryptableMailItem cmi = null;
    2.15 +            MailItemWrapper mi = null;
    2.16  
    2.17              // Try to increment the decryption counter
    2.18              if (this.IncrementDecryptionCounter() == false)
    2.19 @@ -308,13 +309,13 @@
    2.20                      else
    2.21                      {
    2.22                          // Process item
    2.23 -                        cmi = new CryptableMailItem(omiCopy ?? omi, null, true);
    2.24 +                        mi = new MailItemWrapper(omiCopy ?? omi, null, true);
    2.25  
    2.26                          /* Note: Make sure to dispose the MailItem after processing (pass true).
    2.27                           * This is needed as decryption is asynchronous but the MailItem reference still needs to be released.
    2.28                           * Do NOT use omi or cmi references after this point!
    2.29                           */
    2.30 -                        cmi.StartProcessing(false, true);
    2.31 +                        mi.StartProcessing(false, true);
    2.32                          Log.Verbose("DecryptionStack.DecryptionTimer_Tick: started decryption of item with entryId " + omi?.EntryID);
    2.33                      }
    2.34                  }
     3.1 --- a/Extensions/ContactItemExtensions.cs	Wed Mar 13 13:50:02 2019 +0100
     3.2 +++ b/Extensions/ContactItemExtensions.cs	Thu Mar 14 15:36:43 2019 +0100
     3.3 @@ -1,4 +1,5 @@
     3.4 -using System.Runtime.InteropServices;
     3.5 +using pEp.Wrappers;
     3.6 +using System.Runtime.InteropServices;
     3.7  using Outlook = Microsoft.Office.Interop.Outlook;
     3.8  
     3.9  namespace pEp
    3.10 @@ -23,7 +24,7 @@
    3.11              if (Globals.ThisAddIn.Settings.IsDisableProtectionForContactsEnabled)
    3.12              {
    3.13                  properties = contact.UserProperties;
    3.14 -                up = properties.Find(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    3.15 +                up = properties.Find(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    3.16  
    3.17                  if (up == null)
    3.18                  {
    3.19 @@ -61,11 +62,11 @@
    3.20                                                 bool forceUnencrypted)
    3.21          {
    3.22              Outlook.UserProperties properties = contact.UserProperties;
    3.23 -            Outlook.UserProperty up = properties.Find(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    3.24 +            Outlook.UserProperty up = properties.Find(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    3.25  
    3.26              if (up == null)
    3.27              {
    3.28 -                up = contact.UserProperties.Add(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
    3.29 +                up = contact.UserProperties.Add(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
    3.30                                                  Outlook.OlUserPropertyType.olYesNo, false);
    3.31              }
    3.32  
     4.1 --- a/Extensions/MailItemExtensions.cs	Wed Mar 13 13:50:02 2019 +0100
     4.2 +++ b/Extensions/MailItemExtensions.cs	Thu Mar 14 15:36:43 2019 +0100
     4.3 @@ -1,5 +1,6 @@
     4.4  using MimeKit;
     4.5  using pEp.Extensions;
     4.6 +using pEp.Wrappers;
     4.7  using pEpCOMServerAdapterLib;
     4.8  using System;
     4.9  using System.Collections.Generic;
    4.10 @@ -16,7 +17,7 @@
    4.11      /// Contains extensions for the MailItem as well as utility methods specific for pEp.
    4.12      /// </summary>
    4.13      internal static class MailItemExtensions
    4.14 -    {        
    4.15 +    {
    4.16          public const string                     USER_PROPERTY_KEY_ORIG_ENTRY_ID         = "origEntryID";
    4.17          public const string                     USER_PROPERTY_KEY_INSPECTOR_CLOSED      = "inspectorClosed";
    4.18          public const string                     USER_PROPERTY_KEY_IS_INCOMING           = "isIncoming";
    4.19 @@ -272,7 +273,7 @@
    4.20          /// </summary>
    4.21          /// <param name="omi">The Outlook mail item to process with.</param>
    4.22          /// <param name="originalEntryId">The EntryId of the original mail item.</param>
    4.23 -        public static void AddReplyIconsToOriginal(this Outlook.MailItem omi, 
    4.24 +        public static void AddReplyIconsToOriginal(this Outlook.MailItem omi,
    4.25                                                     string originalEntryId)
    4.26          {
    4.27  
    4.28 @@ -337,10 +338,10 @@
    4.29          public static void AvoidWinmailDatAttachment(this Outlook.MailItem omi)
    4.30          {
    4.31              // Remove all pEp user properties
    4.32 -            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    4.33 -            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION);
    4.34 -            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED);
    4.35 -            omi?.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING);
    4.36 +            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
    4.37 +            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION);
    4.38 +            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED);
    4.39 +            omi?.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ORIGINAL_RATING);
    4.40              omi?.DeleteUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID);
    4.41              omi?.DeleteUserProperty(MailItemExtensions.USER_PROPERTY_KEY_PROCESSING_STATE);
    4.42  
    4.43 @@ -706,7 +707,7 @@
    4.44  
    4.45              try
    4.46              {
    4.47 -                folder = omi.Parent as Outlook.Folder;                
    4.48 +                folder = omi.Parent as Outlook.Folder;
    4.49                  accountType = folder.GetAccountType();
    4.50              }
    4.51              catch
    4.52 @@ -1030,11 +1031,11 @@
    4.53          {
    4.54              if (rating >= pEpRating.pEpRatingUnreliable)
    4.55              {
    4.56 -                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED,
    4.57 +                omi?.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED,
    4.58                                            true,
    4.59                                            Outlook.OlUserPropertyType.olYesNo);
    4.60  
    4.61 -                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING,
    4.62 +                omi?.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ORIGINAL_RATING,
    4.63                                            rating.ToEngineString(),
    4.64                                            Outlook.OlUserPropertyType.olText);
    4.65  
    4.66 @@ -2011,7 +2012,7 @@
    4.67                  recipients = null;
    4.68                  store = null;
    4.69              }
    4.70 -        }       
    4.71 +        }
    4.72  
    4.73          /// <summary>
    4.74          /// Processes a mail item asynchronously and sends it out.
    4.75 @@ -2178,7 +2179,7 @@
    4.76          /// <param name="omi">The Outlook mail item to process with.</param>
    4.77          /// <param name="smtpAddress">The address of the account to set.</param>
    4.78          /// <returns>True if the account is set correctly, otherwise false.</returns>
    4.79 -        public static bool SetSendUsingAccount(this Outlook.MailItem omi, 
    4.80 +        public static bool SetSendUsingAccount(this Outlook.MailItem omi,
    4.81                                                string smtpAddress)
    4.82          {
    4.83              bool success = false;
    4.84 @@ -2630,17 +2631,8 @@
    4.85                  }
    4.86  
    4.87                  // Release objects
    4.88 -                if (properties != null)
    4.89 -                {
    4.90 -                    // Marshal.ReleaseComObject(properties);
    4.91 -                    properties = null;
    4.92 -                }
    4.93 -
    4.94 -                if (up != null)
    4.95 -                {
    4.96 -                    // Marshal.ReleaseComObject(up);
    4.97 -                    up = null;
    4.98 -                }
    4.99 +                properties = null;
   4.100 +                up = null;
   4.101              }
   4.102  
   4.103              return (value);
   4.104 @@ -2762,7 +2754,7 @@
   4.105          /// </summary>
   4.106          /// <param name="omi">The Outlook mail item to process with.</param>
   4.107          /// <returns>The WatchedExplorer or WatchedInspector the mail item resides in or null if an error occured.</returns>
   4.108 -        public static WatchedWindow GetWatchedParentWindow(this Outlook.MailItem omi)
   4.109 +        public static WindowBaseWrapper GetParentWindowWrapper(this Outlook.MailItem omi)
   4.110          {
   4.111              return Globals.ThisAddIn.GetWatchedParentWindow(omi);
   4.112          }
   4.113 @@ -2944,7 +2936,7 @@
   4.114                                   *   ON : ForceUnencrypted property exists with a value of 'True'
   4.115                                   *  OFF : ForceUnencrypted property does not exist or has a value of 'False' or null
   4.116                                   */
   4.117 -                                bool? forceUnencrypted = omi.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED) as bool?;
   4.118 +                                bool? forceUnencrypted = omi.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED) as bool?;
   4.119  
   4.120                                  // Set value if it has been retrieved
   4.121                                  if (forceUnencrypted == true)
   4.122 @@ -3058,7 +3050,7 @@
   4.123                                   *   ON : EnableProtection property exists with a value of 'True'
   4.124                                   *  OFF : EnableProtection property does not exist or has a value of 'False' or null
   4.125                                   */
   4.126 -                                bool? enableProtection = (omi.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION)) as bool?;
   4.127 +                                bool? enableProtection = (omi.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION)) as bool?;
   4.128  
   4.129                                  // Set value if it has been retrieved
   4.130                                  if (enableProtection == true)
   4.131 @@ -3231,13 +3223,13 @@
   4.132                                  {
   4.133                                      if ((bool)value)
   4.134                                      {
   4.135 -                                        omi.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
   4.136 +                                        omi.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
   4.137                                                              true,
   4.138                                                              Outlook.OlUserPropertyType.olYesNo);
   4.139                                      }
   4.140                                      else
   4.141                                      {
   4.142 -                                        omi.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
   4.143 +                                        omi.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
   4.144                                      }
   4.145  
   4.146                                      success = true;
   4.147 @@ -3339,13 +3331,13 @@
   4.148                                  {
   4.149                                      if ((bool)value)
   4.150                                      {
   4.151 -                                        omi.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION,
   4.152 +                                        omi.SetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION,
   4.153                                                              true,
   4.154                                                              Outlook.OlUserPropertyType.olYesNo);
   4.155                                      }
   4.156                                      else
   4.157                                      {
   4.158 -                                        omi.DeleteUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ENABLE_PROTECTION);
   4.159 +                                        omi.DeleteUserProperty(MailItemWrapper.USER_PROPERTY_KEY_ENABLE_PROTECTION);
   4.160                                      }
   4.161  
   4.162                                      success = true;
     5.1 --- a/FPPMessage.cs	Wed Mar 13 13:50:02 2019 +0100
     5.2 +++ b/FPPMessage.cs	Thu Mar 14 15:36:43 2019 +0100
     5.3 @@ -367,7 +367,7 @@
     5.4                                      omi = Globals.ThisAddIn.Application.Session.GetItemFromID(this.CurrentEntryId);
     5.5                                  }
     5.6  
     5.7 -                                WatchedWindow window = omi?.GetWatchedParentWindow();
     5.8 +                                WindowBaseWrapper window = omi?.GetParentWindowWrapper();
     5.9                                  if (window != null)
    5.10                                  {
    5.11                                      WindowFormRegionCollection formRegions = Globals.FormRegions[window.Window];
    5.12 @@ -763,7 +763,7 @@
    5.13                              Log.Verbose("DecryptMessage: FormRegionPreviewUnencrypted not visible.");
    5.14                          }
    5.15  
    5.16 -                        omi.GetWatchedParentWindow()?.UpdateFormRegion(true);
    5.17 +                        omi.GetParentWindowWrapper()?.UpdateFormRegion(true);
    5.18                      }
    5.19  
    5.20                      status = Globals.ReturnStatus.Success;
     6.1 --- a/ThisAddIn.cs	Wed Mar 13 13:50:02 2019 +0100
     6.2 +++ b/ThisAddIn.cs	Thu Mar 14 15:36:43 2019 +0100
     6.3 @@ -53,8 +53,8 @@
     6.4          private List<WatchedFolder>         watchedFolders              = new List<WatchedFolder>();
     6.5          private System.Windows.Forms.Timer  inboxCleaner                = null;
     6.6  
     6.7 -        private List<WatchedExplorer>       watchedExplorers            = new List<WatchedExplorer>();
     6.8 -        private List<WatchedInspector>      watchedInspectors           = new List<WatchedInspector>();
     6.9 +        private List<ExplorerWrapper>       watchedExplorers            = new List<ExplorerWrapper>();
    6.10 +        private List<InspectorWrapper>      watchedInspectors           = new List<InspectorWrapper>();
    6.11          private object                      mutexWatchedExplorers       = new object();
    6.12          private object                      mutexWatchedInspectors      = new object();
    6.13          private Outlook.Explorers           explorers                   = null;
    6.14 @@ -214,7 +214,7 @@
    6.15          /// Adds a new WatchedExplorer to the list of watched explorers.
    6.16          /// </summary>
    6.17          /// <param name="watchedExplorer">The WatchedExplorer to add.</param>
    6.18 -        internal void AddToWatchedExplorers(WatchedExplorer watchedExplorer)
    6.19 +        internal void AddToWatchedExplorers(ExplorerWrapper watchedExplorer)
    6.20          {
    6.21              lock (mutexWatchedExplorers)
    6.22              {
    6.23 @@ -226,7 +226,7 @@
    6.24          /// Adds a new WatchedInspector to the list of watched inspectors.
    6.25          /// </summary>
    6.26          /// <param name="watchedInspector">The WatchedInspector to add.</param>
    6.27 -        internal void AddToWatchedInspectors(WatchedInspector watchedInspector)
    6.28 +        internal void AddToWatchedInspectors(InspectorWrapper watchedInspector)
    6.29          {
    6.30              lock (mutexWatchedInspectors)
    6.31              {
    6.32 @@ -238,7 +238,7 @@
    6.33          /// Removes a WatchedExplorer from the list of watched explorers.
    6.34          /// </summary>
    6.35          /// <param name="watchedExplorer">The WatchedExplorer to remove.</param>
    6.36 -        internal void RemoveFromWatchedExplorers(WatchedExplorer watchedExplorer)
    6.37 +        internal void RemoveFromWatchedExplorers(ExplorerWrapper watchedExplorer)
    6.38          {
    6.39              lock (mutexWatchedExplorers)
    6.40              {
    6.41 @@ -250,7 +250,7 @@
    6.42          /// Removes a WatchedInspector from the list of watched inspectors.
    6.43          /// </summary>
    6.44          /// <param name="WatchedInspector">The WatchedInspector to remove.</param>
    6.45 -        internal void RemoveFromWatchedInspectors(WatchedInspector watchedInspector)
    6.46 +        internal void RemoveFromWatchedInspectors(InspectorWrapper watchedInspector)
    6.47          {
    6.48              lock (mutexWatchedInspectors)
    6.49              {
    6.50 @@ -263,7 +263,7 @@
    6.51          /// </summary>
    6.52          /// <param name="omi">The Outlook mail item to process with.</param>
    6.53          /// <returns>The WatchedExplorer or WatchedInspector the mail item resides in or null if an error occured.</returns>
    6.54 -        internal WatchedWindow GetWatchedParentWindow(Outlook.MailItem omi)
    6.55 +        internal WindowBaseWrapper GetWatchedParentWindow(Outlook.MailItem omi)
    6.56          {
    6.57              try
    6.58              {
    6.59 @@ -299,11 +299,11 @@
    6.60          /// </summary>
    6.61          /// <param name="window">The Inspector or Explorer window to get its WatchedWindow for.</param>
    6.62          /// <returns>The watched window or null if not found.</returns>
    6.63 -        internal WatchedWindow GetWatchedWindow(dynamic window)
    6.64 +        internal WindowBaseWrapper GetWindowWrapper(dynamic window)
    6.65          {
    6.66              Outlook.Explorer explorer = null;
    6.67              Outlook.Inspector inspector = null;
    6.68 -            WatchedWindow watchedWindow = null;
    6.69 +            WindowBaseWrapper watchedWindow = null;
    6.70  
    6.71              try
    6.72              {
    6.73 @@ -687,11 +687,11 @@
    6.74          /// Sends a request to recalculate the message rating of all open windows (except one) again.
    6.75          /// </summary>
    6.76          /// <param name="windowToExclude">The window to not calculate its rating for</param>
    6.77 -        internal void RecalculateAllWindows(WatchedWindow windowToExclude)
    6.78 +        internal void RecalculateAllWindows(WindowBaseWrapper windowToExclude)
    6.79          {
    6.80              for (int i = 0; i < this.watchedExplorers.Count; i++)
    6.81              {
    6.82 -                if ((windowToExclude as WatchedExplorer)?.Equals(this.watchedExplorers[i]) != true)
    6.83 +                if ((windowToExclude as ExplorerWrapper)?.Equals(this.watchedExplorers[i]) != true)
    6.84                  {
    6.85                      this.watchedExplorers[i].RequestRatingAndUIUpdate();
    6.86                  }
    6.87 @@ -699,7 +699,7 @@
    6.88  
    6.89              for (int i = 0; i < this.watchedInspectors.Count; i++)
    6.90              {
    6.91 -                if ((windowToExclude as WatchedInspector)?.Equals(this.watchedInspectors[i]) != true)
    6.92 +                if ((windowToExclude as InspectorWrapper)?.Equals(this.watchedInspectors[i]) != true)
    6.93                  {
    6.94                      this.watchedInspectors[i].RequestRatingAndUIUpdate();
    6.95                  }
    6.96 @@ -2802,7 +2802,7 @@
    6.97  
    6.98                      for (int i = 1; i <= this.explorers.Count; i++)
    6.99                      {
   6.100 -                        this.watchedExplorers.Add(new WatchedExplorer(this.explorers[i]));
   6.101 +                        this.watchedExplorers.Add(new ExplorerWrapper(this.explorers[i]));
   6.102                      }
   6.103  
   6.104                      this.explorers.NewExplorer += Explorers_NewExplorer;
   6.105 @@ -2833,7 +2833,7 @@
   6.106          /// <param name="explorer">The newly opened explorer.</param>
   6.107          private void Explorers_NewExplorer(Outlook.Explorer explorer)
   6.108          {
   6.109 -            this.AddToWatchedExplorers(new WatchedExplorer(explorer));
   6.110 +            this.AddToWatchedExplorers(new ExplorerWrapper(explorer));
   6.111          }
   6.112  
   6.113          /// <summary>
   6.114 @@ -2851,7 +2851,7 @@
   6.115  
   6.116                      for (int i = 1; i <= this.inspectors.Count; i++)
   6.117                      {
   6.118 -                        this.watchedInspectors.Add(new WatchedInspector(this.inspectors[i]));
   6.119 +                        this.watchedInspectors.Add(new InspectorWrapper(this.inspectors[i]));
   6.120                      }
   6.121  
   6.122                      this.inspectors.NewInspector += Explorers_NewInspector;
   6.123 @@ -2882,7 +2882,7 @@
   6.124          /// <param name="inspector">The newly opened inspector.</param>
   6.125          private void Explorers_NewInspector(Outlook.Inspector inspector)
   6.126          {
   6.127 -            this.AddToWatchedInspectors(new WatchedInspector(inspector));
   6.128 +            this.AddToWatchedInspectors(new InspectorWrapper(inspector));
   6.129          }
   6.130  
   6.131          /// <summary>
     7.1 --- a/UI/FormControlPreviewMessage.xaml.cs	Wed Mar 13 13:50:02 2019 +0100
     7.2 +++ b/UI/FormControlPreviewMessage.xaml.cs	Thu Mar 14 15:36:43 2019 +0100
     7.3 @@ -359,7 +359,7 @@
     7.4                              // Update UI
     7.5                              try
     7.6                              {
     7.7 -                                WatchedWindow watchedWindow = Globals.ThisAddIn.GetWatchedWindow(Globals.ThisAddIn.Application.ActiveWindow());
     7.8 +                                WindowBaseWrapper watchedWindow = Globals.ThisAddIn.GetWindowWrapper(Globals.ThisAddIn.Application.ActiveWindow());
     7.9                                  watchedWindow.SetRating(pEpCOMServerAdapterLib.pEpRating.pEpRatingUndefined);
    7.10                              }
    7.11                              catch (Exception ex)
     8.1 --- a/UI/FormRegionPreviewUnencrypted.cs	Wed Mar 13 13:50:02 2019 +0100
     8.2 +++ b/UI/FormRegionPreviewUnencrypted.cs	Thu Mar 14 15:36:43 2019 +0100
     8.3 @@ -1,5 +1,6 @@
     8.4  using MimeKit;
     8.5  using pEp.UI;
     8.6 +using pEp.Wrappers;
     8.7  using pEpCOMServerAdapterLib;
     8.8  using System;
     8.9  using System.Windows.Input;
    8.10 @@ -40,7 +41,7 @@
    8.11                  {
    8.12                      e.Cancel = true;
    8.13                  }
    8.14 -                else if (string.IsNullOrEmpty(CryptableMailItem.PreviewAttachedMailId) == false)
    8.15 +                else if (string.IsNullOrEmpty(MailItemWrapper.PreviewAttachedMailId) == false)
    8.16                  {
    8.17                      HeaderList headers = omi.GetParsedTransportMessageHeaders();
    8.18                      string messageId = null;
    8.19 @@ -54,7 +55,7 @@
    8.20                          Log.Verbose("FormRegionPreviewUnencryptedFactory_FormRegionInitializing: Error getting MessageId from item. " + ex.ToString());
    8.21                      }
    8.22  
    8.23 -                    e.Cancel = (messageId?.Equals(CryptableMailItem.PreviewAttachedMailId) != true);
    8.24 +                    e.Cancel = (messageId?.Equals(MailItemWrapper.PreviewAttachedMailId) != true);
    8.25                  }
    8.26                  else
    8.27                  {
     9.1 --- a/UI/FormRegionPrivacyStatus.cs	Wed Mar 13 13:50:02 2019 +0100
     9.2 +++ b/UI/FormRegionPrivacyStatus.cs	Thu Mar 14 15:36:43 2019 +0100
     9.3 @@ -91,7 +91,7 @@
     9.4                  this.OutlookFormRegion.Visible = Globals.ThisAddIn.Settings.IsPrivacyStatusBarEnabled;
     9.5  
     9.6                  omi = this.OutlookItem as Outlook.MailItem;
     9.7 -                WatchedWindow window = omi?.GetWatchedParentWindow();
     9.8 +                WindowBaseWrapper window = omi?.GetParentWindowWrapper();
     9.9                  if (window != null)
    9.10                  {
    9.11                      this.UpdateFormRegion(window.PrivacyState);
    10.1 --- a/UI/RibbonCustomizations.cs	Wed Mar 13 13:50:02 2019 +0100
    10.2 +++ b/UI/RibbonCustomizations.cs	Thu Mar 14 15:36:43 2019 +0100
    10.3 @@ -27,7 +27,6 @@
    10.4          private static bool        DISABLE_FORCE_PROTECTION_DEFAULT    = false;
    10.5          private static bool        FORCE_PROTECTION_DEFAULT            = false;
    10.6          private static bool        FORCE_UNENCRYPTED_DEFAULT           = false;
    10.7 -        private static bool        IS_DRAFT_DEFAULT                    = false;
    10.8          private static bool        NEVER_UNSECURE_DEFAULT              = false;
    10.9          private static pEpRating   RATING_DEFAULT                      = pEpRating.pEpRatingUndefined;
   10.10  
   10.11 @@ -36,7 +35,6 @@
   10.12              DisableForceProtection,
   10.13              ForceProtection,
   10.14              ForceUnencrypted,
   10.15 -            IsDraft,
   10.16              NeverUnsecure,
   10.17              Rating
   10.18          }
   10.19 @@ -231,9 +229,15 @@
   10.20              return formRegion;
   10.21          }
   10.22  
   10.23 +        /// <summary>
   10.24 +        /// Gets a property that has been set via the ribbon controls.
   10.25 +        /// </summary>
   10.26 +        /// <param name="control">The ribbon control for which the property has to .</param>
   10.27 +        /// <param name="property">The property to get.</param>
   10.28 +        /// <returns>The property value or a default value if an error occured.</returns>
   10.29          private static dynamic GetRibbonProperty(Office.IRibbonControl control, MessageProperties property)
   10.30          {
   10.31 -            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control?.Context);
   10.32 +            WindowBaseWrapper window = Globals.ThisAddIn?.GetWindowWrapper(control?.Context);
   10.33  
   10.34              switch (property)
   10.35              {
   10.36 @@ -249,10 +253,6 @@
   10.37                      {
   10.38                          return window?.ForceUnencrypted ?? RibbonCustomizations.FORCE_UNENCRYPTED_DEFAULT;
   10.39                      }
   10.40 -                case MessageProperties.IsDraft:
   10.41 -                    {
   10.42 -                        return window?.IsDraft ?? RibbonCustomizations.IS_DRAFT_DEFAULT;
   10.43 -                    }
   10.44                  case MessageProperties.NeverUnsecure:
   10.45                      {
   10.46                          return window?.NeverUnsecure ?? RibbonCustomizations.NEVER_UNSECURE_DEFAULT;
   10.47 @@ -268,9 +268,15 @@
   10.48              return null;
   10.49          }
   10.50  
   10.51 +        /// <summary>
   10.52 +        /// Sets a property value in the context of a ribbon control.
   10.53 +        /// </summary>
   10.54 +        /// <param name="control">The ribbon control that is connected to the property.</param>
   10.55 +        /// <param name="property">The property to be set.</param>
   10.56 +        /// <param name="value">The property's value to be set.</param>
   10.57          private static void SetRibbonProperty(Office.IRibbonControl control, MessageProperties property, dynamic value)
   10.58          {
   10.59 -            WatchedWindow window = Globals.ThisAddIn?.GetWatchedWindow(control.Context);
   10.60 +            WindowBaseWrapper window = Globals.ThisAddIn?.GetWindowWrapper(control.Context);
   10.61  
   10.62              if (window != null)
   10.63              {
   10.64 @@ -291,11 +297,6 @@
   10.65                              window.ForceUnencrypted = (bool)value;
   10.66                          }
   10.67                          break;
   10.68 -                    case MessageProperties.IsDraft:
   10.69 -                        {
   10.70 -                            window.IsDraft = (bool)value;
   10.71 -                        }
   10.72 -                        break;
   10.73                      case MessageProperties.NeverUnsecure:
   10.74                          {
   10.75                              window.NeverUnsecure = (bool)value;
   10.76 @@ -667,11 +668,11 @@
   10.77                                  // Update UI
   10.78                                  if (string.IsNullOrEmpty(value as string))
   10.79                                  {
   10.80 -                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
   10.81 +                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
   10.82                                  }
   10.83                                  else
   10.84                                  {
   10.85 -                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.SetRating(pEpRating.pEpRatingReliable);
   10.86 +                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.SetRating(pEpRating.pEpRatingReliable);
   10.87                                  }
   10.88                                  break;
   10.89                              }
   10.90 @@ -706,7 +707,7 @@
   10.91                                      omi.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, value);
   10.92  
   10.93                                      // Update UI
   10.94 -                                    Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
   10.95 +                                    Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
   10.96                                  }
   10.97  
   10.98                                  break;
   10.99 @@ -781,7 +782,7 @@
  10.100          private void UpdateUI(Office.IRibbonControl control)
  10.101          {
  10.102              RibbonCustomizations.Invalidate();
  10.103 -            Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.UpdatePrivacyStateAndUI();
  10.104 +            Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.UpdatePrivacyStateAndUI();
  10.105          }
  10.106  
  10.107          /**************************************************************
  10.108 @@ -878,7 +879,7 @@
  10.109              try
  10.110              {
  10.111                  Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
  10.112 -                Globals.ThisAddIn.GetWatchedWindow(control.Context)?.BuildAndShowManager();
  10.113 +                Globals.ThisAddIn.GetWindowWrapper(control.Context)?.BuildAndShowManager();
  10.114              }
  10.115              catch (Exception ex)
  10.116              {
  10.117 @@ -891,7 +892,7 @@
  10.118          /// </summary>
  10.119          public System.Drawing.Bitmap ButtonPrivacyStatus_GetImage(Office.IRibbonControl control)
  10.120          {
  10.121 -            return Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.PrivacyState?.Image;
  10.122 +            return Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.PrivacyState?.Image;
  10.123          }
  10.124  
  10.125          /// <summary>
  10.126 @@ -899,7 +900,7 @@
  10.127          /// </summary>
  10.128          public string ButtonPrivacyStatus_GetLabel(Office.IRibbonControl control)
  10.129          {
  10.130 -            string label = Globals.ThisAddIn.GetWatchedWindow(control?.Context)?.PrivacyState?.Label;
  10.131 +            string label = Globals.ThisAddIn.GetWindowWrapper(control?.Context)?.PrivacyState?.Label;
  10.132  
  10.133              // Workaround to show ampersands correctly
  10.134              if (label?.Contains(" & ") == true)
  10.135 @@ -973,7 +974,7 @@
  10.136          public void ButtonSMIME_Clicked(Office.IRibbonControl control, bool pressed, ref bool cancel)
  10.137          {
  10.138              cancel = false;
  10.139 -            Globals.ThisAddIn.GetWatchedWindow(control.Context)?.RequestRatingAndUIUpdate();
  10.140 +            Globals.ThisAddIn.GetWindowWrapper(control.Context)?.RequestRatingAndUIUpdate();
  10.141          }
  10.142  
  10.143          ///////////////////////////////////////////////////////////
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/Wrappers/ExplorerWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
    11.3 @@ -0,0 +1,375 @@
    11.4 +using pEp.Wrappers;
    11.5 +using System;
    11.6 +using System.Linq;
    11.7 +using System.Xml;
    11.8 +using Outlook = Microsoft.Office.Interop.Outlook;
    11.9 +
   11.10 +namespace pEp
   11.11 +{
   11.12 +    /// <summary>
   11.13 +    /// Stores an Outlook Explorer with connected events.
   11.14 +    /// </summary>
   11.15 +    public class ExplorerWrapper : WindowBaseWrapper
   11.16 +    {
   11.17 +        private string                  lastProcessedEntryId    = null;
   11.18 +        private MailItemWrapper         inlineResponseItem      = null;
   11.19 +
   11.20 +        /**************************************************************
   11.21 +         * 
   11.22 +         * Constructors/Destructors
   11.23 +         * 
   11.24 +         *************************************************************/
   11.25 +
   11.26 +        /// <summary>
   11.27 +        /// Primary constructor.
   11.28 +        /// </summary>
   11.29 +        /// <param name="explorer">The explorer to watch.</param>
   11.30 +        public ExplorerWrapper(Outlook.Explorer explorer)
   11.31 +        {
   11.32 +            this.Explorer = explorer;
   11.33 +
   11.34 +            if (this.Explorer != null)
   11.35 +            {
   11.36 +                this.ConnectWatchedExplorerEvents(true);
   11.37 +            }
   11.38 +        }
   11.39 +
   11.40 +        #region Properties
   11.41 +
   11.42 +        /// <summary>
   11.43 +        /// Gets the Explorer that is wrapped by this WatchedExplorer.
   11.44 +        /// </summary>
   11.45 +        public Outlook.Explorer Explorer { get; private set; } = null;
   11.46 +
   11.47 +        /// <summary>
   11.48 +        /// Gets the Explorer that is wrapped by this WatchedExplorer.
   11.49 +        /// </summary>
   11.50 +        public override dynamic Window
   11.51 +        {
   11.52 +            get { return this.Explorer; }
   11.53 +        }
   11.54 +
   11.55 +        /// <summary>
   11.56 +        /// Gets the window type of this window.
   11.57 +        /// </summary>
   11.58 +        public override WindowType Type
   11.59 +        {
   11.60 +            get { return WindowType.Explorer; }
   11.61 +        }
   11.62 +
   11.63 +        #endregion
   11.64 +
   11.65 +        #region Methods
   11.66 +
   11.67 +        /**************************************************************
   11.68 +         * 
   11.69 +         * Methods
   11.70 +         * 
   11.71 +         *************************************************************/
   11.72 +
   11.73 +        /// <summary>
   11.74 +        /// Clean up any resources being used.
   11.75 +        /// </summary>
   11.76 +        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
   11.77 +        protected override void Dispose(bool disposing)
   11.78 +        {
   11.79 +            if (disposing)
   11.80 +            {
   11.81 +                // Disconnect all events
   11.82 +                this.ConnectWatchedExplorerEvents(false);
   11.83 +
   11.84 +                // Disconnect cryptable mail item
   11.85 +                if (this.inlineResponseItem != null)
   11.86 +                {
   11.87 +                    this.inlineResponseItem.Dispose();
   11.88 +                    this.inlineResponseItem = null;
   11.89 +                }
   11.90 +
   11.91 +                // Set Outlook objects to null
   11.92 +                this.Explorer = null;
   11.93 +
   11.94 +                // Dispose base class
   11.95 +                base.Dispose(disposing);
   11.96 +            }
   11.97 +        }
   11.98 +
   11.99 +        /// <summary>
  11.100 +        /// Connects the events for this watched explorer.
  11.101 +        /// <param name="connect">Whether to connect or disconnect the events.</param>
  11.102 +        /// </summary>
  11.103 +        private void ConnectWatchedExplorerEvents(bool connect)
  11.104 +        {
  11.105 +            try
  11.106 +            {
  11.107 +                if (connect)
  11.108 +                {
  11.109 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close += Explorer_Close;
  11.110 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch += Explorer_FolderSwitch;
  11.111 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose += Explorer_InlineResponseClose;
  11.112 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange += Explorer_SelectionChange;
  11.113 +                }
  11.114 +                else
  11.115 +                {
  11.116 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close -= Explorer_Close;
  11.117 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch -= Explorer_FolderSwitch;
  11.118 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose -= Explorer_InlineResponseClose;
  11.119 +                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange -= Explorer_SelectionChange;
  11.120 +                }
  11.121 +            }
  11.122 +            catch (Exception ex)
  11.123 +            {
  11.124 +                Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
  11.125 +            }
  11.126 +        }
  11.127 +        #endregion
  11.128 +
  11.129 +        #region Event Handling
  11.130 +        /**************************************************************
  11.131 +         * 
  11.132 +         * Event Handling
  11.133 +         * 
  11.134 +         *************************************************************/
  11.135 +
  11.136 +        /// <summary>
  11.137 +        /// Event handler for when a watched explorer is being closed.
  11.138 +        /// </summary>
  11.139 +        private void Explorer_Close()
  11.140 +        {
  11.141 +            Globals.ThisAddIn.RemoveFromWatchedExplorers(this);
  11.142 +            this.Dispose();
  11.143 +        }
  11.144 +
  11.145 +        /// <summary>
  11.146 +        /// Event handler for when a different folder is being selected.
  11.147 +        /// </summary>
  11.148 +        private void Explorer_FolderSwitch()
  11.149 +        {
  11.150 +            Outlook.Folder folder = null;
  11.151 +            Outlook.TableView customView = null;
  11.152 +            Outlook.View view = null;
  11.153 +            Outlook.Views views = null;
  11.154 +
  11.155 +            try
  11.156 +            {
  11.157 +                folder = this.Explorer?.CurrentFolder as Outlook.Folder;
  11.158 +
  11.159 +                // If the "Last Used" contacts folder is selected, make sure the correct view is applied
  11.160 +                if ((folder?.DefaultMessageClass?.Equals(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Contact) == true) &&
  11.161 +                    (folder?.Name?.Equals(Properties.Resources.LastUsedFolderName) == true))
  11.162 +                {
  11.163 +                    view = this.Explorer.CurrentView;
  11.164 +
  11.165 +                    // If the current view isn't the custom one, create it if necessary
  11.166 +                    if (view?.Name?.Equals(Properties.Resources.LastUsedFolderName) != true)
  11.167 +                    {
  11.168 +                        views = this.Explorer.CurrentFolder.Views as Outlook.Views;
  11.169 +
  11.170 +                        try
  11.171 +                        {
  11.172 +                            customView = views[Properties.Resources.LastUsedFolderName] as Outlook.TableView;
  11.173 +                        }
  11.174 +                        catch (Exception ex)
  11.175 +                        {
  11.176 +                            customView = null;
  11.177 +                            Log.Info("Explorer_SelectionChange: Error getting Last Used folder view. " + ex.ToString());
  11.178 +                        }
  11.179 +
  11.180 +                        /* If the custom view doesn't exist, create and apply it.
  11.181 +                         * If it already exists, don't apply it.
  11.182 +                         * Caveat: If the creation of the view went wrong at some point, it will never be set correctly. The alternative
  11.183 +                         *         here would be to set it each time it's not set. This is another problem, however, as we don't know if
  11.184 +                         *         the view of this folder is not the custom one because it has never been set correctly or if the user 
  11.185 +                         *         selects another one. So, in the latter case, we would basically override a user decision.
  11.186 +                         * Note: This whole procedure is a workaround because we can only set the Explorer's current view and not the folder's
  11.187 +                         *       current view directly.
  11.188 +                         */                           
  11.189 +                        if (customView == null)
  11.190 +                        {
  11.191 +                            customView = views.Add(Properties.Resources.LastUsedFolderName, Outlook.OlViewType.olTableView, Outlook.OlViewSaveOption.olViewSaveOptionThisFolderEveryone) as Outlook.TableView;
  11.192 +                            XmlDocument xmlDoc = new XmlDocument();
  11.193 +                            xmlDoc.LoadXml(customView.XML);
  11.194 +                            XmlNodeList childNodes = xmlDoc.LastChild.ChildNodes;
  11.195 +
  11.196 +                            // Create and/or set up Order By property
  11.197 +                            XmlNode orderByNode = childNodes.OfType<XmlNode>().First(a => (a.Name?.Equals("orderby", StringComparison.OrdinalIgnoreCase) == true));
  11.198 +                            if (orderByNode == null)
  11.199 +                            {
  11.200 +                                orderByNode = xmlDoc.CreateNode(XmlNodeType.Element, "orderby", string.Empty);
  11.201 +                                xmlDoc.LastChild.AppendChild(orderByNode);
  11.202 +                            }
  11.203 +                            orderByNode.InnerXml = "<order><heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><sort>desc</sort></order>";
  11.204 +
  11.205 +                            // Create and/or set up Modified column
  11.206 +                            XmlNode modifiedNode = childNodes.OfType<XmlNode>().FirstOrDefault(a => (a.ChildNodes.OfType<XmlNode>().FirstOrDefault(b => (b.Value?.Equals("Modified", StringComparison.OrdinalIgnoreCase) == true)) != null));
  11.207 +
  11.208 +                            if (modifiedNode == null)
  11.209 +                            {
  11.210 +                                modifiedNode = xmlDoc.CreateNode(XmlNodeType.Element, "column", string.Empty);
  11.211 +
  11.212 +                                // Get first column
  11.213 +                                XmlNode fullNameColumn = null;
  11.214 +                                foreach (var node in childNodes)
  11.215 +                                {
  11.216 +                                    if (((node as XmlNode)?.Name?.Equals("column", StringComparison.OrdinalIgnoreCase) == true) &&
  11.217 +                                        ((node as XmlNode)?.FirstChild?.InnerText?.Equals("Full Name", StringComparison.OrdinalIgnoreCase) == true))
  11.218 +                                    {
  11.219 +                                        fullNameColumn = node as XmlNode;
  11.220 +                                        break;
  11.221 +                                    }
  11.222 +                                }
  11.223 +
  11.224 +                                // If not found, just insert after the 4th column
  11.225 +                                if (fullNameColumn == null)
  11.226 +                                {
  11.227 +                                    fullNameColumn = childNodes[4];
  11.228 +                                }
  11.229 +
  11.230 +                                if (fullNameColumn != null)
  11.231 +                                {
  11.232 +                                    xmlDoc.LastChild.InsertAfter(modifiedNode, fullNameColumn);
  11.233 +                                }
  11.234 +                            }
  11.235 +                            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>";
  11.236 +
  11.237 +                            // Set modified XML
  11.238 +                            customView.XML = xmlDoc.OuterXml;
  11.239 +                            customView.Save();
  11.240 +
  11.241 +                            // Apply as current view
  11.242 +                            this.Explorer.CurrentView = customView;
  11.243 +                        }
  11.244 +                    }
  11.245 +                }
  11.246 +            }
  11.247 +            catch (Exception ex)
  11.248 +            {
  11.249 +                Log.Error("Explorer_FolderSwitch: Error setting Last Used folder view. " + ex.ToString());
  11.250 +            }
  11.251 +            finally
  11.252 +            {
  11.253 +                customView = null;
  11.254 +                folder = null;
  11.255 +                view = null;
  11.256 +                views = null;
  11.257 +            }
  11.258 +        }
  11.259 +
  11.260 +        /// <summary>
  11.261 +        /// Event handler for when an inline response is being closed.
  11.262 +        /// </summary>
  11.263 +        private void Explorer_InlineResponseClose()
  11.264 +        {
  11.265 +            Outlook.MailItem omi = null;
  11.266 +
  11.267 +            /* Create a new CryptableMailItem. This is needed so that its
  11.268 +             * MailItem_Write event gets called and the message will get saved
  11.269 +             * securely instead of to the server's draft folder.
  11.270 +             * Note: the form region's CMI is already disposed at this point,
  11.271 +             * so that its Write event will never be called.
  11.272 +             */
  11.273 +            try
  11.274 +            {
  11.275 +                omi = this.Explorer?.ActiveInlineResponse as Outlook.MailItem;
  11.276 +
  11.277 +                if (omi != null)
  11.278 +                {
  11.279 +                    this.inlineResponseItem = new MailItemWrapper(omi, null, false)
  11.280 +                    {
  11.281 +                        IsInlineResponse = true
  11.282 +                    };
  11.283 +                }
  11.284 +            }
  11.285 +            catch (Exception ex)
  11.286 +            {
  11.287 +                Log.Error("WatchedExplorer_InlineResponseClose: Error setting new inline response item. " + ex.ToString());
  11.288 +            }
  11.289 +            finally
  11.290 +            {
  11.291 +                omi = null;
  11.292 +            }
  11.293 +        }
  11.294 +
  11.295 +        /// <summary>
  11.296 +        /// Event handler for when the currently selected item in the explorer changes.
  11.297 +        /// </summary>
  11.298 +        private void Explorer_SelectionChange()
  11.299 +        {
  11.300 +            Outlook.Selection selection = null;
  11.301 +            try
  11.302 +            {
  11.303 +                // Process the newly selected item
  11.304 +                selection = this.Explorer.Selection;
  11.305 +
  11.306 +                /* Do only process the item if one individual item is selected.
  11.307 +                 * Do not process a selected range of items.
  11.308 +                 */
  11.309 +                if (selection.Count == 1)
  11.310 +                {
  11.311 +                    this.CurrentMailItem = selection[1] as Outlook.MailItem;
  11.312 +                    if (this.CurrentMailItem != null)
  11.313 +                    {
  11.314 +                        /* Check if inline response. Note: in Outlook 2010, there is no inline response.
  11.315 +                         * IMPORTANT: Never call Explorer.ActiveInlineResponse on Outlook 2010
  11.316 +                         *            as this might lead to a crash of Outlook (even inside a
  11.317 +                         *            try/catch block)
  11.318 +                         */
  11.319 +                        bool isInlineResponse = false;
  11.320 +                        if (Globals.OutlookVersion != Globals.Version.Outlook2010)
  11.321 +                        {
  11.322 +                            Outlook.MailItem inlineResponse = null;
  11.323 +                            try
  11.324 +                            {
  11.325 +                                inlineResponse = this.Explorer?.ActiveInlineResponse as Outlook.MailItem;
  11.326 +                                if (inlineResponse != null)
  11.327 +                                {
  11.328 +                                    isInlineResponse = true;
  11.329 +                                    this.CurrentMailItem = inlineResponse;
  11.330 +                                }
  11.331 +                            }
  11.332 +                            catch (Exception ex)
  11.333 +                            {
  11.334 +                                Log.Error("Explorer_SelectionChange: Error determining whether it is an inline response. " + ex.ToString());
  11.335 +                            }
  11.336 +                            finally
  11.337 +                            {
  11.338 +                                inlineResponse = null;
  11.339 +                            }
  11.340 +
  11.341 +                            /* If a different mail is clicked in an Window, the SelectionChange
  11.342 +                             * event is always called twice. To prevent a double processing, we only
  11.343 +                             * process a mail item if it is different from the last one that has been
  11.344 +                             * processed.
  11.345 +                             */
  11.346 +                            string entryId = isInlineResponse ? null : this.CurrentMailItem?.EntryID;
  11.347 +                            if (entryId?.Equals(lastProcessedEntryId, StringComparison.OrdinalIgnoreCase) == true)
  11.348 +                            {
  11.349 +                                Log.Verbose("Explorer_SelectionChange: Same EntryId as last item. Skipped processing of item with EntryId " + entryId);
  11.350 +                                return;
  11.351 +                            }
  11.352 +                            else
  11.353 +                            {
  11.354 +                                this.lastProcessedEntryId = entryId;
  11.355 +                            }
  11.356 +                        }
  11.357 +
  11.358 +                        // Initialize mail item
  11.359 +                        this.InitializeWindow(isInlineResponse);
  11.360 +                    }                    
  11.361 +                    else
  11.362 +                    {
  11.363 +                        Log.Error("Explorer_SelectionChange: Error getting current selection.");
  11.364 +                    }
  11.365 +                }
  11.366 +            }
  11.367 +            catch (Exception ex)
  11.368 +            {
  11.369 +                Log.Error("Explorer_SelectionChange: Error occured: " + ex?.ToString());
  11.370 +            }
  11.371 +            finally
  11.372 +            {
  11.373 +                selection = null;
  11.374 +            }
  11.375 +        }
  11.376 +        #endregion
  11.377 +    }
  11.378 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/Wrappers/InspectorWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
    12.3 @@ -0,0 +1,144 @@
    12.4 +using System;
    12.5 +using Outlook = Microsoft.Office.Interop.Outlook;
    12.6 +
    12.7 +namespace pEp
    12.8 +{
    12.9 +    /// <summary>
   12.10 +    /// Stores an Outlook Inspector with connected events.
   12.11 +    /// </summary>
   12.12 +    public class InspectorWrapper : WindowBaseWrapper
   12.13 +    {
   12.14 +
   12.15 +        /**************************************************************
   12.16 +         * 
   12.17 +         * Constructors/Destructors
   12.18 +         * 
   12.19 +         *************************************************************/
   12.20 +
   12.21 +        /// <summary>
   12.22 +        /// Primary constructor.
   12.23 +        /// </summary>
   12.24 +        /// <param name="inspector">The inspector to watch.</param>
   12.25 +        public InspectorWrapper(Outlook.Inspector inspector)
   12.26 +        {
   12.27 +            this.Inspector = inspector;
   12.28 +
   12.29 +            if (this.Inspector != null)
   12.30 +            {
   12.31 +                this.ConnectWatchedInspectorEvents();
   12.32 +
   12.33 +                // Set mail item
   12.34 +                this.CurrentMailItem = this.Inspector.CurrentItem as Outlook.MailItem;
   12.35 +
   12.36 +                if (this.CurrentMailItem != null)
   12.37 +                {
   12.38 +                    this.InitializeWindow();
   12.39 +                }
   12.40 +                else
   12.41 +                {
   12.42 +                    Log.Error("WatchedInspector: Error getting current mail item.");
   12.43 +                }
   12.44 +            }
   12.45 +        }
   12.46 +
   12.47 +        #region Properties
   12.48 +        /// <summary>
   12.49 +        /// Gets the Inspector that is wrapped by this WatchedInspector
   12.50 +        /// </summary>
   12.51 +        public Outlook.Inspector Inspector { get; private set; } = null;
   12.52 +
   12.53 +        /// <summary>
   12.54 +        /// Gets the Inspector that is wrapped by this WatchedInspector.
   12.55 +        /// </summary>
   12.56 +        public override dynamic Window
   12.57 +        {
   12.58 +            get { return this.Inspector; }
   12.59 +        }
   12.60 +
   12.61 +        /// <summary>
   12.62 +        /// Gets the window type of this window.
   12.63 +        /// </summary>
   12.64 +        public override WindowType Type
   12.65 +        {
   12.66 +            get { return WindowType.Inspector; }
   12.67 +        }
   12.68 +        #endregion
   12.69 +
   12.70 +        #region Methods
   12.71 +        /**************************************************************
   12.72 +         * 
   12.73 +         * Methods
   12.74 +         * 
   12.75 +         *************************************************************/
   12.76 +
   12.77 +        /// <summary>
   12.78 +        /// Clean up any resources being used.
   12.79 +        /// </summary>
   12.80 +        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
   12.81 +        protected override void Dispose(bool disposing)
   12.82 +        {
   12.83 +            if (disposing)
   12.84 +            {
   12.85 +                // Disconnect all events
   12.86 +                this.DisconnectWatchedInspectorEvents();
   12.87 +
   12.88 +                // Set Outlook objects to null
   12.89 +                this.Inspector = null;
   12.90 +
   12.91 +                // Dispose base class
   12.92 +                base.Dispose(disposing);
   12.93 +            }
   12.94 +        }
   12.95 +
   12.96 +        /// <summary>
   12.97 +        /// Connects the events for this watched explorer
   12.98 +        /// </summary>
   12.99 +        private void ConnectWatchedInspectorEvents()
  12.100 +        {
  12.101 +            if (this.Inspector != null)
  12.102 +            {
  12.103 +                ((Outlook.InspectorEvents_10_Event)this.Inspector).Close += WatchedInspector_Close;
  12.104 +            }
  12.105 +        }
  12.106 +
  12.107 +        /// <summary>
  12.108 +        /// Disconnects the events from this watched explorer
  12.109 +        /// </summary>
  12.110 +        private void DisconnectWatchedInspectorEvents()
  12.111 +        {
  12.112 +            if (this.Inspector != null)
  12.113 +            {
  12.114 +                ((Outlook.InspectorEvents_10_Event)this.Inspector).Close -= WatchedInspector_Close;
  12.115 +
  12.116 +            }
  12.117 +        }
  12.118 +
  12.119 +        #endregion
  12.120 +
  12.121 +        #region Event Handling
  12.122 +        /**************************************************************
  12.123 +         * 
  12.124 +         * Event Handling
  12.125 +         * 
  12.126 +         *************************************************************/
  12.127 +
  12.128 +        /// <summary>
  12.129 +        /// Event handler for when a watched inspector is being closed.
  12.130 +        /// </summary>
  12.131 +        private void WatchedInspector_Close()
  12.132 +        {
  12.133 +            Globals.ThisAddIn.RemoveFromWatchedInspectors(this);
  12.134 +            this.Dispose();
  12.135 +        }
  12.136 +
  12.137 +        /// <summary>
  12.138 +        /// Event handler for when the processing of an item in the WatchedInspector has finished.
  12.139 +        /// </summary>
  12.140 +        private void Inspector_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
  12.141 +        {
  12.142 +            Log.Error("Inspector_ProcessingCompleted: Not implemented.");
  12.143 +        }
  12.144 +
  12.145 +        #endregion
  12.146 +    }
  12.147 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/Wrappers/MailItemWrapper.cs	Thu Mar 14 15:36:43 2019 +0100
    13.3 @@ -0,0 +1,1947 @@
    13.4 +using MimeKit;
    13.5 +using pEp.UI;
    13.6 +using pEpCOMServerAdapterLib;
    13.7 +using System;
    13.8 +using System.Collections.Generic;
    13.9 +using System.ComponentModel;
   13.10 +using System.IO;
   13.11 +using System.Runtime.CompilerServices;
   13.12 +using System.Runtime.InteropServices;
   13.13 +using System.Threading;
   13.14 +using System.Threading.Tasks;
   13.15 +using Outlook = Microsoft.Office.Interop.Outlook;
   13.16 +
   13.17 +namespace pEp.Wrappers
   13.18 +{
   13.19 +    /// <summary>
   13.20 +    /// Wrapper for the Outlook MailItem supporting encryption.
   13.21 +    /// </summary>
   13.22 +    internal class MailItemWrapper : INotifyPropertyChanged,
   13.23 +                                     IDisposable
   13.24 +    {
   13.25 +        public const string USER_PROPERTY_KEY_FORCE_UNENCRYPTED         = "sendUnencrypted";
   13.26 +        public const string USER_PROPERTY_KEY_ENABLE_PROTECTION         = "enableProtection";
   13.27 +        public const string USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED   = "isOriginallyEncrypted";
   13.28 +        public const string USER_PROPERTY_KEY_ORIGINAL_RATING           = "originalRating";
   13.29 +
   13.30 +        public delegate void StdMailEventHandler(ref bool cancel);
   13.31 +        public delegate void RespondMailEventHandler(object item, ref bool cancel);
   13.32 +        public delegate void GenericHandler(object sender, EventArgs e);
   13.33 +        public delegate void ProcessingCompletedHandler(object sender, MsgProcessor.ProcessingCompletedEventArgs e);
   13.34 +        public delegate void GetMirrorCompletedHandler(object sender, GetMirrorCompletedEventArgs e);
   13.35 +
   13.36 +        /// <summary>
   13.37 +        /// Event when the internal mail item forward event occurs.
   13.38 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   13.39 +        /// Do not try to modify the item directly
   13.40 +        /// </summary>
   13.41 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.42 +        public event RespondMailEventHandler Forward;
   13.43 +
   13.44 +        /// <summary>
   13.45 +        /// Event when the internal mail item open event occurs.
   13.46 +        /// </summary>
   13.47 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.48 +        public event StdMailEventHandler Open;
   13.49 +
   13.50 +        /// <summary>
   13.51 +        /// Event when the internal mail item reply event occurs.
   13.52 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   13.53 +        /// Do not try to modify the item directly
   13.54 +        /// </summary>
   13.55 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.56 +        public event RespondMailEventHandler Reply;
   13.57 +
   13.58 +        /// <summary>
   13.59 +        /// Event when the internal mail item reply to all event occurs.
   13.60 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
   13.61 +        /// Do not try to modify the item directly
   13.62 +        /// </summary>
   13.63 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.64 +        public event RespondMailEventHandler ReplyAll;
   13.65 +
   13.66 +        /// <summary>
   13.67 +        /// Event when the internal mail item send event occurs.
   13.68 +        /// </summary>
   13.69 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.70 +        public event StdMailEventHandler Send;
   13.71 +
   13.72 +        /// <summary>
   13.73 +        /// Event when the internal mail item write event occurs.
   13.74 +        /// </summary>
   13.75 +        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly")]
   13.76 +        public event StdMailEventHandler Write;
   13.77 +
   13.78 +        /// <summary>
   13.79 +        /// Event when either a cryptable mail item property change occurs, or
   13.80 +        /// when the internal mail item property change event occurs.
   13.81 +        /// </summary>
   13.82 +        public event PropertyChangedEventHandler PropertyChanged;
   13.83 +
   13.84 +        /// <summary>
   13.85 +        /// Event when processing of this cryptable mail item is completed.
   13.86 +        /// WARNING: The calling thread is a background worker.
   13.87 +        /// </summary>
   13.88 +        public event ProcessingCompletedHandler ProcessingCompleted;
   13.89 +
   13.90 +        /// <summary>
   13.91 +        /// Event when the get mirror search is completed.
   13.92 +        /// WARNING: The calling thread is a background worker.
   13.93 +        /// </summary>
   13.94 +        public event GetMirrorCompletedHandler GetMirrorCompleted;
   13.95 +
   13.96 +        public delegate void OriginallyEncryptedStatusUpdateHandler(object sender, EventArgs e);
   13.97 +        public event OriginallyEncryptedStatusUpdateHandler OriginallyEncryptedStatusUpdated;
   13.98 +
   13.99 +        private pEpRating            _LastProcessedRating;
  13.100 +        private Globals.ReturnStatus _LastProcessedStatus;
  13.101 +
  13.102 +        private bool                                        disposeAfterProcessing;
  13.103 +        private bool                                        decrementCounter;
  13.104 +        private bool                                        sent;
  13.105 +        private bool                                        isClosed;
  13.106 +
  13.107 +        private Outlook.MailItem                            wrappedMailItem;
  13.108 +        private readonly BackgroundWorker                   mirrorLocator;
  13.109 +        private readonly BackgroundWorker                   processor;
  13.110 +
  13.111 +        private string                                      draftEntryId            = null;
  13.112 +        private string                                      draftFileName           = null;
  13.113 +        private readonly object                             mutexMailItem           = new object();
  13.114 +        private static readonly object                      mutexConversation       = new object();
  13.115 +        private static readonly object                      mutexDecryptionList     = new object();
  13.116 +        private static readonly List<OriginalMailItem>      conversationCache       = new List<OriginalMailItem>();
  13.117 +        private static Dictionary<string, string>           decryptionList          = new Dictionary<string, string>();
  13.118 +
  13.119 +        // Property fields of the wrapped item
  13.120 +        private Outlook.OlDownloadState?                    _DownloadState          = null;
  13.121 +        private bool?                                       _IsDraft                = null;
  13.122 +        private bool?                                       _IsForcefullyProtected  = null;
  13.123 +        private bool?                                       _IsIncoming             = null;
  13.124 +        private bool?                                       _IsInSecureStore        = null;
  13.125 +        private bool?                                       _IsMirror               = null;
  13.126 +        private bool?                                       _IsOriginallyEncrypted  = null;
  13.127 +        private bool?                                       _IsSecure               = null;
  13.128 +
  13.129 +        /// <summary>
  13.130 +        /// Stores the message id of an attached mail item if it is loaded into the preview.
  13.131 +        /// See comments below in MailItem_BeforeAttachmentPreview event handler.
  13.132 +        /// </summary>
  13.133 +        public static string PreviewAttachedMailId = null;
  13.134 +
  13.135 +        /// <summary>
  13.136 +        /// Whether to cancel the opening event of the internal mail item. Default is false.
  13.137 +        /// </summary>
  13.138 +        public bool CancelOpen { get; set; } = false;
  13.139 +
  13.140 +        /// <summary>
  13.141 +        /// The messageId of the internal mail item. Only needed for special cases like attached mails.
  13.142 +        /// </summary>
  13.143 +        public string MessageId { get; set; } = null;
  13.144 +
  13.145 +        /// <summary>
  13.146 +        /// Whether the internal mail item is an inline response
  13.147 +        /// </summary>
  13.148 +        public bool IsInlineResponse { get; set; } = false;
  13.149 +
  13.150 +        /// <summary>
  13.151 +        /// Whether the internal mail item is an attached mail.
  13.152 +        /// </summary>
  13.153 +        public bool IsSecureAttachedMail { get; set; } = false;
  13.154 +
  13.155 +        /// <summary>
  13.156 +        /// The mirror of the internal mail item stored as PEPMessage.
  13.157 +        /// </summary>
  13.158 +        public PEPMessage Mirror { get; set; } = null;
  13.159 +
  13.160 +        /// <summary>
  13.161 +        /// The PEPMessage of this mail item.
  13.162 +        /// </summary>
  13.163 +        public PEPMessage Message { get; set; } = null;
  13.164 +
  13.165 +        /**************************************************************
  13.166 +         * 
  13.167 +         * Constructors/Destructors
  13.168 +         * 
  13.169 +         *************************************************************/
  13.170 +
  13.171 +        /// <summary>
  13.172 +        /// Primary constructor creating the cryptable mail item from an existing outlook mail item.
  13.173 +        /// </summary>
  13.174 +        /// <param name="mailItem">The mail item to wrap and make cryptable.</param>
  13.175 +        /// <param name="defaultRating">The default rating for this cryptable mail item.</param>
  13.176 +        /// <param name="decrementCounter">Whether or not to decrement the decryption counter after processing.</param>
  13.177 +        public MailItemWrapper(Outlook.MailItem mailItem,
  13.178 +                                 pEpRating? defaultRating = null,
  13.179 +                                 bool decrementCounter = false)
  13.180 +        {
  13.181 +            this.wrappedMailItem = mailItem;
  13.182 +            this.ConnectInternalMailItemEvents(true);
  13.183 +
  13.184 +            this.disposeAfterProcessing = false;
  13.185 +            this.decrementCounter = decrementCounter;
  13.186 +            this._LastProcessedRating = defaultRating ?? pEpRating.pEpRatingUndefined;
  13.187 +            this._LastProcessedStatus = Globals.ReturnStatus.Success;
  13.188 +
  13.189 +            // Setup the message processor background worker
  13.190 +            this.processor = new BackgroundWorker
  13.191 +            {
  13.192 +                WorkerSupportsCancellation = false,
  13.193 +            };
  13.194 +            this.processor.RunWorkerCompleted += Processor_RunWorkerCompleted;
  13.195 +            this.processor.DoWork += Processor_DoWork;
  13.196 +
  13.197 +            // Setup the mirror locator background worker
  13.198 +            this.mirrorLocator = new BackgroundWorker
  13.199 +            {
  13.200 +                WorkerSupportsCancellation = false
  13.201 +            };
  13.202 +            this.mirrorLocator.RunWorkerCompleted += MirrorLocator_RunWorkerCompleted;
  13.203 +            this.mirrorLocator.DoWork += MirrorLocator_DoWork;
  13.204 +        }
  13.205 +
  13.206 +        /// <summary>
  13.207 +        /// Destructor.
  13.208 +        /// </summary>
  13.209 +        ~MailItemWrapper()
  13.210 +        {
  13.211 +            // This should have been called in code before garbage collection, but call it just in case
  13.212 +            this.Dispose(true);
  13.213 +        }
  13.214 +
  13.215 +        /**************************************************************
  13.216 +         * 
  13.217 +         * Event Handling
  13.218 +         * 
  13.219 +         *************************************************************/
  13.220 +
  13.221 +        /// <summary>
  13.222 +        /// Event hander for when an attachment is previewed. Occurs before the preview occurs
  13.223 +        /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.beforeattachmentpreview.aspx
  13.224 +        /// </summary>
  13.225 +        /// <param name="attachment">The attachment that is about to be previewed.</param>
  13.226 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.227 +        /// If the event procedure sets this argument to True, the operation is not completed
  13.228 +        /// and the attachment is not previewed.</param>
  13.229 +        private void MailItem_BeforeAttachmentPreview(Outlook.Attachment attachment, ref bool cancel)
  13.230 +        {
  13.231 +            /* Check if the attachment to be previewed is a mail item and store its messageId in the 
  13.232 +             * static PreviewAttachedMailId property. This is a somewhat clumsy workaround, but is needed
  13.233 +             * because we need to know upon processing of the mail item whether it is an attached mail
  13.234 +             * and whether it is opened (a) or previewed (b).
  13.235 +             *      => a. Cancel opening and open mirror
  13.236 +             *      => b. Display mirror in preview window
  13.237 +             * As all methods to store the relevant information directly in the attached mail failed, we 
  13.238 +             * set the messageId during this event and query it in FormRegionPrivacyStatus_FormRegionShowing.
  13.239 +             */
  13.240 +            try
  13.241 +            {
  13.242 +                PEPAttachment attach = new PEPAttachment(attachment);
  13.243 +
  13.244 +                // Exclude based on file name and/or MIME type (for performance)
  13.245 +                if ((attach.Data != null) &&
  13.246 +                    ((Path.GetExtension(attach.FileName)?.Equals(".eml") == true) ||
  13.247 +                     (Path.GetExtension(attach.FileName)?.Equals(".msg") == true) ||
  13.248 +                     (attach.MimeType?.Equals("text/rfc822") == true)))
  13.249 +                {
  13.250 +                    // Try to convert attachment into MIME message
  13.251 +                    MimeMessage message;
  13.252 +                    MemoryStream memoryStream;
  13.253 +                    using (memoryStream = new MemoryStream(attach.Data))
  13.254 +                    {
  13.255 +                        message = MimeMessage.Load(memoryStream);
  13.256 +                    }
  13.257 +
  13.258 +                    // If conversion was successful, attachment is mail
  13.259 +                    if (message != null)
  13.260 +                    {
  13.261 +                        string messageId = null;
  13.262 +
  13.263 +                        // Retrieve the mail's messageId
  13.264 +                        if (message?.Headers?.Contains(HeaderId.MessageId) == true)
  13.265 +                        {
  13.266 +                            messageId = message.Headers?[HeaderId.MessageId];
  13.267 +                        }
  13.268 +
  13.269 +                        // Save messageId
  13.270 +                        if (string.IsNullOrEmpty(messageId) == false)
  13.271 +                        {
  13.272 +                            MailItemWrapper.PreviewAttachedMailId = messageId;
  13.273 +                        }
  13.274 +                    }
  13.275 +                }
  13.276 +            }
  13.277 +            catch (Exception ex)
  13.278 +            {
  13.279 +                MailItemWrapper.PreviewAttachedMailId = null;
  13.280 +                Log.Error("MailItem_BeforeAttachmentPreview: Error determining if attachment is mail. " + ex.ToString());
  13.281 +            }
  13.282 +        }
  13.283 +
  13.284 +        /// <summary>
  13.285 +        /// Event handler for when the internal mail item is closed. Occurs when the inspector 
  13.286 +        /// associated with the item (which is an instance of the parent object) is being closed.
  13.287 +        /// See https://docs.microsoft.com/de-de/office/vba/api/outlook.mailitem.close(even)
  13.288 +        /// </summary>
  13.289 +        /// <param name="cancel">Whether to cancel the event</param>
  13.290 +        private void MailItem_Close(ref bool cancel)
  13.291 +        {
  13.292 +            this.isClosed = (cancel == false);
  13.293 +        }
  13.294 +
  13.295 +        /// <summary>
  13.296 +        /// Event handler for when the internal mail item is forwarded.
  13.297 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
  13.298 +        /// Do not try to modify the item directly
  13.299 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff862702.aspx
  13.300 +        /// </summary>
  13.301 +        /// <param name="item">The new item being forwarded.</param>
  13.302 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs.
  13.303 +        /// If the event procedure sets this argument to True, the forward operation is not completed 
  13.304 +        /// and the new item is not displayed.</param>
  13.305 +        private void MailItem_Forward(object item, ref bool cancel)
  13.306 +        {
  13.307 +            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
  13.308 +            this.Forward?.Invoke(item, ref cancel);
  13.309 +        }
  13.310 +
  13.311 +        /// <summary>
  13.312 +        /// Event handler for when the internal mail item is being opened in an inspector.
  13.313 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
  13.314 +        /// </summary>
  13.315 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.316 +        /// If the event procedure sets this argument to True, the open operation is not completed 
  13.317 +        /// and the inspector is not displayed.</param>
  13.318 +        private void MailItem_Open(ref bool cancel)
  13.319 +        {
  13.320 +            cancel = this.CancelOpen;
  13.321 +            this.Open?.Invoke(ref cancel);
  13.322 +        }
  13.323 +
  13.324 +        /// <summary>
  13.325 +        /// Event handler for when the internal mail item property is changed.
  13.326 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
  13.327 +        /// </summary>
  13.328 +        /// <param name="propertyName">The name of the property that was changed.</param>
  13.329 +        private void MailItem_PropertyChange(string propertyName)
  13.330 +        {
  13.331 +            this.OnPropertyChanged(propertyName);
  13.332 +            return;
  13.333 +        }
  13.334 +
  13.335 +        /// <summary>
  13.336 +        /// Event handler for when the internal mail item is replied to.
  13.337 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
  13.338 +        /// Do not try to modify the item directly
  13.339 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
  13.340 +        /// </summary>
  13.341 +        /// <param name="item">The new item being sent in response to the original message.</param>
  13.342 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.343 +        /// If the event procedure sets this argument to True, the reply operation is not completed 
  13.344 +        /// and the new item is not displayed.</param>
  13.345 +        private void MailItem_Reply(object item, ref bool cancel)
  13.346 +        {
  13.347 +            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
  13.348 +            this.Reply?.Invoke(item, ref cancel);
  13.349 +        }
  13.350 +
  13.351 +        /// <summary>
  13.352 +        /// Event handler for when the internal mail item is replied to all recipients.
  13.353 +        /// Warning: This is called after the item is intialized externally, AND the item will then be changed.
  13.354 +        /// Do not try to modify the item directly
  13.355 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff860938.aspx
  13.356 +        /// </summary>
  13.357 +        /// <param name="item">The new item being sent in response to the original message.</param>
  13.358 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.359 +        /// If the event procedure sets this argument to True, the reply operation is not completed 
  13.360 +        /// and the new item is not displayed.</param>
  13.361 +        private void MailItem_ReplyAll(object item, ref bool cancel)
  13.362 +        {
  13.363 +            this.SetOriginallyEncryptedStatus(item as Outlook.MailItem);
  13.364 +            this.ReplyAll?.Invoke(item, ref cancel);
  13.365 +        }
  13.366 +
  13.367 +        /// <summary>
  13.368 +        /// Event handler for when the internal mail item is sent.
  13.369 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
  13.370 +        /// </summary>
  13.371 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.372 +        /// If the event procedure sets this argument to True, the send operation is not completed 
  13.373 +        /// and the inspector is left open.</param>
  13.374 +        private void MailItem_Send(ref bool cancel)
  13.375 +        {
  13.376 +            this.Send?.Invoke(ref cancel);
  13.377 +            this.sent = true;
  13.378 +        }
  13.379 +
  13.380 +        /// <summary>
  13.381 +        /// Event handler for when the internal mail item is written (Save, SaveAs, etc...)
  13.382 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff868664.aspx
  13.383 +        /// </summary>
  13.384 +        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
  13.385 +        /// If the event procedure sets this argument to True, the save operation is not completed.
  13.386 +        /// </param>
  13.387 +        private void MailItem_Write(ref bool cancel)
  13.388 +        {
  13.389 +#if !READER_RELEASE_MODE
  13.390 +            /* Save drafts for untrusted servers in a secure location.
  13.391 +             * First we try to save it to a custom drafts folder in the pEp store
  13.392 +             * and make this store visible in the favorites.
  13.393 +             * If this fails, as a fallback solution, we offer to save as a message file.
  13.394 +             * Note: Inline responses need to be processed differently.
  13.395 +             */
  13.396 +            if ((this.sent == false) &&
  13.397 +                (this.IsPEPMessage == false) &&
  13.398 +                (this.wrappedMailItem.GetIsDraft()) &&
  13.399 +                ((this.wrappedMailItem.GetIsInSecureStore() || this.wrappedMailItem.GetNeverUnsecure())))
  13.400 +            {
  13.401 +                bool useFallback = false;
  13.402 +                Outlook.Folder parentFolder = null;
  13.403 +                Outlook.Folder pEpDraftsFolder = null;
  13.404 +                Outlook.Inspector currentInspector = null;
  13.405 +                Outlook.Inspector newInspector = null;
  13.406 +                Outlook.MailItem omi = null;
  13.407 +
  13.408 +                Outlook.Application app = null;
  13.409 +                Outlook.Explorer activeExplorer = null;
  13.410 +                Outlook.NavigationPane navPane = null;
  13.411 +                Outlook.NavigationModules navModules = null;
  13.412 +                Outlook.MailModule mailModule = null;
  13.413 +                Outlook.NavigationGroups navGroups = null;
  13.414 +                Outlook.NavigationGroup navGroup = null;
  13.415 +                Outlook.NavigationFolders navFolders = null;
  13.416 +
  13.417 +                try
  13.418 +                {
  13.419 +                    // Get the pEp drafts folder and the current mail item's folder
  13.420 +                    pEpDraftsFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
  13.421 +
  13.422 +                    // Get the caret position to later set it again
  13.423 +                    bool caretPositionRetrieved = false;
  13.424 +                    NativeMethods.Point caretPosition = new NativeMethods.Point(-1,-1);
  13.425 +                    IntPtr inspectorHandle = IntPtr.Zero;
  13.426 +
  13.427 +                    try
  13.428 +                    {
  13.429 +                        // First, get the current process to retrieve a handle to the caret's window
  13.430 +                        uint currentThreadId = NativeMethods.GetCurrentThreadId();
  13.431 +                        NativeMethods.GuiThreadInfo guiThreadInfo = new NativeMethods.GuiThreadInfo();
  13.432 +                        guiThreadInfo.size = Marshal.SizeOf(guiThreadInfo);
  13.433 +
  13.434 +                        if (NativeMethods.GetGUIThreadInfo(currentThreadId, ref guiThreadInfo))
  13.435 +                        {
  13.436 +                            inspectorHandle = guiThreadInfo.hwndCaret;
  13.437 +
  13.438 +                            // Get caret position and convert to screen coordinates
  13.439 +                            if (NativeMethods.GetCaretPos(out caretPosition) &&
  13.440 +                                NativeMethods.ClientToScreen(inspectorHandle, ref caretPosition))
  13.441 +                            {
  13.442 +                                caretPositionRetrieved = true;
  13.443 +                            }
  13.444 +                            else
  13.445 +                            {
  13.446 +                                int error = Marshal.GetLastWin32Error();
  13.447 +                                Log.Error("MailItem_Write: Error getting caret position. Last Win32 error: " + error.ToString("X"));
  13.448 +                            }
  13.449 +                        }
  13.450 +                        else
  13.451 +                        {
  13.452 +                            int error = Marshal.GetLastWin32Error();
  13.453 +                            Log.Error("MailItem_Write: Error getting inspector Handle. Last Win32 error: " + error.ToString("X"));
  13.454 +                        }
  13.455 +                    }
  13.456 +                    catch (Exception ex)
  13.457 +                    {
  13.458 +                        Log.Error("MailItem_Write: Error getting caret position. " + ex.ToString());
  13.459 +                    }
  13.460 +
  13.461 +                    /* Inline responses need a special treatment.
  13.462 +                     * We cannot just intercept the Write event and check, if the item
  13.463 +                     * is in the pEp folder, as it gets synced to the server anyhow if we
  13.464 +                     * don't cancel the event.
  13.465 +                     * So, we look up if the mail item is already present in pEp drafts and overwrite it 
  13.466 +                     * with the current state if possible. If the item isn't there yet, create new item, 
  13.467 +                     * move to pEp drafts folder and save current state.
  13.468 +                     */
  13.469 +                    if (this.IsInlineResponse)
  13.470 +                    {
  13.471 +                        Outlook.Items items = null;
  13.472 +                        Outlook.MailItem draft = null;
  13.473 +
  13.474 +                        try
  13.475 +                        {
  13.476 +                            // Always cancel
  13.477 +                            cancel = true;
  13.478 +
  13.479 +                            // Try to find the draft (if existing)
  13.480 +                            if (string.IsNullOrEmpty(this.draftEntryId) == false)
  13.481 +                            {
  13.482 +                                // Get all items in the pEp drafts folder with the same subject as the current draft
  13.483 +                                items = pEpDraftsFolder?.Items?.Restrict(string.Format("[Subject] = '{0}'", this.wrappedMailItem?.Subject));
  13.484 +
  13.485 +                                for (int i = 1; i <= items?.Count; i++)
  13.486 +                                {
  13.487 +                                    draft = items[i] as Outlook.MailItem;
  13.488 +
  13.489 +                                    if (draftEntryId.Equals(draft?.EntryID) == true)
  13.490 +                                    {
  13.491 +                                        // Draft found. Just break and continue.
  13.492 +                                        break;
  13.493 +                                    }
  13.494 +
  13.495 +                                    draft = null;
  13.496 +                                }
  13.497 +
  13.498 +                                items = null;
  13.499 +                            }
  13.500 +
  13.501 +                            if (PEPMessage.Create(this.wrappedMailItem, out PEPMessage createdMessage) == Globals.ReturnStatus.Success)
  13.502 +                            {
  13.503 +                                if (draft == null)
  13.504 +                                {
  13.505 +                                    draft = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
  13.506 +                                    createdMessage.ApplyTo(draft, true, true);
  13.507 +                                    draft = draft.Move(pEpDraftsFolder);
  13.508 +                                    draft.Save();
  13.509 +                                    this.draftEntryId = draft.EntryID;
  13.510 +                                }
  13.511 +                                else
  13.512 +                                {
  13.513 +                                    createdMessage.ApplyTo(draft, true, true);
  13.514 +                                    draft.Save();
  13.515 +                                }
  13.516 +                            }
  13.517 +                            else
  13.518 +                            {
  13.519 +                                Log.Error("MailItem_Write: Error creating PEPMessage.");
  13.520 +                            }
  13.521 +                        }
  13.522 +                        catch (Exception ex)
  13.523 +                        {
  13.524 +                            Log.Error("MailItem_Write: Error saving inline item. " + ex.ToString());
  13.525 +                        }
  13.526 +                        finally
  13.527 +                        {
  13.528 +                            items = null;
  13.529 +                            omi = null;
  13.530 +                        }
  13.531 +                    }
  13.532 +                    else
  13.533 +                    {
  13.534 +                        // Get the mail item's parent folder
  13.535 +                        parentFolder = this.wrappedMailItem.Parent as Outlook.Folder;
  13.536 +
  13.537 +                        // Save to pEp folder if not already there
  13.538 +                        if (pEpDraftsFolder?.FullFolderPath?.Equals(parentFolder?.FullFolderPath) == false)
  13.539 +                        {
  13.540 +                            currentInspector = this.wrappedMailItem.GetInspector;
  13.541 +                            //omi = this.internalMailItem.Copy();
  13.542 +                            omi = this.wrappedMailItem.Move(pEpDraftsFolder);
  13.543 +
  13.544 +                            if (currentInspector != null)
  13.545 +                            {
  13.546 +                                Outlook.OlWindowState windowState = currentInspector.WindowState;
  13.547 +                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
  13.548 +
  13.549 +                                if (windowState == Outlook.OlWindowState.olNormalWindow)
  13.550 +                                {
  13.551 +                                    newInspector.Left = currentInspector.Left;
  13.552 +                                    newInspector.Top = currentInspector.Top;
  13.553 +                                    newInspector.Width = currentInspector.Width;
  13.554 +                                    newInspector.Height = currentInspector.Height;
  13.555 +                                }
  13.556 +
  13.557 +                                /* In some circumstances (e.g. ForceProtection on Exchange), the Sender information 
  13.558 +                                 * may be missing. If this is the case, try to add it from the internal mail item.
  13.559 +                                 */
  13.560 +                                try
  13.561 +                                {
  13.562 +                                    // Check if there really is no useful Sender information
  13.563 +                                    if ((omi != null) &&
  13.564 +                                        (omi.Sender == null) &&
  13.565 +                                        (string.IsNullOrEmpty(omi.SenderEmailAddress)) &&
  13.566 +                                        (omi.SendUsingAccount == null))
  13.567 +                                    {
  13.568 +                                        // Try to add SendUsingAccount
  13.569 +                                        if (this.wrappedMailItem.SendUsingAccount != null)
  13.570 +                                        {
  13.571 +                                            omi.SendUsingAccount = this.wrappedMailItem.SendUsingAccount;
  13.572 +                                        }
  13.573 +
  13.574 +                                        // Try to add the Sender directly
  13.575 +                                        if (this.wrappedMailItem.Sender != null)
  13.576 +                                        {
  13.577 +                                            omi.Sender = this.wrappedMailItem.Sender;
  13.578 +                                        }
  13.579 +                                    }
  13.580 +                                }
  13.581 +                                catch (Exception ex)
  13.582 +                                {
  13.583 +                                    Log.Error("MailItem_Write: Error determining/setting sender information of new Inspector. " + ex.ToString());
  13.584 +                                }
  13.585 +
  13.586 +                                newInspector.Display();
  13.587 +                                newInspector.WindowState = windowState;
  13.588 +                                currentInspector.Close(Outlook.OlInspectorClose.olDiscard);
  13.589 +
  13.590 +                                // Set caret position again to where it was before
  13.591 +                                if (caretPositionRetrieved)
  13.592 +                                {
  13.593 +                                    try
  13.594 +                                    {
  13.595 +                                        // Set cursor to the caret's previous position
  13.596 +                                        NativeMethods.SetCursorPos(caretPosition.X, caretPosition.Y);
  13.597 +
  13.598 +                                        // Send mouse click event (mouse down and mouse up)
  13.599 +                                        NativeMethods.Input[] inputs = new NativeMethods.Input[1];
  13.600 +                                        inputs[0].Type = (int)NativeMethods.InputType.InputMouse;
  13.601 +                                        inputs[0].Mi.Flags = (int)NativeMethods.MouseEvents.MouseEventFLeftDown | (int)NativeMethods.MouseEvents.MouseEventFLeftUp;
  13.602 +
  13.603 +                                        if (NativeMethods.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(inputs[0])) == 0)
  13.604 +                                        {
  13.605 +                                            int error = Marshal.GetLastWin32Error();
  13.606 +                                            Log.Error("MailItem_Write: Error setting caret to original position. Win32 error " + error.ToString("X"));
  13.607 +                                        }
  13.608 +                                    }
  13.609 +                                    catch (Exception ex)
  13.610 +                                    {
  13.611 +                                        Log.Error("MailItem_Write: Error setting caret to original position. " + ex.ToString());
  13.612 +                                    }
  13.613 +                                }
  13.614 +                            }
  13.615 +                            else
  13.616 +                            {
  13.617 +                                newInspector = Globals.ThisAddIn?.Application?.Inspectors?.Add(omi);
  13.618 +                                newInspector.Display();
  13.619 +                            }
  13.620 +
  13.621 +                            cancel = true;
  13.622 +                        }
  13.623 +                    }
  13.624 +
  13.625 +                    /* Add the pEp drafts folder to favorites.
  13.626 +                     * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
  13.627 +                     * To make this more secure, we only proceed if the pEp store is already visible at this point.
  13.628 +                     * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
  13.629 +                     * to the favorites next time.
  13.630 +                     */
  13.631 +                    if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
  13.632 +                    {
  13.633 +                        // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
  13.634 +                        app = Globals.ThisAddIn?.Application;
  13.635 +                        activeExplorer = app?.ActiveExplorer();
  13.636 +                        navPane = activeExplorer?.NavigationPane;
  13.637 +                        navModules = navPane?.Modules;
  13.638 +                        mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
  13.639 +                        navGroups = mailModule?.NavigationGroups;
  13.640 +                        navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
  13.641 +                        navFolders = navGroup?.NavigationFolders;
  13.642 +
  13.643 +                        /* Check, if pEp drafts folder is already in favorites
  13.644 +                         * WARNING: If for whatever reason, the pEp store is not visible
  13.645 +                         * at this point, the Add() method crashes Outlook!
  13.646 +                         */
  13.647 +                        if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
  13.648 +                        {
  13.649 +                            if (navFolders != null)
  13.650 +                            {
  13.651 +                                navFolders.Add(pEpDraftsFolder);
  13.652 +                            }
  13.653 +                            else
  13.654 +                            {
  13.655 +                                Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
  13.656 +                            }
  13.657 +                        }
  13.658 +                    }
  13.659 +                    else
  13.660 +                    {
  13.661 +                        Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
  13.662 +                    }
  13.663 +                }
  13.664 +                catch (Exception ex)
  13.665 +                {
  13.666 +                    Log.Error("MailItem_Write: Error while saving to pEp Drafts folder. " + ex.ToString());
  13.667 +                    useFallback = true;
  13.668 +                }
  13.669 +                finally
  13.670 +                {
  13.671 +                    currentInspector = null;
  13.672 +                    parentFolder = null;
  13.673 +                    pEpDraftsFolder = null;
  13.674 +                    omi = null;
  13.675 +
  13.676 +                    app = null;
  13.677 +                    activeExplorer = null;
  13.678 +                    navPane = null;
  13.679 +                    navModules = null;
  13.680 +                    mailModule = null;
  13.681 +                    navGroups = null;
  13.682 +                    navGroup = null;
  13.683 +                    navFolders = null;
  13.684 +                }
  13.685 +
  13.686 +                if (useFallback)
  13.687 +                {
  13.688 +                    Log.Verbose("MailItem_Write: pEp folder could not be found or created. Trying fallback");
  13.689 +
  13.690 +                    // Fallback solution
  13.691 +                    if (draftFileName == null)
  13.692 +                    {
  13.693 +                        var result = System.Windows.MessageBox.Show(Properties.Resources.DraftProtection_Warning, Properties.Resources.DraftProtection_Title, System.Windows.MessageBoxButton.YesNo, System.Windows.MessageBoxImage.Exclamation);
  13.694 +                        if (result == System.Windows.MessageBoxResult.Yes)
  13.695 +                        {
  13.696 +                            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
  13.697 +                            {
  13.698 +                                Filter = Properties.Resources.DraftProtection_MSG_Format + " (*.msg)|*.msg",
  13.699 +                                FilterIndex = 1
  13.700 +                            };
  13.701 +                            if (string.IsNullOrEmpty(this.wrappedMailItem.Subject) == false)
  13.702 +                                sfd.FileName = this.wrappedMailItem.Subject;
  13.703 +                            var r = sfd.ShowDialog();
  13.704 +                            if (r == System.Windows.Forms.DialogResult.OK)
  13.705 +                            {
  13.706 +                                draftFileName = sfd.FileName;
  13.707 +                                this.wrappedMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
  13.708 +                            }
  13.709 +                        }
  13.710 +
  13.711 +                        cancel = true;
  13.712 +                    }
  13.713 +                    else
  13.714 +                    {
  13.715 +                        this.wrappedMailItem.SaveAs(draftFileName, Outlook.OlSaveAsType.olMSGUnicode);
  13.716 +                        cancel = true;
  13.717 +                    }
  13.718 +                }
  13.719 +            }
  13.720 +#endif
  13.721 +            this.Write?.Invoke(ref cancel);
  13.722 +            return;
  13.723 +        }
  13.724 +
  13.725 +        /**************************************************************
  13.726 +         * 
  13.727 +         * Property Accessors
  13.728 +         * 
  13.729 +         *************************************************************/
  13.730 +
  13.731 +        /// <summary>
  13.732 +        /// Returns a constant that belongs to the OlDownloadState enumeration indicating the download state of the item.
  13.733 +        /// This forwards the call to the internal mail item.
  13.734 +        /// See: https://msdn.microsoft.com/en-us/library/office/ff866978.aspx
  13.735 +        /// </summary>
  13.736 +        public Outlook.OlDownloadState DownloadState
  13.737 +        {
  13.738 +            get => this._DownloadState ?? ((Outlook.OlDownloadState)(this._DownloadState = this.wrappedMailItem.DownloadState));
  13.739 +        }
  13.740 +
  13.741 +        /// <summary>
  13.742 +        /// Gets whether the mail item is currently being processed.
  13.743 +        /// </summary>
  13.744 +        public bool IsBeingProcessed
  13.745 +        {
  13.746 +            get => this.processor.IsBusy;
  13.747 +        }
  13.748 +
  13.749 +        /// <summary>
  13.750 +        /// Gets whether the mail item is marked as a draft (unsent).
  13.751 +        /// </summary>
  13.752 +        public bool IsDraft
  13.753 +        {
  13.754 +            get => this._IsDraft ?? ((bool)(this._IsDraft = this.wrappedMailItem.GetIsDraft()));
  13.755 +        }
  13.756 +
  13.757 +        /// <summary>
  13.758 +        /// Gets whether the mail item is marked as incoming (received mail, not sent).
  13.759 +        /// </summary>
  13.760 +        public bool IsIncoming
  13.761 +        {
  13.762 +            get => this._IsIncoming ?? ((bool)(this._IsIncoming = this.wrappedMailItem.GetIsIncoming()));
  13.763 +        }
  13.764 +
  13.765 +        /// <summary>
  13.766 +        /// Gets whether the wrapped mail item was marked as being originally encrypted.
  13.767 +        /// This should have been set by calling SetIsOriginallyEncryptedByCache() during the 
  13.768 +        /// EncryptedConversationCacheUpdated event.
  13.769 +        /// False is returned if the property is either false or null (doesn't exist).
  13.770 +        /// </summary>
  13.771 +        public bool IsOriginallyEncrypted
  13.772 +        {
  13.773 +            get => this._IsOriginallyEncrypted ?? ((bool)(this._IsOriginallyEncrypted = ((this.wrappedMailItem.GetUserProperty(MailItemWrapper.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED) as bool?) == true)));
  13.774 +        }
  13.775 +
  13.776 +        /// <summary>
  13.777 +        /// Determines whether the mail item has been processed through pEp. This is done by checking if a pEp protocol
  13.778 +        /// version is available for the item.
  13.779 +        /// </summary>
  13.780 +        protected bool IsPEPMessage
  13.781 +        {
  13.782 +            get => (MailItemExtensions.GetPEPProperty(wrappedMailItem, MailItemExtensions.PEPProperty.PEPProtocolVersion, out object version) && (version != null));
  13.783 +        }
  13.784 +
  13.785 +        /// <summary>
  13.786 +        /// Gets whether the mail item is in a secure store (untrusted server).
  13.787 +        /// </summary>
  13.788 +        public bool IsInSecureStore
  13.789 +        {
  13.790 +            get => this._IsInSecureStore ?? ((bool)(this._IsInSecureStore = this.wrappedMailItem.GetIsInSecureStore()));
  13.791 +        }
  13.792 +
  13.793 +        /// <summary>
  13.794 +        /// Gets whether the mail item is secure (encrypted).
  13.795 +        /// </summary>
  13.796 +        public bool IsSecure
  13.797 +        {
  13.798 +            get => this._IsSecure ?? ((bool)(this._IsSecure = this.wrappedMailItem.GetIsSecure()));
  13.799 +        }
  13.800 +
  13.801 +        /// <summary>
  13.802 +        /// Gets whether the mail item is securely stored.
  13.803 +        /// </summary>
  13.804 +        public bool IsSecurelyStored
  13.805 +        {
  13.806 +            get => (((this.IsSecure || this.IsForcefullyProtected) && this.IsInSecureStore) || (this.NeverUnsecure && (this.IsMirror == false)));
  13.807 +        }
  13.808 +
  13.809 +        /// <summary>
  13.810 +        /// Gets whether the mail item is a mirror item.
  13.811 +        /// </summary>
  13.812 +        public bool IsMirror
  13.813 +        {
  13.814 +            get => this._IsMirror ?? ((bool)(this._IsMirror = this.wrappedMailItem.GetIsMirror()));
  13.815 +        }
  13.816 +
  13.817 +        /// <summary>
  13.818 +        /// Gets whether the mail item is forcefully protected.
  13.819 +        /// </summary>
  13.820 +        public bool IsForcefullyProtected
  13.821 +        {
  13.822 +            get => this._IsForcefullyProtected ?? ((bool)(this._IsForcefullyProtected = this.wrappedMailItem.GetIsForcefullyProtected()));
  13.823 +        }
  13.824 +
  13.825 +        /// <summary>
  13.826 +        /// Gets or sets whether this cryptable mail item is marked to never be unsecure (always encrypted).
  13.827 +        /// This information is stored as a MAPI property of the wrapped mail item.
  13.828 +        /// Warning: This will call .Save() on the MailItem.
  13.829 +        /// </summary>
  13.830 +        public bool NeverUnsecure
  13.831 +        {
  13.832 +            get
  13.833 +            {
  13.834 +                object propValue;
  13.835 +
  13.836 +                lock (mutexMailItem)
  13.837 +                {
  13.838 +                    // Return status can be ignored here, using the auto default value is good enough
  13.839 +                    this.wrappedMailItem.GetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, out propValue);
  13.840 +                }
  13.841 +
  13.842 +                return ((bool)propValue);
  13.843 +            }
  13.844 +            set
  13.845 +            {
  13.846 +                lock (mutexMailItem)
  13.847 +                {
  13.848 +                    // Return status can be ignored
  13.849 +                    this.wrappedMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, value);
  13.850 +                    this.wrappedMailItem.Save();
  13.851 +                }
  13.852 +
  13.853 +                this.OnPropertyChanged();
  13.854 +            }
  13.855 +        }
  13.856 +
  13.857 +        /// <summary>
  13.858 +        /// Gets the status after the last message processing.
  13.859 +        /// This should be used to determine if a failure occured.
  13.860 +        /// Success is the default if no processing has been completed.
  13.861 +        /// </summary>
  13.862 +        public Globals.ReturnStatus LastProcessedStatus
  13.863 +        {
  13.864 +            get { return (this._LastProcessedStatus); }
  13.865 +        }
  13.866 +
  13.867 +        /// <summary>
  13.868 +        /// Gets the personal identity using the internal mail item.
  13.869 +        /// Warning: This can return null.
  13.870 +        /// </summary>
  13.871 +        public PEPIdentity Myself
  13.872 +        {
  13.873 +            get
  13.874 +            {
  13.875 +                PEPIdentity ident = null;
  13.876 +                Globals.ReturnStatus sts;
  13.877 +
  13.878 +                lock (mutexMailItem)
  13.879 +                {
  13.880 +                    sts = PEPIdentity.GetOwnIdentity(this.wrappedMailItem, out ident);
  13.881 +                }
  13.882 +
  13.883 +                if (sts != Globals.ReturnStatus.Success)
  13.884 +                {
  13.885 +                    ident = null;
  13.886 +                }
  13.887 +
  13.888 +                return (ident);
  13.889 +            }
  13.890 +        }
  13.891 +
  13.892 +        /**************************************************************
  13.893 +         * 
  13.894 +         * Decryption
  13.895 +         * 
  13.896 +         *************************************************************/
  13.897 +
  13.898 +        /// <summary>
  13.899 +        /// Decrypts (if necessary, managing any mirrors) and returns the pEp rating for this cryptable mail item.
  13.900 +        /// The calculated rating will be returned but it is already set as the property value by this method.
  13.901 +        /// If rating is ever undefined: it can be assumed an error occured.
  13.902 +        /// </summary>
  13.903 +        private ProcessingResult ProcessAndGetRating(string entryId)
  13.904 +        {
  13.905 +            ProcessingResult result = new ProcessingResult();
  13.906 +
  13.907 +            Log.Verbose("ProcessAndGetRating: Started.");
  13.908 +
  13.909 +            lock (mutexMailItem)
  13.910 +            {
  13.911 +                bool isDraft;
  13.912 +                bool isPEPInternal = false;
  13.913 +                bool isSecurelyStored = false;
  13.914 +                bool isSubmitted;
  13.915 +                bool fullCalculation = true;
  13.916 +                bool preProcessingPropertySet = false;
  13.917 +                bool saveInternalMailItem = false;
  13.918 +                Outlook.MailItem mirrorMailItem = null;
  13.919 +                PEPMessage message = null;
  13.920 +                PEPMessage mirror = null;
  13.921 +                pEpDecryptFlags decryptionFlags;
  13.922 +                MsgProcessor msgProcessor = new MsgProcessor();
  13.923 +                Globals.ReturnStatus sts1;
  13.924 +                Globals.ReturnStatus status = Globals.ReturnStatus.Success;
  13.925 +
  13.926 +                // Reset status
  13.927 +                this._LastProcessedStatus = Globals.ReturnStatus.Success;
  13.928 +
  13.929 +                // Log the download status which can influence later processing
  13.930 +                try
  13.931 +                {
  13.932 +                    Log.Verbose("ProcessAndGetRating: DownloadState=" + this.wrappedMailItem.DownloadState.ToString());
  13.933 +                }
  13.934 +                catch { }
  13.935 +
  13.936 +                // Detect if the mail item is a draft
  13.937 +                isDraft = this.wrappedMailItem.GetIsDraft();
  13.938 +                isSubmitted = this.wrappedMailItem.GetIsSubmitted();
  13.939 +                Outlook.OlAccountType accountType = this.wrappedMailItem.GetAccountType();
  13.940 +
  13.941 +                // Do not processes deleted messages on IMAP
  13.942 +                if ((fullCalculation) &&
  13.943 +                    (accountType == Outlook.OlAccountType.olImap) &&
  13.944 +                    (MapiHelper.GetProperty(this.wrappedMailItem, MapiProperty.PidLidImapMarkedForDeletion, "0").ToString() == "1"))
  13.945 +                {
  13.946 +                    Log.Verbose("ProcessAndGetRating: Deleted IMAP message detected, skipping processing");
  13.947 +                    result.Rating = pEpRating.pEpRatingUndefined;
  13.948 +                    fullCalculation = false;
  13.949 +                }
  13.950 +
  13.951 +                // Check if the mail item is a mirror and use stored rating
  13.952 +                if ((fullCalculation) &&
  13.953 +                    (this.wrappedMailItem.GetIsMirror()))
  13.954 +                {
  13.955 +                    // Get UI rating from mirror
  13.956 +                    try
  13.957 +                    {
  13.958 +                        if (PEPMessage.Create(this.wrappedMailItem, out mirror) == Globals.ReturnStatus.Success)
  13.959 +                        {
  13.960 +                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
  13.961 +                            this.Message = mirror;
  13.962 +                        }
  13.963 +                    }
  13.964 +                    catch (Exception ex)
  13.965 +                    {
  13.966 +                        Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
  13.967 +                        result.Rating = mirror.Rating;
  13.968 +                    }
  13.969 +
  13.970 +                    // If the value was undefined, don't use it. Recalculation is needed.
  13.971 +                    if (result.Rating != pEpRating.pEpRatingUndefined)
  13.972 +                    {
  13.973 +                        Log.Verbose("ProcessAndGetRating: Mirror detected, using stored rating.");
  13.974 +                        fullCalculation = false;
  13.975 +                    }
  13.976 +                }
  13.977 +
  13.978 +                /* Check if the mail item is a draft (if the Unsent flag is set)
  13.979 +                 * If the message is a draft, the outgoing rating will be used, value is not stored.
  13.980 +                 * This check is technically not required as the logic below will detect Outgoing messages and do the same.
  13.981 +                 * However, it's potentially quicker (and more robust) to handle this special case.
  13.982 +                 * Note: It's important that the message is not submitted (since it could already be encrypted).
  13.983 +                 */
  13.984 +                if ((fullCalculation) &&
  13.985 +                    (isDraft) &&
  13.986 +                    (isSubmitted == false))
  13.987 +                {
  13.988 +                    Log.Verbose("ProcessAndGetRating: Draft detected, using outgoing rating.");
  13.989 +
  13.990 +                    result.Rating = this.wrappedMailItem.GetOutgoingRating(true);
  13.991 +                    fullCalculation = false;
  13.992 +                }
  13.993 +
  13.994 +                // Check if untrusted server and search for mirror. Use mirror rating if available
  13.995 +                isSecurelyStored = (this.wrappedMailItem.GetIsSecurelyStored() || this.IsSecureAttachedMail);
  13.996 +                if (fullCalculation &&
  13.997 +                    isSecurelyStored)
  13.998 +                {
  13.999 +                    // If internal mail item is attached mail, use message id for mirror lookup
 13.1000 +                    string messageId = null;
 13.1001 +                    if (this.IsSecureAttachedMail)
 13.1002 +                    {
 13.1003 +                        messageId = this.MessageId;
 13.1004 +                    }
 13.1005 +
 13.1006 +                    mirrorMailItem = this.wrappedMailItem.GetMirror(messageId);
 13.1007 +                    if ((mirrorMailItem != null) &&
 13.1008 +                        (PEPMessage.Create(mirrorMailItem, out mirror) == Globals.ReturnStatus.Success))
 13.1009 +                    {
 13.1010 +                        fullCalculation = false;
 13.1011 +                        this.Mirror = mirror;
 13.1012 +
 13.1013 +                        // Get UI rating from mirror
 13.1014 +                        try
 13.1015 +                        {
 13.1016 +                            result.Rating = AdapterExtensions.ReevaluateMessageRating(mirror);
 13.1017 +                        }
 13.1018 +                        catch (Exception ex)
 13.1019 +                        {
 13.1020 +                            Log.Error("ProcessAndGetRating: Error reevaluating mirror rating. " + ex.ToString());
 13.1021 +                            result.Rating = mirror.Rating;
 13.1022 +                        }
 13.1023 +
 13.1024 +                        this.Mirror.Rating = result.Rating;
 13.1025 +                    }
 13.1026 +                }
 13.1027 +
 13.1028 +                // Full calculation if no special cases were found
 13.1029 +                if (fullCalculation)
 13.1030 +                {
 13.1031 +                    // Check if message has autoconsume header and set pEp internal category if necessary
 13.1032 +                    try
 13.1033 +                    {
 13.1034 +                        if (this.wrappedMailItem.GetIsAutoConsume())
 13.1035 +                        {
 13.1036 +                            isPEPInternal = true;
 13.1037 +
 13.1038 +                            /* Set the mail item as read and apply again the category to make sure it is really set. As those
 13.1039 +                             * two operations require the mail item to be saved afterwards, do NOT apply it to ActiveSync 
 13.1040 +                             * messages, as saving with ActiveSync accounts tends to fail and then leads to "Save message?" dialogs
 13.1041 +                             * popping up during shutdown of Outlook. (see OUT-216).
 13.1042 +                             */
 13.1043 +                            if (accountType != Outlook.OlAccountType.olEas)
 13.1044 +                            {
 13.1045 +                                Globals.ThisAddIn.CreatePEPCategories();
 13.1046 +
 13.1047 +                                // Only one category is needed to hide the MailItem -- delete any others
 13.1048 +                                this.wrappedMailItem.Categories = Globals.PEP_INTERNAL_CATEGORY_NAME;
 13.1049 +                                this.wrappedMailItem.UnRead = false;
 13.1050 +                                preProcessingPropertySet = true;
 13.1051 +                            }
 13.1052 +                        }
 13.1053 +                    }
 13.1054 +                    catch (Exception ex)
 13.1055 +                    {
 13.1056 +                        Log.Error("ProcessAndGetRating: Could not set pEp internal category, " + ex.ToString());
 13.1057 +                    }
 13.1058 +
 13.1059 +                    /* Apply a custom message class to secure mail items in secure stores (doesn't apply for pEp internal messages). This is needed for the
 13.1060 +                     * FormRegionPreviewUnencrypted to be shown in Outlook 2010 (technically, all versions require this according to the documentation).
 13.1061 +                     * See: https://msdn.microsoft.com/en-us/library/office/ff866019.aspx
 13.1062 +                     * 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
 13.1063 +                     * which then leads to the form region not being properly displayed at the first click (OUT-68).
 13.1064 +                     */
 13.1065 +                    if ((isPEPInternal == false) &&
 13.1066 +                         ((Globals.OutlookVersion == Globals.Version.Outlook2010) &&
 13.1067 +                          (this.wrappedMailItem.GetIsInSecureStore() || this.wrappedMailItem.GetNeverUnsecure())))
 13.1068 +                    {
 13.1069 +                        try
 13.1070 +                        {
 13.1071 +                            MapiHelper.SetProperty(this.wrappedMailItem, MapiProperty.PidTagMessageClass, MapiPropertyValue.PidTagMessageClassSecurePEP);
 13.1072 +                            preProcessingPropertySet = true;
 13.1073 +                        }
 13.1074 +                        catch (Exception ex)
 13.1075 +                        {
 13.1076 +                            Log.Error("ProcessAndGetRating: Could not set custom message class, " + ex.ToString());
 13.1077 +                        }
 13.1078 +                    }
 13.1079 +
 13.1080 +                    // Save any changes
 13.1081 +                    if (preProcessingPropertySet)
 13.1082 +                    {
 13.1083 +                        try
 13.1084 +                        {
 13.1085 +                            this.wrappedMailItem.Save();
 13.1086 +                        }
 13.1087 +                        catch (Exception ex)
 13.1088 +                        {
 13.1089 +                            Log.Error("ProcessAndGetRating: Could not save pre-processing properties, " + ex.ToString());
 13.1090 +                        }
 13.1091 +                    }
 13.1092 +
 13.1093 +                    // Process mail item
 13.1094 +                    sts1 = PEPMessage.Create(this.wrappedMailItem, out message);
 13.1095 +
 13.1096 +                    // If Key Import Wizard is open, add mail to list to process later
 13.1097 +                    if ((KeySyncWizard.Wizard?.IsVisible == true) &&
 13.1098 +                        (message.Direction == pEpMsgDirection.pEpDirIncoming) &&
 13.1099 +                        (message.To?.Count == 1) &&
 13.1100 +                        (message.From?.EqualsByAddress(message.To[0]) == true))
 13.1101 +                    {
 13.1102 +                        KeySyncWizard.Wizard?.AddToReceivedSyncMessages(message);
 13.1103 +                    }
 13.1104 +
 13.1105 +                    // Define decryption flags
 13.1106 +                    decryptionFlags = isSecurelyStored ? pEpDecryptFlags.pEpDecryptFlagUntrustedServer : pEpDecryptFlags.pEpDecryptFlagsNone;
 13.1107 +
 13.1108 +                    /* Check if the message is an attached disclaimer message.
 13.1109 +                     * The definition for such a message is that it's a secure attached
 13.1110 +                     * message with the same subject as the outer message.
 13.1111 +                     * See also comments in PEPAttachment.CheckIfAttachedMailAndAddToCache().
 13.1112 +                     */
 13.1113 +                    if ((message.Attachments?.Count == 1) &&
 13.1114 +                        (message.Attachments[0].AttachedDisclaimerMessage?.ShortMsg?.Equals(message.ShortMsg) == true))
 13.1115 +                    {
 13.1116 +                        var msg = message.Attachments[0].AttachedDisclaimerMessage.Copy();
 13.1117 +                        message.Attachments.Clear();
 13.1118 +                        for (int i = 0; i < msg.Attachments.Count; i++)
 13.1119 +                        {
 13.1120 +                            message.Attachments.Add(msg.Attachments[i]);
 13.1121 +                        }
 13.1122 +                    }
 13.1123 +
 13.1124 +                    // Process
 13.1125 +                    status = msgProcessor.ProcessMessage(ref message,
 13.1126 +                                                         sts1,
 13.1127 +                                                         this.wrappedMailItem.GetIsInSecureStore(),
 13.1128 +                                                         this.wrappedMailItem.GetIsInSentFolder(),
 13.1129 +                                                         isDraft,
 13.1130 +                                                         out mirror,
 13.1131 +                                                         out PEPMessage processedMessage,
 13.1132 +                                                         out pEpRating processedRating,
 13.1133 +                                                         ref decryptionFlags);
 13.1134 +
 13.1135 +                    if (status == Globals.ReturnStatus.Success)
 13.1136 +                    {
 13.1137 +                        // Handle the consumed flag marking for deletion
 13.1138 +                        if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagConsume))
 13.1139 +                        {
 13.1140 +                            // Delete the mail item from Outlook
 13.1141 +                            try
 13.1142 +                            {
 13.1143 +                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.wrappedMailItem.Subject + " received on " + this.wrappedMailItem.ReceivedTime.ToString());
 13.1144 +                            }
 13.1145 +                            catch { }
 13.1146 +                            this.wrappedMailItem.PermanentlyDelete();
 13.1147 +                            this.disposeAfterProcessing = true;
 13.1148 +
 13.1149 +                            Log.Verbose("ProcessAndGetRating: Processed message consumed");
 13.1150 +                        }
 13.1151 +                        else if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagIgnore))
 13.1152 +                        {
 13.1153 +                            try
 13.1154 +                            {
 13.1155 +                                Log.SensitiveData("ProcessAndGetRating: Processed msg with subject " + this.wrappedMailItem.Subject + " received on " + this.wrappedMailItem.ReceivedTime.ToString());
 13.1156 +                            }
 13.1157 +                            catch { }
 13.1158 +                            Log.Verbose("ProcessAndGetRating: Processed message ignored.");
 13.1159 +                        }
 13.1160 +                        else if ((Globals.ThisAddIn.OutlookOptions.ReadAsPlain) &&
 13.1161 +                                 (isSecurelyStored))
 13.1162 +                        {
 13.1163 +                            this.Mirror = mirror;
 13.1164 +                        }
 13.1165 +                        else
 13.1166 +                        {
 13.1167 +                            // Save processed message data to Outlook
 13.1168 +                            if (processedMessage != null)
 13.1169 +                            {
 13.1170 +
 13.1171 +                                // Set the mail item
 13.1172 +                                if (mirror != null)
 13.1173 +                                {
 13.1174 +                                    // Save mirror as property of this cryptable mail item
 13.1175 +                                    this.Mirror = mirror;
 13.1176 +                                    this.Mirror.Rating = processedRating;
 13.1177 +
 13.1178 +                                    if (mirrorMailItem == null)
 13.1179 +                                    {
 13.1180 +                                        // If internal mail item is attached mail, use message id for mirror creation
 13.1181 +                                        string messageId = null;
 13.1182 +                                        if (this.IsSecureAttachedMail)
 13.1183 +                                        {
 13.1184 +                                            messageId = this.MessageId;
 13.1185 +                                        }
 13.1186 +
 13.1187 +                                        mirrorMailItem = this.wrappedMailItem.CreateMirrorOMI(messageId);
 13.1188 +                                    }
 13.1189 +
 13.1190 +                                    // Apply message to mirror and save
 13.1191 +                                    processedMessage.ApplyTo(mirrorMailItem, true, true);
 13.1192 +
 13.1193 +                                    try
 13.1194 +                                    {
 13.1195 +                                        mirrorMailItem.Save();
 13.1196 +                                    }
 13.1197 +                                    catch (Exception ex)
 13.1198 +                                    {
 13.1199 +                                        Log.Error("ProcessAndGetRating: Error saving mirror item. " + ex.ToString());
 13.1200 +                                    }
 13.1201 +
 13.1202 +                                    // If needed, set SmartNoAttach MAPI property to hide the attachments icon
 13.1203 +                                    if ((accountType != Outlook.OlAccountType.olImap) &&
 13.1204 +                                        (processedMessage.Attachments?.Count == 0) &&
 13.1205 +                                        (this.wrappedMailItem.Attachments?.Count > 0))
 13.1206 +                                    {
 13.1207 +                                        // Note: The documented MAPI property PidLidSmartNoAttach (0x8514000B) doesn't work for some reason
 13.1208 +                                        result.PropertiesToSet.Add(MapiProperty.PidTagSmartNoAttach2, true);
 13.1209 +                                    }
 13.1210 +
 13.1211 +                                    /* If we have extra keys and are on an untrusted server, reencrypt message
 13.1212 +                                     * for myself and the extra keys.
 13.1213 +                                     */
 13.1214 +                                    if (decryptionFlags.HasFlag(pEpDecryptFlags.pEpDecryptFlagSrcModified))
 13.1215 +                                    {
 13.1216 +                                        if (message.ApplyTo(this.wrappedMailItem, false, false, true, false) == Globals.ReturnStatus.Success)
 13.1217 +                                        {
 13.1218 +                                            saveInternalMailItem = true;
 13.1219 +                                        }
 13.1220 +                                        else
 13.1221 +                                        {
 13.1222 +                                            Log.Error("ProcessAndGetRating: Error reencrypting with extra keys.");
 13.1223 +                                        }
 13.1224 +                                    }
 13.1225 +                                }
 13.1226 +                                else
 13.1227 +                                {
 13.1228 +                                    // Trusted server: apply message and save
 13.1229 +                                    processedMessage.ApplyTo(this.wrappedMailItem, true, false);
 13.1230 +                                    saveInternalMailItem = true;
 13.1231 +                                }
 13.1232 +                            }
 13.1233 +                            // If processed message is null (= didn't run through decryption (again)), update UI rating
 13.1234 +                            else
 13.1235 +                            {
 13.1236 +                                /* In rare circumstances (i.e. when a user makes a handshake using
 13.1237 +                                 * an FPP message) we can get here. In this case, we need to set the
 13.1238 +                                 * rating manually to reliable or higher (reevaluate).
 13.1239 +                                 */
 13.1240 +                                if ((string.IsNullOrEmpty(message.ForceProtectionId) == false) &&
 13.1241 +                                    (message.Rating == pEpRating.pEpRatingUndefined))
 13.1242 +                                {
 13.1243 +                                    message.Rating = processedRating;
 13.1244 +                                    processedRating = AdapterExtensions.ReevaluateFPPMessageRating(message);
 13.1245 +                                }
 13.1246 +                                else
 13.1247 +                                {
 13.1248 +                                    processedRating = AdapterExtensions.ReevaluateMessageRating(message, processedRating);
 13.1249 +                                }
 13.1250 +                            }
 13.1251 +                        }
 13.1252 +                    }
 13.1253 +
 13.1254 +                    // Remove the pEp Processing category if needed
 13.1255 +                    if (Globals.ThisAddIn.Settings.IsUXImprovementEnabled &&
 13.1256 +                        this.wrappedMailItem.RemovePEPProcessingCategory())
 13.1257 +                    {
 13.1258 +                        if (message?.Direction != null)
 13.1259 +                        {
 13.1260 +                            this.wrappedMailItem.UnRead = (message.Direction == pEpMsgDirection.pEpDirIncoming);
 13.1261 +                        }
 13.1262 +                        else
 13.1263 +                        {
 13.1264 +                            this.wrappedMailItem.UnRead = (this.wrappedMailItem.GetIsInSentFolder() == false);
 13.1265 +                        }
 13.1266 +                        saveInternalMailItem = true;
 13.1267 +                    }
 13.1268 +
 13.1269 +                    // Save internal mail item if necessary
 13.1270 +                    if (saveInternalMailItem)
 13.1271 +                    {
 13.1272 +                        bool saveError = false;
 13.1273 +                        try
 13.1274 +                        {
 13.1275 +                            this.wrappedMailItem.Save();
 13.1276 +                        }
 13.1277 +                        catch (Exception ex)
 13.1278 +                        {
 13.1279 +                            saveError = true;
 13.1280 +                            Log.Error("ProcessAndGetRating: Error saving internal mail item. " + ex.ToString());
 13.1281 +                        }
 13.1282 +
 13.1283 +                        // If an error occured during saving, try to forcefully save
 13.1284 +                        if (saveError)
 13.1285 +                        {
 13.1286 +                            try
 13.1287 +                            {
 13.1288 +                                int sts = Mapi.Save(this.wrappedMailItem, Mapi.SaveOption.KEEP_OPEN_READWRITE);
 13.1289 +                                Log.Verbose("ProcessAndGetRating: Saving using backup method. Return status is " + sts.ToString("X"));
 13.1290 +
 13.1291 +                                if (sts != (uint)Mapi.HResult.S_OK)
 13.1292 +                                {
 13.1293 +                                    sts = Mapi.Save(this.wrappedMailItem, Mapi.SaveOption.FORCE_SAVE);
 13.1294 +                                    Log.Verbose("ProcessAndGetRating: Saving with FORCE_SAVE flag returned " + sts.ToString("X"));
 13.1295 +                                }
 13.1296 +                            }
 13.1297 +                            catch (Exception ex)
 13.1298 +                            {
 13.1299 +                                Log.Error("ProcessAndGetRating: Error forcefully saving internal mail item. " + ex.ToString());
 13.1300 +                            }
 13.1301 +                        }
 13.1302 +                    }
 13.1303 +
 13.1304 +                    this.Message = processedMessage ?? message;
 13.1305 +                    this.Message.Rating = processedRating;
 13.1306 +                    result.Rating = processedRating;
 13.1307 +                }
 13.1308 +
 13.1309 +                // Save processing status
 13.1310 +                this._LastProcessedRating = result.Rating;
 13.1311 +                this._LastProcessedStatus = status;
 13.1312 +
 13.1313 +                // If it's an incoming message, do some caching (entry ids of drafts are empty)
 13.1314 +                if (string.IsNullOrEmpty(entryId) == false)
 13.1315 +                {
 13.1316 +                    // Save rating in db
 13.1317 +                    PEPDatabase.StoreOrUpdateRating(entryId, result.Rating);
 13.1318 +
 13.1319 +                    // Save message in cache
 13.1320 +                    if (isSecurelyStored)
 13.1321 +                    {
 13.1322 +                        if (Mirror != null)
 13.1323 +                        {
 13.1324 +                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Mirror, Rating = result.Rating });
 13.1325 +                        }
 13.1326 +                        else if ((Message != null) &&
 13.1327 +                                 (Message.IsSecure == false))
 13.1328 +                        {
 13.1329 +                            PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = Message, Rating = result.Rating });
 13.1330 +                        }
 13.1331 +                    }
 13.1332 +                    else
 13.1333 +                    {
 13.1334 +                        PEPCache.AddItemToCache(entryId, new PEPCache.CacheItem { Mirror = null, Rating = result.Rating });
 13.1335 +                    }
 13.1336 +                }
 13.1337 +
 13.1338 +                // Release objects
 13.1339 +                mirrorMailItem = null;
 13.1340 +
 13.1341 +                // Release the decryption lock
 13.1342 +                lock (mutexDecryptionList)
 13.1343 +                {
 13.1344 +                    try
 13.1345 +                    {
 13.1346 +                        if ((string.IsNullOrEmpty(entryId) == false) &&
 13.1347 +                            (decryptionList?.Count > 0))
 13.1348 +                        {
 13.1349 +                            decryptionList.Remove(entryId);
 13.1350 +                            Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
 13.1351 +                                        (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
 13.1352 +                        }
 13.1353 +                    }
 13.1354 +                    catch
 13.1355 +                    {
 13.1356 +                        Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
 13.1357 +                    }
 13.1358 +
 13.1359 +                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
 13.1360 +                }
 13.1361 +            }
 13.1362 +
 13.1363 +            Log.Verbose("ProcessAndGetRating: Completed. Result is " + Enum.GetName(typeof(pEpRating), result.Rating));
 13.1364 +
 13.1365 +            return result;
 13.1366 +        }
 13.1367 +
 13.1368 +        /// <summary>
 13.1369 +        /// Starts the processing of the mail item which can result in decryption or encryption of the message.
 13.1370 +        /// </summary>
 13.1371 +        /// <param name="disposeAfterComplete">Set to true in order to release/dispose the internal MailItem and this MailItemWrapper 
 13.1372 +        /// after processing is complete. This would be used for background processing where the reference is not maintained in the UI.
 13.1373 +        /// WARNING: do not set to true if you will use this MailItem or MailItemWrapper later!</param>
 13.1374 +        /// <returns>True if the processing started successfully, otherwise false if it is already busy.</returns>
 13.1375 +        public async void StartProcessing(bool isDraft, bool disposeAfterComplete = false)
 13.1376 +        {
 13.1377 +            if (this.processor.IsBusy == false)
 13.1378 +            {
 13.1379 +                string entryId = null;
 13.1380 +                this.disposeAfterProcessing = disposeAfterComplete;
 13.1381 +
 13.1382 +                bool process = await Task.Run(() =>
 13.1383 +                {
 13.1384 +                    int sleepTime = 1000; // 1 second in milliseconds
 13.1385 +                    int curWaitTime = 0;
 13.1386 +                    int maxWaitTime = 60000; // 1 minute in milliseconds
 13.1387 +                    bool isAlreadyBeingDecrypted = false;
 13.1388 +                    bool isAutoConsume = false;
 13.1389 +
 13.1390 +                    lock (mutexMailItem)
 13.1391 +                    {
 13.1392 +                        /* Explicitly add try/catch block to catch error getting EntryID.
 13.1393 +                         * This should theoretically never happen, but was seen in practice.
 13.1394 +                         */
 13.1395 +                        try
 13.1396 +                        {
 13.1397 +                            entryId = this.wrappedMailItem.EntryID;
 13.1398 +                            isAutoConsume = this.wrappedMailItem.GetIsAutoConsume();
 13.1399 +                        }
 13.1400 +                        catch
 13.1401 +                        {
 13.1402 +                            Log.Error("ProcessAndGetRating: internalMailItem is invalid or EntryID could not get retrieved");
 13.1403 +                            this._LastProcessedRating = pEpRating.pEpRatingUndefined;
 13.1404 +                            this._LastProcessedStatus = Globals.ReturnStatus.Failure;
 13.1405 +                            return false;
 13.1406 +                        }
 13.1407 +                    }
 13.1408 +
 13.1409 +                    // Make sure this mail item is not already being decrypted
 13.1410 +                    if (string.IsNullOrEmpty(entryId) == false)
 13.1411 +                    {
 13.1412 +                        do
 13.1413 +                        {
 13.1414 +                            /* Check if the EntryID is already in the decrypting list
 13.1415 +                             * If so, it is being decrypted already and we must wait
 13.1416 +                             * If it isn't already being decrypted, then add it to the decryption list
 13.1417 +                             */
 13.1418 +                            lock (mutexDecryptionList)
 13.1419 +                            {
 13.1420 +                                if (decryptionList.ContainsKey(entryId))
 13.1421 +                                {
 13.1422 +                                    isAlreadyBeingDecrypted = true;
 13.1423 +                                }
 13.1424 +                                else
 13.1425 +                                {
 13.1426 +                                    isAlreadyBeingDecrypted = false;
 13.1427 +
 13.1428 +                                    /* Add the entryID to the decryption list and we can start decryption
 13.1429 +                                     * It is important to do this all under the same lock
 13.1430 +                                     * 
 13.1431 +                                     * Note: It’s known the EntryID is not guaranteed to be unique for a given MailItem across different stores.
 13.1432 +                                     * However, only the EntryID is used in the decryption list.
 13.1433 +                                     * This is not an issue as worse-case is simply waiting for a different MailItem with the same EntryID to finish.
 13.1434 +                                     */
 13.1435 +                                    decryptionList.Add(entryId, "");
 13.1436 +                                    Log.Verbose("ProcessAndGetRating: Added EntryID to decryption list. " + entryId);
 13.1437 +                                    Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
 13.1438 +                                    break;
 13.1439 +                                }
 13.1440 +                            }
 13.1441 +
 13.1442 +                            // Wait for the other thread to finish
 13.1443 +                            if (isAlreadyBeingDecrypted)
 13.1444 +                            {
 13.1445 +                                // Do not process multiple times if it is an automatic message
 13.1446 +                                if (isAutoConsume)
 13.1447 +                                {
 13.1448 +                                    curWaitTime = maxWaitTime + 1;
 13.1449 +                                    Log.Verbose("ProcessAndGetRating: Setting timeout for AutoConsume message.");
 13.1450 +                                }
 13.1451 +                                else
 13.1452 +                                {
 13.1453 +                                    Log.Verbose("ProcessAndGetRating: Waiting for other decryption thread to finish. " + entryId);
 13.1454 +                                    Thread.Sleep(sleepTime);
 13.1455 +                                    curWaitTime += sleepTime;
 13.1456 +                                }
 13.1457 +                            }
 13.1458 +                        }
 13.1459 +                        while ((isAlreadyBeingDecrypted) && (curWaitTime < maxWaitTime));
 13.1460 +                    }
 13.1461 +                    else
 13.1462 +                    {
 13.1463 +                        // Log the issue unless the MailItem is an unsaved draft message
 13.1464 +                        if (isDraft == false)
 13.1465 +                        {
 13.1466 +                            Log.Warning("ProcessAndGetRating: EntryID does not exist, unable to lock during decryption.");
 13.1467 +                        }
 13.1468 +                        else
 13.1469 +                        {
 13.1470 +                            Log.Verbose("ProcessAndGetRating: Could not add EntryID to decryption list lock because message is an unsaved draft.");
 13.1471 +                        }
 13.1472 +                    }
 13.1473 +
 13.1474 +                    // Exit if timeout occured
 13.1475 +                    if ((isAlreadyBeingDecrypted) ||
 13.1476 +                        (curWaitTime >= maxWaitTime))
 13.1477 +                    {
 13.1478 +                        Log.Error("ProcessAndGetRating: Exited by timeout. " + (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
 13.1479 +
 13.1480 +                        // Save processing status
 13.1481 +                        this._LastProcessedRating = pEpRating.pEpRatingCannotDecrypt;
 13.1482 +                        this._LastProcessedStatus = Globals.ReturnStatus.Failure;
 13.1483 +
 13.1484 +                        // Remove entryId from decryption list
 13.1485 +                        lock (mutexDecryptionList)
 13.1486 +                        {
 13.1487 +                            try
 13.1488 +                            {
 13.1489 +                                decryptionList.Remove(entryId);
 13.1490 +                                Log.Verbose("ProcessAndGetRating: Removed EntryID from decryption list. " +
 13.1491 +                                            (string.IsNullOrEmpty(entryId) ? "<no ID>" : entryId));
 13.1492 +                            }
 13.1493 +                            catch
 13.1494 +                            {
 13.1495 +                                Log.Error("ProcessAndGetRating: Error removing EntryID from decryption list.");
 13.1496 +                            }
 13.1497 +
 13.1498 +                            Log.Verbose("ProcessAndGetRating: Active decryption count = " + decryptionList.Count.ToString());
 13.1499 +                        }
 13.1500 +
 13.1501 +                        return false;
 13.1502 +                    }
 13.1503 +
 13.1504 +                    return true;
 13.1505 +                });
 13.1506 +
 13.1507 +                if (process)
 13.1508 +                {
 13.1509 +                    this.processor.RunWorkerAsync(entryId);
 13.1510 +                }
 13.1511 +            }
 13.1512 +        }
 13.1513 +
 13.1514 +        /// <summary>
 13.1515 +        /// Event handler for when the processor background worker is doing work.
 13.1516 +        /// </summary>
 13.1517 +        private void Processor_DoWork(object sender, DoWorkEventArgs e)
 13.1518 +        {
 13.1519 +            e.Result = this.ProcessAndGetRating(e.Argument as string);
 13.1520 +            return;
 13.1521 +        }
 13.1522 +
 13.1523 +        /// <summary>
 13.1524 +        /// Event handler for when the processor background worker is completed.
 13.1525 +        /// </summary>
 13.1526 +        private void Processor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
 13.1527 +        {
 13.1528 +            MsgProcessor.ProcessingCompletedEventArgs args;
 13.1529 +
 13.1530 +            // Decrement decryption counter after decryption has finished (if necessary)
 13.1531 +            if (this.decrementCounter)
 13.1532 +            {
 13.1533 +                ThisAddIn.DecryptionStack.DecrementDecryptionCounter();
 13.1534 +            }
 13.1535 +
 13.1536 +            // Catch any errors that occured during processing
 13.1537 +            if (e.Error != null)
 13.1538 +            {
 13.1539 +                Log.Error("Processor_RunWorkerCompleted: Error during processing of mail item. " + e.Error.ToString());
 13.1540 +
 13.1541 +                if (this.disposeAfterProcessing)
 13.1542 +                {
 13.1543 +                    this.Dispose(false);
 13.1544 +
 13.1545 +                    // Must be called last!
 13.1546 +                    this.DisposeInternalMailItem();
 13.1547 +                }
 13.1548 +
 13.1549 +                return;
 13.1550 +            }
 13.1551 +
 13.1552 +            // Get processing result
 13.1553 +            ProcessingResult result = e.Result as ProcessingResult;
 13.1554 +
 13.1555 +            // Dispose if necessary
 13.1556 +            if (this.disposeAfterProcessing)
 13.1557 +            {
 13.1558 +                /* If there are MAPI properties to set, we have to marshal
 13.1559 +                 * this call to the main thread. If not, we can just dispose it
 13.1560 +                 * on the current one.
 13.1561 +                 */
 13.1562 +                if (result?.PropertiesToSet?.Count > 0)
 13.1563 +                {
 13.1564 +                    KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
 13.1565 +                    {
 13.1566 +                        this.wrappedMailItem?.SetMAPIProperties(result.PropertiesToSet);
 13.1567 +
 13.1568 +                        this.Dispose(false);
 13.1569 +
 13.1570 +                        // Must be called last!
 13.1571 +                        this.DisposeInternalMailItem();
 13.1572 +                    }));
 13.1573 +                }
 13.1574 +                else
 13.1575 +                {
 13.1576 +                    this.Dispose(false);
 13.1577 +
 13.1578 +                    // Must be called last!
 13.1579 +                    this.DisposeInternalMailItem();
 13.1580 +                }
 13.1581 +            }
 13.1582 +            else
 13.1583 +            {
 13.1584 +                // Raise complete event (only if dispose after decryption is not true since .this reference is returned)
 13.1585 +                args = new MsgProcessor.ProcessingCompletedEventArgs();
 13.1586 +
 13.1587 +                // Check for errors during processing but invoke anyhow to complete process (needed to look up mirror).
 13.1588 +                if (e.Error == null)
 13.1589 +                {
 13.1590 +                    args.ProcessedRating = result.Rating;
 13.1591 +                    args.PropertiesToSet = result.PropertiesToSet;
 13.1592 +                }
 13.1593 +                else
 13.1594 +                {
 13.1595 +                    args.ProcessedRating = pEpRating.pEpRatingUndefined;
 13.1596 +                }
 13.1597 +
 13.1598 +                this.ProcessingCompleted?.Invoke(this, args);
 13.1599 +            }
 13.1600 +        }
 13.1601 +
 13.1602 +        /**************************************************************
 13.1603 +         * 
 13.1604 +         * Mirror Locator
 13.1605 +         * 
 13.1606 +         *************************************************************/
 13.1607 +
 13.1608 +        /// <summary>
 13.1609 +        /// Starts the process to locate the mirror of the mail item.
 13.1610 +        /// </summary>
 13.1611 +        public void StartGetMirror(string messageId = null)
 13.1612 +        {
 13.1613 +            if (this.mirrorLocator.IsBusy == false)
 13.1614 +            {
 13.1615 +                this.mirrorLocator.RunWorkerAsync(messageId);
 13.1616 +            }
 13.1617 +
 13.1618 +            return;
 13.1619 +        }
 13.1620 +
 13.1621 +        /// <summary>
 13.1622 +        /// Event handler for when the mirror locator background worker is doing work.
 13.1623 +        /// </summary>
 13.1624 +        private void MirrorLocator_DoWork(object sender, DoWorkEventArgs e)
 13.1625 +        {
 13.1626 +            PEPMessage mirror = null;
 13.1627 +            Outlook.MailItem omi = null;
 13.1628 +            e.Result = null;
 13.1629 +            Globals.ReturnStatus sts;
 13.1630 +
 13.1631 +            Log.Verbose("MirrorLocator_DoWork: Started");
 13.1632 +
 13.1633 +            try
 13.1634 +            {
 13.1635 +                if (this.Mirror != null)
 13.1636 +                {
 13.1637 +                    // If we already have a mirror, use it
 13.1638 +                    e.Result = this.Mirror;
 13.1639 +                }
 13.1640 +                else
 13.1641 +                {
 13.1642 +                    // If no stored mirror is there, look it up
 13.1643 +                    lock (mutexMailItem)
 13.1644 +                    {
 13.1645 +                        string id = e.Argument as string;
 13.1646 +                        omi = this.wrappedMailItem.GetMirror(id);
 13.1647 +
 13.1648 +                        if (omi != null)
 13.1649 +                        {
 13.1650 +                            Log.Verbose("MirrorLocator_DoWork: Mirror found");
 13.1651 +
 13.1652 +                            sts = PEPMessage.Create(omi, out mirror);
 13.1653 +                        }
 13.1654 +                    }
 13.1655 +
 13.1656 +                    e.Result = mirror;
 13.1657 +                }
 13.1658 +            }
 13.1659 +            catch (Exception ex)
 13.1660 +            {
 13.1661 +                Log.Error("MirrorLocator_DoWork: Failed to find mirror OMI, " + ex.ToString());
 13.1662 +            }
 13.1663 +            finally
 13.1664 +            {
 13.1665 +                omi = null;
 13.1666 +            }
 13.1667 +
 13.1668 +            Log.Verbose("MirrorLocator_DoWork: Completed");
 13.1669 +        }
 13.1670 +
 13.1671 +        /// <summary>
 13.1672 +        /// Event handler for when the mirror locator background worker is completed.
 13.1673 +        /// </summary>
 13.1674 +        private void MirrorLocator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
 13.1675 +        {
 13.1676 +            this.GetMirrorCompleted?.Invoke(this, new GetMirrorCompletedEventArgs(e.Result == null ? null : (PEPMessage)e.Result));
 13.1677 +            return;
 13.1678 +        }
 13.1679 +
 13.1680 +        /**************************************************************
 13.1681 +         * 
 13.1682 +         * Methods
 13.1683 +         * 
 13.1684 +         *************************************************************/
 13.1685 +
 13.1686 +        /// <summary>
 13.1687 +        /// Releases all resources and disconnects internal events.
 13.1688 +        /// The internal mail item will NOT be released -- this is managed externally.
 13.1689 +        /// </summary>
 13.1690 +        public void Dispose()
 13.1691 +        {
 13.1692 +            this.Dispose(true);
 13.1693 +            // Note: GC.SuppressFinalize(this); is not called because that just seems bad
 13.1694 +            return;
 13.1695 +        }
 13.1696 +
 13.1697 +        /// <summary>
 13.1698 +        /// Releases the internal Outlook.MailItem wrapped by this MailItemWrapper.
 13.1699 +        /// In general, this shouldn't be used as the MailItems are managed externally.
 13.1700 +        /// However, there are some cases where the MailItem needs to be disposed and the MailItemWrapper is the only
 13.1701 +        /// object that maintains the reference.
 13.1702 +        /// </summary>
 13.1703 +        public void DisposeInternalMailItem()
 13.1704 +        {
 13.1705 +            if (this.wrappedMailItem != null)
 13.1706 +            {
 13.1707 +                // Marshal.ReleaseComObject(this.internalMailItem);
 13.1708 +                this.wrappedMailItem = null;
 13.1709 +            }
 13.1710 +
 13.1711 +            return;
 13.1712 +        }
 13.1713 +
 13.1714 +        /// <summary>
 13.1715 +        /// Releases resources and disconnects internal events.
 13.1716 +        /// This exists to make code-analysis not throw old warnings.
 13.1717 +        /// </summary>
 13.1718 +        /// <param name="disposing">True to clean up native and managed resources. 
 13.1719 +        /// False to clean up only native resources.</param>
 13.1720 +        protected virtual void Dispose(bool disposing)
 13.1721 +        {
 13.1722 +            // Free managed resources
 13.1723 +            if (disposing)
 13.1724 +            {
 13.1725 +                // Disconnect mail item events
 13.1726 +                this.ConnectInternalMailItemEvents(false);
 13.1727 +
 13.1728 +                /* The BackgroundWorker class doesn't actually implement any functionality in Dispose.
 13.1729 +                 * It's simply inherited from the base implementation.
 13.1730 +                 * Just to make this clear (especially for code analysis) it is called and documented here.
 13.1731 +                 */
 13.1732 +                if (this.processor != null)
 13.1733 +                {
 13.1734 +                    this.processor.RunWorkerCompleted -= Processor_RunWorkerCompleted;
 13.1735 +                    this.processor.DoWork -= Processor_DoWork;
 13.1736 +                    this.processor.Dispose();
 13.1737 +                }
 13.1738 +                if (this.mirrorLocator != null)
 13.1739 +                {
 13.1740 +                    this.mirrorLocator.RunWorkerCompleted -= MirrorLocator_RunWorkerCompleted;
 13.1741 +                    this.mirrorLocator.DoWork -= MirrorLocator_DoWork;
 13.1742 +                    this.mirrorLocator.Dispose();
 13.1743 +                }
 13.1744 +            }
 13.1745 +
 13.1746 +            this.wrappedMailItem = null;
 13.1747 +        }
 13.1748 +
 13.1749 +        /// <summary>
 13.1750 +        /// Attempts to resolve all the Recipient objects in the Recipients collection of
 13.1751 +        /// the internal mail item against the Address Book (similar to 'Check Names').
 13.1752 +        /// This will first save the mail item (if it's not a draft), then forward the call to Recipients.ResolveAll().
 13.1753 +        /// See: https://msdn.microsoft.com/en-us/library/office/microsoft.office.interop.outlook.recipients.resolveall
 13.1754 +        /// </summary>
 13.1755 +        public void ResolveAllRecipients()
 13.1756 +        {
 13.1757 +            lock (mutexMailItem)
 13.1758 +            {
 13.1759 +                try
 13.1760 +                {
 13.1761 +                    /* Calling Save() for drafts might cause a crash, as this then interferes
 13.1762 +                     * with the protected storing of drafts for untrusted servers.
 13.1763 +                     */
 13.1764 +                    if (this.wrappedMailItem.GetIsDraft() == false)
 13.1765 +                    {
 13.1766 +                        this.wrappedMailItem.Save();
 13.1767 +                    }
 13.1768 +                    bool result = this.wrappedMailItem.Recipients.ResolveAll();
 13.1769 +                }
 13.1770 +                catch (Exception ex)
 13.1771 +                {
 13.1772 +                    Log.Error("ResolveAllRecipients: exception " + ex.ToString());
 13.1773 +                }
 13.1774 +            }
 13.1775 +
 13.1776 +            return;
 13.1777 +        }
 13.1778 +
 13.1779 +        /// <summary>
 13.1780 +        /// Checks if the original item was encrypted and sets the user property to the
 13.1781 +        /// reply/forward item if needed.
 13.1782 +        /// This method evokes the OriginallyEncryptedStatusUpdated because it is possible
 13.1783 +        /// that the FormRegionPrivacyStatus has already been initialized when this method
 13.1784 +        /// is run. However, it might be necessary to check if the original item was encrypted
 13.1785 +        /// in order to decide whether to encrypt the reply/forward, so we need to update its
 13.1786 +        /// status.
 13.1787 +        /// </summary>
 13.1788 +        /// <param name="replyItem">The reply/forward item</param>
 13.1789 +        private void SetOriginallyEncryptedStatus(Outlook.MailItem replyItem)
 13.1790 +        {
 13.1791 +            if (this._LastProcessedRating >= pEpRating.pEpRatingUnreliable)
 13.1792 +            {
 13.1793 +                replyItem?.SetOriginallyEncryptedStatus(this._LastProcessedRating);
 13.1794 +
 13.1795 +                OriginallyEncryptedStatusUpdated?.Invoke(this, new EventArgs());
 13.1796 +            }
 13.1797 +        }
 13.1798 +
 13.1799 +        /// <summary>
 13.1800 +        /// Displays the unencrypted mirror mail item (if it exists) associated with the wrapped mail item.
 13.1801 +        /// </summary>
 13.1802 +        /// <returns>True if successful, otherwise false.</returns>
 13.1803 +        public bool DisplayMirror()
 13.1804 +        {
 13.1805 +            if (this.processor.IsBusy ||
 13.1806 +                this.mirrorLocator.IsBusy)
 13.1807 +            {
 13.1808 +                // Don't try to locate the mirror if it's being used
 13.1809 +                return (false);
 13.1810 +            }
 13.1811 +            else
 13.1812 +            {
 13.1813 +                Outlook.MailItem omi = this.wrappedMailItem.GetMirror();
 13.1814 +
 13.1815 +                if (omi == null)
 13.1816 +                {
 13.1817 +                    return (false);
 13.1818 +                }
 13.1819 +                else
 13.1820 +                {
 13.1821 +                    omi.Display();
 13.1822 +                }
 13.1823 +            }
 13.1824 +
 13.1825 +            return true;
 13.1826 +        }
 13.1827 +
 13.1828 +        /**************************************************************
 13.1829 +         * 
 13.1830 +         * Event Methods
 13.1831 +         * 
 13.1832 +         *************************************************************/
 13.1833 +
 13.1834 +        /// <summary>
 13.1835 +        /// Raises the property change event, if possible, with the given arguments.
 13.1836 +        /// </summary>
 13.1837 +        /// <param name="propertyName">The name of the property that was changed.</param>
 13.1838 +        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
 13.1839 +        {
 13.1840 +            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 13.1841 +        }
 13.1842 +
 13.1843 +        /// <summary>
 13.1844 +        /// Dis/connects all necessary events to/from the internal mail item.
 13.1845 +        /// This will then expose these events through the cryptable mail item directly.
 13.1846 +        /// </summary>
 13.1847 +        /// <param name="connect">Whether to connect or disconnect events.</param>
 13.1848 +        private void ConnectInternalMailItemEvents(bool connect)
 13.1849 +        {
 13.1850 +            if (this.wrappedMailItem != null)
 13.1851 +            {
 13.1852 +                /* OUT-285: This should probably never fail, but during dis/connection
 13.1853 +                 * of an account, this method raised an InvalidCastException, so we will 
 13.1854 +                 * catch any error here anyway.
 13.1855 +                 */
 13.1856 +                try
 13.1857 +                {
 13.1858 +                    // Connect or disconnect events
 13.1859 +                    if (connect)
 13.1860 +                    {
 13.1861 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).BeforeAttachmentPreview += MailItem_BeforeAttachmentPreview;
 13.1862 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Close += MailItem_Close;
 13.1863 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Forward += MailItem_Forward;
 13.1864 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Open += MailItem_Open;
 13.1865 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).PropertyChange += MailItem_PropertyChange;
 13.1866 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Reply += MailItem_Reply;
 13.1867 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).ReplyAll += MailItem_ReplyAll;
 13.1868 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Send += MailItem_Send;
 13.1869 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Write += MailItem_Write;
 13.1870 +                    }
 13.1871 +                    else
 13.1872 +                    {
 13.1873 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).BeforeAttachmentPreview -= MailItem_BeforeAttachmentPreview;
 13.1874 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Close -= MailItem_Close;
 13.1875 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Forward -= MailItem_Forward;
 13.1876 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Open -= MailItem_Open;
 13.1877 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).PropertyChange -= MailItem_PropertyChange;
 13.1878 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Reply -= MailItem_Reply;
 13.1879 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).ReplyAll -= MailItem_ReplyAll;
 13.1880 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Send -= MailItem_Send;
 13.1881 +                        ((Outlook.ItemEvents_10_Event)this.wrappedMailItem).Write -= MailItem_Write;
 13.1882 +                    }
 13.1883 +                }
 13.1884 +                catch (Exception ex)
 13.1885 +                {
 13.1886 +                    Log.Error("ConnectInternalMailItemEvents: Error occured. " + ex.ToString());
 13.1887 +                }
 13.1888 +            }
 13.1889 +
 13.1890 +            return;
 13.1891 +        }
 13.1892 +
 13.1893 +        /**************************************************************
 13.1894 +         * 
 13.1895 +         * Sub-classes
 13.1896 +         * 
 13.1897 +         *************************************************************/
 13.1898 +
 13.1899 +        /// <summary>
 13.1900 +        /// Class used to store the arguments in the GetMirrorCompleted event.
 13.1901 +        /// </summary>
 13.1902 +        internal class GetMirrorCompletedEventArgs : EventArgs
 13.1903 +        {
 13.1904 +            /// <summary>
 13.1905 +            /// The located mirror after the get mirror process is complete.
 13.1906 +            /// </summary>
 13.1907 +            public PEPMessage Mirror = null;
 13.1908 +
 13.1909 +            /// <summary>
 13.1910 +            /// Constructs a new GetMirrorCompletedEventArgs with the given arguments.
 13.1911 +            /// </summary>
 13.1912 +            /// <param name="mirror">The located mirror after the get mirror process completes.</param>
 13.1913 +            public GetMirrorCompletedEventArgs(PEPMessage mirror)
 13.1914 +            {
 13.1915 +                this.Mirror = mirror;
 13.1916 +            }
 13.1917 +        }
 13.1918 +
 13.1919 +        /// <summary>
 13.1920 +        /// Class used to store an entry in the encrypted conversation cache.
 13.1921 +        /// This will identify the original parent encrypted mail item.
 13.1922 +        /// </summary>
 13.1923 +        private class OriginalMailItem
 13.1924 +        {
 13.1925 +            public string ConversationId { get; set; }
 13.1926 +            public string ConversationIndex { get; set; }
 13.1927 +            public string ConversationTopic { get; set; }
 13.1928 +            public string EntryId { get; set; }
 13.1929 +            public bool IsEncrypted { get; set; }
 13.1930 +
 13.1931 +            public OriginalMailItem()
 13.1932 +            {
 13.1933 +                this.ConversationId = null;
 13.1934 +                this.ConversationIndex = null;
 13.1935 +                this.ConversationTopic = null;
 13.1936 +                this.EntryId = null;
 13.1937 +                this.IsEncrypted = false;
 13.1938 +            }
 13.1939 +        }
 13.1940 +
 13.1941 +        /// <summary>
 13.1942 +        /// Class used to store a processing result.
 13.1943 +        /// </summary>
 13.1944 +        internal class ProcessingResult
 13.1945 +        {
 13.1946 +            public pEpRating Rating { get; set; } = pEpRating.pEpRatingUndefined;
 13.1947 +            public Dictionary<MapiProperty.MapiProp, object> PropertiesToSet { get; set; } = new Dictionary<MapiProperty.MapiProp, object>();
 13.1948 +        }
 13.1949 +    }
 13.1950 +}
    14.1 --- a/Wrappers/WatchedExplorer.cs	Wed Mar 13 13:50:02 2019 +0100
    14.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.3 @@ -1,374 +0,0 @@
    14.4 -using System;
    14.5 -using System.Linq;
    14.6 -using System.Xml;
    14.7 -using Outlook = Microsoft.Office.Interop.Outlook;
    14.8 -
    14.9 -namespace pEp
   14.10 -{
   14.11 -    /// <summary>
   14.12 -    /// Stores an Outlook Explorer with connected events.
   14.13 -    /// </summary>
   14.14 -    public class WatchedExplorer : WatchedWindow
   14.15 -    {
   14.16 -        private string                  lastProcessedEntryId    = null;
   14.17 -        private CryptableMailItem       inlineResponseItem      = null;
   14.18 -
   14.19 -        /**************************************************************
   14.20 -         * 
   14.21 -         * Constructors/Destructors
   14.22 -         * 
   14.23 -         *************************************************************/
   14.24 -
   14.25 -        /// <summary>
   14.26 -        /// Primary constructor.
   14.27 -        /// </summary>
   14.28 -        /// <param name="explorer">The explorer to watch.</param>
   14.29 -        public WatchedExplorer(Outlook.Explorer explorer)
   14.30 -        {
   14.31 -            this.Explorer = explorer;
   14.32 -
   14.33 -            if (this.Explorer != null)
   14.34 -            {
   14.35 -                this.ConnectWatchedExplorerEvents(true);
   14.36 -            }
   14.37 -        }
   14.38 -
   14.39 -        #region Properties
   14.40 -
   14.41 -        /// <summary>
   14.42 -        /// Gets the Explorer that is wrapped by this WatchedExplorer.
   14.43 -        /// </summary>
   14.44 -        public Outlook.Explorer Explorer { get; private set; } = null;
   14.45 -
   14.46 -        /// <summary>
   14.47 -        /// Gets the Explorer that is wrapped by this WatchedExplorer.
   14.48 -        /// </summary>
   14.49 -        public override dynamic Window
   14.50 -        {
   14.51 -            get { return this.Explorer; }
   14.52 -        }
   14.53 -
   14.54 -        /// <summary>
   14.55 -        /// Gets the window type of this window.
   14.56 -        /// </summary>
   14.57 -        public override WindowType Type
   14.58 -        {
   14.59 -            get { return WindowType.Explorer; }
   14.60 -        }
   14.61 -
   14.62 -        #endregion
   14.63 -
   14.64 -        #region Methods
   14.65 -
   14.66 -        /**************************************************************
   14.67 -         * 
   14.68 -         * Methods
   14.69 -         * 
   14.70 -         *************************************************************/
   14.71 -
   14.72 -        /// <summary>
   14.73 -        /// Clean up any resources being used.
   14.74 -        /// </summary>
   14.75 -        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
   14.76 -        protected override void Dispose(bool disposing)
   14.77 -        {
   14.78 -            if (disposing)
   14.79 -            {
   14.80 -                // Disconnect all events
   14.81 -                this.ConnectWatchedExplorerEvents(false);
   14.82 -
   14.83 -                // Disconnect cryptable mail item
   14.84 -                if (this.inlineResponseItem != null)
   14.85 -                {
   14.86 -                    this.inlineResponseItem.Dispose();
   14.87 -                    this.inlineResponseItem = null;
   14.88 -                }
   14.89 -
   14.90 -                // Set Outlook objects to null
   14.91 -                this.Explorer = null;
   14.92 -
   14.93 -                // Dispose base class
   14.94 -                base.Dispose(disposing);
   14.95 -            }
   14.96 -        }
   14.97 -
   14.98 -        /// <summary>
   14.99 -        /// Connects the events for this watched explorer.
  14.100 -        /// <param name="connect">Whether to connect or disconnect the events.</param>
  14.101 -        /// </summary>
  14.102 -        private void ConnectWatchedExplorerEvents(bool connect)
  14.103 -        {
  14.104 -            try
  14.105 -            {
  14.106 -                if (connect)
  14.107 -                {
  14.108 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close += Explorer_Close;
  14.109 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch += Explorer_FolderSwitch;
  14.110 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose += Explorer_InlineResponseClose;
  14.111 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange += Explorer_SelectionChange;
  14.112 -                }
  14.113 -                else
  14.114 -                {
  14.115 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).Close -= Explorer_Close;
  14.116 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).FolderSwitch -= Explorer_FolderSwitch;
  14.117 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).InlineResponseClose -= Explorer_InlineResponseClose;
  14.118 -                    ((Outlook.ExplorerEvents_10_Event)this.Explorer).SelectionChange -= Explorer_SelectionChange;
  14.119 -                }
  14.120 -            }
  14.121 -            catch (Exception ex)
  14.122 -            {
  14.123 -                Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
  14.124 -            }
  14.125 -        }
  14.126 -        #endregion
  14.127 -
  14.128 -        #region Event Handling
  14.129 -        /**************************************************************
  14.130 -         * 
  14.131 -         * Event Handling
  14.132 -         * 
  14.133 -         *************************************************************/
  14.134 -
  14.135 -        /// <summary>
  14.136 -        /// Event handler for when a watched explorer is being closed.
  14.137 -        /// </summary>
  14.138 -        private void Explorer_Close()
  14.139 -        {
  14.140 -            Globals.ThisAddIn.RemoveFromWatchedExplorers(this);
  14.141 -            this.Dispose();
  14.142 -        }
  14.143 -
  14.144 -        /// <summary>
  14.145 -        /// Event handler for when a different folder is being selected.
  14.146 -        /// </summary>
  14.147 -        private void Explorer_FolderSwitch()
  14.148 -        {
  14.149 -            Outlook.Folder folder = null;
  14.150 -            Outlook.TableView customView = null;
  14.151 -            Outlook.View view = null;
  14.152 -            Outlook.Views views = null;
  14.153 -
  14.154 -            try
  14.155 -            {
  14.156 -                folder = this.Explorer?.CurrentFolder as Outlook.Folder;
  14.157 -
  14.158 -                // If the "Last Used" contacts folder is selected, make sure the correct view is applied
  14.159 -                if ((folder?.DefaultMessageClass?.Equals(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Contact) == true) &&
  14.160 -                    (folder?.Name?.Equals(Properties.Resources.LastUsedFolderName) == true))
  14.161 -                {
  14.162 -                    view = this.Explorer.CurrentView;
  14.163 -
  14.164 -                    // If the current view isn't the custom one, create it if necessary
  14.165 -                    if (view?.Name?.Equals(Properties.Resources.LastUsedFolderName) != true)
  14.166 -                    {
  14.167 -                        views = this.Explorer.CurrentFolder.Views as Outlook.Views;
  14.168 -
  14.169 -                        try
  14.170 -                        {
  14.171 -                            customView = views[Properties.Resources.LastUsedFolderName] as Outlook.TableView;
  14.172 -                        }
  14.173 -                        catch (Exception ex)
  14.174 -                        {
  14.175 -                            customView = null;
  14.176 -                            Log.Info("Explorer_SelectionChange: Error getting Last Used folder view. " + ex.ToString());
  14.177 -                        }
  14.178 -
  14.179 -                        /* If the custom view doesn't exist, create and apply it.
  14.180 -                         * If it already exists, don't apply it.
  14.181 -                         * Caveat: If the creation of the view went wrong at some point, it will never be set correctly. The alternative
  14.182 -                         *         here would be to set it each time it's not set. This is another problem, however, as we don't know if
  14.183 -                         *         the view of this folder is not the custom one because it has never been set correctly or if the user 
  14.184 -                         *         selects another one. So, in the latter case, we would basically override a user decision.
  14.185 -                         * Note: This whole procedure is a workaround because we can only set the Explorer's current view and not the folder's
  14.186 -                         *       current view directly.
  14.187 -                         */                           
  14.188 -                        if (customView == null)
  14.189 -                        {
  14.190 -                            customView = views.Add(Properties.Resources.LastUsedFolderName, Outlook.OlViewType.olTableView, Outlook.OlViewSaveOption.olViewSaveOptionThisFolderEveryone) as Outlook.TableView;
  14.191 -                            XmlDocument xmlDoc = new XmlDocument();
  14.192 -                            xmlDoc.LoadXml(customView.XML);
  14.193 -                            XmlNodeList childNodes = xmlDoc.LastChild.ChildNodes;
  14.194 -
  14.195 -                            // Create and/or set up Order By property
  14.196 -                            XmlNode orderByNode = childNodes.OfType<XmlNode>().First(a => (a.Name?.Equals("orderby", StringComparison.OrdinalIgnoreCase) == true));
  14.197 -                            if (orderByNode == null)
  14.198 -                            {
  14.199 -                                orderByNode = xmlDoc.CreateNode(XmlNodeType.Element, "orderby", string.Empty);
  14.200 -                                xmlDoc.LastChild.AppendChild(orderByNode);
  14.201 -                            }
  14.202 -                            orderByNode.InnerXml = "<order><heading>Modified</heading><prop>DAV:getlastmodified</prop><type>datetime</type><sort>desc</sort></order>";
  14.203 -
  14.204 -                            // Create and/or set up Modified column
  14.205 -                            XmlNode modifiedNode = childNodes.OfType<XmlNode>().FirstOrDefault(a => (a.ChildNodes.OfType<XmlNode>().FirstOrDefault(b => (b.Value?.Equals("Modified", StringComparison.OrdinalIgnoreCase) == true)) != null));
  14.206 -
  14.207 -                            if (modifiedNode == null)
  14.208 -                            {
  14.209 -                                modifiedNode = xmlDoc.CreateNode(XmlNodeType.Element, "column", string.Empty);
  14.210 -
  14.211 -                                // Get first column
  14.212 -                                XmlNode fullNameColumn = null;
  14.213 -                                foreach (var node in childNodes)
  14.214 -                                {
  14.215 -                                    if (((node as XmlNode)?.Name?.Equals("column", StringComparison.OrdinalIgnoreCase) == true) &&
  14.216 -                                        ((node as XmlNode)?.FirstChild?.InnerText?.Equals("Full Name", StringComparison.OrdinalIgnoreCase) == true))
  14.217 -                                    {
  14.218 -                                        fullNameColumn = node as XmlNode;
  14.219 -                                        break;
  14.220 -                                    }
  14.221 -                                }
  14.222 -
  14.223 -                                // If not found, just insert after the 4th column
  14.224 -                                if (fullNameColumn == null)
  14.225 -                                {
  14.226 -                                    fullNameColumn = childNodes[4];
  14.227 -                                }
  14.228 -
  14.229 -                                if (fullNameColumn != null)
  14.230 -                                {
  14.231 -                                    xmlDoc.LastChild.InsertAfter(modifiedNode, fullNameColumn);
  14.232 -                                }
  14.233 -                            }
  14.234 -                            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>";
  14.235 -
  14.236 -                            // Set modified XML
  14.237 -                            customView.XML = xmlDoc.OuterXml;
  14.238 -                            customView.Save();
  14.239 -
  14.240 -                            // Apply as current view
  14.241 -                            this.Explorer.CurrentView = customView;
  14.242 -                        }
  14.243 -                    }
  14.244 -                }
  14.245 -            }
  14.246 -            catch (Exception ex)
  14.247 -            {
  14.248 -                Log.Error("Explorer_FolderSwitch: Error setting Last Used folder view. " + ex.ToString());
  14.249 -            }
  14.250 -            finally
  14.251 -            {
  14.252 -                customView = null;
  14.253 -                folder = null;
  14.254 -                view = null;
  14.255 -                views = null;
  14.256 -            }
  14.257 -        }
  14.258 -
  14.259 -        /// <summary>
  14.260 -        /// Event handler for when an inline response is being closed.
  14.261 -        /// </summary>
  14.262 -        private void Explorer_InlineResponseClose()
  14.263 -        {
  14.264 -            Outlook.MailItem omi = null;
  14.265 -
  14.266 -            /* Create a new CryptableMailItem. This is needed so that its
  14.267 -             * MailItem_Write event gets called and the message will get saved
  14.268 -             * securely instead of to the server's draft folder.
  14.269 -             * Note: the form region's CMI is already disposed at this point,
  14.270 -             * so that its Write event will never be called.
  14.271 -             */
  14.272 -            try
  14.273 -            {
  14.274 -                omi = this.Explorer?.ActiveInlineResponse as Outlook.MailItem;
  14.275 -
  14.276 -                if (omi != null)
  14.277 -                {
  14.278 -                    this.inlineResponseItem = new CryptableMailItem(omi, null, false)
  14.279 -                    {
  14.280 -                        IsInlineResponse = true
  14.281 -                    };
  14.282 -                }
  14.283 -            }
  14.284 -            catch (Exception ex)
  14.285 -            {
  14.286 -                Log.Error("WatchedExplorer_InlineResponseClose: Error setting new inline response item. " + ex.ToString());
  14.287 -            }
  14.288 -            finally
  14.289 -            {
  14.290 -                omi = null;
  14.291 -            }
  14.292 -        }
  14.293 -
  14.294 -        /// <summary>
  14.295 -        /// Event handler for when the currently selected item in the explorer changes.
  14.296 -        /// </summary>
  14.297 -        private void Explorer_SelectionChange()
  14.298 -        {
  14.299 -            Outlook.Selection selection = null;
  14.300 -            try
  14.301 -            {
  14.302 -                // Process the newly selected item
  14.303 -                selection = this.Explorer.Selection;
  14.304 -
  14.305 -                /* Do only process the item if one individual item is selected.
  14.306 -                 * Do not process a selected range of items.
  14.307 -                 */
  14.308 -                if (selection.Count == 1)
  14.309 -                {
  14.310 -                    this.CurrentMailItem = selection[1] as Outlook.MailItem;
  14.311 -                    if (this.CurrentMailItem != null)
  14.312 -                    {
  14.313 -                        /* Check if inline response. Note: in Outlook 2010, there is no inline response.
  14.314 -                         * IMPORTANT: Never call Explorer.ActiveInlineResponse on Outlook 2010
  14.315 -                         *            as this might lead to a crash of Outlook (even inside a
  14.316 -                         *            try/catch block)
  14.317 -                         */
  14.318 -                        bool isInlineResponse = false;
  14.319 -                        if (Globals.OutlookVersion != Globals.Version.Outlook2010)
  14.320 -                        {
  14.321 -                            Outlook.MailItem inlineResponse = null;
  14.322 -                            try
  14.323 -                            {
  14.324 -                                inlineResponse = this.Explorer?.ActiveInlineResponse as Outlook.MailItem;
  14.325 -                                if (inlineResponse != null)
  14.326 -                                {
  14.327 -                                    isInlineResponse = true;
  14.328 -                                    this.CurrentMailItem = inlineResponse;
  14.329 -                                }
  14.330 -                            }
  14.331 -                            catch (Exception ex)
  14.332 -                            {
  14.333 -                                Log.Error("Explorer_SelectionChange: Error determining whether it is an inline response. " + ex.ToString());
  14.334 -                            }
  14.335 -                            finally
  14.336 -                            {
  14.337 -                                inlineResponse = null;
  14.338 -                            }
  14.339 -
  14.340 -                            /* If a different mail is clicked in an Window, the SelectionChange
  14.341 -                             * event is always called twice. To prevent a double processing, we only
  14.342 -                             * process a mail item if it is different from the last one that has been
  14.343 -                             * processed.
  14.344 -                             */
  14.345 -                            string entryId = isInlineResponse ? null : this.CurrentMailItem?.EntryID;
  14.346 -                            if (entryId?.Equals(lastProcessedEntryId, StringComparison.OrdinalIgnoreCase) == true)
  14.347 -                            {
  14.348 -                                Log.Verbose("Explorer_SelectionChange: Same EntryId as last item. Skipped processing of item with EntryId " + entryId);
  14.349 -                                return;
  14.350 -                            }
  14.351 -                            else
  14.352 -                            {
  14.353 -                                this.lastProcessedEntryId = entryId;
  14.354 -                            }
  14.355 -                        }
  14.356 -
  14.357 -                        // Initialize mail item
  14.358 -                        this.InitializeWindow(isInlineResponse);
  14.359 -                    }                    
  14.360 -                    else
  14.361 -                    {
  14.362 -                        Log.Error("Explorer_SelectionChange: Error getting current selection.");
  14.363 -                    }
  14.364 -                }
  14.365 -            }
  14.366 -            catch (Exception ex)
  14.367 -            {
  14.368 -                Log.Error("Explorer_SelectionChange: Error occured: " + ex?.ToString());
  14.369 -            }
  14.370 -            finally
  14.371 -            {
  14.372 -                selection = null;
  14.373 -            }
  14.374 -        }
  14.375 -        #endregion
  14.376 -    }
  14.377 -}
    15.1 --- a/Wrappers/WatchedInspector.cs	Wed Mar 13 13:50:02 2019 +0100
    15.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.3 @@ -1,144 +0,0 @@
    15.4 -using System;
    15.5 -using Outlook = Microsoft.Office.Interop.Outlook;
    15.6 -
    15.7 -namespace pEp
    15.8 -{
    15.9 -    /// <summary>
   15.10 -    /// Stores an Outlook Explorer with connected events.
   15.11 -    /// </summary>
   15.12 -    public class WatchedInspector : WatchedWindow
   15.13 -    {
   15.14 -
   15.15 -        /**************************************************************
   15.16 -         * 
   15.17 -         * Constructors/Destructors
   15.18 -         * 
   15.19 -         *************************************************************/
   15.20 -
   15.21 -        /// <summary>
   15.22 -        /// Primary constructor.
   15.23 -        /// </summary>
   15.24 -        /// <param name="inspector">The inspector to watch.</param>
   15.25 -        public WatchedInspector(Outlook.Inspector inspector)
   15.26 -        {
   15.27 -            this.Inspector = inspector;
   15.28 -
   15.29 -            if (this.Inspector != null)
   15.30 -            {
   15.31 -                this.ConnectWatchedInspectorEvents();
   15.32 -
   15.33 -                // Set mail item
   15.34 -                this.CurrentMailItem = this.Inspector.CurrentItem as Outlook.MailItem;
   15.35 -
   15.36 -                if (this.CurrentMailItem != null)
   15.37 -                {
   15.38 -                    this.InitializeWindow();
   15.39 -                }
   15.40 -                else
   15.41 -                {
   15.42 -                    Log.Error("WatchedInspector: Error getting current mail item.");
   15.43 -                }
   15.44 -            }
   15.45 -        }
   15.46 -
   15.47 -        #region Properties
   15.48 -        /// <summary>
   15.49 -        /// Gets the Inspector that is wrapped by this WatchedInspector
   15.50 -        /// </summary>
   15.51 -        public Outlook.Inspector Inspector { get; private set; } = null;
   15.52 -
   15.53 -        /// <summary>
   15.54 -        /// Gets the Inspector that is wrapped by this WatchedInspector.
   15.55 -        /// </summary>
   15.56 -        public override dynamic Window
   15.57 -        {
   15.58 -            get { return this.Inspector; }
   15.59 -        }
   15.60 -
   15.61 -        /// <summary>
   15.62 -        /// Gets the window type of this window.
   15.63 -        /// </summary>
   15.64 -        public override WindowType Type
   15.65 -        {
   15.66 -            get { return WindowType.Inspector; }
   15.67 -        }
   15.68 -        #endregion
   15.69 -
   15.70 -        #region Methods
   15.71 -        /**************************************************************
   15.72 -         * 
   15.73 -         * Methods
   15.74 -         * 
   15.75 -         *************************************************************/
   15.76 -
   15.77 -        /// <summary>
   15.78 -        /// Clean up any resources being used.
   15.79 -        /// </summary>
   15.80 -        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
   15.81 -        protected override void Dispose(bool disposing)
   15.82 -        {
   15.83 -            if (disposing)
   15.84 -            {
   15.85 -                // Disconnect all events
   15.86 -                this.DisconnectWatchedInspectorEvents();
   15.87 -
   15.88 -                // Set Outlook objects to null
   15.89 -                this.Inspector = null;
   15.90 -
   15.91 -                // Dispose base class
   15.92 -                base.Dispose(disposing);
   15.93 -            }
   15.94 -        }
   15.95 -
   15.96 -        /// <summary>
   15.97 -        /// Connects the events for this watched explorer
   15.98 -        /// </summary>
   15.99 -        private void ConnectWatchedInspectorEvents()
  15.100 -        {
  15.101 -            if (this.Inspector != null)
  15.102 -            {
  15.103 -                ((Outlook.InspectorEvents_10_Event)this.Inspector).Close += WatchedInspector_Close;
  15.104 -            }
  15.105 -        }
  15.106 -
  15.107 -        /// <summary>
  15.108 -        /// Disconnects the events from this watched explorer
  15.109 -        /// </summary>
  15.110 -        private void DisconnectWatchedInspectorEvents()
  15.111 -        {
  15.112 -            if (this.Inspector != null)
  15.113 -            {
  15.114 -                ((Outlook.InspectorEvents_10_Event)this.Inspector).Close -= WatchedInspector_Close;
  15.115 -
  15.116 -            }
  15.117 -        }
  15.118 -
  15.119 -        #endregion
  15.120 -
  15.121 -        #region Event Handling
  15.122 -        /**************************************************************
  15.123 -         * 
  15.124 -         * Event Handling
  15.125 -         * 
  15.126 -         *************************************************************/
  15.127 -
  15.128 -        /// <summary>
  15.129 -        /// Event handler for when a watched inspector is being closed.
  15.130 -        /// </summary>
  15.131 -        private void WatchedInspector_Close()
  15.132 -        {
  15.133 -            Globals.ThisAddIn.RemoveFromWatchedInspectors(this);
  15.134 -            this.Dispose();
  15.135 -        }
  15.136 -
  15.137 -        /// <summary>
  15.138 -        /// Event handler for when the processing of an item in the WatchedInspector has finished.
  15.139 -        /// </summary>
  15.140 -        private void Inspector_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
  15.141 -        {
  15.142 -            Log.Error("Inspector_ProcessingCompleted: Not implemented.");
  15.143 -        }
  15.144 -
  15.145 -        #endregion
  15.146 -    }
  15.147 -}
    16.1 --- a/Wrappers/WatchedWindow.cs	Wed Mar 13 13:50:02 2019 +0100
    16.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.3 @@ -1,1594 +0,0 @@
    16.4 -using pEp.UI;
    16.5 -using pEpCOMServerAdapterLib;
    16.6 -using System;
    16.7 -using System.ComponentModel;
    16.8 -using System.Windows.Forms;
    16.9 -using Outlook = Microsoft.Office.Interop.Outlook;
   16.10 -
   16.11 -namespace pEp
   16.12 -{
   16.13 -    /// <summary>
   16.14 -    /// Stores an Outlook Window with connected events.
   16.15 -    /// </summary>
   16.16 -    public abstract class WatchedWindow : IDisposable
   16.17 -    {
   16.18 -        private CryptableMailItem               cryptableMailItem           = null;
   16.19 -        private bool                            displayMirrorRequested      = false;
   16.20 -        private HandshakeDialog                 handshakeDialog             = null;
   16.21 -        private bool                            isEnabled                   = true;
   16.22 -        private bool                            isStarted                   = false;
   16.23 -        private bool                            processingOngoing           = false;
   16.24 -        private bool                            refreshOngoing              = false;
   16.25 -        private bool                            repeatProcessing            = false;
   16.26 -        private int                             repeatCounter               = 0;
   16.27 -        private const int                       maxRepeatCount              = 5;
   16.28 -
   16.29 -        public enum WindowType
   16.30 -        {
   16.31 -            Undefined,
   16.32 -            Inspector,
   16.33 -            Explorer
   16.34 -        }
   16.35 -
   16.36 -        #region Properties
   16.37 -
   16.38 -        /// <summary>
   16.39 -        /// The mail item that is connected to this Inspector/Explorer window.
   16.40 -        /// </summary>
   16.41 -        public Outlook.MailItem CurrentMailItem { get; set; } = null;
   16.42 -
   16.43 -        /// <summary>
   16.44 -        /// Gets or sets whether to disable the Force Protection option.
   16.45 -        /// </summary>
   16.46 -        public bool DisableForceProtection { get; set; } = false;
   16.47 -
   16.48 -        /// <summary>
   16.49 -        /// Gets or sets whether to send this message forcefully protected.
   16.50 -        /// </summary>
   16.51 -        public bool ForceProtection { get; set; } = false;
   16.52 -
   16.53 -        /// <summary>
   16.54 -        /// Gets or sets whether to send this message forcefully unencrypted.
   16.55 -        /// </summary>
   16.56 -        public bool ForceUnencrypted { get; set; } = false;
   16.57 -
   16.58 -        /// <summary>
   16.59 -        /// Gets or sets whether the message is a draft message.
   16.60 -        /// </summary>
   16.61 -        public bool IsDraft { get; set; } = false;
   16.62 -
   16.63 -        /// <summary>
   16.64 -        /// Gets or sets whether to always store this message as if on an untrusted server.
   16.65 -        /// </summary>
   16.66 -        public bool NeverUnsecure { get; set; } = false;
   16.67 -
   16.68 -        /// <summary>
   16.69 -        /// The privacy state of this form region.
   16.70 -        /// </summary>
   16.71 -        internal PrivacyState PrivacyState { get; private set; } = new PrivacyState();
   16.72 -
   16.73 -        /// <summary>
   16.74 -        /// Gets the rating of this message.
   16.75 -        /// </summary>
   16.76 -        public pEpRating Rating { get; private set; } = pEpRating.pEpRatingUndefined;
   16.77 -
   16.78 -        /// <summary>
   16.79 -        /// Sets the rating of this message and updates the UI.
   16.80 -        /// </summary>
   16.81 -        /// <param name="rating">The message rating.</param>
   16.82 -        public void SetRating(pEpRating rating)
   16.83 -        {
   16.84 -            this.Rating = rating;
   16.85 -            this.UpdatePrivacyStateAndUI();
   16.86 -        }
   16.87 -
   16.88 -        /// <summary>
   16.89 -        /// The timer that schedules the updates of this window.
   16.90 -        /// </summary>
   16.91 -        public System.Windows.Forms.Timer TimerRefresh { get; set; } = new System.Windows.Forms.Timer();
   16.92 -
   16.93 -        /// <summary>
   16.94 -        /// Gets the associated Explorer/Inspector window. To be overwritten in child class.
   16.95 -        /// </summary>
   16.96 -        public abstract dynamic Window { get; }
   16.97 -
   16.98 -        /// <summary>
   16.99 -        /// Gets the window type of this window. To be overwritten in child class.
  16.100 -        /// </summary>
  16.101 -        public abstract WindowType Type { get; }
  16.102 -
  16.103 -        #endregion
  16.104 -
  16.105 -        #region Constructors / Destructors
  16.106 -
  16.107 -        /// <summary>
  16.108 -        /// Destructor.
  16.109 -        /// </summary>
  16.110 -        ~WatchedWindow()
  16.111 -        {
  16.112 -            this.Dispose(true);
  16.113 -        }
  16.114 -        #endregion
  16.115 -
  16.116 -        #region Methods
  16.117 -        /**************************************************************
  16.118 -         * 
  16.119 -         * Methods
  16.120 -         * 
  16.121 -         *************************************************************/
  16.122 -
  16.123 -        /// <summary>
  16.124 -        /// Releases all resources and disconnects internal events.
  16.125 -        /// </summary>
  16.126 -        public void Dispose()
  16.127 -        {
  16.128 -            this.Dispose(true);
  16.129 -        }
  16.130 -
  16.131 -        /// <summary>
  16.132 -        /// Clean up any resources being used.
  16.133 -        /// </summary>
  16.134 -        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  16.135 -        protected virtual void Dispose(bool disposing)
  16.136 -        {
  16.137 -            if (disposing)
  16.138 -            {
  16.139 -                // Disconnect cryptable mail item
  16.140 -                if (this.cryptableMailItem != null)
  16.141 -                {
  16.142 -                    try
  16.143 -                    {
  16.144 -                        this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
  16.145 -                        this.cryptableMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
  16.146 -                        this.cryptableMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
  16.147 -                        this.cryptableMailItem.Open -= MailItem_Open;
  16.148 -                        this.cryptableMailItem.Send -= MailItem_Send;
  16.149 -                        this.cryptableMailItem.OriginallyEncryptedStatusUpdated -= CryptableMailItem_OriginallyEncryptedStatusUpdated;
  16.150 -                    }
  16.151 -                    catch { }
  16.152 -
  16.153 -                    this.cryptableMailItem.Dispose();
  16.154 -                    this.cryptableMailItem = null;
  16.155 -                }
  16.156 -
  16.157 -                // Disconnect other
  16.158 -                this.SetIsEnabled(false);
  16.159 -
  16.160 -                // Set Outlook objects to null
  16.161 -                this.CurrentMailItem = null;
  16.162 -
  16.163 -                // Dispose of timer
  16.164 -                if (this.TimerRefresh != null)
  16.165 -                {
  16.166 -                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
  16.167 -                    this.TimerRefresh.Dispose();
  16.168 -                    this.TimerRefresh = null;
  16.169 -                }
  16.170 -            }
  16.171 -        }
  16.172 -
  16.173 -        /// <summary>
  16.174 -        /// Builds the latest state of the encryption status manager then shows the UI.
  16.175 -        /// </summary>
  16.176 -        public void BuildAndShowManager()
  16.177 -        {
  16.178 -            /* Resolve all recipients -- this ensures the identities list is correctly populated
  16.179 -             * 
  16.180 -             * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
  16.181 -             * This is because the resolve process can modify the contents of the mail item which triggers an event.
  16.182 -             * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
  16.183 -             * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
  16.184 -             * cannot be resolved (no address).
  16.185 -             */
  16.186 -            try
  16.187 -            {
  16.188 -                this.ResolveAllRecipients();
  16.189 -            }
  16.190 -            catch (Exception ex)
  16.191 -            {
  16.192 -                Log.Verbose("BuildAndShowManager: Error resolving recipients. " + ex.ToString());
  16.193 -            }
  16.194 -
  16.195 -            // Build the dialog
  16.196 -            try
  16.197 -            {
  16.198 -                // The PEPMessage to build the dialog with
  16.199 -                PEPMessage message = null;
  16.200 -
  16.201 -                // The own identity to build the dialog with
  16.202 -                PEPIdentity myself = this.cryptableMailItem?.Myself;
  16.203 -
  16.204 -                // If message is a draft, create it directly from the Outlook mail item
  16.205 -                if (this.IsDraft)
  16.206 -                {
  16.207 -                    Log.Verbose("BuildAndShowManager: Creating PEPMessage from draft.");
  16.208 -
  16.209 -                    if (PEPMessage.Create(this.CurrentMailItem, out message, true) == Globals.ReturnStatus.Success)
  16.210 -                    {
  16.211 -                        // Calculate rating
  16.212 -                        message.Rating = message.GetOutgoingRating();
  16.213 -
  16.214 -                        // If Force Protection is set, assign a random GUID
  16.215 -                        if ((this.ForceProtection) &&
  16.216 -                            (this.DisableForceProtection == false))
  16.217 -                        {
  16.218 -                            message.ForceProtectionId = Guid.NewGuid().ToString();
  16.219 -                        }
  16.220 -
  16.221 -                        // If message is Force Unencrypted, assign it
  16.222 -                        message.ForceUnencrypted = this.ForceUnencrypted;
  16.223 -                    }
  16.224 -                    else
  16.225 -                    {
  16.226 -                        Log.Error("BuildAndShowManager: Error creating PEPMessage from draft.");
  16.227 -                        message = null;
  16.228 -                    }
  16.229 -                }
  16.230 -                else
  16.231 -                {
  16.232 -                    // Else, use either the cryptable mail item's associated mirror or message
  16.233 -                    message = this.cryptableMailItem?.Mirror ?? this.cryptableMailItem?.Message;
  16.234 -                    Log.Verbose(string.Format("BuildAndShowManager: Message {0} retrieved from CryptableMailItem", ((message != null) ? "successfully" : "could not be")));
  16.235 -
  16.236 -                    // As fallback, if we don't have a message yet, create it
  16.237 -                    if (message == null)
  16.238 -                    {
  16.239 -                        Log.Verbose("BuildAndShowManager: Using fallback method to get message.");
  16.240 -
  16.241 -                        Outlook.MailItem mirror = null;
  16.242 -
  16.243 -                        try
  16.244 -                        {
  16.245 -                            // For securely stored mails, try to look up mirror
  16.246 -                            if (this.CurrentMailItem?.GetIsSecurelyStored() == true)
  16.247 -                            {
  16.248 -                                mirror = this.CurrentMailItem?.GetMirror();
  16.249 -
  16.250 -                                if (mirror != null)
  16.251 -                                {
  16.252 -                                    // If mirror is found, use it to create PEPMessage
  16.253 -                                    Log.Verbose("BuildAndShowManager: Mirror found.");
  16.254 -
  16.255 -                                    if (PEPMessage.Create(mirror, out message) != Globals.ReturnStatus.Success)
  16.256 -                                    {
  16.257 -                                        message = null;
  16.258 -                                        Log.Error("BuildAndShowManager: Error creating PEPMessage.");
  16.259 -                                    }
  16.260 -                                    else
  16.261 -                                    {
  16.262 -                                        message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
  16.263 -                                    }
  16.264 -                                }
  16.265 -                                else
  16.266 -                                {
  16.267 -                                    // If no mirror is found, decrypt message and use decrypted one (do not 
  16.268 -                                    // decrypt forcefully protected messages).
  16.269 -                                    if ((PEPMessage.Create(this.CurrentMailItem, out message) == Globals.ReturnStatus.Success) &&
  16.270 -                                        (string.IsNullOrEmpty(message.ForceProtectionId)))
  16.271 -                                    {
  16.272 -                                        var msgProcessor = new MsgProcessor();
  16.273 -                                        pEpDecryptFlags flags = pEpDecryptFlags.pEpDecryptFlagsNone;
  16.274 -                                        pEpRating rating = msgProcessor.Decrypt(ref message, out PEPMessage decryptedMsg, out string[] keyList, ref flags);
  16.275 -                                        if (decryptedMsg != null)
  16.276 -                                        {
  16.277 -                                            message = decryptedMsg;
  16.278 -                                        }
  16.279 -                                        message.Rating = rating;
  16.280 -                                    }
  16.281 -                                    else
  16.282 -                                    {
  16.283 -                                        message = null;
  16.284 -                                        Log.Error("BuildAndShowManager: Error creating PEPMessage from mirror.");
  16.285 -                                    }
  16.286 -                                }
  16.287 -                            }
  16.288 -
  16.289 -                            // If we don't have a PEPMessage yet, create it
  16.290 -                            if (message == null)
  16.291 -                            {
  16.292 -                                Log.Verbose("BuildAndShowManager: Creating PEPMessage.");
  16.293 -
  16.294 -                                if (PEPMessage.Create(this.CurrentMailItem, out message) != Globals.ReturnStatus.Success)
  16.295 -                                {
  16.296 -                                    message = null;
  16.297 -                                    Log.Error("BuildAndShowManager: Error creating PEPMessage.");
  16.298 -                                }
  16.299 -                                else
  16.300 -                                {
  16.301 -                                    message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
  16.302 -                                }
  16.303 -                            }
  16.304 -
  16.305 -                            // Get myself identiy if we don't have it yet
  16.306 -                            if (myself == null)
  16.307 -                            {
  16.308 -                                myself = this.CurrentMailItem.GetMyselfIdentity();
  16.309 -                            }
  16.310 -                        }
  16.311 -                        catch (Exception ex)
  16.312 -                        {
  16.313 -                            Log.Error("BuildAndShowManager: Error converting message. " + ex.ToString());
  16.314 -                        }
  16.315 -                        finally
  16.316 -                        {
  16.317 -                            mirror = null;
  16.318 -                        }
  16.319 -                    }
  16.320 -                }
  16.321 -
  16.322 -                // Build dialog
  16.323 -                if (message != null)
  16.324 -                {
  16.325 -                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
  16.326 -                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
  16.327 -                    handshakeDialog.Closed += HandshakeDialog_Closed;
  16.328 -                    handshakeDialog.Show();
  16.329 -                }
  16.330 -                else
  16.331 -                {
  16.332 -                    throw new Exception("Could not build handshake dialog. Message is null.");
  16.333 -                }
  16.334 -            }
  16.335 -            catch (Exception ex)
  16.336 -            {
  16.337 -                Globals.StopAndSendCrashReport(ex);
  16.338 -            }
  16.339 -        }
  16.340 -
  16.341 -        /// <summary>
  16.342 -        /// Initializes the watched explorer or inspector window.
  16.343 -        /// </summary>
  16.344 -        /// <param name="isInlineResponse">Whether this window is an inline response.</param>
  16.345 -        protected void InitializeWindow(bool isInlineResponse = false)
  16.346 -        {
  16.347 -            bool enableFormRegion = false;
  16.348 -            bool cancelOpenEvent = false;
  16.349 -            bool isSecureAttachedMail = false;
  16.350 -            string messageId = null;
  16.351 -            PEPCache.CacheItem cacheItem = null;
  16.352 -
  16.353 -            try
  16.354 -            {
  16.355 -                // Check if draft
  16.356 -                this.IsDraft = this.CurrentMailItem.GetIsDraft();
  16.357 -
  16.358 -                /* Set immediately a provisional rating in order to have a less flickery
  16.359 -                 * UI experience.
  16.360 -                 * The provisional rating is either a stored rating or, in case we have a
  16.361 -                 * reply message, the rating of the original (the item we reply to).
  16.362 -                 * This provisional rating will be replace with the real one once the full
  16.363 -                 * processing is complete.
  16.364 -                 */
  16.365 -                pEpRating provisionalRating = pEpRating.pEpRatingUndefined;
  16.366 -
  16.367 -                // Try to get an original rating (in case of reply messages)
  16.368 -                if (this.IsDraft)
  16.369 -                {
  16.370 -                    if (this.CurrentMailItem?.Recipients?.Count > 0)
  16.371 -                    {
  16.372 -                        string originalRatingString = this.CurrentMailItem.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING) as string;
  16.373 -
  16.374 -                        // If we have an original rating, parse it and set it.
  16.375 -                        if (string.IsNullOrEmpty(originalRatingString) == false)
  16.376 -                        {
  16.377 -                            provisionalRating = AdapterExtensions.ParseRatingString(originalRatingString);
  16.378 -                        }
  16.379 -                    }
  16.380 -                }
  16.381 -                else
  16.382 -                {
  16.383 -                    // Try to get item from cache
  16.384 -                    cacheItem = PEPCache.GetItemFromCache(this.CurrentMailItem.EntryID);
  16.385 -
  16.386 -                    if (cacheItem != null)
  16.387 -                    {
  16.388 -                        // Set rating from cache
  16.389 -                        provisionalRating = cacheItem?.Rating ?? pEpRating.pEpRatingUndefined;
  16.390 -                    }
  16.391 -                    else
  16.392 -                    {
  16.393 -                        // Get rating from db
  16.394 -                        provisionalRating = PEPDatabase.GetRating(this.CurrentMailItem.EntryID);
  16.395 -
  16.396 -                        // If there is no rating in the db, use stored or default rating
  16.397 -                        if (provisionalRating == pEpRating.pEpRatingUndefined)
  16.398 -                        {
  16.399 -                            provisionalRating = this.CurrentMailItem.GetStoredRating() ?? pEpRating.pEpRatingUndefined;
  16.400 -                        }
  16.401 -                    }
  16.402 -                }
  16.403 -
  16.404 -                // Only set rating if one has been retrieved
  16.405 -                if (provisionalRating != pEpRating.pEpRatingUndefined)
  16.406 -                {
  16.407 -                    this.SetRating(provisionalRating);
  16.408 -                    Log.Verbose("InitializeWindow: Provisional rating {0} shown.", Enum.GetName(typeof(pEpRating), provisionalRating));
  16.409 -                }
  16.410 -
  16.411 -                // Do not process S/MIME messages
  16.412 -                if (this.CurrentMailItem.GetIsSMIMEEnabled())
  16.413 -                {
  16.414 -                    Log.Verbose("InitializeWindow: S/MIME message detected. Won't be processed.");
  16.415 -
  16.416 -                    // Set unencrypted rating
  16.417 -                    this.SetRating(pEpRating.pEpRatingUnencrypted);
  16.418 -
  16.419 -                    // Set icon(s) if necessary     
  16.420 -                    if ((IsDraft == false) &&
  16.421 -                        (this.CurrentMailItem.SetEncryptionIcons()))
  16.422 -                    {
  16.423 -                        try
  16.424 -                        {
  16.425 -                            this.CurrentMailItem.Save();
  16.426 -                        }
  16.427 -                        catch (Exception ex)
  16.428 -                        {
  16.429 -                            Log.Error("InitializeWindow: Error saving message after changing icon. " + ex.ToString());
  16.430 -                        }
  16.431 -                    }
  16.432 -
  16.433 -                    return;
  16.434 -                }
  16.435 -
  16.436 -                /* Check if item is attached mail. For performance reasons,
  16.437 -                 * only do the whole check if an item has been loaded to the
  16.438 -                 * cache of attached mails and if item might be secure.
  16.439 -                 */
  16.440 -                if ((PEPAttachment.AttachedMailsCache.Count > 0) &&
  16.441 -                    (this.CurrentMailItem.Attachments?.Count == 2))
  16.442 -                {
  16.443 -                    try
  16.444 -                    {
  16.445 -                        // Check if mail item is an attached mail
  16.446 -                        if (this.CurrentMailItem.GetIsAttachedMail(out messageId))
  16.447 -                        {
  16.448 -                            Outlook.MailItem mirror = null;
  16.449 -
  16.450 -                            // Try to get the mirror
  16.451 -                            mirror = this.CurrentMailItem.GetMirror(messageId);
  16.452 -
  16.453 -                            // If mirror was not found, decrypt and create mirror
  16.454 -                            if (mirror != null)
  16.455 -                            {
  16.456 -                                isSecureAttachedMail = true;
  16.457 -                            }
  16.458 -                            else
  16.459 -                            {
  16.460 -                                if ((PEPMessage.Create(this.CurrentMailItem, out PEPMessage pEpMessage) == Globals.ReturnStatus.Success) &&
  16.461 -                                    (pEpMessage.IsSecure))
  16.462 -                                {
  16.463 -                                    MsgProcessor msgProcessor = new MsgProcessor();
  16.464 -                                    if (msgProcessor.Decrypt(pEpMessage, out PEPMessage decryptedMessage))
  16.465 -                                    {
  16.466 -                                        isSecureAttachedMail = true;
  16.467 -                                        mirror = this.CurrentMailItem.CreateMirrorOMI(messageId);
  16.468 -                                        decryptedMessage.ApplyTo(mirror, true, false);
  16.469 -                                        mirror?.Save();
  16.470 -                                    }
  16.471 -                                    else
  16.472 -                                    {
  16.473 -                                        Log.Error("InitializeWindow: Decryption of attached mail was not successful.");
  16.474 -                                    }
  16.475 -                                }
  16.476 -                            }
  16.477 -
  16.478 -                            // Check if attachment is being opened or if only the preview is needed
  16.479 -                            if (CryptableMailItem.PreviewAttachedMailId?.Equals(messageId) != true)
  16.480 -                            {
  16.481 -                                // Display mirror and cancel opening of original
  16.482 -                                cancelOpenEvent = true;
  16.483 -                                mirror?.Display();
  16.484 -                            }
  16.485 -
  16.486 -                            // Not needed anymore after this point
  16.487 -                            CryptableMailItem.PreviewAttachedMailId = null;
  16.488 -                        }
  16.489 -                    }
  16.490 -                    catch (Exception ex)
  16.491 -                    {
  16.492 -                        messageId = null;
  16.493 -                        Log.Error("InitializeWindow: Error checking for attached mail. " + ex.ToString());
  16.494 -                    }
  16.495 -                }
  16.496 -
  16.497 -                // Check for item from cache and show it if possible
  16.498 -                if ((this.IsDraft == false) &&
  16.499 -                    (cacheItem?.Mirror != null) &&
  16.500 -                    (this.CurrentMailItem.GetIsInSecureStore()))
  16.501 -                {
  16.502 -                    WindowFormRegionCollection formRegions = null;
  16.503 -                    try
  16.504 -                    {
  16.505 -                        formRegions = Globals.FormRegions[this.Window];
  16.506 -                    }
  16.507 -                    catch (Exception ex)
  16.508 -                    {
  16.509 -                        Log.Error("InitializeWindow: Error getting form region collection. " + ex.ToString());
  16.510 -                    }
  16.511 -
  16.512 -                    this.GetFormRegionPreviewUnencrypted()?.DisplayState?.SetMessage(cacheItem.Mirror);
  16.513 -                }
  16.514 -
  16.515 -                this.cryptableMailItem = new CryptableMailItem(this.CurrentMailItem, provisionalRating)
  16.516 -                {
  16.517 -                    // Set inline response property
  16.518 -                    IsInlineResponse = isInlineResponse
  16.519 -                };
  16.520 -
  16.521 -                // Set properties for encrypted attached mail
  16.522 -                if (isSecureAttachedMail)
  16.523 -                {
  16.524 -                    this.cryptableMailItem.MessageId = messageId;
  16.525 -                    this.cryptableMailItem.IsSecureAttachedMail = true;
  16.526 -                }
  16.527 -
  16.528 -                // Connect cryptable mail item events
  16.529 -                if (this.cryptableMailItem != null)
  16.530 -                {
  16.531 -                    // If we don't open the original, set property and return
  16.532 -                    if (cancelOpenEvent)
  16.533 -                    {
  16.534 -                        this.cryptableMailItem.Open += MailItem_Open;
  16.535 -                        this.cryptableMailItem.CancelOpen = true;
  16.536 -                        return;
  16.537 -                    }
  16.538 -                    else
  16.539 -                    {
  16.540 -                        try
  16.541 -                        {
  16.542 -                            this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
  16.543 -                            this.cryptableMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
  16.544 -                            this.cryptableMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
  16.545 -                            this.cryptableMailItem.Send += MailItem_Send;
  16.546 -
  16.547 -                            if (this.cryptableMailItem.IsSecurelyStored)
  16.548 -                            {
  16.549 -                                this.cryptableMailItem.Open += MailItem_Open;
  16.550 -                            }
  16.551 -                        }
  16.552 -                        catch (Exception ex)
  16.553 -                        {
  16.554 -                            Log.Error("BuildAndShowManager: Error occured. " + ex.ToString());
  16.555 -                        }
  16.556 -
  16.557 -                        if (this.CurrentMailItem.GetIsPEPEnabled())
  16.558 -                        {
  16.559 -                            // If pEp is enabled, show the form region
  16.560 -                            enableFormRegion = true;
  16.561 -                        }
  16.562 -                        else
  16.563 -                        {
  16.564 -                            /* If pEp is disabled, process item and show form region in the following cases:
  16.565 -                             * 1. Incoming items: if decrypt always option is set
  16.566 -                             * 2. Outgoing items: if EnableProtection option is set
  16.567 -                             *                    Note: if this property isn't set, subscribe to originally 
  16.568 -                             *                          encrypted status update event handler in case the 
  16.569 -                             *                          current code runs before CryptableMailItem.MailItem_Reply
  16.570 -                             *                          or CryptableMailItem.MailItem_Forward.
  16.571 -                             */
  16.572 -                            if (this.IsDraft)
  16.573 -                            {
  16.574 -                                enableFormRegion = true;
  16.575 -                                this.cryptableMailItem.OriginallyEncryptedStatusUpdated += CryptableMailItem_OriginallyEncryptedStatusUpdated;
  16.576 -                            }
  16.577 -                            else
  16.578 -                            {
  16.579 -                                enableFormRegion = this.CurrentMailItem.GetIsDecryptAlwaysEnabled();
  16.580 -                            }
  16.581 -                        }
  16.582 -                    }
  16.583 -                }
  16.584 -
  16.585 -                // Update pEp enabled status
  16.586 -                this.SetIsEnabled(enableFormRegion);
  16.587 -
  16.588 -                if (this.isEnabled)
  16.589 -                {
  16.590 -                    // If forcefully protected, run dedicated decryption
  16.591 -                    if (this.CurrentMailItem.GetIsForcefullyProtected())
  16.592 -                    {
  16.593 -                        FPPMessage fppMessage = new FPPMessage(this.CurrentMailItem);
  16.594 -                        if ((fppMessage?.GetMessageType() != null) ||
  16.595 -                            (fppMessage?.CurrentMessage?.IsSecure == true))
  16.596 -                        {
  16.597 -                            fppMessage.ProcessIncoming(true);
  16.598 -                        }
  16.599 -                        else
  16.600 -                        {
  16.601 -                            this.TimerRefresh_Tick(null, new EventArgs());
  16.602 -                        }
  16.603 -                    }
  16.604 -                    else
  16.605 -                    {
  16.606 -                        // Call the timer tick method manually to refresh data with no delay
  16.607 -                        this.TimerRefresh_Tick(null, new EventArgs());
  16.608 -                    }
  16.609 -                }
  16.610 -            }
  16.611 -            catch (Exception ex)
  16.612 -            {
  16.613 -                Log.Error("BuildAndShowManager: Error. " + ex.ToString());
  16.614 -            }
  16.615 -        }
  16.616 -
  16.617 -        /// <summary>
  16.618 -        /// Schedules for the pEp rating and UI (including displayed mirror) to be updated.
  16.619 -        /// This can be called many times with no issue as the update is only run every n milliseconds.
  16.620 -        /// </summary>
  16.621 -        public void RequestRatingAndUIUpdate()
  16.622 -        {
  16.623 -            if (this.isEnabled)
  16.624 -            {
  16.625 -                this.TimerRefresh.Enabled = true;
  16.626 -            }
  16.627 -        }
  16.628 -
  16.629 -        /// <summary>
  16.630 -        /// Immediately starts the update of UI rating based on the associated mail item.
  16.631 -        /// This will start decryption as necessary and also will update the displayed mirror.
  16.632 -        /// This method by-passes the refresh timer completely.
  16.633 -        /// WARNING: This method assumes the message is fully downloaded already.
  16.634 -        /// </summary>
  16.635 -        private void ImmediateRatingAndUIUpdate()
  16.636 -        {
  16.637 -            if ((this.isEnabled) &&
  16.638 -                (this.cryptableMailItem != null))
  16.639 -            {
  16.640 -                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
  16.641 -
  16.642 -                // Start the rating calculation/decryption process
  16.643 -                this.cryptableMailItem.StartProcessing(this.IsDraft);
  16.644 -                this.processingOngoing = true;
  16.645 -
  16.646 -                // If we have a draft message, fetch directly a preview outgoing rating
  16.647 -                if (this.IsDraft)
  16.648 -                {
  16.649 -                    pEpRating rating = this.GetOutgoingRatingPreview();
  16.650 -
  16.651 -                    if (rating != pEpRating.pEpRatingUndefined)
  16.652 -                    {
  16.653 -                        this.SetRating(rating);
  16.654 -                    }
  16.655 -                }
  16.656 -            }
  16.657 -        }
  16.658 -
  16.659 -        /// <summary>
  16.660 -        /// Gets a preview of the outgoing rating which is faster than the full version.
  16.661 -        /// Caveat: might show a wrong rating in case of missing keys.
  16.662 -        /// </summary>
  16.663 -        /// <returns>A preview of the outgoing rating.</returns>
  16.664 -        private pEpRating GetOutgoingRatingPreview()
  16.665 -        {
  16.666 -            pEpRating rating = pEpRating.pEpRatingUndefined;
  16.667 -
  16.668 -            try
  16.669 -            {
  16.670 -                rating = this.CurrentMailItem?.GetOutgoingRating(false, true) ?? pEpRating.pEpRatingUndefined;
  16.671 -            }
  16.672 -            catch (Exception ex)
  16.673 -            {
  16.674 -                rating = pEpRating.pEpRatingUndefined;
  16.675 -                Log.Error("ImmediateRatingAndUIUpdate: Error getting outgoing preview rating. " + ex.ToString());
  16.676 -            }
  16.677 -
  16.678 -            return rating;
  16.679 -        }
  16.680 -
  16.681 -        /// <summary>
  16.682 -        /// Updates the privacy state and the UI (ribbon and form region).
  16.683 -        /// </summary>
  16.684 -        public void UpdatePrivacyStateAndUI()
  16.685 -        {
  16.686 -            try
  16.687 -            {
  16.688 -                this.PrivacyState = new PrivacyState(this.Rating,
  16.689 -                                                     this.ForceProtection,
  16.690 -                                                     this.ForceUnencrypted);
  16.691 -                RibbonCustomizations.Invalidate();
  16.692 -                this.GetFormRegionPrivacyStatus()?.UpdateFormRegion(this.PrivacyState);
  16.693 -            }
  16.694 -            catch (Exception ex)
  16.695 -            {
  16.696 -                Log.Error("UpdateUI: Error occured. " + ex.ToString());
  16.697 -            }
  16.698 -        }
  16.699 -
  16.700 -        /// <summary>
  16.701 -        /// Gathers all form regions for this WatchedWindow.
  16.702 -        /// </summary>
  16.703 -        /// <returns>The gathered form regions.</returns>
  16.704 -        internal WindowFormRegionCollection GetFormRegions()
  16.705 -        {
  16.706 -            /* We have to find out here if the window is an explorer or an inspector.
  16.707 -             * Calling Globals.FormRegions[] with an ambiguous window type leads to a crash.
  16.708 -             */
  16.709 -            Outlook.Explorer explorer;
  16.710 -            Outlook.Inspector inspector;
  16.711 -            WindowFormRegionCollection formRegions = null;
  16.712 -            try
  16.713 -            {
  16.714 -                if (this.Window != null)
  16.715 -                {
  16.716 -                    if (this.Type == WindowType.Explorer)
  16.717 -                    {
  16.718 -                        explorer = this.Window as Outlook.Explorer;
  16.719 -                        formRegions = Globals.FormRegions[explorer];
  16.720 -                    }
  16.721 -                    else if (this.Type == WindowType.Inspector)
  16.722 -                    {
  16.723 -                        inspector = this.Window as Outlook.Inspector;
  16.724 -                        formRegions = Globals.FormRegions[inspector];
  16.725 -                    }
  16.726 -                }
  16.727 -                else
  16.728 -                {
  16.729 -                    Log.Warning("GetFormRegions: Could not get form regions. Current window is null.");
  16.730 -                }
  16.731 -            }
  16.732 -            catch (Exception ex)
  16.733 -            {
  16.734 -                formRegions = null;
  16.735 -                Log.Error("GetFormRegions: Error getting form regions collection. " + ex.ToString());
  16.736 -            }
  16.737 -            finally
  16.738 -            {
  16.739 -                explorer = null;
  16.740 -                inspector = null;
  16.741 -            }
  16.742 -
  16.743 -            return formRegions;
  16.744 -        }
  16.745 -
  16.746 -        /// <summary>
  16.747 -        /// Gets the FormRegionPrivacyStatus of this WatchedWindow (if available).
  16.748 -        /// </summary>
  16.749 -        /// <returns>The FormRegionPrivacyStatus of this window or null.</returns>
  16.750 -        internal FormRegionPrivacyStatus GetFormRegionPrivacyStatus()
  16.751 -        {
  16.752 -            return this.GetFormRegions()?.FormRegionPrivacyStatus;
  16.753 -        }
  16.754 -
  16.755 -        /// <summary>
  16.756 -        /// Gets the FormRegionPreviewUnencrypted of this WatchedWindow (if available).
  16.757 -        /// </summary>
  16.758 -        /// <returns>The FormRegionPreviewUnencrypted of this window or null.</returns>
  16.759 -        internal FormRegionPreviewUnencrypted GetFormRegionPreviewUnencrypted()
  16.760 -        {
  16.761 -            return this.GetFormRegions()?.FormRegionPreviewUnencrypted;
  16.762 -        }
  16.763 -
  16.764 -        /// <summary>
  16.765 -        /// Resets the Enabled status of this form region and recalculates the rating if necessary.
  16.766 -        /// </summary>
  16.767 -        /// <param name="enable">Whether to enable the form region.</param>
  16.768 -        public void UpdateFormRegion(bool enable)
  16.769 -        {
  16.770 -            this.SetIsEnabled(enable);
  16.771 -
  16.772 -            // Refresh the UI
  16.773 -            if (enable)
  16.774 -            {
  16.775 -                this.ResolveAllRecipients();
  16.776 -                this.RequestRatingAndUIUpdate();
  16.777 -            }
  16.778 -        }
  16.779 -
  16.780 -        /// <summary>
  16.781 -        /// Workaround method to update the current inspector window. This is done by moving the mail item
  16.782 -        /// to a temporary folder first and then back to the current folder. Both folders CANNOT be the same.
  16.783 -        /// As a fallback, the mail item stays in the temporary folder if moving back to the current folder
  16.784 -        /// fails.
  16.785 -        /// </summary>
  16.786 -        private void UpdateInspector()
  16.787 -        {
  16.788 -            Outlook.Application application = null;
  16.789 -            Outlook.Folder currentFolder = null;
  16.790 -            Outlook.Folder tempFolder = null;
  16.791 -            Outlook.Inspector currentInspector = null;
  16.792 -            Outlook.Inspector newInspector = null;
  16.793 -            Outlook.MailItem tempMailItem = null;
  16.794 -            Outlook.Store store = null;
  16.795 -            Outlook.MailItem omi = this.CurrentMailItem;
  16.796 -
  16.797 -            if (omi != null)
  16.798 -            {
  16.799 -                try
  16.800 -                {
  16.801 -                    application = omi.Application;
  16.802 -                    currentInspector = omi.GetInspector;
  16.803 -                    currentFolder = omi.Parent as Outlook.Folder;
  16.804 -
  16.805 -                    if ((currentInspector != null) &&
  16.806 -                        (application != null) &&
  16.807 -                        (currentFolder != null))
  16.808 -                    {
  16.809 -                        var left = currentInspector.Left;
  16.810 -                        var top = currentInspector.Top;
  16.811 -                        var width = currentInspector.Width;
  16.812 -                        var height = currentInspector.Height;
  16.813 -                        var windowState = currentInspector.WindowState;
  16.814 -
  16.815 -                        /* Check, if in trusted store. In that case, use the default drafts folder
  16.816 -                         * as temporary folder. If the store is untrusted, use the pEp drafts folder.
  16.817 -                         */
  16.818 -                        store = currentFolder.Store;
  16.819 -                        if (store?.GetIsSecureStorageEnabled() ?? false)
  16.820 -                        {
  16.821 -                            tempFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
  16.822 -                        }
  16.823 -                        else
  16.824 -                        {
  16.825 -                            tempFolder = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
  16.826 -                        }
  16.827 -
  16.828 -                        if (tempFolder != null)
  16.829 -                        {
  16.830 -                            tempMailItem = omi.Move(tempFolder) as Outlook.MailItem;
  16.831 -
  16.832 -                            if (tempMailItem != null)
  16.833 -                            {
  16.834 -                                try
  16.835 -                                {
  16.836 -                                    omi = tempMailItem.Move(currentFolder) as Outlook.MailItem;
  16.837 -                                }
  16.838 -                                catch
  16.839 -                                {
  16.840 -                                    omi = tempMailItem.Copy();
  16.841 -                                }
  16.842 -
  16.843 -                                newInspector = application.Inspectors.Add(omi);
  16.844 -
  16.845 -                                if (windowState == Outlook.OlWindowState.olNormalWindow)
  16.846 -                                {
  16.847 -                                    newInspector.Left = left;
  16.848 -                                    newInspector.Top = top;
  16.849 -                                    newInspector.Width = width;
  16.850 -                                    newInspector.Height = height;
  16.851 -                                }
  16.852 -
  16.853 -                                newInspector.Display();
  16.854 -                                newInspector.WindowState = windowState;
  16.855 -
  16.856 -                                repeatProcessing = false;
  16.857 -                            }
  16.858 -                        }
  16.859 -                        else
  16.860 -                        {
  16.861 -                            Log.Error("UpdateInspector: Cannot get temporary folder.");
  16.862 -                        }
  16.863 -                    }
  16.864 -                    else
  16.865 -                    {
  16.866 -                        Log.Verbose("UpdateInspector: Error retrieving inspector window or application.");
  16.867 -                    }
  16.868 -                }
  16.869 -                catch (Exception ex)
  16.870 -                {
  16.871 -                    Log.Verbose("UpdateInspector: Error updating inspector window. " + ex.ToString());
  16.872 -                }
  16.873 -                finally
  16.874 -                {
  16.875 -                    application = null;
  16.876 -                    currentInspector = null;
  16.877 -                    newInspector = null;
  16.878 -                    omi = null;
  16.879 -                    tempMailItem = null;
  16.880 -                }
  16.881 -            }
  16.882 -        }
  16.883 -
  16.884 -        /// <summary>
  16.885 -        /// Clears the associated unencrypted preview and displays the given note (if any).
  16.886 -        /// </summary>
  16.887 -        /// <param name="note">The note to display.</param>
  16.888 -        private void SetNote(string note = null)
  16.889 -        {
  16.890 -            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
  16.891 -
  16.892 -            if ((formRegions != null) &&
  16.893 -                (string.IsNullOrEmpty(note) == false))
  16.894 -            {
  16.895 -                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
  16.896 -                    (formRegions.FormRegionPreviewUnencrypted.Visible))
  16.897 -                {
  16.898 -                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetNote(note);
  16.899 -                }
  16.900 -            }
  16.901 -        }
  16.902 -
  16.903 -        /// <summary>
  16.904 -        /// Sets whether processing of the mail item is enabled.
  16.905 -        /// This should commonly be set from the .GetIsPEPEnabled() value.
  16.906 -        /// </summary>
  16.907 -        private void SetIsEnabled(bool enabled)
  16.908 -        {
  16.909 -            Globals.ReturnStatus sts;
  16.910 -            Outlook.Recipient currUser = null;
  16.911 -            Outlook.Account currAccount = null;
  16.912 -            Outlook.Account sendingAccount = null;
  16.913 -            Outlook.NameSpace ns = null;
  16.914 -
  16.915 -            this.isEnabled = enabled;
  16.916 -
  16.917 -            if (enabled)
  16.918 -            {
  16.919 -                // Do not allow initialization more than once
  16.920 -                if (this.isStarted == false)
  16.921 -                {
  16.922 -                    /* It's possible for new draft MailItems to be created outside the context of an account.
  16.923 -                     * In this situation the SendUsingAccount will always be null which of course breaks several pEp operations.
  16.924 -                     * The operations themselves cannot make the assumption about what account information to use.
  16.925 -                     * Therefore, the situation is detected here and for draft mail items a null SendUsingAccount will be 
  16.926 -                     * set with the session's default account.
  16.927 -                     */
  16.928 -                    if (this.IsDraft)
  16.929 -                    {
  16.930 -                        try
  16.931 -                        {
  16.932 -                            sendingAccount = this.CurrentMailItem.SendUsingAccount;
  16.933 -                            if (sendingAccount == null)
  16.934 -                            {
  16.935 -                                ns = Globals.ThisAddIn.Application.Session;
  16.936 -                                currUser = ns.CurrentUser;
  16.937 -                                sts = PEPIdentity.Create(currUser, out PEPIdentity currIdent);
  16.938 -
  16.939 -                                if (sts == Globals.ReturnStatus.Success)
  16.940 -                                {
  16.941 -                                    sendingAccount = AccountExtensions.GetDefaultAccount(Outlook.OlDefaultFolders.olFolderDrafts);
  16.942 -                                    if (sendingAccount != null)
  16.943 -                                    {
  16.944 -                                        this.CurrentMailItem.SendUsingAccount = currAccount;
  16.945 -                                    }
  16.946 -                                }
  16.947 -                            }
  16.948 -
  16.949 -                            // Check if account is already registered in pEp list and add it if necessary
  16.950 -                            var acctSettings = Globals.ThisAddIn.Settings.GetAccountSettings(sendingAccount?.SmtpAddress);
  16.951 -                            if (acctSettings == null)
  16.952 -                            {
  16.953 -                                Log.Verbose("SetIsEnabled: New account detected. Creating pEp settings.");
  16.954 -
  16.955 -                                // Create pEp settings for the new account
  16.956 -                                acctSettings = sendingAccount.CreatePEPSettings();
  16.957 -
  16.958 -                                // Add account to list
  16.959 -                                Globals.ThisAddIn.Settings.AccountsAddedWhileRunningList.Add(acctSettings?.SmtpAddress);
  16.960 -                                Log.Verbose("SetIsEnabled: New account registered in pEp settings.");
  16.961 -
  16.962 -                                // Generate key
  16.963 -                                Globals.ThisAddIn.RegisterMyself(acctSettings);
  16.964 -                                Log.Verbose("SetIsEnabled: Myself registered.");
  16.965 -
  16.966 -                                // Set rules and view filters
  16.967 -                                Globals.ThisAddIn.SetRulesAndViewFilters(sendingAccount, Globals.ThisAddIn.Settings.HideInternalMessages);
  16.968 -                            }
  16.969 -                        }
  16.970 -                        catch (Exception ex)
  16.971 -                        {
  16.972 -                            Log.Error("SetIsEnabled: Error occured. " + ex.ToString());
  16.973 -                        }
  16.974 -                        finally
  16.975 -                        {
  16.976 -                            currAccount = null;
  16.977 -                            currUser = null;
  16.978 -                            ns = null;
  16.979 -                            sendingAccount = null;
  16.980 -                        }
  16.981 -                    }
  16.982 -
  16.983 -                    // Connect refresh timer
  16.984 -                    this.TimerRefresh.Tick += TimerRefresh_Tick;
  16.985 -                    this.isStarted = true;
  16.986 -                }
  16.987 -            }
  16.988 -            else
  16.989 -            {
  16.990 -                // Stop and disconnect the refresh timer
  16.991 -                if (this.TimerRefresh != null)
  16.992 -                {
  16.993 -                    this.TimerRefresh.Stop();
  16.994 -                    this.TimerRefresh.Enabled = false;
  16.995 -                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
  16.996 -                }
  16.997 -
  16.998 -                this.isStarted = false;
  16.999 -            }
 16.1000 -        }
 16.1001 -
 16.1002 -        /// <summary>
 16.1003 -        /// Resolves all recipients of the Outlook mail item.
 16.1004 -        /// </summary>
 16.1005 -        private void ResolveAllRecipients()
 16.1006 -        {
 16.1007 -            if ((this.isEnabled) &&
 16.1008 -                (this.cryptableMailItem != null))
 16.1009 -            {
 16.1010 -                /*
 16.1011 -                 * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
 16.1012 -                 * This is because the resolve process can modify the contents of the mail item which triggers an event.
 16.1013 -                 * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
 16.1014 -                 * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
 16.1015 -                 * cannot be resolved(no address).
 16.1016 -                 */
 16.1017 -                try
 16.1018 -                {
 16.1019 -                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
 16.1020 -                    this.cryptableMailItem.ResolveAllRecipients();
 16.1021 -                    this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
 16.1022 -                }
 16.1023 -                catch (Exception ex)
 16.1024 -                {
 16.1025 -                    Log.Error("Error resolving recipients. " + ex.ToString());
 16.1026 -                }
 16.1027 -            }
 16.1028 -        }
 16.1029 -        #endregion
 16.1030 -
 16.1031 -        #region Event Handling
 16.1032 -        /**************************************************************
 16.1033 -         * 
 16.1034 -         * Event Handling
 16.1035 -         * 
 16.1036 -         *************************************************************/
 16.1037 -
 16.1038 -        /// <summary>
 16.1039 -        /// Event handler for when the processing is completed in the associated mail item.
 16.1040 -        /// This will then update the form region UI and the privacy status window as needed.
 16.1041 -        /// </summary>
 16.1042 -        private void MailItem_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
 16.1043 -        {
 16.1044 -            Log.Verbose("MailItem_ProcessingComplete: Decryption completed.");
 16.1045 -
 16.1046 -            try
 16.1047 -            {
 16.1048 -                // Marshal code back to UI thread as necessary
 16.1049 -                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
 16.1050 -                {
 16.1051 -                    if (this.isEnabled)
 16.1052 -                    {
 16.1053 -                        try
 16.1054 -                        {
 16.1055 -                            this.SetRating(e.ProcessedRating);
 16.1056 -
 16.1057 -                            // Set MAPI properties if needed
 16.1058 -                            if (e.PropertiesToSet?.Count > 0)
 16.1059 -                            {
 16.1060 -                                this.CurrentMailItem?.SetMAPIProperties(e.PropertiesToSet);
 16.1061 -                            }
 16.1062 -                            Log.Verbose("MailItem_ProcessingComplete: Status bar updated with rating " + Enum.GetName(typeof(pEpRating), e.ProcessedRating));
 16.1063 -                        }
 16.1064 -                        catch (Exception ex)
 16.1065 -                        {
 16.1066 -                            Log.Verbose("MailItem_ProcessingComplete: Error. " + ex.ToString());
 16.1067 -                        }
 16.1068 -
 16.1069 -                        if (repeatProcessing &&
 16.1070 -                            (repeatCounter++ < maxRepeatCount))
 16.1071 -                        {
 16.1072 -                            repeatProcessing = false;
 16.1073 -                            this.RequestRatingAndUIUpdate();
 16.1074 -                        }
 16.1075 -                        else
 16.1076 -                        {
 16.1077 -                            /* Check if the mail item is in Outbox and update the inspector window if possible.
 16.1078 -                             * This is the case when a submitted, but not yet sent email is opened again when working 
 16.1079 -                             * offline or without internet connection. Without this update, Outlook removes the message class 
 16.1080 -                             * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
 16.1081 -                             * opened again (i.e. is lost).
 16.1082 -                             */
 16.1083 -                            try
 16.1084 -                            {
 16.1085 -                                if ((this.CurrentMailItem?.GetIsSubmitted() == true) &&
 16.1086 -                                    (this.IsDraft))
 16.1087 -                                {
 16.1088 -                                    UpdateInspector();
 16.1089 -                                }
 16.1090 -                            }
 16.1091 -                            catch (Exception ex)
 16.1092 -                            {
 16.1093 -                                Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
 16.1094 -                            }
 16.1095 -
 16.1096 -                            /* Create the unencrypted preview if the mail item is encrypted and
 16.1097 -                             * it is in an encrypted (untrusted) store
 16.1098 -                             * 
 16.1099 -                             * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
 16.1100 -                             * it also is initialized after FormRegionPreviewUnencrypted.
 16.1101 -                             */
 16.1102 -                            try
 16.1103 -                            {
 16.1104 -                                if (this.cryptableMailItem.IsSecurelyStored || this.cryptableMailItem.IsSecureAttachedMail)
 16.1105 -                                {
 16.1106 -                                    Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
 16.1107 -                                    this.cryptableMailItem.StartGetMirror(this.cryptableMailItem.MessageId);
 16.1108 -                                }
 16.1109 -                                else
 16.1110 -                                {
 16.1111 -                                    this.SetNote();
 16.1112 -                                }
 16.1113 -                            }
 16.1114 -                            catch (Exception ex)
 16.1115 -                            {
 16.1116 -                                // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
 16.1117 -                                // While rare, just log the issue and stop the process
 16.1118 -                                Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
 16.1119 -                            }
 16.1120 -
 16.1121 -                            /* OUT-470: Workaround until this is implemented in the engine:
 16.1122 -                             * Only enable Force Protection if all recipients are grey
 16.1123 -                             */
 16.1124 -                            if (this.IsDraft)
 16.1125 -                            {
 16.1126 -                                bool disableForceProtection = false;
 16.1127 -                                Outlook.Recipients recipients = null;
 16.1128 -                                Outlook.Recipient recipient = null;
 16.1129 -                                PEPIdentity pEpIdentity = null;
 16.1130 -
 16.1131 -                                try
 16.1132 -                                {
 16.1133 -                                    recipients = this.CurrentMailItem?.Recipients;
 16.1134 -                                    if (recipients?.Count > 0)
 16.1135 -                                    {
 16.1136 -                                        for (int i = 1; i <= recipients.Count; i++)
 16.1137 -                                        {
 16.1138 -                                            recipient = recipients[i];
 16.1139 -                                            if ((PEPIdentity.Create(recipient, out pEpIdentity, false) == Globals.ReturnStatus.Success) &&
 16.1140 -                                                ((PEPIdentity.GetIsOwnIdentity(pEpIdentity.Address) ||
 16.1141 -                                                 (ThisAddIn.PEPEngine.IdentityRating(pEpIdentity.ToCOMType()) >= pEpRating.pEpRatingReliable))))
 16.1142 -                                            {
 16.1143 -                                                disableForceProtection = true;
 16.1144 -                                                Log.Verbose("MailItem_ProcessingComplete: Secure recipient found. Disabling force protection.");
 16.1145 -                                                break;
 16.1146 -                                            }
 16.1147 -                                        }
 16.1148 -                                    }
 16.1149 -                                    else
 16.1150 -                                    {
 16.1151 -                                        // If there aren't any recipients (anymore), reset values
 16.1152 -                                        this.DisableForceProtection = false;
 16.1153 -                                        this.ForceProtection = false;
 16.1154 -                                        this.NeverUnsecure = false;
 16.1155 -                                        this.ForceUnencrypted = false;
 16.1156 -                                    }
 16.1157 -                                }
 16.1158 -                                catch (Exception ex)
 16.1159 -                                {
 16.1160 -                                    Log.Error("MailItem_ProcessingComplete: Error occured. " + ex.ToString());
 16.1161 -                                }
 16.1162 -                                finally
 16.1163 -                                {
 16.1164 -                                    recipient = null;
 16.1165 -                                    recipients = null;
 16.1166 -                                }
 16.1167 -
 16.1168 -                                this.DisableForceProtection = disableForceProtection;
 16.1169 -                            }
 16.1170 -                        }
 16.1171 -                    }
 16.1172 -                }));
 16.1173 -            }
 16.1174 -            catch (Exception ex)
 16.1175 -            {
 16.1176 -                Log.Error("MailItem_ProcessingComplete: Error setting UI state, " + ex.ToString());
 16.1177 -            }
 16.1178 -
 16.1179 -            this.processingOngoing = false;
 16.1180 -        }
 16.1181 -
 16.1182 -        /// <summary>
 16.1183 -        /// Event handler for when the get mirror locating process is complete for the associated mail item.
 16.1184 -        /// This will then update the unencrypted preview in the UI.
 16.1185 -        /// </summary>
 16.1186 -        private void MailItem_GetMirrorCompleted(object sender, CryptableMailItem.GetMirrorCompletedEventArgs e)
 16.1187 -        {
 16.1188 -            try
 16.1189 -            {
 16.1190 -                // Marshal code back to UI thread as necessary
 16.1191 -                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
 16.1192 -                {
 16.1193 -                    if (this.isEnabled)
 16.1194 -                    {
 16.1195 -                        // If the message was forcefully protected, there is no mirror and we show the actual message
 16.1196 -                        if ((e.Mirror == null) &&
 16.1197 -                            (this.CurrentMailItem?.GetIsForcefullyProtected() == true))
 16.1198 -                        {
 16.1199 -                            if (PEPMessage.Create(this.CurrentMailItem, out PEPMessage mirror) == Globals.ReturnStatus.Success)
 16.1200 -                            {
 16.1201 -                                e.Mirror = mirror;
 16.1202 -                            }
 16.1203 -                        }
 16.1204 -
 16.1205 -                        if ((e.Mirror == null) &&
 16.1206 -                            (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.Failure))
 16.1207 -                        {
 16.1208 -                            this.SetNote(Properties.Resources.Message_OpenError);
 16.1209 -                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, failure during decryption.");
 16.1210 -                        }
 16.1211 -                        else if ((e.Mirror == null) &&
 16.1212 -                                 (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
 16.1213 -                        {
 16.1214 -                            this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
 16.1215 -                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
 16.1216 -                        }
 16.1217 -                        else
 16.1218 -                        {
 16.1219 -                            FormRegionPreviewUnencrypted formRegionPreviewUnencrypted = this.GetFormRegionPreviewUnencrypted();
 16.1220 -
 16.1221 -                            // If we have a FormRegionPreviewUnencrypted and it's visible, show preview
 16.1222 -                            if (formRegionPreviewUnencrypted?.Visible == true)
 16.1223 -                            {
 16.1224 -                                formRegionPreviewUnencrypted.DisplayState.OriginalEntryId = this.CurrentMailItem?.EntryID;
 16.1225 -                                formRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
 16.1226 -
 16.1227 -                                Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
 16.1228 -                            }
 16.1229 -                            else
 16.1230 -                            {
 16.1231 -                                Log.Error("MailItem_GetMirrorComplete: FormRegionPreviewUnencrypted is null or invisible.");
 16.1232 -                            }
 16.1233 -                        }
 16.1234 -
 16.1235 -                        // Display the mirror if necessary
 16.1236 -                        if ((this.cryptableMailItem != null) &&
 16.1237 -                            (this.displayMirrorRequested))
 16.1238 -                        {
 16.1239 -                            this.cryptableMailItem.DisplayMirror();
 16.1240 -                            this.displayMirrorRequested = false;
 16.1241 -                        }
 16.1242 -                    }
 16.1243 -                }));
 16.1244 -            }
 16.1245 -            catch (Exception ex)
 16.1246 -            {
 16.1247 -                Log.Error("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
 16.1248 -            }
 16.1249 -        }
 16.1250 -
 16.1251 -        /// <summary>
 16.1252 -        /// Event handler for the mail item originally encrypted status updated.
 16.1253 -        /// This event is fired after the status has been updated with parent information following a
 16.1254 -        /// forward or reply mail item event (on a different, likely parent, mail item).
 16.1255 -        /// </summary>
 16.1256 -        protected void CryptableMailItem_OriginallyEncryptedStatusUpdated(object sender, EventArgs e)
 16.1257 -        {
 16.1258 -            // Process the mail item now that the cache is updated
 16.1259 -            if (this.cryptableMailItem.IsOriginallyEncrypted)
 16.1260 -            {
 16.1261 -                this.cryptableMailItem.StartProcessing(this.IsDraft);
 16.1262 -            }
 16.1263 -        }
 16.1264 -
 16.1265 -        /// <summary>
 16.1266 -        /// Event handler for when a mail item is being opened in an inspector.
 16.1267 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
 16.1268 -        /// </summary>
 16.1269 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
 16.1270 -        /// If the event procedure sets this argument to True, the open operation is not completed 
 16.1271 -        /// and the inspector is not displayed.</param>
 16.1272 -        protected void MailItem_Open(ref bool cancel)
 16.1273 -        {
 16.1274 -            if ((this.isEnabled) &&
 16.1275 -                (this.cryptableMailItem != null))
 16.1276 -            {
 16.1277 -                // If cryptable mail item is not to be opened, cancel opening
 16.1278 -                if (this.cryptableMailItem.CancelOpen)
 16.1279 -                {
 16.1280 -                    cancel = true;
 16.1281 -                }
 16.1282 -                else if ((this.cryptableMailItem.IsSecurelyStored) &&
 16.1283 -                         (this.cryptableMailItem.IsIncoming || this.cryptableMailItem.IsOriginallyEncrypted || !this.cryptableMailItem.IsDraft))
 16.1284 -                {
 16.1285 -                    // Try to open the mirror
 16.1286 -                    cancel = this.cryptableMailItem.DisplayMirror();
 16.1287 -                }
 16.1288 -            }
 16.1289 -        }
 16.1290 -
 16.1291 -        /// <summary>
 16.1292 -        /// Event handler for when a mail item is sent.
 16.1293 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
 16.1294 -        /// </summary>
 16.1295 -        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
 16.1296 -        /// If the event procedure sets this argument to True, the send operation is not completed 
 16.1297 -        /// and the inspector is left open.</param>
 16.1298 -        protected void MailItem_Send(ref bool cancel)
 16.1299 -        {
 16.1300 -            DialogResult result;
 16.1301 -
 16.1302 -            if (this.isEnabled)
 16.1303 -            {
 16.1304 -                if ((this.cryptableMailItem.IsBeingProcessed) ||
 16.1305 -                    (this.processingOngoing))
 16.1306 -                {
 16.1307 -                    /* If the mail item is still being processed, this means that the message might go out with
 16.1308 -                     * a different rating than the one that was shown in the UI when sending was initiated.
 16.1309 -                     * As a trade-off between security and user experience, we make at least sure that the
 16.1310 -                     * current outgoing rating preview (which is only wrong under rare circumstances) is not
 16.1311 -                     * smaller than the one shown in the UI. If this is the case, just abort sending.
 16.1312 -                     */
 16.1313 -                    pEpRating outgoingPreviewRating = this.GetOutgoingRatingPreview();
 16.1314 -                    if (this.Rating != outgoingPreviewRating)
 16.1315 -                    {
 16.1316 -                        if (this.Rating > outgoingPreviewRating)
 16.1317 -                        {
 16.1318 -                            Log.Verbose("MailItem_Send: Mail item still being processed.");
 16.1319 -                            cancel = true;
 16.1320 -                            return;
 16.1321 -                        }
 16.1322 -
 16.1323 -                        this.SetRating(outgoingPreviewRating);
 16.1324 -                    }
 16.1325 -                }
 16.1326 -
 16.1327 -                // Show warning message if needed
 16.1328 -                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
 16.1329 -                    (this.Rating < pEpRating.pEpRatingUnreliable) &&
 16.1330 -                    (this.cryptableMailItem.IsOriginallyEncrypted))
 16.1331 -                {
 16.1332 -
 16.1333 -#if READER_RELEASE_MODE
 16.1334 -                    FormReaderSplash warningMessage = new FormReaderSplash(true);
 16.1335 -                    result = warningMessage.ShowDialog();
 16.1336 -
 16.1337 -                    if (result != DialogResult.OK)
 16.1338 -                    {
 16.1339 -                        // Cancel sending
 16.1340 -                        cancel = true;
 16.1341 -                    }
 16.1342 -#else
 16.1343 -                    result = MessageBox.Show(Properties.Resources.Message_WarningSecurityLoss,
 16.1344 -                                             Properties.Resources.Message_TitleConfirmOperation,
 16.1345 -                                             MessageBoxButtons.YesNo,
 16.1346 -                                             MessageBoxIcon.Warning);
 16.1347 -
 16.1348 -                    if (result == DialogResult.No)
 16.1349 -                    {
 16.1350 -                        // Cancel sending
 16.1351 -                        cancel = true;
 16.1352 -                    }
 16.1353 -#endif
 16.1354 -                }
 16.1355 -
 16.1356 -                if (cancel == false)
 16.1357 -                {
 16.1358 -                    if ((this.Type == WindowType.Inspector) &&
 16.1359 -                        (this.cryptableMailItem.IsInlineResponse == false) &&
 16.1360 -                        (this.CurrentMailItem.GetProcessingState() == null))
 16.1361 -                    {                        
 16.1362 -                        IntPtr hWnd = NativeMethods.GetActiveWindow();    
 16.1363 -                        NativeMethods.SetWindowPos(hWnd, NativeMethods.HWND_BOTTOM, 0, 0, 0, 0, NativeMethods.SetWindowPosFlags.DoNotActivate |
 16.1364 -                                                                                                NativeMethods.SetWindowPosFlags.IgnoreMove |
 16.1365 -                                                                                                NativeMethods.SetWindowPosFlags.DoNotReposition |
 16.1366 -                                                                                                NativeMethods.SetWindowPosFlags.IgnoreResize |
 16.1367 -                                                                                                NativeMethods.SetWindowPosFlags.HideWindow);
 16.1368 -                        this.CurrentMailItem.SetProcessingState(MailItemExtensions.ProcessingState.ProcessInBackground);
 16.1369 -                        Log.Verbose("MailItem_Send: Inspector window closed.");
 16.1370 -                    }
 16.1371 -
 16.1372 -                    // Set pEp options if needed
 16.1373 -                    if ((this.ForceProtection) &&
 16.1374 -                        (this.DisableForceProtection == false))
 16.1375 -                    {
 16.1376 -                        this.CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceProtection, Guid.NewGuid().ToString());
 16.1377 -                    }
 16.1378 -                    else if (this.ForceUnencrypted)
 16.1379 -                    {
 16.1380 -                        this.CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, true);
 16.1381 -                    }
 16.1382 -
 16.1383 -                    if (this.NeverUnsecure)
 16.1384 -                    {
 16.1385 -                        this.CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, true);
 16.1386 -                    }
 16.1387 -
 16.1388 -                    // Reset pEp options
 16.1389 -                    this.ForceProtection = false;
 16.1390 -                    this.DisableForceProtection = false;
 16.1391 -                    this.ForceUnencrypted = false;
 16.1392 -                    this.NeverUnsecure = false;
 16.1393 -
 16.1394 -                    // Stop and disconnect the refresh timer
 16.1395 -                    // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
 16.1396 -                    this.TimerRefresh.Stop();
 16.1397 -                    this.TimerRefresh.Enabled = false;
 16.1398 -                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
 16.1399 -                }
 16.1400 -            }
 16.1401 -        }
 16.1402 -
 16.1403 -        /// <summary>
 16.1404 -        /// Event handler for when a mail item property is changed.
 16.1405 -        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
 16.1406 -        /// </summary>
 16.1407 -        /// <param name="propertyName">The name of the property that was changed.</param>
 16.1408 -        protected void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
 16.1409 -        {
 16.1410 -            switch (e.PropertyName.ToUpperInvariant())
 16.1411 -            {
 16.1412 -                case "BCC":
 16.1413 -                    {
 16.1414 -                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
 16.1415 -                        break;
 16.1416 -                    }
 16.1417 -                case "CC":
 16.1418 -                    {
 16.1419 -                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
 16.1420 -                        break;
 16.1421 -                    }
 16.1422 -                case "SENTONBEHALFOFNAME":
 16.1423 -                    {
 16.1424 -                        // Always fired with "SENDUSINGACCOUNT" so is ignored
 16.1425 -                        break;
 16.1426 -                    }
 16.1427 -                case "SENDUSINGACCOUNT":
 16.1428 -                    {
 16.1429 -                        // Update pEp enabled status
 16.1430 -                        this.isStarted = false;
 16.1431 -                        this.SetIsEnabled((this.CurrentMailItem)?.GetEnableFormRegion() ?? false);
 16.1432 -
 16.1433 -                        // Refresh the UI
 16.1434 -                        this.ResolveAllRecipients();
 16.1435 -                        this.RequestRatingAndUIUpdate();
 16.1436 -                        RibbonCustomizations.Invalidate();
 16.1437 -
 16.1438 -                        break;
 16.1439 -                    }
 16.1440 -                case "TO":
 16.1441 -                    {
 16.1442 -                        if (this.isEnabled)
 16.1443 -                        {
 16.1444 -                            this.RequestRatingAndUIUpdate();
 16.1445 -                        }
 16.1446 -                        break;
 16.1447 -                    }
 16.1448 -            }
 16.1449 -        }
 16.1450 -
 16.1451 -        /// <summary>
 16.1452 -        /// Event handler for when a handshake dialog was updated.
 16.1453 -        /// </summary>
 16.1454 -        protected void HandshakeDialog_Updated(object sender, EventArgs e)
 16.1455 -        {
 16.1456 -            // Update current form region
 16.1457 -            this.RequestRatingAndUIUpdate();
 16.1458 -
 16.1459 -            /* If a handshake is performed while having the same message open both in an inspector
 16.1460 -             * and an Window window, the one that didn't trigger the handshake won't get updated
 16.1461 -             * automatically. Therefore, after a handshake, we also update all other open windows.
 16.1462 -             */
 16.1463 -            try
 16.1464 -            {
 16.1465 -                Globals.ThisAddIn.RecalculateAllWindows(this);
 16.1466 -            }
 16.1467 -            catch (Exception ex)
 16.1468 -            {
 16.1469 -                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
 16.1470 -            }
 16.1471 -        }
 16.1472 -
 16.1473 -        /// <summary>
 16.1474 -        /// Event handler for when a handshake dialog was closed.
 16.1475 -        /// </summary>
 16.1476 -        protected void HandshakeDialog_Closed(object sender, EventArgs e)
 16.1477 -        {
 16.1478 -            if (this.handshakeDialog != null)
 16.1479 -            {
 16.1480 -                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
 16.1481 -                this.handshakeDialog.Closed -= HandshakeDialog_Closed;
 16.1482 -                this.handshakeDialog = null;
 16.1483 -            }
 16.1484 -        }
 16.1485 -
 16.1486 -        /// <summary>
 16.1487 -        /// Event handler called after the refresh timer has elapsed.
 16.1488 -        /// </summary>
 16.1489 -        private void TimerRefresh_Tick(object sender, EventArgs e)
 16.1490 -        {
 16.1491 -            bool tryAgain = false;
 16.1492 -#pragma warning disable 219
 16.1493 -            bool markForDownload = false;
 16.1494 -#pragma warning restore 219
 16.1495 -            this.TimerRefresh.Enabled = false; // Only once
 16.1496 -            Outlook.OlDownloadState dlState;
 16.1497 -
 16.1498 -            /* The Refresh/UI_Update process:
 16.1499 -             * There are the following components:
 16.1500 -             *   1. TimerRefresh_Tick
 16.1501 -             *        This is the main timer tick event handler called any time
 16.1502 -             *        a refresh was requested (RequestRatingAndUIUpdate) and hasn't been run yet. 
 16.1503 -             *        A refresh is requested either at initialization or when a property changes
 16.1504 -             *        (such as MailItem_PropertyChanged). It is on a timer as many 
 16.1505 -             *        property change events could occur rapidy, but only one refresh should
 16.1506 -             *        occur for performance reasons.
 16.1507 -             * 
 16.1508 -             *   2. ImmediateRatingAndUIUpdate
 16.1509 -             *        This will re-calculate the mail item's rating.
 16.1510 -             *        This internally just calls CryptableMailItem.StartProcessing.
 16.1511 -             * 
 16.1512 -             *   3. MailItem_ProcessingCompleted
 16.1513 -             *        When processing of the mail item is complete, this even handler will be called.
 16.1514 -             *        This will update the UI with the latest rating then call StartGetMirror.
 16.1515 -             *        The CopyStateToUI method is used which means any open privacy status form will also
 16.1516 -             *        be updated.
 16.1517 -             * 
 16.1518 -             *   4. MailItem_GetMirrorComplete
 16.1519 -             *        This is the final step in updating the UI, after a mirror is located, it's contents
 16.1520 -             *        will be shown in the unencrypted preview.
 16.1521 -             * 
 16.1522 -             * The general calling sequence is as shown above 1->4 with each component calling the next.
 16.1523 -             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
 16.1524 -             */
 16.1525 -
 16.1526 -            // Ensure the tick method is not called more than once
 16.1527 -            if ((this.isEnabled) &&
 16.1528 -                (refreshOngoing == false))
 16.1529 -            {
 16.1530 -                this.refreshOngoing = true;
 16.1531 -
 16.1532 -                if ((this.cryptableMailItem != null) &&
 16.1533 -                    (this.cryptableMailItem.IsBeingProcessed == false))
 16.1534 -                {
 16.1535 -                    // Attempt to get the download state
 16.1536 -                    try
 16.1537 -                    {
 16.1538 -                        dlState = this.cryptableMailItem.DownloadState;
 16.1539 -                    }
 16.1540 -                    catch (Exception ex)
 16.1541 -                    {
 16.1542 -                        Log.Warning("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
 16.1543 -
 16.1544 -                        // Assume everything is downloaded, but try to download again as well
 16.1545 -                        dlState = Outlook.OlDownloadState.olFullItem;
 16.1546 -                        markForDownload = true;
 16.1547 -                    }
 16.1548 -
 16.1549 -                    if (dlState == Outlook.OlDownloadState.olFullItem)
 16.1550 -                    {
 16.1551 -                        this.ImmediateRatingAndUIUpdate();
 16.1552 -                    }
 16.1553 -                    else
 16.1554 -                    {
 16.1555 -                        markForDownload = true;
 16.1556 -                    }
 16.1557 -
 16.1558 -                    /* 12/16/2016: It could be verified via testing that setting the MarkForDownload property
 16.1559 -                     * can be a way to crash Outlook under certain circumstances (e.g. with IMAP on Outlook 2010 or on Windows 7). 
 16.1560 -                     * This then is not caught by a try/catch block and therefore has to be considered an Outlook bug.
 16.1561 -                     * It seems that in newer versions of Outlook/Windows, they fixed it, causing exceptions, if at all.
 16.1562 -                     * For now, the following is commented out to prevent a crash. If at any point we see that header-only
 16.1563 -                     * messages cause bigger issues, this decision has to be reevaluated.
 16.1564 -                     */
 16.1565 -                    //if (markForDownload)
 16.1566 -                    //{
 16.1567 -                    //    // Try to mark the message for full download
 16.1568 -                    //    try
 16.1569 -                    //    {
 16.1570 -                    //        this.cryptableMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
 16.1571 -                    //        tryAgain = true;
 16.1572 -                    //    }
 16.1573 -                    //    catch (Exception ex)
 16.1574 -                    //    {
 16.1575 -                    //        Log.Warning("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
 16.1576 -                    //    }
 16.1577 -                    //}
 16.1578 -                }
 16.1579 -                else
 16.1580 -                {
 16.1581 -                    repeatProcessing = true;
 16.1582 -                }
 16.1583 -
 16.1584 -                // Set the timer to refresh again later automatically
 16.1585 -                if (tryAgain)
 16.1586 -                {