Add WatchedExplorers and some modifications Redesign_Ribbon
authorThomas
Tue, 27 Jun 2017 16:30:01 +0200
branchRedesign_Ribbon
changeset 1722ec861834fbc6
parent 1721 8feb2e923d07
child 1727 196787433292
Add WatchedExplorers and some modifications
MsgProcessor.cs
Properties/Resources.Designer.cs
Properties/Resources.resx
Resources/ImageRatingGreen.png
Resources/ImageRatingRed.png
Resources/ImageRatingYellow.png
ThisAddIn.cs
UI/RibbonCustomizations.cs
UI/RibbonCustomizationsExplorer.xml
pEpForOutlook.csproj
     1.1 --- a/MsgProcessor.cs	Thu Jun 22 16:57:39 2017 +0200
     1.2 +++ b/MsgProcessor.cs	Tue Jun 27 16:30:01 2017 +0200
     1.3 @@ -23,6 +23,7 @@
     1.4          /// </summary>
     1.5          public event ProcessingCompletedHandler ProcessingCompleted;
     1.6  
     1.7 +        public const string UNKNOWN_SENDER                            = "unknown";
     1.8          public const string USER_PROPERTY_KEY_FORCE_UNENCRYPTED       = "sendUnencrypted";
     1.9          public const string USER_PROPERTY_KEY_IS_INCOMING             = "isIncoming";
    1.10          public const string USER_PROPERTY_KEY_IS_MIRROR               = "isMirror";
    1.11 @@ -31,6 +32,8 @@
    1.12  
    1.13          private static object                     mutexMirror           = new object();
    1.14          private static Dictionary<string, string> mirrorCache           = new Dictionary<string, string>();
    1.15 +        private static object                     mutexCopiedItemsList  = new object();
    1.16 +        private static List<string>               copiedItemsList       = new List<string>();
    1.17          private BackgroundWorker backgroundProcessor;
    1.18  
    1.19  
    1.20 @@ -142,175 +145,218 @@
    1.21              return (false);
    1.22          }
    1.23  
    1.24 -        public void Process(MsgContainer srcMessageContainer)
    1.25 +        /// <summary>
    1.26 +        /// Gets whether a given EntryID is in the list of copied items.
    1.27 +        /// </summary>
    1.28 +        /// <param name="entryId">The EntryID to check for.</param>
    1.29 +        /// <returns>True, if in the list. Otherwise false.</returns>
    1.30 +        public static bool IsInCopiedItemsList(string entryId)
    1.31 +        {
    1.32 +            bool isInList = false;
    1.33 +
    1.34 +            lock (mutexCopiedItemsList)
    1.35 +            {
    1.36 +                if (copiedItemsList.Contains(entryId))
    1.37 +                {
    1.38 +                    isInList = true;
    1.39 +                }
    1.40 +            }
    1.41 +
    1.42 +            return isInList;
    1.43 +        }
    1.44 +
    1.45 +        public void ProcessMailItem(MsgContainer msgContainer, bool updateUI = false)
    1.46 +        {
    1.47 +            if (msgContainer != null)
    1.48 +            {
    1.49 +                var msgProcessor = new MsgProcessor();
    1.50 +
    1.51 +                // Set current synchronization context to main thread
    1.52 +                SynchronizationContext.SetSynchronizationContext(ThisAddIn.UIThreadSynchronizationContext);
    1.53 +
    1.54 +                try
    1.55 +                {
    1.56 +                    // Process mail item in background
    1.57 +                    Task.Factory.StartNew(() =>
    1.58 +                    {
    1.59 +                        return this.Process(msgContainer);
    1.60 +
    1.61 +                    }).ContinueWith(task =>
    1.62 +                    {
    1.63 +                        // Complete processing on main thread. Apply to omi (if necessary) and update rating.                           
    1.64 +                        var result = task.Result as MsgContainer;
    1.65 +
    1.66 +                        if (result != null)
    1.67 +                        {
    1.68 +                            this.CompleteProcessing(result, updateUI);
    1.69 +                        }
    1.70 +
    1.71 +                        // Remove EntryId from decryption list.
    1.72 +                        Globals.ThisAddIn.RemoveFromEncryptionList(msgContainer.EntryId);
    1.73 +
    1.74 +                    }, TaskScheduler.FromCurrentSynchronizationContext());
    1.75 +                }
    1.76 +                catch (Exception e)
    1.77 +                {
    1.78 +                    Log.Error("ProcessMailItem: " + e.ToString());
    1.79 +                }
    1.80 +            }
    1.81 +        }
    1.82 +
    1.83 +        public MsgContainer Process(MsgContainer msgContainer)
    1.84          {
    1.85              bool process = true;
    1.86 -            PEPMessage processedMessage;
    1.87 -            PEPMessage mirror;
    1.88 +            PEPMessage mirrorMessage = null;
    1.89 +            PEPMessage processedMessage = null;
    1.90              pEpRating processedRating;
    1.91              pEpDecryptFlags decryptionFlags;
    1.92              MsgContainer processedMessageContainer = null;
    1.93              Globals.ReturnStatus sts;
    1.94 -            Outlook.MailItem omi = null;
    1.95 +            Outlook.MailItem mirror = null;
    1.96  
    1.97              try
    1.98              {
    1.99 -                SynchronizationContext.SetSynchronizationContext(ThisAddIn.UIThreadSynchronizationContext);
   1.100 +                processedMessageContainer = msgContainer.Copy();
   1.101  
   1.102 -                Task task = Task.Factory.StartNew(()=>
   1.103 +                if (msgContainer.IsInSecureStore)
   1.104                  {
   1.105                      try
   1.106                      {
   1.107 -                        processedMessageContainer = srcMessageContainer.Copy();
   1.108 +                        mirror = MsgProcessor.GetMirror(msgContainer?.EntryId, msgContainer?.Message?.From?.UserName);
   1.109 +                    }
   1.110 +                    catch (Exception e)
   1.111 +                    {
   1.112 +                        mirror = null;
   1.113 +                        Log.Error("MsgProcessor.Process: Error getting mirror item. " + e.Message);
   1.114 +                    }
   1.115  
   1.116 -                        if (srcMessageContainer.IsInSecureStore)
   1.117 +                    if (mirror != null)
   1.118 +                    {
   1.119 +                        if (PEPMessage.Create(mirror, out mirrorMessage) == Globals.ReturnStatus.Success)
   1.120                          {
   1.121 -                            try
   1.122 -                            {
   1.123 -                                mirror = MsgProcessor.GetMirror(srcMessageContainer);
   1.124 -                            }
   1.125 -                            catch (Exception e)
   1.126 -                            {
   1.127 -                                mirror = null;
   1.128 -                                Log.Error("MsgProcessor.Process: Error getting mirror item. " + e.Message);
   1.129 -                            }
   1.130 -
   1.131 -                            if (mirror != null)
   1.132 -                            {
   1.133 -                                process = false;
   1.134 -                                processedMessageContainer.MirrorCreated = false;
   1.135 -                                processedMessageContainer.Message = null;
   1.136 -                                processedMessageContainer.Rating = AdapterExtensions.ReevaluateMessageRating(mirror, mirror.Rating);
   1.137 -                            }
   1.138 -
   1.139 -                            processedMessageContainer.Mirror = mirror;
   1.140 -                        }
   1.141 -
   1.142 -                        if (process)
   1.143 -                        {
   1.144 -                            sts = this.ProcessMessage(srcMessageContainer.Message,
   1.145 -                                              srcMessageContainer.MessageCreationStatus,
   1.146 -                                              srcMessageContainer.IsInSecureStore,
   1.147 -                                              srcMessageContainer.IsInSentFolder,
   1.148 -                                              srcMessageContainer.IsDraft,
   1.149 -                                              out mirror,
   1.150 -                                              out processedMessage,
   1.151 -                                              out processedRating,
   1.152 -                                              out decryptionFlags);
   1.153 -
   1.154 -                            processedMessageContainer.MessageCreationStatus = sts;
   1.155 -                            processedMessageContainer.DecryptionFlags = decryptionFlags;
   1.156 -                            processedMessageContainer.EntryId = srcMessageContainer.EntryId;
   1.157 -                            processedMessageContainer.Message = processedMessage;
   1.158 -                            processedMessageContainer.Rating = processedRating;
   1.159 -
   1.160 -                            if (mirror != null)
   1.161 -                            {
   1.162 -                                processedMessageContainer.Mirror = mirror;
   1.163 -                                processedMessageContainer.MirrorCreated = true;
   1.164 -                            }
   1.165 -
   1.166 -                            if (sts != Globals.ReturnStatus.Success)
   1.167 -                            {
   1.168 -                                processedMessageContainer.Error = new Exception(sts.ToString());
   1.169 -                            }
   1.170 +                            process = false;
   1.171 +                            processedMessageContainer.MirrorCreated = false;
   1.172 +                            processedMessageContainer.Message = null;
   1.173 +                            processedMessageContainer.Rating = AdapterExtensions.ReevaluateMessageRating(mirrorMessage, mirrorMessage.Rating);
   1.174                          }
   1.175                          else
   1.176                          {
   1.177 -                            if (srcMessageContainer.Message != null)
   1.178 +                            mirrorMessage = null;
   1.179 +                            Log.Error("MsgProcessor.Process: Error creating mirror message.");
   1.180 +                        }
   1.181 +                    }
   1.182 +
   1.183 +                    processedMessageContainer.Mirror = mirrorMessage;
   1.184 +                }
   1.185 +                else
   1.186 +                {
   1.187 +                    if (processedMessageContainer.Message != null)
   1.188 +                    {
   1.189 +                        processedMessageContainer.Rating = AdapterExtensions.ReevaluateMessageRating(msgContainer.Message, msgContainer.Message.Rating);
   1.190 +                    }
   1.191 +                    else
   1.192 +                    {
   1.193 +                        processedMessageContainer.Error = new Exception("Message is null.");
   1.194 +                    }
   1.195 +                }
   1.196 +
   1.197 +                if (process)
   1.198 +                {
   1.199 +                    sts = this.ProcessMessage(msgContainer.Message,
   1.200 +                                      msgContainer.MessageCreationStatus,
   1.201 +                                      msgContainer.IsInSecureStore,
   1.202 +                                      msgContainer.IsInSentFolder,
   1.203 +                                      msgContainer.IsDraft,
   1.204 +                                      out mirrorMessage,
   1.205 +                                      out processedMessage,
   1.206 +                                      out processedRating,
   1.207 +                                      out decryptionFlags);
   1.208 +
   1.209 +                    processedMessageContainer.MessageCreationStatus = sts;
   1.210 +                    processedMessageContainer.DecryptionFlags = decryptionFlags;
   1.211 +                    processedMessageContainer.Message = processedMessage;
   1.212 +                    processedMessageContainer.Rating = processedRating;
   1.213 +
   1.214 +                    if (mirrorMessage != null)
   1.215 +                    {
   1.216 +                        processedMessageContainer.Mirror = mirrorMessage;
   1.217 +                        processedMessageContainer.MirrorCreated = true;
   1.218 +                    }
   1.219 +
   1.220 +                    if (sts != Globals.ReturnStatus.Success)
   1.221 +                    {
   1.222 +                        processedMessageContainer.Error = new Exception(sts.ToString());
   1.223 +                    }
   1.224 +                }
   1.225 +            }
   1.226 +            catch (Exception e)
   1.227 +            {
   1.228 +                processedMessageContainer.Error = e;
   1.229 +            }
   1.230 +
   1.231 +            return processedMessageContainer;
   1.232 +        }
   1.233 +
   1.234 +        public void CompleteProcessing(MsgContainer msgContainer, bool updateUI = false)
   1.235 +        {
   1.236 +            Outlook.MailItem omi = null;
   1.237 +
   1.238 +            if (msgContainer != null)
   1.239 +            {
   1.240 +                try
   1.241 +                {
   1.242 +                    if (msgContainer.Error == null)
   1.243 +                    {
   1.244 +                        if ((msgContainer.DecryptionFlags == pEpDecryptFlags.pEpDecryptFlagConsume) ||
   1.245 +                            (msgContainer.DecryptionFlags == pEpDecryptFlags.pEpDecryptFlagIgnore))
   1.246 +                        {
   1.247 +                            Log.Verbose("MsgProcessor.Process: pEp internal message processed.");
   1.248 +                        }
   1.249 +                        else
   1.250 +                        {
   1.251 +                            if ((msgContainer.IsInSecureStore || msgContainer.IsNeverUnsecure) &&
   1.252 +                                (msgContainer.Mirror != null))
   1.253                              {
   1.254 -                                processedMessageContainer.Rating = AdapterExtensions.ReevaluateMessageRating(srcMessageContainer.Message, srcMessageContainer.Message.Rating);
   1.255 +                                MsgProcessor.SetMirror(msgContainer);
   1.256 +
   1.257 +                                if (msgContainer.MirrorCreated)
   1.258 +                                {
   1.259 +                                    omi = this.CreateMirrorOMI(msgContainer.EntryId);
   1.260 +                                }
   1.261 +
   1.262 +                                if (omi != null)
   1.263 +                                {
   1.264 +                                    msgContainer.Mirror.ApplyTo(omi, true, false);
   1.265 +                                    omi.Save();
   1.266 +                                }
   1.267                              }
   1.268 -                            else
   1.269 +                            else if (msgContainer.Message != null)
   1.270                              {
   1.271 -                                processedMessageContainer.Error = new Exception("Message is null.");
   1.272 +                                omi = Globals.ThisAddIn.Application.Session.GetItemFromID(msgContainer?.EntryId);
   1.273 +                                msgContainer.Message.ApplyTo(omi, true, false);
   1.274 +                                omi.Save();
   1.275 +                            }
   1.276 +
   1.277 +                            // Update UI rating if necessary
   1.278 +                            if (updateUI)
   1.279 +                            {
   1.280 +                                RibbonCustomizations.Invalidate(msgContainer.Rating);
   1.281                              }
   1.282                          }
   1.283                      }
   1.284 -                    catch (Exception e)
   1.285 +                    else
   1.286                      {
   1.287 -                        processedMessageContainer.Error = e;
   1.288 +                        throw new Exception("MsgProcessor.Process: msgContainer is null.");
   1.289                      }
   1.290 -
   1.291 -                    return processedMessageContainer;
   1.292 -
   1.293 -                }).ContinueWith(tsk =>
   1.294 +                }
   1.295 +                catch (Exception e)
   1.296                  {
   1.297 -                    try
   1.298 -                    {
   1.299 -                        var msgContainer = tsk.Result as MsgContainer;
   1.300 -
   1.301 -                        if (msgContainer != null)
   1.302 -                        {
   1.303 -                            if (msgContainer.Error == null)
   1.304 -                            {
   1.305 -                                if ((msgContainer.DecryptionFlags == pEpDecryptFlags.pEpDecryptFlagConsume) ||
   1.306 -                                    (msgContainer.DecryptionFlags == pEpDecryptFlags.pEpDecryptFlagIgnore))
   1.307 -                                {
   1.308 -                                    Log.Verbose("MsgProcessor.Process: pEp internal message processed.");
   1.309 -                                }
   1.310 -                                else
   1.311 -                                {
   1.312 -                                    if ((msgContainer.IsInSecureStore || msgContainer.IsNeverUnsecure) &&
   1.313 -                                        (msgContainer.Mirror != null))
   1.314 -                                    {
   1.315 -                                        MsgProcessor.SetMirror(msgContainer);
   1.316 -                                    }
   1.317 -
   1.318 -                                    if ((msgContainer.MirrorCreated) ||
   1.319 -                                        (msgContainer.Message != null))
   1.320 -                                    {
   1.321 -                                        Outlook.MailItem mailItem = Globals.ThisAddIn.Application.Session.GetItemFromID(processedMessageContainer?.EntryId);
   1.322 -
   1.323 -                                        if (msgContainer.MirrorCreated)
   1.324 -                                        {
   1.325 -                                            omi = this.CreateMirrorOMI(mailItem); 
   1.326 -                                        }
   1.327 -                                        else
   1.328 -                                        {
   1.329 -                                            omi = mailItem;
   1.330 -                                        }
   1.331 -
   1.332 -                                        mailItem = null;  
   1.333 -                                    }                                    
   1.334 -
   1.335 -                                    if (omi != null)
   1.336 -                                    {
   1.337 -                                        PEPMessage msgToApply = (msgContainer.Mirror != null) ? msgContainer.Mirror : msgContainer.Message;
   1.338 -
   1.339 -                                        if (msgToApply != null)
   1.340 -                                        {
   1.341 -                                            msgToApply.ApplyTo(omi, true, false);
   1.342 -                                            omi.Save();
   1.343 -                                        }
   1.344 -                                    }
   1.345 -
   1.346 -                                    // Update UI rating
   1.347 -                                    RibbonCustomizations.Invalidate(msgContainer.Rating);
   1.348 -                                }
   1.349 -                            }
   1.350 -                            else
   1.351 -                            {
   1.352 -                                throw new Exception("MsgProcessor.Process: msgContainer is null.");
   1.353 -                            }
   1.354 -                        }
   1.355 -                    }
   1.356 -                    catch (Exception e)
   1.357 -                    {
   1.358 -                        Log.Error("MsgProcessor.Process: Error applying mail item." + e.Message);
   1.359 -                    }
   1.360 -                    finally
   1.361 -                    {
   1.362 -                        omi = null;
   1.363 -                        Globals.ThisAddIn.RemoveFromEncryptionList(srcMessageContainer.EntryId);
   1.364 -                    }
   1.365 -
   1.366 -                }, TaskScheduler.FromCurrentSynchronizationContext());
   1.367 -
   1.368 -            }
   1.369 -            catch (Exception e)
   1.370 -            {
   1.371 -                Log.Error("MsgProcessor.Process: Error processing mail item." + e.Message);
   1.372 +                    Log.Error("MsgProcessor.Process: Error applying mail item." + e.Message);
   1.373 +                }
   1.374 +                finally
   1.375 +                {
   1.376 +                    omi = null;
   1.377 +                }
   1.378              }
   1.379          }
   1.380  
   1.381 @@ -1257,12 +1303,10 @@
   1.382              return (success);
   1.383          }
   1.384  
   1.385 -        public static PEPMessage GetMirror(MsgContainer msgContainer)
   1.386 +        public static Outlook.MailItem GetMirror(string entryId, string userName)
   1.387          {
   1.388              string mirrorID;
   1.389              string origEntryID;
   1.390 -            PEPMessage mirror = null;
   1.391 -            PEPMessage message = null;
   1.392              Outlook.MailItem mirrorItem = null;
   1.393              Outlook.MailItem currMirror = null;
   1.394              Outlook.NameSpace ns = Globals.ThisAddIn.Application.Session;
   1.395 @@ -1271,25 +1315,18 @@
   1.396              Outlook.Items targetFolderItems = null;
   1.397  
   1.398              // Try to find in cache
   1.399 -            if (mirrorItem == null)
   1.400 +            try
   1.401              {
   1.402 -                try
   1.403 +                lock (mutexMirror)
   1.404                  {
   1.405 -                    lock (mutexMirror)
   1.406 -                    {
   1.407 -                        mirrorID = mirrorCache[msgContainer.EntryId];
   1.408 -                    }
   1.409 +                    mirrorID = mirrorCache[entryId];
   1.410 +                }
   1.411  
   1.412 -                    mirrorItem = (Outlook.MailItem)ns.GetItemFromID(mirrorID, pEpStore.StoreID);
   1.413 -                }
   1.414 -                catch
   1.415 -                {
   1.416 -                    if (mirrorItem != null)
   1.417 -                    {
   1.418 -                        // Marshal.ReleaseComObject(mirror);
   1.419 -                        mirrorItem = null;
   1.420 -                    }
   1.421 -                }
   1.422 +                mirrorItem = (Outlook.MailItem)ns.GetItemFromID(mirrorID, pEpStore.StoreID);
   1.423 +            }
   1.424 +            catch
   1.425 +            {
   1.426 +                mirrorItem = null;
   1.427              }
   1.428  
   1.429              // Try to find same EntryID
   1.430 @@ -1297,15 +1334,11 @@
   1.431              {
   1.432                  try
   1.433                  {
   1.434 -                    mirrorItem = (Outlook.MailItem)ns.GetItemFromID(msgContainer.EntryId, pEpStore.StoreID);
   1.435 +                    mirrorItem = (Outlook.MailItem)ns.GetItemFromID(entryId, pEpStore.StoreID);
   1.436                  }
   1.437                  catch
   1.438                  {
   1.439 -                    if (mirrorItem != null)
   1.440 -                    {
   1.441 -                        // Marshal.ReleaseComObject(mirror);
   1.442 -                        mirrorItem = null;
   1.443 -                    }
   1.444 +                    mirrorItem = null;
   1.445                  }
   1.446              }
   1.447  
   1.448 @@ -1316,7 +1349,7 @@
   1.449  
   1.450                  try
   1.451                  {
   1.452 -                    targetFolder = MsgProcessor.GetMirrorFolder(msgContainer);
   1.453 +                    targetFolder = MsgProcessor.GetMirrorFolder(userName);
   1.454                      targetFolderItems = targetFolder.Items;
   1.455  
   1.456                      /* Add user property to folder if not there already:
   1.457 @@ -1330,14 +1363,14 @@
   1.458                          up.Add(USER_PROPERTY_KEY_ORIG_ENTRY_ID, Outlook.OlUserPropertyType.olText);
   1.459                      }
   1.460  
   1.461 -                    string filter = string.Format("[{0}] = '{1}'", USER_PROPERTY_KEY_ORIG_ENTRY_ID, msgContainer.EntryId);
   1.462 +                    string filter = string.Format("[{0}] = '{1}'", USER_PROPERTY_KEY_ORIG_ENTRY_ID, entryId);
   1.463                      mirrorItem = targetFolderItems.Find(filter) as Outlook.MailItem;
   1.464  
   1.465                      if (mirrorItem != null)
   1.466                      {
   1.467                          lock (mutexMirror)
   1.468                          {
   1.469 -                            mirrorCache[msgContainer.EntryId] = mirrorItem.EntryID;
   1.470 +                            mirrorCache[entryId] = mirrorItem.EntryID;
   1.471                          }
   1.472                      }
   1.473                  }
   1.474 @@ -1355,7 +1388,7 @@
   1.475              // Nothing worked, search each item by user property (slow)
   1.476              if (mirrorItem == null)
   1.477              {
   1.478 -                targetFolder = MsgProcessor.GetMirrorFolder(msgContainer);
   1.479 +                targetFolder = MsgProcessor.GetMirrorFolder(userName);
   1.480                  targetFolderItems = targetFolder.Items;
   1.481  
   1.482                  // Note: index starts at 1
   1.483 @@ -1368,11 +1401,11 @@
   1.484                          currMirror = (Outlook.MailItem)targetFolderItems[i];
   1.485                          origEntryID = (string)currMirror.GetUserProperty(USER_PROPERTY_KEY_ORIG_ENTRY_ID, "");
   1.486  
   1.487 -                        if (origEntryID == msgContainer.EntryId)
   1.488 +                        if (origEntryID == entryId)
   1.489                          {
   1.490                              lock (mutexMirror)
   1.491                              {
   1.492 -                                mirrorCache[msgContainer.EntryId] = currMirror.EntryID;
   1.493 +                                mirrorCache[entryId] = currMirror.EntryID;
   1.494                              }
   1.495  
   1.496                              mirrorItem = currMirror;
   1.497 @@ -1381,65 +1414,29 @@
   1.498                      }
   1.499                      catch { }
   1.500  
   1.501 -                    if (currMirror != null)
   1.502 -                    {
   1.503 -                        // Marshal.ReleaseComObject(currMirror);
   1.504 -                        currMirror = null;
   1.505 -                    }
   1.506 +                    currMirror = null;
   1.507                  }
   1.508              }
   1.509  
   1.510 -            // Create mirror from mirror mail item
   1.511 -            if (mirrorItem != null)
   1.512 -            {
   1.513 -                if (PEPMessage.Create(mirrorItem, out mirror) != Globals.ReturnStatus.Success)
   1.514 -                {
   1.515 -                    mirror = null;
   1.516 -                }
   1.517 -
   1.518 -                mirrorItem = null;
   1.519 -            }
   1.520 -
   1.521              /* Release objects
   1.522               * Note: Do not release mirror or currMirror (which may point to mirror).
   1.523               * These are returned for external use.
   1.524               */
   1.525 -            if (ns != null)
   1.526 -            {
   1.527 -                //Marshal.ReleaseComObject(ns);
   1.528 -                ns = null;
   1.529 -            }
   1.530 +            ns = null;
   1.531 +            pEpStore = null;
   1.532 +            targetFolder = null;
   1.533 +            targetFolderItems = null;
   1.534  
   1.535 -            if (pEpStore != null)
   1.536 -            {
   1.537 -                //Marshal.ReleaseComObject(pEpStore);
   1.538 -                pEpStore = null;
   1.539 -            }
   1.540 -            if (targetFolder != null)
   1.541 -            {
   1.542 -                // Marshal.ReleaseComObject(targetFolder);
   1.543 -                targetFolder = null;
   1.544 -            }
   1.545 -
   1.546 -            if (targetFolderItems != null)
   1.547 -            {
   1.548 -                // Marshal.ReleaseComObject(targetFolderItems);
   1.549 -                targetFolderItems = null;
   1.550 -            }
   1.551 -
   1.552 -            return (mirror);
   1.553 +            return (mirrorItem);
   1.554          }
   1.555  
   1.556 -        public static Outlook.Folder GetMirrorFolder(MsgContainer msgContainer)
   1.557 +        public static Outlook.Folder GetMirrorFolder(string userName)
   1.558          {
   1.559 -            string userName = null;
   1.560              string[] specialChars;
   1.561              Outlook.Folder folder;
   1.562              Outlook.Folders folders = Globals.ThisAddIn.PEPStoreRootFolder.Folders;
   1.563              StringBuilder strBuilder = new StringBuilder();
   1.564  
   1.565 -            userName = msgContainer?.Message?.From?.UserName;
   1.566 -
   1.567              if (userName != null)
   1.568              {
   1.569                  /* Remove special characters from folder name.
   1.570 @@ -1478,12 +1475,7 @@
   1.571                  Log.Verbose("GetUnencryptedFolder: Creating new folder.");
   1.572              }
   1.573  
   1.574 -            // Release objects
   1.575 -            if (folders != null)
   1.576 -            {
   1.577 -                // Marshal.ReleaseComObject(folders);
   1.578 -                folders = null;
   1.579 -            }
   1.580 +            folders = null;
   1.581  
   1.582              return (folder);
   1.583          }
   1.584 @@ -1536,200 +1528,130 @@
   1.585              //}
   1.586          }
   1.587  
   1.588 -        private Outlook.MailItem CreateMirrorOMI(Outlook.MailItem original)
   1.589 +        private Outlook.MailItem CreateMirrorOMI(string entryId)
   1.590          {
   1.591              bool created = false;
   1.592              byte[] bytes;
   1.593              string str;
   1.594              System.Int32 messageFlags;
   1.595              Outlook.MailItem omi = null;
   1.596 -            Outlook.Folder folder = original.GetMirrorFolder();
   1.597 +            Outlook.MailItem original = null;
   1.598 +            Outlook.Folder folder = null;
   1.599 +
   1.600  
   1.601              try
   1.602              {
   1.603 -                Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
   1.604 -
   1.605 -                omi = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
   1.606 -                omi.UnRead = false;
   1.607 -
   1.608 -                // Set received and sent time
   1.609 -                try
   1.610 -                {
   1.611 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageDeliveryTime, original.ReceivedTime.ToUniversalTime());
   1.612 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagClientSubmitTime, original.SentOn.ToUniversalTime());
   1.613 -                }
   1.614 -                catch (Exception e)
   1.615 -                {
   1.616 -                    Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + e.Message);
   1.617 -                    throw;
   1.618 -                }
   1.619 -
   1.620 -                // Attempt to set sender information
   1.621 -                try
   1.622 -                {
   1.623 -                    omi.Sender = original.Sender;
   1.624 -                }
   1.625 -                catch (Exception e)
   1.626 -                {
   1.627 -                    Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + e.Message);
   1.628 -                }
   1.629 -
   1.630 -                try
   1.631 -                {
   1.632 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderName, original.SenderName);
   1.633 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderEmailAddress, original.SenderEmailAddress);
   1.634 -
   1.635 -                    // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
   1.636 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(original, MapiProperty.PidTagSenderEntryId));
   1.637 -                }
   1.638 -                catch (Exception e)
   1.639 -                {
   1.640 -                    Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + e.Message);
   1.641 -                    throw;
   1.642 -                }
   1.643 -
   1.644 -                try
   1.645 -                {
   1.646 -                    omi.SendUsingAccount = original.SendUsingAccount;
   1.647 -                }
   1.648 -                catch (Exception e)
   1.649 -                {
   1.650 -                    Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + e.Message);
   1.651 -                }
   1.652 -
   1.653 -                // Set flags
   1.654 -                messageFlags = (System.Int32)MapiHelper.GetProperty(omi, MapiProperty.PidTagMessageFlags);
   1.655 -                messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
   1.656 -                messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
   1.657 -                try
   1.658 -                {
   1.659 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageFlags, messageFlags);
   1.660 -                }
   1.661 -                catch (Exception e)
   1.662 -                {
   1.663 -                    Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + e.Message);
   1.664 -                }
   1.665 -
   1.666 -                // Conversation information
   1.667 -                try
   1.668 -                {
   1.669 -                    /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
   1.670 -                     * This is by design since this property is computed automatically from other properties.
   1.671 -                     * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
   1.672 -                     */
   1.673 -
   1.674 -                    str = original.ConversationIndex;
   1.675 -                    if (str != null)
   1.676 -                    {
   1.677 -                        bytes = new byte[str.Length / 2];
   1.678 -                        for (int i = 0; i < str.Length; i += 2)
   1.679 -                        {
   1.680 -                            bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16);
   1.681 -                        }
   1.682 -
   1.683 -                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndex, bytes);
   1.684 -                    }
   1.685 -
   1.686 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndexTracking, false);
   1.687 -                    MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationTopic, original.ConversationTopic);
   1.688 -                }
   1.689 -                catch (Exception e)
   1.690 -                {
   1.691 -                    Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + e.Message);
   1.692 -                }
   1.693 -
   1.694 -                omi.To = original.To;
   1.695 -                omi.CC = original.CC;
   1.696 -                omi.BCC = original.BCC;
   1.697 -                omi.Subject = "pEp";
   1.698 -                omi.Body = string.Empty;
   1.699 -                omi.Save();
   1.700 -
   1.701 -                /* Set all received-by information
   1.702 -                 * 
   1.703 -                 * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
   1.704 -                 * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
   1.705 -                 * 
   1.706 -                 * In most situations the received-by information will not be needed.
   1.707 -                 * Decryption for example uses the recipients/identities in the original mail item itself.
   1.708 -                 * However, the GetMyIdentity(omi) method requires this information in some cases:
   1.709 -                 *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
   1.710 -                 *    using aliases or when forwarding emails from another account.
   1.711 -                 *  • This is primarily needed when displaying mirrors themselves then opening the privacy status manager.
   1.712 -                 */
   1.713 -                try
   1.714 -                {
   1.715 -                    omi.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName,
   1.716 -                                        MapiHelper.GetProperty(original, MapiProperty.PidTagReceivedByEmailAddress),
   1.717 -                                        Outlook.OlUserPropertyType.olText);
   1.718 -                    omi.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
   1.719 -                                        MapiHelper.GetProperty(original, MapiProperty.PidTagReceivedByName),
   1.720 -                                        Outlook.OlUserPropertyType.olText);
   1.721 -                }
   1.722 -                catch (Exception e)
   1.723 -                {
   1.724 -                    Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + e.Message);
   1.725 -                }
   1.726 -
   1.727 -                // Mark the mail item as a mirror
   1.728 -                omi.SetUserProperty(USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
   1.729 -
   1.730 -                /* Set the incoming status of the new mail item.
   1.731 -                 * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
   1.732 -                 * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
   1.733 -                 */
   1.734 -                if (original.GetIsIncoming())
   1.735 -                {
   1.736 -                    omi.SetUserProperty(USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
   1.737 -                }
   1.738 -                else
   1.739 -                {
   1.740 -                    omi.SetUserProperty(USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
   1.741 -                }
   1.742 -
   1.743 -                // Add the original EntryID
   1.744 -                omi.SetUserProperty(USER_PROPERTY_KEY_ORIG_ENTRY_ID, original.EntryID);
   1.745 -                omi.Save();
   1.746 -
   1.747 -                // Move the mirror copy to the correct folder
   1.748 -                // This is needed as some account-types/office versions will still create a mail item in the default folder
   1.749 -                // even if folder.Items.Add is used to specify a location.
   1.750 -                // WARNING: this creates a new mail item that will no longer be referenced here!!
   1.751 -                omi.Move(folder);
   1.752 -                created = true;
   1.753 +                original = Globals.ThisAddIn.Application.Session.GetItemFromID(entryId);
   1.754              }
   1.755              catch (Exception e)
   1.756              {
   1.757 -                Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + e.Message);
   1.758 -                omi.PermanentlyDelete();
   1.759 -                omi = null;
   1.760 +                Log.Error("CreateMirrorOMI: Error getting original mail item. " + e.ToString());
   1.761 +                original = null;
   1.762              }
   1.763  
   1.764 -            if (created == false)
   1.765 +            if (original != null)
   1.766              {
   1.767                  try
   1.768                  {
   1.769 -                    Log.Verbose("CreateMirrorOMI: Creating by copy.");
   1.770 +                    Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
   1.771  
   1.772 -                    // Release any partially created omi from a failed copy
   1.773 -                    omi = null;
   1.774 +                    folder = original.GetMirrorFolder();
   1.775  
   1.776 -                    /* Attempt to create the mirror by copying
   1.777 -                     * Depending on account types, anything after Office 2010 can have the following error:
   1.778 -                     *  System.Runtime.InteropServices.COMException (0x80040102): Sorry, Exchange ActiveSync doesn't
   1.779 -                     *  support what you're trying to do. 
   1.780 -                     *    at Microsoft.Office.Interop.Outlook._MailItem.Copy()
   1.781 -                     * When this happens a new mail item must be created.
   1.782 -                     */
   1.783 -                    lock (mutexCopiedItemsList)
   1.784 +                    omi = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
   1.785 +                    omi.UnRead = false;
   1.786 +
   1.787 +                    // Set received and sent time
   1.788 +                    try
   1.789                      {
   1.790 -                        omi = (Outlook.MailItem)original.Copy();
   1.791 -                        if (copiedItemsList.Contains(omi.EntryID) == false)
   1.792 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageDeliveryTime, original.ReceivedTime.ToUniversalTime());
   1.793 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagClientSubmitTime, original.SentOn.ToUniversalTime());
   1.794 +                    }
   1.795 +                    catch (Exception e)
   1.796 +                    {
   1.797 +                        Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + e.Message);
   1.798 +                        throw;
   1.799 +                    }
   1.800 +
   1.801 +                    // Attempt to set sender information
   1.802 +                    try
   1.803 +                    {
   1.804 +                        omi.Sender = original.Sender;
   1.805 +                    }
   1.806 +                    catch (Exception e)
   1.807 +                    {
   1.808 +                        Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + e.Message);
   1.809 +                    }
   1.810 +
   1.811 +                    try
   1.812 +                    {
   1.813 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderName, original.SenderName);
   1.814 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderEmailAddress, original.SenderEmailAddress);
   1.815 +
   1.816 +                        // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
   1.817 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(original, MapiProperty.PidTagSenderEntryId));
   1.818 +                    }
   1.819 +                    catch (Exception e)
   1.820 +                    {
   1.821 +                        Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + e.Message);
   1.822 +                        throw;
   1.823 +                    }
   1.824 +
   1.825 +                    try
   1.826 +                    {
   1.827 +                        omi.SendUsingAccount = original.SendUsingAccount;
   1.828 +                    }
   1.829 +                    catch (Exception e)
   1.830 +                    {
   1.831 +                        Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + e.Message);
   1.832 +                    }
   1.833 +
   1.834 +                    // Set flags
   1.835 +                    messageFlags = (System.Int32)MapiHelper.GetProperty(omi, MapiProperty.PidTagMessageFlags);
   1.836 +                    messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
   1.837 +                    messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
   1.838 +                    try
   1.839 +                    {
   1.840 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageFlags, messageFlags);
   1.841 +                    }
   1.842 +                    catch (Exception e)
   1.843 +                    {
   1.844 +                        Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + e.Message);
   1.845 +                    }
   1.846 +
   1.847 +                    // Conversation information
   1.848 +                    try
   1.849 +                    {
   1.850 +                        /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
   1.851 +                         * This is by design since this property is computed automatically from other properties.
   1.852 +                         * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
   1.853 +                         */
   1.854 +
   1.855 +                        str = original.ConversationIndex;
   1.856 +                        if (str != null)
   1.857                          {
   1.858 -                            copiedItemsList.Add(omi.EntryID);
   1.859 +                            bytes = new byte[str.Length / 2];
   1.860 +                            for (int i = 0; i < str.Length; i += 2)
   1.861 +                            {
   1.862 +                                bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16);
   1.863 +                            }
   1.864 +
   1.865 +                            MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndex, bytes);
   1.866                          }
   1.867 +
   1.868 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndexTracking, false);
   1.869 +                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationTopic, original.ConversationTopic);
   1.870                      }
   1.871 -                    omi.UnRead = false;
   1.872 +                    catch (Exception e)
   1.873 +                    {
   1.874 +                        Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + e.Message);
   1.875 +                    }
   1.876 +
   1.877 +                    omi.To = original.To;
   1.878 +                    omi.CC = original.CC;
   1.879 +                    omi.BCC = original.BCC;
   1.880 +                    omi.Subject = "pEp";
   1.881 +                    omi.Body = string.Empty;
   1.882 +                    omi.Save();
   1.883  
   1.884                      /* Set all received-by information
   1.885                       * 
   1.886 @@ -1752,7 +1674,10 @@
   1.887                                              MapiHelper.GetProperty(original, MapiProperty.PidTagReceivedByName),
   1.888                                              Outlook.OlUserPropertyType.olText);
   1.889                      }
   1.890 -                    catch { }
   1.891 +                    catch (Exception e)
   1.892 +                    {
   1.893 +                        Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + e.Message);
   1.894 +                    }
   1.895  
   1.896                      // Mark the mail item as a mirror
   1.897                      omi.SetUserProperty(USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
   1.898 @@ -1770,49 +1695,130 @@
   1.899                          omi.SetUserProperty(USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
   1.900                      }
   1.901  
   1.902 -                    // Add the original EntryID to the mirror copy
   1.903 -                    // This must be done before the move as the reference is then lost
   1.904 +                    // Add the original EntryID
   1.905                      omi.SetUserProperty(USER_PROPERTY_KEY_ORIG_ENTRY_ID, original.EntryID);
   1.906                      omi.Save();
   1.907  
   1.908                      // Move the mirror copy to the correct folder
   1.909 +                    // This is needed as some account-types/office versions will still create a mail item in the default folder
   1.910 +                    // even if folder.Items.Add is used to specify a location.
   1.911                      // WARNING: this creates a new mail item that will no longer be referenced here!!
   1.912                      omi.Move(folder);
   1.913 +                    created = true;
   1.914                  }
   1.915                  catch (Exception e)
   1.916                  {
   1.917 -                    Log.Error("CreateMirrorOMI: Creating by copy failed. " + e.Message);
   1.918 +                    Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + e.Message);
   1.919 +                    omi.PermanentlyDelete();
   1.920 +                    omi = null;
   1.921                  }
   1.922 -                finally
   1.923 +
   1.924 +                if (created == false)
   1.925                  {
   1.926 -                    lock (mutexCopiedItemsList)
   1.927 +                    try
   1.928                      {
   1.929 -                        if (copiedItemsList.Contains(omi?.EntryID))
   1.930 +                        Log.Verbose("CreateMirrorOMI: Creating by copy.");
   1.931 +
   1.932 +                        // Release any partially created omi from a failed copy
   1.933 +                        omi = null;
   1.934 +
   1.935 +                        /* Attempt to create the mirror by copying
   1.936 +                         * Depending on account types, anything after Office 2010 can have the following error:
   1.937 +                         *  System.Runtime.InteropServices.COMException (0x80040102): Sorry, Exchange ActiveSync doesn't
   1.938 +                         *  support what you're trying to do. 
   1.939 +                         *    at Microsoft.Office.Interop.Outlook._MailItem.Copy()
   1.940 +                         * When this happens a new mail item must be created.
   1.941 +                         */
   1.942 +                        lock (mutexCopiedItemsList)
   1.943                          {
   1.944 -                            copiedItemsList.Remove(omi?.EntryID);
   1.945 +                            omi = (Outlook.MailItem)original.Copy();
   1.946 +                            if (copiedItemsList.Contains(omi.EntryID) == false)
   1.947 +                            {
   1.948 +                                copiedItemsList.Add(omi.EntryID);
   1.949 +                            }
   1.950 +                        }
   1.951 +                        omi.UnRead = false;
   1.952 +
   1.953 +                        /* Set all received-by information
   1.954 +                         * 
   1.955 +                         * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
   1.956 +                         * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
   1.957 +                         * 
   1.958 +                         * In most situations the received-by information will not be needed.
   1.959 +                         * Decryption for example uses the recipients/identities in the original mail item itself.
   1.960 +                         * However, the GetMyIdentity(omi) method requires this information in some cases:
   1.961 +                         *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
   1.962 +                         *    using aliases or when forwarding emails from another account.
   1.963 +                         *  • This is primarily needed when displaying mirrors themselves then opening the privacy status manager.
   1.964 +                         */
   1.965 +                        try
   1.966 +                        {
   1.967 +                            omi.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName,
   1.968 +                                                MapiHelper.GetProperty(original, MapiProperty.PidTagReceivedByEmailAddress),
   1.969 +                                                Outlook.OlUserPropertyType.olText);
   1.970 +                            omi.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
   1.971 +                                                MapiHelper.GetProperty(original, MapiProperty.PidTagReceivedByName),
   1.972 +                                                Outlook.OlUserPropertyType.olText);
   1.973 +                        }
   1.974 +                        catch { }
   1.975 +
   1.976 +                        // Mark the mail item as a mirror
   1.977 +                        omi.SetUserProperty(USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
   1.978 +
   1.979 +                        /* Set the incoming status of the new mail item.
   1.980 +                         * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
   1.981 +                         * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
   1.982 +                         */
   1.983 +                        if (original.GetIsIncoming())
   1.984 +                        {
   1.985 +                            omi.SetUserProperty(USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
   1.986 +                        }
   1.987 +                        else
   1.988 +                        {
   1.989 +                            omi.SetUserProperty(USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
   1.990 +                        }
   1.991 +
   1.992 +                        // Add the original EntryID to the mirror copy
   1.993 +                        // This must be done before the move as the reference is then lost
   1.994 +                        omi.SetUserProperty(USER_PROPERTY_KEY_ORIG_ENTRY_ID, original.EntryID);
   1.995 +                        omi.Save();
   1.996 +
   1.997 +                        // Move the mirror copy to the correct folder
   1.998 +                        // WARNING: this creates a new mail item that will no longer be referenced here!!
   1.999 +                        omi.Move(folder);
  1.1000 +                    }
  1.1001 +                    catch (Exception e)
  1.1002 +                    {
  1.1003 +                        Log.Error("CreateMirrorOMI: Creating by copy failed. " + e.Message);
  1.1004 +                    }
  1.1005 +                    finally
  1.1006 +                    {
  1.1007 +                        lock (mutexCopiedItemsList)
  1.1008 +                        {
  1.1009 +                            if (copiedItemsList.Contains(omi?.EntryID))
  1.1010 +                            {
  1.1011 +                                copiedItemsList.Remove(omi?.EntryID);
  1.1012 +                            }
  1.1013                          }
  1.1014                      }
  1.1015                  }
  1.1016              }
  1.1017  
  1.1018              // Release objects
  1.1019 -            if (omi != null)
  1.1020 -            {
  1.1021 -                // Marshal.ReleaseComObject(omi);
  1.1022 -                omi = null;
  1.1023 -            }
  1.1024 -
  1.1025 -            if (folder != null)
  1.1026 -            {
  1.1027 -                // Marshal.ReleaseComObject(folder);
  1.1028 -                folder = null;
  1.1029 -            }
  1.1030 +            omi = null;
  1.1031 +            folder = null;
  1.1032  
  1.1033              /* Locate and return the mirror that was just created.
  1.1034               * During this find method, the mirror cache will be updated when found.
  1.1035               * It is important to do this here as any .Move methods create a new mail item.
  1.1036               */
  1.1037 -            return (MsgProcessor.GetMirror(original));
  1.1038 +            string userName = null;
  1.1039 +            if (PEPIdentity.GetFromUserName(original, out userName) != Globals.ReturnStatus.Success)
  1.1040 +            {
  1.1041 +                Log.Error("MsgProcessor.CreateMirrorOMI: Error getting From user name.");
  1.1042 +            }
  1.1043 +
  1.1044 +            return (MsgProcessor.GetMirror(original.EntryID, userName));
  1.1045          }
  1.1046  
  1.1047  
     2.1 --- a/Properties/Resources.Designer.cs	Thu Jun 22 16:57:39 2017 +0200
     2.2 +++ b/Properties/Resources.Designer.cs	Tue Jun 27 16:30:01 2017 +0200
     2.3 @@ -619,6 +619,36 @@
     2.4          /// <summary>
     2.5          ///   Looks up a localized resource of type System.Drawing.Bitmap.
     2.6          /// </summary>
     2.7 +        public static System.Drawing.Bitmap ImageRatingGreen {
     2.8 +            get {
     2.9 +                object obj = ResourceManager.GetObject("ImageRatingGreen", resourceCulture);
    2.10 +                return ((System.Drawing.Bitmap)(obj));
    2.11 +            }
    2.12 +        }
    2.13 +        
    2.14 +        /// <summary>
    2.15 +        ///   Looks up a localized resource of type System.Drawing.Bitmap.
    2.16 +        /// </summary>
    2.17 +        public static System.Drawing.Bitmap ImageRatingRed {
    2.18 +            get {
    2.19 +                object obj = ResourceManager.GetObject("ImageRatingRed", resourceCulture);
    2.20 +                return ((System.Drawing.Bitmap)(obj));
    2.21 +            }
    2.22 +        }
    2.23 +        
    2.24 +        /// <summary>
    2.25 +        ///   Looks up a localized resource of type System.Drawing.Bitmap.
    2.26 +        /// </summary>
    2.27 +        public static System.Drawing.Bitmap ImageRatingYellow {
    2.28 +            get {
    2.29 +                object obj = ResourceManager.GetObject("ImageRatingYellow", resourceCulture);
    2.30 +                return ((System.Drawing.Bitmap)(obj));
    2.31 +            }
    2.32 +        }
    2.33 +        
    2.34 +        /// <summary>
    2.35 +        ///   Looks up a localized resource of type System.Drawing.Bitmap.
    2.36 +        /// </summary>
    2.37          public static System.Drawing.Bitmap ImageReaderSplash {
    2.38              get {
    2.39                  object obj = ResourceManager.GetObject("ImageReaderSplash", resourceCulture);
     3.1 --- a/Properties/Resources.resx	Thu Jun 22 16:57:39 2017 +0200
     3.2 +++ b/Properties/Resources.resx	Tue Jun 27 16:30:01 2017 +0200
     3.3 @@ -762,4 +762,13 @@
     3.4    <data name="Handshake_ConfirmFingerprint" xml:space="preserve">
     3.5      <value>Confirm fingerprint</value>
     3.6    </data>
     3.7 +  <data name="ImageRatingGreen" type="System.Resources.ResXFileRef, System.Windows.Forms">
     3.8 +    <value>..\resources\imageratinggreen.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
     3.9 +  </data>
    3.10 +  <data name="ImageRatingRed" type="System.Resources.ResXFileRef, System.Windows.Forms">
    3.11 +    <value>..\resources\imageratingred.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
    3.12 +  </data>
    3.13 +  <data name="ImageRatingYellow" type="System.Resources.ResXFileRef, System.Windows.Forms">
    3.14 +    <value>..\resources\imageratingyellow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
    3.15 +  </data>
    3.16  </root>
    3.17 \ No newline at end of file
     4.1 Binary file Resources/ImageRatingGreen.png has changed
     5.1 Binary file Resources/ImageRatingRed.png has changed
     6.1 Binary file Resources/ImageRatingYellow.png has changed
     7.1 --- a/ThisAddIn.cs	Thu Jun 22 16:57:39 2017 +0200
     7.2 +++ b/ThisAddIn.cs	Tue Jun 27 16:30:01 2017 +0200
     7.3 @@ -48,7 +48,6 @@
     7.4          private static SynchronizationContext           _UIThreadSynchronizationContext     = null;
     7.5          private Outlook.Folder                          _PEPStoreRootFolder                 = null;
     7.6          private PEPSettings                             _Settings                           = null;
     7.7 -        private Outlook.Explorers                       _Explorers                          = null;
     7.8  
     7.9  #if !READER_RELEASE_MODE
    7.10          private AdapterCallbacks                        adapterCallbacks                    = null;
    7.11 @@ -59,6 +58,7 @@
    7.12          private FormControlOptions.State                lastOptionsState                    = null;
    7.13          private Dictionary<string, string>              userIdCache                         = new Dictionary<string, string>();
    7.14          private List<WatchedFolder>                     watchedFolders                      = new List<WatchedFolder>();
    7.15 +        private List<WatchedExplorer>                   watchedExplorers                    = new List<WatchedExplorer>();
    7.16          private System.Windows.Forms.Timer              inboxCleaner                        = null;
    7.17          private HashSet<string>                         decryptionList                      = new HashSet<string>();
    7.18          private List<Outlook.Explorer>                  explorerList                        = new List<Outlook.Explorer>();
    7.19 @@ -69,19 +69,10 @@
    7.20           * Property Accessors
    7.21           * 
    7.22           *************************************************************/
    7.23 -
    7.24 -        internal Outlook.Explorers Explorers
    7.25 -        {
    7.26 -            get
    7.27 -            {
    7.28 -                if (this._Explorers == null)
    7.29 -                {
    7.30 -                    this._Explorers = this.Application.Explorers;
    7.31 -                }
    7.32 -
    7.33 -                return this._Explorers;
    7.34 -            }
    7.35 -        }
    7.36 +        /// <summary>
    7.37 +        /// Holds an instance of the application's epxlorers.
    7.38 +        /// </summary>
    7.39 +        internal Outlook.Explorers Explorers { get; set; } = null;
    7.40  
    7.41          /// <summary>
    7.42          /// Gets the list of languages supported in the pEp engine.
    7.43 @@ -2832,7 +2823,6 @@
    7.44              this._Settings = new PEPSettings();
    7.45              this._Settings.LoadFromRegistry();
    7.46              this.SyncAccountsList();
    7.47 -            this.ConnectExplorers();
    7.48  
    7.49  #if !READER_RELEASE_MODE
    7.50              // Connect callbacks, use PEPEngine property accessor in case the engine is not already initialized
    7.51 @@ -2877,6 +2867,8 @@
    7.52                      this.SetOutlookRegistryOptions();
    7.53                      Log.Info("ThisAddIn_Startup: Connect Watched folders");
    7.54                      this.ConnectWatchedFolders();
    7.55 +                    Log.Info("ThisAddIn_Startup: Connect Watched explorers");
    7.56 +                    this.ConnectWatchedExplorers();
    7.57  
    7.58                      // Connect application events
    7.59                      Log.Info("ThisAddIn_Startup: Connect Application Events");
    7.60 @@ -2907,161 +2899,32 @@
    7.61              return;
    7.62          }
    7.63  
    7.64 -        #region Explorer event handling
    7.65 -        private void ConnectExplorers()
    7.66 +        /// <summary>
    7.67 +        /// Connects all explorers with their respective events and the Explorers collection
    7.68 +        /// with the NewExplorer event.
    7.69 +        /// </summary>
    7.70 +        private void ConnectWatchedExplorers()
    7.71          {
    7.72 +            this.Explorers = this.Application.Explorers;
    7.73 +
    7.74              for (int i = 1; i <= this.Explorers.Count; i++)
    7.75              {
    7.76 -                explorerList.Add(this.Explorers[i]);
    7.77 -            }
    7.78 -
    7.79 -            for (int i = 0; i < explorerList.Count; i++)
    7.80 -            {
    7.81 -                this.ConnectExplorerEvents(this.explorerList[i]);
    7.82 +                this.watchedExplorers.Add(new WatchedExplorer(this.Explorers[i]));
    7.83              }
    7.84  
    7.85              this.Explorers.NewExplorer += Explorers_NewExplorer;
    7.86          }
    7.87  
    7.88 -        private void ConnectExplorerEvents(Outlook.Explorer explorer)
    7.89 +        /// <summary>
    7.90 +        /// Event handler for when a new explorer is being opened and 
    7.91 +        /// added to the Explorers collection.
    7.92 +        /// </summary>
    7.93 +        /// <param name="Explorer">The newly opened explorer.</param>
    7.94 +        private void Explorers_NewExplorer(Outlook.Explorer explorer)
    7.95          {
    7.96 -            if (explorer != null)
    7.97 -            {
    7.98 -                ((Outlook.ExplorerEvents_10_Event)explorer).BeforeFolderSwitch += Explorer_BeforeFolderSwitch;
    7.99 -                ((Outlook.ExplorerEvents_10_Event)explorer).Close += Explorer_Close;
   7.100 -                ((Outlook.ExplorerEvents_10_Event)explorer).SelectionChange += Explorer_SelectionChange;
   7.101 -            }
   7.102 +            this.watchedExplorers.Add(new WatchedExplorer(explorer));
   7.103          }
   7.104  
   7.105 -        private void DisconnectExplorerEvents(Outlook.Explorer explorer)
   7.106 -        {
   7.107 -            if (explorer != null)
   7.108 -            {
   7.109 -                ((Outlook.ExplorerEvents_10_Event)explorer).BeforeFolderSwitch -= Explorer_BeforeFolderSwitch;
   7.110 -                ((Outlook.ExplorerEvents_10_Event)explorer).Close -= Explorer_Close;
   7.111 -                ((Outlook.ExplorerEvents_10_Event)explorer).SelectionChange -= Explorer_SelectionChange;
   7.112 -            }
   7.113 -        }
   7.114 -
   7.115 -        private void Explorer_BeforeFolderSwitch(object newFolder, ref bool cancel)
   7.116 -        {
   7.117 -            Outlook.Explorer explorer = null;
   7.118 -            Outlook.Folder currentFolder = null;
   7.119 -            Outlook.Folder newFol = newFolder as Outlook.Folder;
   7.120 -
   7.121 -            if (newFol != null)
   7.122 -            {
   7.123 -                try
   7.124 -                {
   7.125 -                    this.ConnectFolderEvents(newFol);
   7.126 -                    explorer = newFol.GetExplorer();
   7.127 -                    currentFolder = explorer.CurrentFolder as Outlook.Folder;
   7.128 -                    this.DisconnectFolderEvents(currentFolder);
   7.129 -                }
   7.130 -                catch (Exception e)
   7.131 -                {
   7.132 -
   7.133 -                }
   7.134 -                finally
   7.135 -                {
   7.136 -                    explorer = null;
   7.137 -                    currentFolder = null;
   7.138 -                    newFol = null;
   7.139 -                }
   7.140 -            }
   7.141 -        }
   7.142 -
   7.143 -        private void Explorer_Close()
   7.144 -        {
   7.145 -            Outlook.Explorer explorer1 = null;
   7.146 -            Outlook.Explorer explorer2 = null;
   7.147 -
   7.148 -            var explorers = this.Application.Explorers;
   7.149 -
   7.150 -            if (explorers != null)
   7.151 -            {
   7.152 -                for (int i = 0; i < this.explorerList.Count; i++)
   7.153 -                {
   7.154 -                    explorer1 = explorerList[i];
   7.155 -                    bool exists = false;
   7.156 -
   7.157 -                    for (int j = 1; j <= explorers.Count; j++)
   7.158 -                    {
   7.159 -                        explorer2 = explorers[j];
   7.160 -
   7.161 -                        if (explorer1?.Equals(explorer2) ?? false)
   7.162 -                        {
   7.163 -                            exists = true;
   7.164 -                            explorer2 = null;
   7.165 -                            break;
   7.166 -                        }
   7.167 -
   7.168 -                        explorer2 = null;
   7.169 -                    }
   7.170 -
   7.171 -                    if (exists == false)
   7.172 -                    {
   7.173 -                        this.DisconnectExplorerEvents(explorer1);
   7.174 -                        this.explorerList.Remove(explorer1);
   7.175 -                    }
   7.176 -
   7.177 -                    explorer1 = null;
   7.178 -                }
   7.179 -            }
   7.180 -        }
   7.181 -
   7.182 -        private void Explorers_NewExplorer(Outlook.Explorer Explorer)
   7.183 -        {
   7.184 -            this.ConnectExplorerEvents(Explorer);
   7.185 -            explorerList.Add(Explorer);
   7.186 -        }
   7.187 -
   7.188 -        private void Explorer_SelectionChange()
   7.189 -        {
   7.190 -            var exp = this.Application.ActiveExplorer();
   7.191 -            var selection = exp.Selection;
   7.192 -            for (int i = 1; i <= selection.Count; i++)
   7.193 -            {
   7.194 -                var omi = selection[i] as Outlook.MailItem;
   7.195 -                if ((omi != null) &&
   7.196 -                    (AddToEncryptionList(omi.EntryID)))
   7.197 -                {
   7.198 -                    RibbonCustomizations.Invalidate();
   7.199 -
   7.200 -                    var msgContainer = new MsgContainer(omi);
   7.201 -                    var msgProcessor = new MsgProcessor();
   7.202 -
   7.203 -                    omi = null;
   7.204 -
   7.205 -                    msgProcessor.Process(msgContainer);
   7.206 -                }
   7.207 -            }
   7.208 -        }
   7.209 -        #endregion
   7.210 -
   7.211 -        #region Folder event handling
   7.212 -        private void ConnectFolderEvents(Outlook.Folder folder)
   7.213 -        {
   7.214 -            if (folder != null)
   7.215 -            {
   7.216 -                folder.BeforeItemMove += Folder_BeforeItemMove;
   7.217 -            }
   7.218 -        }
   7.219 -
   7.220 -        private void DisconnectFolderEvents(Outlook.Folder folder)
   7.221 -        {
   7.222 -            if (folder != null)
   7.223 -            {
   7.224 -                folder.BeforeItemMove -= Folder_BeforeItemMove;
   7.225 -            }
   7.226 -        }
   7.227 -
   7.228 -        private void Folder_BeforeItemMove(object Item, Outlook.MAPIFolder MoveTo, ref bool Cancel)
   7.229 -        {
   7.230 -            // Look up mirror if available and delete, too.
   7.231 -        }
   7.232 -        #endregion
   7.233 -
   7.234          /// <summary>
   7.235          /// Enables the automatic deletion of old keysync messages if not already enabled.
   7.236          /// This gets automatically disabled again if no keysync messages are found in the inbox.
   7.237 @@ -3445,7 +3308,6 @@
   7.238              string[] idList;
   7.239              Outlook.NameSpace ns = this.Application.Session;
   7.240              Outlook.MailItem omi = null;
   7.241 -            CryptableMailItem cmi;
   7.242  
   7.243              Log.Verbose("Application_NewMailEx: Started processing new items.");
   7.244  
   7.245 @@ -3461,18 +3323,9 @@
   7.246                          // Only process if pEp is enabled
   7.247                          if (omi.GetIsPEPEnabled())
   7.248                          {
   7.249 -                            //cmi = new CryptableMailItem(omi);
   7.250 -
   7.251 -                            ///* Note: Make sure to dispose the MailItem after processing (pass true).
   7.252 -                            // * This is needed as decryption is asynchronous but the MailItem reference still needs to be released.
   7.253 -                            // * Do NOT use omi or cmi references after this point!
   7.254 -                            // */
   7.255 -                            //cmi.StartProcessing(true);
   7.256 -
   7.257                              var msgContainer = new MsgContainer(omi);
   7.258                              var msgProcessor = new MsgProcessor();
   7.259 -                            //msgProcessor.StartProcessing(msgContainer);                           
   7.260 -                            msgProcessor.Process(msgContainer);
   7.261 +                            msgProcessor.ProcessMailItem(msgContainer);
   7.262                          }
   7.263                          else
   7.264                          {
   7.265 @@ -4340,7 +4193,8 @@
   7.266                  bool process = false;
   7.267                  object propValue = null;
   7.268                  Outlook.MailItem omi = null;
   7.269 -                CryptableMailItem cmi;
   7.270 +                MsgContainer msgContainer = null;
   7.271 +                MsgProcessor msgProcessor = null;
   7.272  
   7.273                  try
   7.274                  {
   7.275 @@ -4376,7 +4230,7 @@
   7.276                           * at a later stage, we might run into problems with a loop of copied items that will be processed, copied during creation
   7.277                           * of the mirror, raise an ItemAdd event for the new copy and so on.
   7.278                           */
   7.279 -                        else if (CryptableMailItem.IsInCopiedItemsList(omi?.EntryID) == false)
   7.280 +                        else if (MsgProcessor.IsInCopiedItemsList(omi?.EntryID) == false)
   7.281                          {
   7.282                              // Do not process Sent folders of secure stores (not needed)
   7.283                              if ((omi.GetIsInSecureStore()) &&
   7.284 @@ -4392,22 +4246,24 @@
   7.285                              {
   7.286                                  process = true;
   7.287                              }
   7.288 -
   7.289                          }
   7.290  
   7.291                          if (process)
   7.292                          {
   7.293 -                            cmi = new CryptableMailItem(omi);
   7.294 -
   7.295 -                            /* Note: Make sure to dispose the MailItem after processing (pass true).
   7.296 -                             * This is needed as decryption is asynchronous but the MailItem reference still needs to be released.
   7.297 -                             * Do NOT use omi or cmi references after this point!
   7.298 -                             */
   7.299 -                            cmi.StartProcessing(true);
   7.300 +                            msgContainer = new MsgContainer(omi);
   7.301 +                            msgProcessor = new MsgProcessor();
   7.302 +                            msgProcessor.ProcessMailItem(msgContainer);
   7.303                          }
   7.304                      }
   7.305                  }
   7.306 -                catch { }
   7.307 +                catch (Exception ex)
   7.308 +                {
   7.309 +                    Log.Error("Items_ItemAdd: Error. " + ex.ToString());
   7.310 +                }
   7.311 +                finally
   7.312 +                {
   7.313 +                    omi = null;
   7.314 +                }
   7.315  
   7.316                  return;
   7.317              }
   7.318 @@ -4432,5 +4288,204 @@
   7.319                  return;
   7.320              }
   7.321          }
   7.322 +
   7.323 +
   7.324 +        /// <summary>
   7.325 +        /// Stores an Outlook Explorer with connected events.
   7.326 +        /// </summary>
   7.327 +        private class WatchedExplorer : IDisposable
   7.328 +        {
   7.329 +            /// <summary>
   7.330 +            /// Occurs when the component is disposed by a call to the Dispose method.
   7.331 +            /// </summary>
   7.332 +            public event EventHandler Disposed;
   7.333 +
   7.334 +            private Outlook.Explorer            explorer;
   7.335 +            private Outlook.Folder              currentFolder;
   7.336 +
   7.337 +            /**************************************************************
   7.338 +             * 
   7.339 +             * Constructors/Destructors
   7.340 +             * 
   7.341 +             *************************************************************/
   7.342 +
   7.343 +            /// <summary>
   7.344 +            /// Primary constructor.
   7.345 +            /// </summary>
   7.346 +            /// <param name="explorer">The explorer to watch.</param>
   7.347 +            public WatchedExplorer(Outlook.Explorer explorer)
   7.348 +            {
   7.349 +                this.explorer = explorer;
   7.350 +
   7.351 +                if (this.explorer != null)
   7.352 +                {
   7.353 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close += WatchedExplorer_Close;
   7.354 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).SelectionChange += WatchedExplorer_SelectionChange;
   7.355 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).BeforeFolderSwitch += WatchedExplorer_BeforeFolderSwitch;
   7.356 +
   7.357 +                    this.currentFolder = this.explorer.CurrentFolder as Outlook.Folder;
   7.358 +                    this.ConnectFolderEvents(this.currentFolder);
   7.359 +                }
   7.360 +            }
   7.361 +
   7.362 +            /// <summary>
   7.363 +            /// Destructor.
   7.364 +            /// </summary>
   7.365 +            ~WatchedExplorer()
   7.366 +            {
   7.367 +                this.Dispose();
   7.368 +            }
   7.369 +
   7.370 +            /**************************************************************
   7.371 +             * 
   7.372 +             * Methods
   7.373 +             * 
   7.374 +             *************************************************************/
   7.375 +
   7.376 +            /// <summary>
   7.377 +            /// Releases all resources and disconnects internal events.
   7.378 +            /// </summary>
   7.379 +            public void Dispose()
   7.380 +            {
   7.381 +                if (this.explorer != null)
   7.382 +                {
   7.383 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close -= WatchedExplorer_Close;
   7.384 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).SelectionChange -= WatchedExplorer_SelectionChange;
   7.385 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).BeforeFolderSwitch -= WatchedExplorer_BeforeFolderSwitch;
   7.386 +
   7.387 +                    this.DisconnectFolderEvents(this.currentFolder);
   7.388 +
   7.389 +                    this.explorer = null;
   7.390 +                }
   7.391 +
   7.392 +                // Raise the disposed event
   7.393 +                if (this.Disposed != null)
   7.394 +                    this.Disposed.Invoke(this, new EventArgs());
   7.395 +
   7.396 +                return;
   7.397 +            }
   7.398 +
   7.399 +            /**************************************************************
   7.400 +             * 
   7.401 +             * Event Handling
   7.402 +             * 
   7.403 +             *************************************************************/
   7.404 +
   7.405 +            private void WatchedExplorer_BeforeFolderSwitch(object newFolder, ref bool cancel)
   7.406 +            {
   7.407 +                this.DisconnectFolderEvents(this.currentFolder);
   7.408 +                this.currentFolder = newFolder as Outlook.Folder;
   7.409 +                this.ConnectFolderEvents(this.currentFolder);
   7.410 +            }
   7.411 +
   7.412 +            private void WatchedExplorer_Close()
   7.413 +            {
   7.414 +                Outlook.Explorer explorer = null;
   7.415 +
   7.416 +                try
   7.417 +                {
   7.418 +                    for (int i = 0; i < Globals.ThisAddIn?.watchedExplorers?.Count; i++)
   7.419 +                    {
   7.420 +                        explorer = Globals.ThisAddIn?.watchedExplorers[i]?.explorer;
   7.421 +
   7.422 +                        if (explorer?.Equals(this.explorer) ?? false)
   7.423 +                        {
   7.424 +                            Globals.ThisAddIn.watchedExplorers.Remove(Globals.ThisAddIn?.watchedExplorers[i]);
   7.425 +                            i--;
   7.426 +                        }
   7.427 +
   7.428 +                        explorer = null;
   7.429 +                    }
   7.430 +                }
   7.431 +                catch (Exception e)
   7.432 +                {
   7.433 +                    Log.Error("WatchedExplorer_Close: Error removing explorer. " + e.ToString());
   7.434 +                }
   7.435 +                finally
   7.436 +                {
   7.437 +                    explorer = null;
   7.438 +                }
   7.439 +
   7.440 +                this.Dispose();
   7.441 +            }
   7.442 +
   7.443 +            private void WatchedExplorer_SelectionChange()
   7.444 +            {
   7.445 +                Outlook.MailItem omi = null;
   7.446 +                Outlook.Selection selection = null;
   7.447 +
   7.448 +                try
   7.449 +                {
   7.450 +                    // Process the newly selected item
   7.451 +                    selection = this.explorer.Selection;
   7.452 +
   7.453 +                    /* Do only process the item if one individual item is selected.
   7.454 +                     * Do not process a selected range of items.
   7.455 +                     */
   7.456 +                    if (selection.Count == 1)
   7.457 +                    {
   7.458 +                        omi = selection[1] as Outlook.MailItem;
   7.459 +
   7.460 +                        // If the item cannot be added to the encryption list,
   7.461 +                        // this means that it is already being decrypted.
   7.462 +                        if ((omi != null) &&
   7.463 +                            (Globals.ThisAddIn.AddToEncryptionList(omi.EntryID)))
   7.464 +                        {
   7.465 +                            // Create message container
   7.466 +                            var msgContainer = new MsgContainer(omi);
   7.467 +
   7.468 +                            // Process mail item
   7.469 +                            var msgProcessor = new MsgProcessor();
   7.470 +                            msgProcessor.ProcessMailItem(msgContainer, true);
   7.471 +                        }
   7.472 +                    }
   7.473 +                }
   7.474 +                catch (Exception e)
   7.475 +                {
   7.476 +                    Log.Error("Explorer_SelectionChange: Error. " + e.Message);
   7.477 +                }
   7.478 +                finally
   7.479 +                {
   7.480 +                    omi = null;
   7.481 +                    selection = null;
   7.482 +                }
   7.483 +            }
   7.484 +
   7.485 +            /// <summary>
   7.486 +            /// Connects the given folder with all its events.
   7.487 +            /// </summary>
   7.488 +            /// <param name="folder">The folder to connect its events.</param>
   7.489 +            private void ConnectFolderEvents(Outlook.Folder folder)
   7.490 +            {
   7.491 +                if (folder != null)
   7.492 +                {
   7.493 +                    folder.BeforeItemMove += Folder_BeforeItemMove;
   7.494 +                }
   7.495 +            }
   7.496 +
   7.497 +            /// <summary>
   7.498 +            /// Disconnects the given folder from all its events.
   7.499 +            /// </summary>
   7.500 +            /// <param name="folder">The folder to disconnect its events.</param>
   7.501 +            private void DisconnectFolderEvents(Outlook.Folder folder)
   7.502 +            {
   7.503 +                if (folder != null)
   7.504 +                {
   7.505 +                    folder.BeforeItemMove -= Folder_BeforeItemMove;
   7.506 +                }
   7.507 +            }
   7.508 +
   7.509 +            /// <summary>
   7.510 +            /// Event handler for when an item is moved from one folder to another.
   7.511 +            /// This is used to detect the deletion of a mail item.
   7.512 +            /// </summary>
   7.513 +            /// <param name="Item">The item being moved.</param>
   7.514 +            /// <param name="MoveTo">The folder the item is moved to.</param>
   7.515 +            /// <param name="Cancel">Whether to cancel the event.</param>
   7.516 +            private void Folder_BeforeItemMove(object Item, Outlook.MAPIFolder MoveTo, ref bool Cancel)
   7.517 +            {
   7.518 +                // Look up mirror if available and delete, too.
   7.519 +            }
   7.520 +        }
   7.521      }
   7.522  }
     8.1 --- a/UI/RibbonCustomizations.cs	Thu Jun 22 16:57:39 2017 +0200
     8.2 +++ b/UI/RibbonCustomizations.cs	Tue Jun 27 16:30:01 2017 +0200
     8.3 @@ -418,13 +418,13 @@
     8.4                  case pEpRating.pEpRatingMistrust:
     8.5                  case pEpRating.pEpRatingB0rken:
     8.6                  case pEpRating.pEpRatingUnderAttack:
     8.7 -                    return Properties.Resources.ImagePrivacyStatusRed;
     8.8 +                    return Properties.Resources.ImageRatingRed;
     8.9                  case pEpRating.pEpRatingReliable:
    8.10 -                    return Properties.Resources.ImagePrivacyStatusYellow;
    8.11 +                    return Properties.Resources.ImageRatingYellow;
    8.12                  case pEpRating.pEpRatingTrusted:
    8.13                  case pEpRating.pEpRatingTrustedAndAnonymized:
    8.14                  case pEpRating.pEpRatingFullyAnonymous:
    8.15 -                    return Properties.Resources.ImagePrivacyStatusGreen;
    8.16 +                    return Properties.Resources.ImageRatingGreen;
    8.17                  case pEpRating.pEpRatingUndefined:
    8.18                  case pEpRating.pEpRatingCannotDecrypt:
    8.19                  case pEpRating.pEpRatingHaveNoKey:
    8.20 @@ -491,7 +491,25 @@
    8.21          /// </summary>
    8.22          public bool ButtonPEPRating_GetVisible(Office.IRibbonControl control)
    8.23          {
    8.24 -            return (false); // Unimplemented
    8.25 +            switch (RibbonCustomizations.Rating)
    8.26 +            {
    8.27 +                case pEpRating.pEpRatingMistrust:
    8.28 +                case pEpRating.pEpRatingB0rken:
    8.29 +                case pEpRating.pEpRatingUnderAttack:
    8.30 +                case pEpRating.pEpRatingReliable:
    8.31 +                case pEpRating.pEpRatingTrusted:
    8.32 +                case pEpRating.pEpRatingTrustedAndAnonymized:
    8.33 +                case pEpRating.pEpRatingFullyAnonymous:
    8.34 +                    return true;
    8.35 +                case pEpRating.pEpRatingCannotDecrypt:
    8.36 +                case pEpRating.pEpRatingHaveNoKey:
    8.37 +                case pEpRating.pEpRatingUnencrypted:
    8.38 +                case pEpRating.pEpRatingUnencryptedForSome:
    8.39 +                case pEpRating.pEpRatingUnreliable:
    8.40 +                case pEpRating.pEpRatingUndefined:
    8.41 +                default:
    8.42 +                    return false;
    8.43 +            }
    8.44          }
    8.45  
    8.46  
     9.1 --- a/UI/RibbonCustomizationsExplorer.xml	Thu Jun 22 16:57:39 2017 +0200
     9.2 +++ b/UI/RibbonCustomizationsExplorer.xml	Tue Jun 27 16:30:01 2017 +0200
     9.3 @@ -19,12 +19,13 @@
     9.4          </group>
     9.5          <group id="ThePEPButton"
     9.6                 insertAfterMso="GroupSendReceive"
     9.7 +               getVisible="ButtonPEPRating_GetVisible"
     9.8                 label="p≡p">
     9.9            <button id="ButtonPEPRating"
    9.10                    size="large"
    9.11                    getImage="ButtonPEPRating_GetImage"
    9.12                    getLabel="ButtonPEPRating_GetLabel"
    9.13 -                  getSupertip="ButtonPEPRating_GetSupertip"
    9.14 +                  getSupertip="ButtonPEPRating_GetSupertip"                  
    9.15                    onAction="ButtonPEPRating_Click" />
    9.16          </group>
    9.17        </tab>
    10.1 --- a/pEpForOutlook.csproj	Thu Jun 22 16:57:39 2017 +0200
    10.2 +++ b/pEpForOutlook.csproj	Tue Jun 27 16:30:01 2017 +0200
    10.3 @@ -531,6 +531,9 @@
    10.4      <Resource Include="Resources\ImagePrivacyStatusNoColorInvert.png" />
    10.5      <Resource Include="Resources\ImagePrivacyStatusRedInvert.png" />
    10.6      <Resource Include="Resources\ImagePrivacyStatusYellowInvert.png" />
    10.7 +    <Resource Include="Resources\ImageRatingGreen.png" />
    10.8 +    <Resource Include="Resources\ImageRatingRed.png" />
    10.9 +    <Resource Include="Resources\ImageRatingYellow.png" />
   10.10      <Content Include="Resources\ImageReaderSplash.png" />
   10.11      <Content Include="Resources\ImageUpgradePEP.png" />
   10.12      <Resource Include="Resources\ImageNeverUnsecureOff.png" />