ThisAddIn.cs
author Thomas
Mon, 25 Mar 2019 13:27:16 +0100
branchsync
changeset 2610 09fde2338362
parent 2594 b4351ec5c330
parent 2607 8a9eddf5347a
child 2627 47eb50143f2a
permissions -rw-r--r--
Merge with default
     1 using pEp.Extensions;
     2 using pEp.UI;
     3 using pEpCOMServerAdapterLib;
     4 using System;
     5 using System.Collections.Generic;
     6 using System.ComponentModel;
     7 using System.Globalization;
     8 using System.IO;
     9 using System.Runtime.InteropServices;
    10 using System.Threading.Tasks;
    11 using System.Windows.Forms;
    12 using Office = Microsoft.Office.Core;
    13 using Outlook = Microsoft.Office.Interop.Outlook;
    14 
    15 namespace pEp
    16 {
    17     public partial class ThisAddIn
    18     {
    19         #region VSTO generated code
    20 
    21         /// <summary>
    22         /// Required method for Designer support - do not modify
    23         /// the contents of this method with the code editor.
    24         /// </summary>
    25         private void InternalStartup()
    26         {
    27             this.Startup += new System.EventHandler(ThisAddIn_Startup);
    28             this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
    29         }
    30 
    31         #endregion
    32 
    33         /// <summary>
    34         /// Custom event for when the add-in is starting for the first time.
    35         /// </summary>
    36         internal event EventHandler FirstStartup;
    37 
    38         private List<KeyValuePair<CultureInfo, string>> _LanguageList       = null;
    39         private static pEpEngine                        _PEPEngine          = null;
    40         private static Exception                        _PEPEngineException = null;
    41         private Outlook.Folder                          _PEPStoreRootFolder = null;
    42         private PEPSettings                             _Settings           = null;
    43         private OutlookOptions                          _OutlookOptions     = null;
    44         private static DecryptionStack                  _DecryptionStack    = null;
    45 
    46 #if !READER_RELEASE_MODE
    47         private AdapterCallbacks adapterCallbacks = null;
    48 #endif
    49 
    50         private bool                        initialized                 = false;
    51         private bool                        isItemSendHandlerEnabled    = true;
    52         private FormControlOptions.State    lastOptionsState            = null;
    53         private List<WatchedFolder>         watchedFolders              = new List<WatchedFolder>();
    54         private System.Windows.Forms.Timer  inboxCleaner                = null;
    55 
    56         private List<WatchedExplorer>       watchedExplorers            = new List<WatchedExplorer>();
    57         private List<WatchedInspector>      watchedInspectors           = new List<WatchedInspector>();
    58         private object                      mutexWatchedExplorers       = new object();
    59         private object                      mutexWatchedInspectors      = new object();
    60         private Outlook.Explorers           explorers                   = null;
    61         private Outlook.Inspectors          inspectors                  = null;
    62 
    63         /**************************************************************
    64          * 
    65          * Property Accessors
    66          * 
    67          *************************************************************/
    68 
    69         /// <summary>
    70         /// Gets the list of languages supported in the pEp engine.
    71         /// The list of language includes a key-value pair of the culture as well as a 
    72         /// display phrase in the native language for the trustwords.
    73         /// (phrase example: "I want to display the trustwords in English language")
    74         /// </summary>
    75         internal List<KeyValuePair<CultureInfo, string>> LanguageList
    76         {
    77             get
    78             {
    79                 string code;
    80                 string phrase;
    81                 string engineList;
    82                 string[] languages;
    83                 string[] language;
    84 
    85                 if (this._LanguageList == null)
    86                 {
    87                     this._LanguageList = new List<KeyValuePair<CultureInfo, string>>();
    88 
    89                     try
    90                     {
    91                         engineList = ThisAddIn.PEPEngine.GetLanguageList();
    92                     }
    93                     catch
    94                     {
    95                         engineList = "";
    96                         Log.Error("LanguageList: Failed to get list from engine.");
    97                     }
    98 
    99                     languages = engineList.Split('\n');
   100 
   101                     // Go through each language group
   102                     for (int i = 0; i < languages.Length; i++)
   103                     {
   104                         language = languages[i].Split(',');
   105 
   106                         if (language.Length == 3)
   107                         {
   108                             code = language[0].Trim();
   109                             code = code.Replace("\"", "");
   110 
   111                             phrase = language[1].Trim();
   112                             phrase = phrase.Replace("\"", "");
   113 
   114                             this._LanguageList.Add(new KeyValuePair<CultureInfo, string>(new CultureInfo(code),
   115                                                                                          phrase));
   116                         }
   117                     }
   118                 }
   119 
   120                 return (this._LanguageList);
   121             }
   122         }
   123 
   124         /// <summary>
   125         /// Gets the static pEp engine reference.
   126         /// </summary>
   127         internal static pEpEngine PEPEngine
   128         {
   129             get
   130             {
   131                 if (ThisAddIn._PEPEngine == null)
   132                 {
   133                     try
   134                     {
   135                         ThisAddIn._PEPEngine = new pEpEngine();
   136                     }
   137                     catch (Exception ex)
   138                     {
   139                         // As Globals.StopAndSendCrashReport below internally tries to access the engine
   140                         // several times, we need to prevent infinite recursion in case of engine
   141                         // initializaition failure.
   142                         if (_PEPEngineException != null)
   143                             return null;
   144                         _PEPEngineException = ex;
   145 
   146                         string summaryMessage = Properties.Resources.Message_InitError + " " +
   147                                                 Properties.Resources.Message_Reinstall;
   148                         Globals.StopAndSendCrashReport(ex, summaryMessage, false, true);
   149 
   150                         return (null);
   151                     }
   152                 }
   153 
   154                 return (ThisAddIn._PEPEngine);
   155             }
   156         }
   157 
   158         /// <summary>
   159         /// Gets the root folder of the pEp data store.
   160         /// This is primarily used to save unencrypted outlook mail items (mirrors).
   161         /// </summary>
   162         internal Outlook.Folder PEPStoreRootFolder
   163         {
   164             get { return (this._PEPStoreRootFolder); }
   165         }
   166 
   167         /// <summary>
   168         /// Gets the current pEp settings for the add-in.
   169         /// </summary>
   170         internal PEPSettings Settings
   171         {
   172             get { return (this._Settings); }
   173         }
   174 
   175         /// <summary>
   176         /// Gets the Outlook options set in the program.
   177         /// </summary>
   178         internal OutlookOptions OutlookOptions
   179         {
   180             get { return (this._OutlookOptions); }
   181         }
   182 
   183         /// <summary>
   184         /// Gets the decryption stack.
   185         /// </summary>
   186         internal static DecryptionStack DecryptionStack
   187         {
   188             get
   189             {
   190                 if (ThisAddIn._DecryptionStack == null)
   191                 {
   192                     ThisAddIn._DecryptionStack = new DecryptionStack();
   193                 }
   194 
   195                 return ThisAddIn._DecryptionStack;
   196             }
   197         }
   198 
   199         /**************************************************************
   200          * 
   201          * Methods
   202          * 
   203          *************************************************************/
   204 
   205         /// <summary>
   206         /// Required override to add ribbon extensions.
   207         /// </summary>
   208         protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
   209         {
   210             return new RibbonCustomizations();
   211         }
   212 
   213         /// <summary>
   214         /// Adds a new WatchedExplorer to the list of watched explorers.
   215         /// </summary>
   216         /// <param name="watchedExplorer">The WatchedExplorer to add.</param>
   217         internal void AddToWatchedExplorers(WatchedExplorer watchedExplorer)
   218         {
   219             lock (mutexWatchedExplorers)
   220             {
   221                 this.watchedExplorers.Add(watchedExplorer);
   222             }
   223         }
   224 
   225         /// <summary>
   226         /// Adds a new WatchedInspector to the list of watched inspectors.
   227         /// </summary>
   228         /// <param name="watchedInspector">The WatchedInspector to add.</param>
   229         internal void AddToWatchedInspectors(WatchedInspector watchedInspector)
   230         {
   231             lock (mutexWatchedInspectors)
   232             {
   233                 this.watchedInspectors.Add(watchedInspector);
   234             }
   235         }
   236 
   237         /// <summary>
   238         /// Removes a WatchedExplorer from the list of watched explorers.
   239         /// </summary>
   240         /// <param name="watchedExplorer">The WatchedExplorer to remove.</param>
   241         internal void RemoveFromWatchedExplorers(WatchedExplorer watchedExplorer)
   242         {
   243             lock (mutexWatchedExplorers)
   244             {
   245                 this.watchedExplorers.Remove(watchedExplorer);
   246             }
   247         }
   248 
   249         /// <summary>
   250         /// Removes a WatchedInspector from the list of watched inspectors.
   251         /// </summary>
   252         /// <param name="WatchedInspector">The WatchedInspector to remove.</param>
   253         internal void RemoveFromWatchedInspectors(WatchedInspector watchedInspector)
   254         {
   255             lock (mutexWatchedInspectors)
   256             {
   257                 this.watchedInspectors.Remove(watchedInspector);
   258             }
   259         }
   260 
   261         /// <summary>
   262         /// Gets the WatchedExplorer or WatchedInspector in which the given mail item resides.
   263         /// </summary>
   264         /// <param name="omi">The Outlook mail item to process with.</param>
   265         /// <returns>The WatchedExplorer or WatchedInspector the mail item resides in or null if an error occured.</returns>
   266         internal WatchedWindow GetWatchedParentWindow(Outlook.MailItem omi)
   267         {
   268             try
   269             {
   270                 // First, check all watched explorers
   271                 foreach (var watchedExplorer in this.watchedExplorers)
   272                 {
   273                     if (watchedExplorer?.CurrentMailItem?.MAPIOBJECT?.Equals(omi?.MAPIOBJECT) == true)
   274                     {
   275                         return watchedExplorer;
   276                     }
   277                 }
   278 
   279                 // If window hasn't been found yet, check inspectors
   280                 foreach (var watchedInspector in this.watchedInspectors)
   281                 {
   282                     if (watchedInspector?.CurrentMailItem?.MAPIOBJECT?.Equals(omi?.MAPIOBJECT) == true)
   283                     {
   284                         return watchedInspector;
   285                     }
   286                 }
   287             }
   288             catch (Exception ex)
   289             {
   290                 Log.Error("GetWatchedParentWindow: Error getting window. " + ex.ToString());
   291             }
   292 
   293             // If no window has been found, return null
   294             return null;
   295         }
   296 
   297         /// <summary>
   298         /// Gets the watched window for an Inspector or Explorer object.
   299         /// </summary>
   300         /// <param name="window">The Inspector or Explorer window to get its WatchedWindow for.</param>
   301         /// <returns>The watched window or null if not found.</returns>
   302         internal WatchedWindow GetWatchedWindow(dynamic window)
   303         {
   304             Outlook.Explorer explorer = null;
   305             Outlook.Inspector inspector = null;
   306             WatchedWindow watchedWindow = null;
   307 
   308             try
   309             {
   310                 // First, try if window is an explorer
   311                 explorer = window as Outlook.Explorer;
   312                 if (explorer != null)
   313                 {
   314                     if (this.watchedExplorers.Count == 1)
   315                     {
   316                         watchedWindow = this.watchedExplorers[0];
   317                     }
   318                     else
   319                     {
   320                         foreach (var watchedExplorer in this.watchedExplorers)
   321                         {
   322                             if (watchedExplorer?.Explorer?.Equals(explorer) == true)
   323                             {
   324                                 watchedWindow = watchedExplorer;
   325                                 break;
   326                             }
   327                         }
   328                     }
   329                 }
   330                 else
   331                 {
   332                     // If window is no explorer, try if it is an inspector
   333                     inspector = window as Outlook.Inspector;
   334                     if (inspector != null)
   335                     {
   336                         if (this.watchedInspectors.Count == 1)
   337                         {
   338                             watchedWindow = this.watchedInspectors[0];
   339                         }
   340                         else
   341                         {
   342                             foreach (var watchedInspector in this.watchedInspectors)
   343                             {
   344                                 if (watchedInspector?.Inspector?.Equals(inspector) == true)
   345                                 {
   346                                     watchedWindow = watchedInspector;
   347                                     break;
   348                                 }
   349                             }
   350                         }
   351                     }
   352                 }
   353             }
   354             catch (Exception ex)
   355             {
   356                 Log.Error("GetWatchedWindow: Error occured. " + ex.ToString());
   357             }
   358             finally
   359             {
   360                 explorer = null;
   361                 inspector = null;
   362             }
   363 
   364             return watchedWindow;
   365         }
   366 
   367         /// <summary>
   368         /// This updates the accounts list in pEp settings with the ones found in Outlook, adding new accounts and removing
   369         /// all accounts that are not there anymore.
   370         /// </summary>
   371         internal void SyncAccountsList()
   372         {
   373             bool accountAdded = false;
   374             bool exists;
   375             string dialogMessage = string.Empty;
   376             Outlook.NameSpace ns = null;
   377             Outlook.Account account = null;
   378             Outlook.Accounts accounts = null;
   379             Outlook.Store store = null;
   380             Outlook.Stores stores = null;
   381             PEPSettings.PEPAccountSettings acctSettings;
   382             List<string> sharedAccountStores = new List<string>();
   383 
   384             try
   385             {
   386                 ns = Application.Session;
   387                 accounts = ns?.Accounts;
   388 
   389                 if (this._Settings != null)
   390                 {
   391                     // Add any new Outlook accounts to the account settings list
   392                     for (int i = 1; i <= accounts.Count; i++)
   393                     {
   394                         account = accounts[i];
   395 
   396                         if (string.IsNullOrWhiteSpace(account.SmtpAddress) == false)
   397                         {
   398                             // Check if it is already in the list
   399                             var accountSettings = this._Settings.GetAccountSettings(account.SmtpAddress);
   400                             if (accountSettings == null)
   401                             {
   402                                 // Create pEp settings for the new account
   403                                 account.CreatePEPSettings();
   404                                 accountAdded = true;
   405                             }
   406                             else
   407                             {
   408                                 // Check for properties that might have not been set correctly due to errors
   409                                 // UserName
   410                                 if (string.IsNullOrEmpty(accountSettings.UserName))
   411                                 {
   412                                     try
   413                                     {
   414                                         accountSettings.UserName = account.UserName;
   415                                     }
   416                                     catch (Exception ex)
   417                                     {
   418                                         Log.Error("SyncAccountsList: Error adding user name. " + ex.ToString());
   419                                     }
   420                                 }
   421                             }
   422                         }
   423                         else
   424                         {
   425                             Log.Warning("SyncAccountsList: Invalid Smtp address detected, skipping account.");
   426                         }
   427 
   428                         account = null;
   429                     }
   430 
   431                     // Add shared mail boxes
   432                     stores = ns?.Stores;
   433                     for (int i = 1; i <= stores.Count; i++)
   434                     {
   435                         store = stores[i];
   436                         if (store.ExchangeStoreType == Outlook.OlExchangeStoreType.olExchangeMailbox)
   437                         {
   438                             if (store.GetSmtpAddress(out string address, out string userName))
   439                             {
   440                                 if (this.Settings.GetAccountSettings(address) == null)
   441                                 {
   442                                     // Add to account settings if necessary
   443                                     Log.Verbose("GetSmtpAddress: Adding shared account " + address);
   444                                     this.Settings.AccountSettingsList.Add(new PEPSettings.PEPAccountSettings()
   445                                     {
   446                                         SmtpAddress = address,
   447                                         IsSecureStorageEnabled = false,
   448                                         IsSyncEnabled = false,
   449                                         Type = Outlook.OlAccountType.olExchange.ToString(),
   450                                         UserName = userName
   451                                     });
   452 
   453                                     accountAdded = true;
   454                                 }
   455 
   456                                 sharedAccountStores.Add(address);
   457                             }
   458                         }
   459                     }
   460 
   461                     // Remove any entries of the account settings list not in Outlook
   462                     // This is needed to skip any entries in the registry that may be invalid, user created, or no longer in Outlook
   463                     for (int i = (this._Settings.AccountSettingsList.Count - 1); i >= 0; i--)
   464                     {
   465                         acctSettings = this._Settings.AccountSettingsList[i];
   466 
   467                         // Check if it exists in Outlook
   468                         exists = false;
   469                         for (int j = 1; j <= accounts.Count; j++)
   470                         {
   471                             account = accounts[j];
   472 
   473                             if (acctSettings.EqualsByAddress(account.SmtpAddress))
   474                             {
   475                                 exists = true;
   476                             }
   477 
   478                             account = null;
   479 
   480                             if (exists)
   481                             {
   482                                 break;
   483                             }
   484                         }
   485 
   486                         // Delete if necessary
   487                         if ((exists == false) &&
   488                             (Globals.ThisAddIn.Settings?.AccountsAddedWhileRunningList?.Contains(acctSettings?.SmtpAddress) != true) &&
   489                             (sharedAccountStores.Contains(acctSettings.SmtpAddress) == false))
   490                         {
   491                             this._Settings.AccountSettingsList.RemoveAt(i);
   492                         }
   493                     }
   494 
   495                     if (accountAdded)
   496                     {
   497                         // Set view filters and rules
   498                         this.SetRulesAndViewFilters(this._Settings?.HideInternalMessages ?? PEPSettings.HIDE_INTERNAL_MESSAGES_DEFAULT);
   499                     }
   500                 }
   501             }
   502             catch (Exception ex)
   503             {
   504                 Log.Error("SyncAccountsList: Error occured. " + ex.ToString());
   505             }
   506             finally
   507             {
   508                 ns = null;
   509                 account = null;
   510                 accounts = null;
   511             }
   512         }
   513 
   514         /// <summary>
   515         /// Syncronizes the current settings class with the pEp for Outlook instance and the pEp engine.
   516         /// Warning: This code should be kept synchronized with the Settings_PropertyChanged event.
   517         /// <param name="syncAccountsList">Whether to also update the accounts list in pEp settings. 
   518         /// </summary>
   519         internal void SyncWithSettings(bool syncAccountsList = false)
   520         {
   521             bool exists;
   522             string dialogMessage = string.Empty;
   523             pEpIdentity[] ownIdentities;
   524             List<KeyValuePair<CultureInfo, string>> languages;
   525 
   526             try
   527             {
   528                 if (this._Settings != null)
   529                 {
   530                     // Update the Outlook accounts list with the one maintained in pEp settings if needed.
   531                     if (syncAccountsList)
   532                     {
   533                         this.SyncAccountsList();
   534                     }
   535 
   536                     /* Sync the account settings with the engine's own identity flags.
   537                      * Warning: RegisterMyself() must already have been called so the engine has all own identities.
   538                      * The engine can commonly have more own identities than what is in the accounts list.
   539                      * This isn't a problem though and engine-only identities will not be changed here.
   540                      */
   541                     ownIdentities = ThisAddIn.PEPEngine.OwnIdentitiesRetrieve();
   542                     foreach (PEPSettings.PEPAccountSettings acctSettings in this._Settings.AccountSettingsList)
   543                     {
   544                         // Find the own identity that matches with the account settings
   545                         foreach (pEpIdentity ident in ownIdentities)
   546                         {
   547                             pEpIdentity ownIdent = ident;
   548 
   549                             if (acctSettings.EqualsByAddress(ownIdent.Address))
   550                             {
   551                                 // Sync the engine's own identity flags with the account or global settings
   552                                 if (this._Settings.IsSyncEnabledForAllAccounts)
   553                                 {
   554                                     if (ownIdent.GetIsSyncEnabled() == false)
   555                                     {
   556                                         ThisAddIn.PEPEngine.UnsetIdentityFlags(ref ownIdent, pEpIdentityFlags.pEpIdfNotForSync);
   557                                     }
   558                                 }
   559                                 else if (ownIdent.GetIsSyncEnabled() != acctSettings.IsSyncEnabled)
   560                                 {
   561                                     if (acctSettings.IsSyncEnabled)
   562                                     {
   563                                         ThisAddIn.PEPEngine.UnsetIdentityFlags(ref ownIdent, pEpIdentityFlags.pEpIdfNotForSync);
   564                                     }
   565                                     else
   566                                     {
   567                                         ThisAddIn.PEPEngine.SetIdentityFlags(ref ownIdent, pEpIdentityFlags.pEpIdfNotForSync);
   568                                     }
   569                                 }
   570                                 break;
   571                             }
   572                         }
   573                     }
   574 
   575                     // Sync IsKeyServerUsed with engine
   576                     if (this._Settings.IsKeyServerUsed)
   577                     {
   578                         ThisAddIn.PEPEngine.StartKeyserverLookup();
   579                     }
   580                     else
   581                     {
   582                         ThisAddIn.PEPEngine.StopKeyserverLookup();
   583                     }
   584 
   585                     // Sync IsPassiveModeEnabled with engine
   586                     ThisAddIn.PEPEngine.PassiveMode(this._Settings.IsPassiveModeEnabled);
   587 
   588                     // Sync IsPEPFolderVisible with Outlook
   589                     this.SetPEPStoreRootFolderVisibility(this._Settings.IsPEPFolderVisible);
   590 
   591                     // Sync IsUnencryptedSubjectEnabled with engine
   592                     ThisAddIn.PEPEngine.UnencryptedSubject(this._Settings.IsUnencryptedSubjectEnabled);
   593 
   594                     // Sync IsVerboseLoggingEnabled with engine
   595                     ThisAddIn.PEPEngine.VerboseLogging(this._Settings.IsVerboseLoggingEnabled);
   596 
   597                     // Sync TrustwordsCulture with engine
   598                     if (this._Settings.TrustwordsCulture != null)
   599                     {
   600                         // Validate it exists in the engine list
   601                         exists = false;
   602                         languages = this.LanguageList;
   603                         foreach (KeyValuePair<CultureInfo, string> entry in languages)
   604                         {
   605                             if (entry.Key.LCID == this._Settings.TrustwordsCulture.LCID)
   606                             {
   607                                 exists = true;
   608                                 break;
   609                             }
   610                         }
   611 
   612                         if (exists == false)
   613                         {
   614                             // Reset to default
   615                             this._Settings.TrustwordsCulture = this.GetActiveUICulture();
   616                             Log.Warning("SyncWithSettings: Invalid TrustwordsCulture detected, setting to default.");
   617                         }
   618                     }
   619                     else
   620                     {
   621                         // Reset to default
   622                         this._Settings.TrustwordsCulture = this.GetActiveUICulture();
   623                     }
   624                 }
   625             }
   626             catch (Exception ex)
   627             {
   628                 Log.Error("SyncWithSettings: Failure occured, " + ex.ToString());
   629             }
   630         }
   631 
   632         /// <summary>
   633         /// Compares the given settings with the current state of Outlook and detects any changes.
   634         /// This is currently only used to identify first startup.
   635         /// </summary>
   636         /// <param name="lastSettings">The last settings to compare with. 
   637         /// This should be the settings just loaded from the registry at startup (last saved settings).</param>
   638         private void DetectChangesFromLastSettings(PEPSettings lastSettings)
   639         {
   640             // Detect first startup
   641             if (lastSettings.IsFirstStartupComplete == false)
   642             {
   643                 this.FirstStartup?.Invoke(this, new EventArgs());
   644             }
   645         }
   646 
   647         /// <summary>
   648         /// Detects and disables GPG for Windows GpgOL Outlook add-in.
   649         /// </summary>
   650         /// <returns>True if the GpgOL add-in was disabled.</returns>
   651         private bool DisableGpgOL()
   652         {
   653             bool wasDisabled = false;
   654             Office.COMAddIns comAddIns = null;
   655 
   656             try
   657             {
   658                 comAddIns = Globals.ThisAddIn.Application.COMAddIns;
   659                 foreach (Office.COMAddIn addin in comAddIns)
   660                 {
   661                     if (string.Equals(addin.Description, "GpgOL - The GnuPG Outlook Plugin", StringComparison.OrdinalIgnoreCase))
   662                     {
   663                         addin.Connect = false;
   664                         wasDisabled = true;
   665 
   666                         Log.Info("DisableGpgOL: GpgOL was detected and disabled.");
   667                     }
   668                 }
   669             }
   670             catch (Exception ex)
   671             {
   672                 Log.Error("DisableGpgOL: Error trying to disable GpgOL, " + ex.ToString());
   673             }
   674             finally
   675             {
   676                 if (comAddIns != null)
   677                 {
   678                     // Marshal.ReleaseComObject(comAddIns);
   679                     comAddIns = null;
   680                 }
   681             }
   682 
   683             return (wasDisabled);
   684         }
   685 
   686         /// <summary>
   687         /// Sends a request to recalculate the message rating of all open windows (except one) again.
   688         /// </summary>
   689         /// <param name="windowToExclude">The window to not calculate its rating for</param>
   690         internal void RecalculateAllWindows(WatchedWindow windowToExclude)
   691         {
   692             for (int i = 0; i < this.watchedExplorers.Count; i++)
   693             {
   694                 if ((windowToExclude as WatchedExplorer)?.Equals(this.watchedExplorers[i]) != true)
   695                 {
   696                     this.watchedExplorers[i].RequestRatingAndUIUpdate();
   697                 }
   698             }
   699 
   700             for (int i = 0; i < this.watchedInspectors.Count; i++)
   701             {
   702                 if ((windowToExclude as WatchedInspector)?.Equals(this.watchedInspectors[i]) != true)
   703                 {
   704                     this.watchedInspectors[i].RequestRatingAndUIUpdate();
   705                 }
   706             }
   707         }
   708 
   709         /// <summary>
   710         /// Registers each own identity in the pEp engine.
   711         /// An own identity represents each account in Outlook.
   712         /// </summary>
   713         internal void RegisterMyself()
   714         {
   715             if (Globals.ThisAddIn.Settings.AccountSettingsList != null)
   716             {
   717                 foreach (var acctSettings in Globals.ThisAddIn.Settings.AccountSettingsList)
   718                 {
   719                     this.RegisterMyself(acctSettings);
   720                 }
   721             }
   722         }
   723 
   724         /// <summary>
   725         /// Registers a pEpIdentity in the pEp engine.
   726         /// </summary>
   727         internal void RegisterMyself(PEPSettings.PEPAccountSettings acctSettings)
   728         {
   729             pEpIdentity ownIdentity;
   730 
   731             if (acctSettings != null)
   732             {
   733                 // Create pEpIdentity
   734                 ownIdentity = new pEpIdentity
   735                 {
   736                     Address = acctSettings.SmtpAddress,
   737                     UserId = PEPSettings.PEP_OWN_USER_ID,
   738                     UserName = acctSettings.UserName
   739                 };
   740 
   741                 // Set not for sync flag if necessary
   742                 if ((acctSettings.Type.Contains("Imap")) ||
   743                     ((Globals.ThisAddIn.Settings.IsSyncEnabledForAllAccounts == false) &&
   744                      (acctSettings.IsSyncEnabled == false)))
   745                 {
   746                     ownIdentity.Flags = pEpIdentityFlags.pEpIdfNotForSync;
   747                 }
   748 
   749                 // Log information if invalid
   750                 if (string.IsNullOrWhiteSpace(ownIdentity.Address))
   751                 {
   752                     Log.Warning("RegisterMyself: Myself doesn't have an address.");
   753                 }
   754 
   755                 if (string.IsNullOrWhiteSpace(ownIdentity.UserName))
   756                 {
   757                     Log.Warning("RegisterMyself: Myself doesn't have a user name.");
   758                 }
   759 
   760                 /* Call engine to register myself (doesn't matter if already done in a past instance)
   761                  * Note that key generation can take place during the call to Myself if it's a new installation
   762                  * and the engine is unable to elect a key. In this situation key generation can take some time.
   763                  * It takes long-enough for the call to the adapter to timeout here and throw an exception.
   764                  * However, since the fingerprint of the own identity is not actually needed here, the assumption is 
   765                  * made that the engine will be OK and continue processing.
   766                  * The exception is simply ignored and we go to the next identity. 
   767                  */
   768                 try
   769                 {
   770                     ThisAddIn.PEPEngine.Myself(ownIdentity);
   771                 }
   772                 catch (COMException ex)
   773                 {
   774                     Log.Warning("RegisterMyself: Engine returned exception, " + ex.ToString());
   775                 }
   776             }
   777             else
   778             {
   779                 Log.Error("RegisterMyself: account settings are null.");
   780             }
   781         }
   782 
   783         /// <summary>
   784         /// Create a new Outlook MailItem from the given PEPMessage and send it.
   785         /// The sent message will not be processed by the 'Application_ItemSend' event.
   786         /// WARNING: Exchange ActiveSync accounts ignore the deleteAfterSend parameter (always false).
   787         /// </summary>
   788         /// <param name="message">The message to send.</param>
   789         /// <param name="deleteAfterSend">Whether the message is deleted after sending (true) or a copy is saved (false).</param>
   790         /// <param name="validateSendingAccount">Validates that the SendingAccount matches the From identity of the given message.
   791         /// This can catch situations (and throw exceptions) where the default account would be used instead.</param>
   792         /// <param name="processMessage">Whether or not to process this message through the pEp engine.</param>
   793         internal void CreateAndSendMessage(PEPMessage message,
   794                                            bool deleteAfterSend,
   795                                            bool validateSendingAccount,
   796                                            bool processMessage = false)
   797         {
   798             Outlook.MailItem newItem;
   799             Globals.ReturnStatus sts;
   800 
   801             this.isItemSendHandlerEnabled = processMessage;
   802 
   803             try
   804             {
   805                 newItem = Application.CreateItem(Outlook.OlItemType.olMailItem);
   806 
   807                 /* Notes:
   808                  * Do NOT include internal Header Fields (MAPI properties) on outgoing messages!
   809                  * The sender must be set from the from identity (setSender=true)
   810                  */
   811                 sts = message.ApplyTo(newItem, false, true);
   812 
   813                 if (sts == Globals.ReturnStatus.Success)
   814                 {
   815                     // Check that the sending account is the From identity
   816                     if ((validateSendingAccount) &&
   817                         (message.From != null))
   818                     {
   819                         if (newItem.SetSendUsingAccount(message.From.Address) == false)
   820                         {
   821                             throw new Exception("Sending account does not match from identity or error setting Send account");
   822                         }
   823                     }
   824 
   825                     // Do not allow TNEF/RTF format with 'winmail.dat' attachment
   826                     MapiHelper.SetProperty(newItem, MapiProperty.PidLidUseTnef, false);
   827 
   828                     // If ForceUnencrypted property is set, add it to mail item (only if message is to be processed)
   829                     if (processMessage && 
   830                         message.ForceUnencrypted)
   831                     {
   832                         newItem.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, true);
   833                     }
   834 
   835                     /* Send
   836                      * 
   837                      * Note: For ActiveSync accounts, the DeleteAfterSubmit property is ignored.
   838                      * This means the message will always appear in the sent folder by default.
   839                      * The reason for this is unknown.
   840                      * 
   841                      * It's possible this is related to the ActiveSync specification version
   842                      * and therefore may behave differently depending on Outlook version.
   843                      * More research is needed here.
   844                      */
   845                     newItem.DeleteAfterSubmit = deleteAfterSend;
   846                     ((Outlook._MailItem)newItem).Send();
   847 
   848                     newItem = null;
   849                 }
   850                 else
   851                 {
   852                     newItem.PermanentlyDelete();
   853                     newItem = null;
   854 
   855                     throw new Exception("Failed to create MailItem to send");
   856                 }
   857             }
   858             catch
   859             {
   860                 throw new Exception("CreateMessageAndSend: Failed to send MailItem.");
   861             }
   862             finally
   863             {
   864                 this.isItemSendHandlerEnabled = true;
   865             }
   866         }
   867 
   868         /// <summary>
   869         /// Create a new 'sent' Outlook MailItem and place it in the given store.
   870         /// WARNING: Exchange ActiveSync accounts are not supported by this method. The sent
   871         /// message will always appear in the drafts folder.
   872         /// </summary>
   873         /// <param name="sendingStore">The store to save the sent message to.</param>
   874         /// <param name="acctSettings">The sending account settings.</param>
   875         /// <param name="sentMessage">The message that is sent.</param>
   876         /// <param name="storedRating">The rating to store to the sent message mail item.
   877         /// Will only be set if not undefined (default). Warning: Only use this on trusted servers.</param>
   878         private void CreateNewSentMail(Outlook.Store sendingStore,
   879                                        PEPSettings.PEPAccountSettings acctSettings,
   880                                        PEPMessage sentMessage,
   881                                        pEpRating storedRating = pEpRating.pEpRatingUndefined)
   882         {
   883             Int32 messageFlags;
   884             Outlook.MailItem sentMailItem = null;
   885             Outlook.Folder sentFolder = null;
   886             Outlook.NameSpace ns = Application.Session;
   887             Outlook.Folder rootFolder = null;
   888             Outlook.Folders folders = null;
   889             Outlook.Folder folder = null;
   890 
   891             /* The process is:
   892              * 1. Use the Store.GetDefaultFolder(olFolderSentMail) to try to get the default Sent folder. 
   893              *    However, this can fail for a number of reasons, depending on server and folder configuration.
   894              * 2. As a fallback, search for the Sent folder by matching the Sent folder Entry ID
   895              *    However, this can also fail if no Sent folder Entry ID has been recorded.
   896              * 3. As another fallback, search by Folder name ("SENT") for an existing Sent folder
   897              *    If found, record the folder's Entry ID. If not, goto point 4.
   898              * 4. If everything of the above fails, create a new Sent folder and record the Entry ID.     
   899              */
   900 
   901             try
   902             {
   903                 if ((sendingStore != null) &&
   904                     (acctSettings != null) &&
   905                     (sentMessage != null))
   906                 {
   907                     rootFolder = (Outlook.Folder)sendingStore.GetRootFolder();
   908                     if (rootFolder != null)
   909                     {
   910                         folders = rootFolder.Folders;
   911                     }
   912 
   913                     // Step 1
   914                     try
   915                     {
   916                         sentFolder = (Outlook.Folder)sendingStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
   917                     }
   918                     catch
   919                     {
   920                         if (sentFolder != null)
   921                         {
   922                             // Marshal.ReleaseComObject(sentFolder);
   923                             sentFolder = null;
   924                         }
   925                     }
   926 
   927                     // Step 2
   928                     if (sentFolder == null)
   929                     {
   930                         try
   931                         {
   932                             /* Search for folder by entry ID
   933                              * Normally, the way to go would be the following line:
   934                              * sentFolder = (Outlook.Folder)ns.GetItemFromID(acctSettings.SentFolderEntryId, sendingStore.StoreID);
   935                              * However, for some reason, this can come up with the following error: "Could not open the item. Try again."
   936                              * Therefore, the below solution is used:
   937                              */
   938                             if (folders != null)
   939                             {
   940                                 for (int i = 1; i <= folders.Count; i++)
   941                                 {
   942                                     folder = (Outlook.Folder)folders[i];
   943 
   944                                     if (folder != null)
   945                                     {
   946                                         if ((string.IsNullOrEmpty(folder.EntryID) == false) &&
   947                                             (string.Equals(folder.EntryID, acctSettings.SentFolderEntryId)))
   948                                         {
   949                                             sentFolder = folder;
   950                                             break;
   951                                         }
   952 
   953                                         // Marshal.ReleaseComObject(folder);
   954                                         folder = null;
   955                                     }
   956                                 }
   957                             }
   958                         }
   959                         catch
   960                         {
   961                             if (sentFolder != null)
   962                             {
   963                                 // Marshal.ReleaseComObject(sentFolder);
   964                                 sentFolder = null;
   965                             }
   966                         }
   967                     }
   968 
   969                     // Step 3
   970                     if (sentFolder == null)
   971                     {
   972                         try
   973                         {
   974                             //Search for folder by name
   975                             if (folders != null)
   976                             {
   977                                 for (int i = 1; i <= folders.Count; i++)
   978                                 {
   979                                     folder = (Outlook.Folder)folders[i];
   980 
   981                                     if (folder != null)
   982                                     {
   983                                         if ((string.IsNullOrEmpty(folder.Name) == false) &&
   984                                             (folder.Name.Trim().StartsWith(Globals.CUSTOM_SENT_FOLDER_NAME, StringComparison.OrdinalIgnoreCase)))
   985                                         {
   986                                             sentFolder = folder;
   987                                             break;
   988                                         }
   989 
   990                                         // Marshal.ReleaseComObject(folder);
   991                                         folder = null;
   992                                     }
   993                                 }
   994                             }
   995                         }
   996                         catch
   997                         {
   998                             if (sentFolder != null)
   999                             {
  1000                                 // Marshal.ReleaseComObject(sentFolder);
  1001                                 sentFolder = null;
  1002                             }
  1003                         }
  1004                     }
  1005 
  1006                     // Step 4
  1007                     if (sentFolder == null)
  1008                     {
  1009                         try
  1010                         {
  1011                             // Create folder
  1012                             if (folders != null)
  1013                             {
  1014                                 sentFolder = (Outlook.Folder)folders.Add(Globals.CUSTOM_SENT_FOLDER_NAME);
  1015                             }
  1016                         }
  1017                         catch (Exception ex)
  1018                         {
  1019                             if (sentFolder != null)
  1020                             {
  1021                                 // Marshal.ReleaseComObject(sentFolder);
  1022                                 sentFolder = null;
  1023                             }
  1024 
  1025                             Log.Error("CreateNewSentMail: No Sent folder found and no new Sent folder could be created because of the following error: " + ex.ToString());
  1026                         }
  1027                     }
  1028 
  1029                     if (sentFolder != null)
  1030                     {
  1031                         acctSettings.SentFolderEntryId = sentFolder.EntryID;
  1032 
  1033                         // Create the basic sent mail item
  1034                         sentMailItem = (Outlook.MailItem)sentFolder.Items.Add(Outlook.OlItemType.olMailItem);
  1035                         sentMessage.ApplyTo(sentMailItem, false, true); // Do NOT include internal Header Fields (MAPI properties)!
  1036 
  1037                         // Set the date and time the mail item was sent
  1038                         try
  1039                         {
  1040                             MapiHelper.SetProperty(sentMailItem, MapiProperty.PidTagClientSubmitTime, DateTime.Now.ToUniversalTime());
  1041                         }
  1042                         catch { }
  1043 
  1044                         // Set flags
  1045                         try
  1046                         {
  1047                             messageFlags = (System.Int32)MapiHelper.GetProperty(sentMailItem, MapiProperty.PidTagMessageFlags);
  1048                             messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
  1049                             messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
  1050                             MapiHelper.SetProperty(sentMailItem, MapiProperty.PidTagMessageFlags, messageFlags);
  1051                         }
  1052                         catch { }
  1053 
  1054                         // Save pEp rating
  1055                         try
  1056                         {
  1057                             sentMailItem.SetPEPProperty(MailItemExtensions.PEPProperty.Rating, storedRating);
  1058                         }
  1059                         catch { }
  1060 
  1061                         // Save changes to the mail item (must be done last for some properties)
  1062                         sentMailItem.Save();
  1063 
  1064                         /* Attempt to move to the sent folder.
  1065                          * For ActiveSync accounts, this will fail with the error:
  1066                          * 'Sorry, Exchange ActiveSync doesn't support what you're trying to do.'
  1067                          * This is because the .Items.Add(folder) will ignore the specified folder and create in local Drafts.
  1068                          * Then "Exchange ActiveSync doesn’t support the Drafts folder" so it can't be moved out.
  1069                          * Even in the Outlook UI a draft cannot be 'dragged' out of the drafts folder.
  1070                          */
  1071                         try
  1072                         {
  1073                             sentMailItem.Move(sentFolder);
  1074                         }
  1075                         catch { }
  1076                     }
  1077                 }
  1078             }
  1079             catch (Exception ex)
  1080             {
  1081                 Log.Error("CreateNewSentMail: Error occured, " + ex.ToString());
  1082                 throw;
  1083             }
  1084             finally
  1085             {
  1086                 folder = null;
  1087                 folders = null;
  1088                 ns = null;
  1089                 rootFolder = null;
  1090                 sentFolder = null;
  1091                 sentMailItem = null;
  1092             }
  1093         }
  1094 
  1095         /// <summary>
  1096         /// Gets whether the given account is trusted (on the account whitelist).
  1097         /// Character case and whitespace is ignored during comparison.
  1098         /// </summary>
  1099         /// <param name="address">The address of the account.</param>
  1100         /// <returns>True if the account with the given address is trusted by default (on the whitelist), otherwise false.</returns>
  1101         private bool GetIsAccountTrusted(string address)
  1102         {
  1103             bool isTrusted = false;
  1104             string searchAddress = address.ToUpperInvariant().Trim();
  1105             string searchDomain = searchAddress.Contains("@") ? searchAddress.Substring(searchAddress.LastIndexOf("@")) : null;
  1106             string whitelistAccount;
  1107 
  1108             for (int i = 0; i < this._Settings.AccountWhitelist.Length; i++)
  1109             {
  1110                 whitelistAccount = this._Settings.AccountWhitelist[i].ToUpperInvariant().Trim();
  1111 
  1112                 // Check for exact match
  1113                 if (searchAddress == whitelistAccount)
  1114                 {
  1115                     isTrusted = true;
  1116                     break;
  1117                 }
  1118 
  1119                 // Check for domain match
  1120                 if ((searchDomain != null) &&
  1121                     whitelistAccount.StartsWith("@") &&
  1122                     (searchDomain == whitelistAccount))
  1123                 {
  1124                     isTrusted = true;
  1125                     break;
  1126                 }
  1127             }
  1128 
  1129             return (isTrusted);
  1130         }
  1131 
  1132         /// <summary>
  1133         /// Copies any necessary data from the given options form state back into this add-ins current state.
  1134         /// The registry is also updated by this method.
  1135         /// </summary>
  1136         /// <param name="state">The state to copy data from.</param>
  1137         internal void SetOptionsState(FormControlOptions.State state)
  1138         {
  1139             bool isBlacklisted;
  1140             string fpr1;
  1141             string fpr2;
  1142             string[] blacklist;
  1143             PEPSettings.PEPAccountSettings acctSettings;
  1144 
  1145             if (state != null)
  1146             {
  1147                 // Get the blacklist
  1148                 try
  1149                 {
  1150                     blacklist = ThisAddIn.PEPEngine.BlacklistRetrieve();
  1151                 }
  1152                 catch (COMException ex)
  1153                 {
  1154                     blacklist = new string[0];
  1155                     Log.Error("SetOptionsState: Error getting blacklist from engine. " + ex.ToString());
  1156                 }
  1157 
  1158                 // Remove any fingerprints no longer in the engine blacklist
  1159                 if (blacklist != null)
  1160                 {
  1161                     for (int i = (blacklist.Length - 1); i >= 0; i--)
  1162                     {
  1163                         fpr1 = this.RemoveFprFormatting(blacklist[i]);
  1164                         isBlacklisted = false;
  1165 
  1166                         if (string.IsNullOrEmpty(fpr1) == false)
  1167                         {
  1168                             // Check if fingerprint is still blacklisted
  1169                             foreach (KVPair<PEPIdentity, bool> entry in state.Blacklist)
  1170                             {
  1171                                 fpr2 = this.RemoveFprFormatting(entry.Key.Fingerprint);
  1172 
  1173                                 // Value is true if the entry is blacklisted
  1174                                 if ((string.Equals(fpr1, fpr2, StringComparison.OrdinalIgnoreCase)) &&
  1175                                     (entry.Value))
  1176                                 {
  1177                                     isBlacklisted = true;
  1178                                     break;
  1179                                 }
  1180                             }
  1181 
  1182                             if (isBlacklisted == false)
  1183                             {
  1184                                 try
  1185                                 {
  1186                                     ThisAddIn.PEPEngine.BlacklistDelete(fpr1);
  1187                                 }
  1188                                 catch (COMException ex)
  1189                                 {
  1190                                     Log.Error("SetOptionsState: Failed to delete blacklist entry, " + ex.ToString());
  1191                                 }
  1192                             }
  1193                         }
  1194                     }
  1195                 }
  1196 
  1197                 // Add any new fingerprints to the engine blacklist
  1198                 foreach (KVPair<PEPIdentity, bool> entry in state.Blacklist)
  1199                 {
  1200                     fpr1 = this.RemoveFprFormatting(entry.Key.Fingerprint);
  1201 
  1202                     // Value is true if the entry is blacklisted
  1203                     if ((entry.Value) &&
  1204                         (string.IsNullOrEmpty(fpr1) == false))
  1205                     {
  1206                         try
  1207                         {
  1208                             if (ThisAddIn.PEPEngine.BlacklistIsListed(fpr1) == false)
  1209                             {
  1210                                 ThisAddIn.PEPEngine.BlacklistAdd(fpr1);
  1211                             }
  1212                         }
  1213                         catch (COMException ex)
  1214                         {
  1215                             Log.Error("SetOptionsState: Failed to add new blacklist entry, " + ex.ToString());
  1216                         }
  1217                     }
  1218                 }
  1219 
  1220                 foreach (FormControlOptions.AccountState entry in state.AccountSettingsList)
  1221                 {
  1222                     /* pEp internally uses account types as defined by microsoft.
  1223                      * This means they have 'ol' before the type (Example: 'olImap').
  1224                      * This isn't always user friendly so for the options UI the 'ol' is removed.
  1225                      * However, when comparing again with the settings list, this 'ol' must be added back.
  1226                      */
  1227                     acctSettings = this._Settings.GetAccountSettings(entry.SmtpAddress);
  1228 
  1229                     if (acctSettings != null)
  1230                     {
  1231                         // Modify existing value
  1232                         // The following are skipped: SentFolderEntryId, SmtpAddress & Type
  1233                         acctSettings.IsDecryptAlwaysEnabled = entry.IsDecryptAlwaysEnabled;
  1234                         acctSettings.IsPEPEnabled = entry.IsPEPEnabled;
  1235                         acctSettings.IsSecureStorageEnabled = entry.IsSecureStorageEnabled;
  1236                         acctSettings.IsSyncEnabled = entry.IsSyncEnabled;
  1237                     }
  1238                     else
  1239                     {
  1240                         Log.Warning("SetOptionsState: Existing account settings not found.");
  1241                     }
  1242                 }
  1243 
  1244                 // Un/set rules and view filters if necessary
  1245                 if (state.HideInternalMessages != this._Settings.HideInternalMessages)
  1246                 {
  1247                     this.SetRules(state.HideInternalMessages);
  1248                 }
  1249                 this._Settings.HideInternalMessages = state.HideInternalMessages;
  1250 
  1251                 this._Settings.IsAutoUpdateEnabled = state.IsAutoUpdateEnabled;
  1252                 this._Settings.IsEncryptAllAccountsEnabled = state.IsEncryptAllAccountsEnabled;
  1253                 this._Settings.IsKeyServerUsed = state.IsKeyServerUsed;
  1254                 this._Settings.IsNeverUnsecureOptionVisible = state.IsNeverUnsecureOptionVisible;
  1255                 this._Settings.IsPassiveModeEnabled = state.IsPassiveModeEnabled;
  1256                 this._Settings.IsPEPFolderVisible = state.IsPEPFolderVisible;
  1257                 this._Settings.IsPrivacyStatusBarEnabled = state.IsPrivacyStatusBarEnabled;
  1258                 this._Settings.IsSecurityLossWarningEnabled = state.IsSecurityLossWarningEnabled;
  1259                 this._Settings.IsSyncEnabledForAllAccounts = state.IsSyncEnabledForAllAccounts;
  1260                 this._Settings.IsUnencryptedSubjectEnabled = state.IsUnencryptedSubjectEnabled;
  1261                 this._Settings.IsVerboseLoggingEnabled = state.IsVerboseLoggingEnabled;
  1262                 this._Settings.TrustwordsCulture = ((state.TrustwordsCulture != null) ? new CultureInfo(state.TrustwordsCulture.LCID) : null);
  1263 
  1264                 // Save last state for next options opening
  1265                 this.lastOptionsState = state.Copy();
  1266 
  1267                 // Update registry (in case of unforseen app shutdown)
  1268                 this._Settings.SaveToRegistry();
  1269             }
  1270         }
  1271 
  1272         /// <summary>
  1273         /// Builds a new options form state using this add-ins current state.
  1274         /// </summary>
  1275         /// <returns>A new options form state.</returns>
  1276         internal FormControlOptions.State GetOptionsState()
  1277         {
  1278             bool isDefaultStore = false;
  1279             bool exists;
  1280             string fpr1;
  1281             string fpr2;
  1282             string[] blacklist;
  1283             StringPair[] keylist;
  1284             PEPIdentity newIdent;
  1285             PEPSettings.PEPAccountSettings newAcctSettings;
  1286             FormControlOptions.State state;
  1287             Outlook.NameSpace ns = this.Application.Session;
  1288             Outlook.Store defaultStore = null;
  1289 
  1290             // Check if pEp is the default store
  1291             try
  1292             {
  1293                 defaultStore = ns.DefaultStore;
  1294                 isDefaultStore = (defaultStore.StoreID == this._PEPStoreRootFolder.StoreID);
  1295             }
  1296             catch
  1297             {
  1298                 isDefaultStore = false;
  1299             }
  1300 
  1301             // Load from last state if possible
  1302             if (this.lastOptionsState != null)
  1303             {
  1304                 state = this.lastOptionsState.Copy();
  1305             }
  1306             else
  1307             {
  1308                 state = new FormControlOptions.State();
  1309             }
  1310 
  1311             // Get complete OpenPGP key list
  1312             try
  1313             {
  1314                 keylist = ThisAddIn.PEPEngine.OpenPGPListKeyinfo(null);
  1315             }
  1316             catch (COMException ex)
  1317             {
  1318                 keylist = new StringPair[0];
  1319                 Log.Error("GetOptionsState: Error getting OpenPGP keylist from engine. " + ex.ToString());
  1320             }
  1321 
  1322             // Get the blacklist
  1323             try
  1324             {
  1325                 blacklist = ThisAddIn.PEPEngine.BlacklistRetrieve();
  1326             }
  1327             catch (COMException ex)
  1328             {
  1329                 blacklist = new string[0];
  1330                 Log.Error("GetOptionsState: Error getting blacklist from engine. " + ex.ToString());
  1331             }
  1332 
  1333             // Add the OpenPGP keylist to the UI blacklist
  1334             state.Blacklist.Clear();
  1335             if (keylist != null)
  1336             {
  1337                 foreach (StringPair ident in keylist)
  1338                 {
  1339                     fpr1 = this.RemoveFprFormatting(ident.Name);
  1340                     exists = false;
  1341 
  1342                     if (string.IsNullOrEmpty(fpr1) == false)
  1343                     {
  1344                         // Check if it exists in the blacklist
  1345                         if (blacklist != null)
  1346                         {
  1347                             foreach (string fpr in blacklist)
  1348                             {
  1349                                 fpr2 = this.RemoveFprFormatting(fpr);
  1350 
  1351                                 if (string.Equals(fpr1, fpr2, StringComparison.OrdinalIgnoreCase))
  1352                                 {
  1353                                     exists = true;
  1354                                     break;
  1355                                 }
  1356                             }
  1357                         }
  1358 
  1359                         // Build entry to add
  1360                         newIdent = PEPIdentity.Parse(ident.Value);
  1361                         newIdent.Fingerprint = this.ToQuadruple(fpr1, false);
  1362 
  1363                         state.Blacklist.Add(new KVPair<PEPIdentity, bool>(newIdent, exists));
  1364                     }
  1365                 }
  1366             }
  1367 
  1368             // Add any fingerprints that exist only in the engine blacklist to the UI blacklist
  1369             if (blacklist != null)
  1370             {
  1371                 foreach (string fpr in blacklist)
  1372                 {
  1373                     fpr1 = this.RemoveFprFormatting(fpr);
  1374                     exists = false;
  1375 
  1376                     // Check if it already exists in the UI blacklist by fingerprint
  1377                     foreach (KVPair<PEPIdentity, bool> entry in state.Blacklist)
  1378                     {
  1379                         fpr2 = this.RemoveFprFormatting(entry.Key.Fingerprint);
  1380 
  1381                         if (string.Equals(fpr1, fpr2, StringComparison.OrdinalIgnoreCase))
  1382                         {
  1383                             exists = true;
  1384                             break;
  1385                         }
  1386                     }
  1387 
  1388                     if (exists == false)
  1389                     {
  1390                         newIdent = new PEPIdentity
  1391                         {
  1392                             Fingerprint = this.ToQuadruple(fpr1, false)
  1393                         };
  1394 
  1395                         // Always put at the beginning so it's easier for the user to find
  1396                         state.Blacklist.Insert(0, new KVPair<PEPIdentity, bool>(newIdent, true));
  1397                     }
  1398                 }
  1399             }
  1400 
  1401             state.BlacklistEnteredFingerprint = null;
  1402             state.BlacklistSelectedIndex = -1;
  1403 
  1404             // Build AccountSettingsList
  1405             state.AccountSettingsList.Clear();
  1406             for (int i = 0; i < this._Settings.AccountSettingsList.Count; i++)
  1407             {
  1408                 newAcctSettings = this._Settings.AccountSettingsList[i].Copy();
  1409 
  1410                 /* pEp internally uses account types as defined by microsoft.
  1411                  * This means they have 'ol' before the type (Example: 'olImap').
  1412                  * This isn't always user friendly so for the options UI the 'ol' is removed.
  1413                  */
  1414                 if ((string.IsNullOrEmpty(newAcctSettings.Type) == false) &&
  1415                     (newAcctSettings.Type.StartsWith("ol", StringComparison.OrdinalIgnoreCase)))
  1416                 {
  1417                     newAcctSettings.Type = newAcctSettings.Type.Substring(2);
  1418                 }
  1419 
  1420                 state.AccountSettingsList.Add(new FormControlOptions.AccountState(newAcctSettings));
  1421             }
  1422 
  1423             state.HideInternalMessages = this._Settings.HideInternalMessages;
  1424             state.IsAutoUpdateEnabled = this._Settings.IsAutoUpdateEnabled;
  1425             state.IsDeveloperModeEnabled = this._Settings.IsDeveloperModeEnabled;
  1426             state.IsEncryptAllAccountsEnabled = this._Settings.IsEncryptAllAccountsEnabled;
  1427             state.IsKeyServerUsed = this._Settings.IsKeyServerUsed;
  1428             state.IsNeverUnsecureOptionVisible = this._Settings.IsNeverUnsecureOptionVisible;
  1429             state.IsPassiveModeEnabled = this._Settings.IsPassiveModeEnabled;
  1430             state.IsPEPFolderDefaultStore = isDefaultStore;
  1431             state.IsPEPFolderVisible = (isDefaultStore ? true : this._Settings.IsPEPFolderVisible);
  1432             state.IsPrivacyStatusBarEnabled = this._Settings.IsPrivacyStatusBarEnabled;
  1433             state.IsSecurityLossWarningEnabled = this._Settings.IsSecurityLossWarningEnabled;
  1434             state.IsSyncEnabledForAllAccounts = this._Settings.IsSyncEnabledForAllAccounts;
  1435             state.IsTNEFDisabled = this._Settings.IsTNEFDisabled;
  1436             state.IsUnencryptedSubjectEnabled = this._Settings.IsUnencryptedSubjectEnabled;
  1437             state.IsVerboseLoggingEnabled = this._Settings.IsVerboseLoggingEnabled;
  1438             state.PEPCopyright = Globals.PEP_COPYRIGHT;
  1439             state.PEPName = (Globals.RELEASE_MODE == Globals.ReleaseMode.Reader ? Globals.PEP_DISPLAY_NAME_READER : Globals.PEP_DISPLAY_NAME);
  1440             state.SystemInfo = Globals.GetSystemInfoList();
  1441             state.TrustwordsCulture = ((this._Settings.TrustwordsCulture != null) ? new CultureInfo(this._Settings.TrustwordsCulture.LCID) : null);
  1442 
  1443             // Release objects
  1444             defaultStore = null;
  1445             ns = null;
  1446 
  1447             return (state);
  1448         }
  1449 
  1450         /// <summary>
  1451         /// Connects events for folder/item detection in Outlook.
  1452         /// Included folders are:
  1453         ///  • Default Sent folders for only ActiveSync accounts
  1454         ///  • Default Inbox folders for all accounts
  1455         /// </summary>
  1456         private void ConnectWatchedFolders()
  1457         {
  1458             Outlook.Store store = null;
  1459             Outlook.Stores stores = null;
  1460             Outlook.Folder folder = null;
  1461             Outlook.NameSpace ns = null;
  1462 
  1463             try
  1464             {
  1465                 ns = this.Application.Session;
  1466                 stores = ns.Stores;
  1467 
  1468                 for (int i = 1; i <= stores.Count; i++)
  1469                 {
  1470                     // Note: accessing the stores can fail if the data file is missing or is in use by another program. 
  1471                     try
  1472                     {
  1473                         store = stores[i];
  1474                     }
  1475                     catch (Exception ex)
  1476                     {
  1477                         Log.Warning("ConnectWatchedFolders: Failed to get store, " + ex.ToString());
  1478                     }
  1479 
  1480                     if (store != null)
  1481                     {
  1482                         // Add default inbox folder
  1483                         folder = null;
  1484                         try
  1485                         {
  1486                             folder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
  1487                         }
  1488                         catch (Exception ex)
  1489                         {
  1490                             if (folder != null)
  1491                             {
  1492                                 // Marshal.ReleaseComObject(folder);
  1493                                 folder = null;
  1494                             }
  1495 
  1496                             Log.Warning("ConnectWatchedFolders: Failure getting default inbox folder. " + ex.ToString());
  1497                         }
  1498 
  1499                         // Add the folder to the watched list (do not release it)
  1500                         if (folder != null)
  1501                         {
  1502                             this.watchedFolders.Add(new WatchedFolder(folder, Outlook.OlDefaultFolders.olFolderInbox));
  1503                         }
  1504 
  1505                         // Add Sent folder. This is needed so sent mails get decrypted on trusted servers to make the search function working
  1506                         try
  1507                         {
  1508                             folder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
  1509                         }
  1510                         catch (Exception ex)
  1511                         {
  1512                             if (folder != null)
  1513                             {
  1514                                 // Marshal.ReleaseComObject(folder);
  1515                                 folder = null;
  1516                             }
  1517 
  1518                             Log.Warning("ConnectWatchedFolders: Failure getting default sent folder. " + ex.ToString());
  1519                         }
  1520 
  1521                         // Add the folder to the watched list (do not release it)
  1522                         if (folder != null)
  1523                         {
  1524                             this.watchedFolders.Add(new WatchedFolder(folder, Outlook.OlDefaultFolders.olFolderSentMail));
  1525                         }
  1526 
  1527                         //Marshal.ReleaseComObject(store);
  1528                         store = null;
  1529                     }
  1530                 }
  1531             }
  1532             catch (Exception ex)
  1533             {
  1534                 Log.Error("ConnectWatchedFolders: Failure occured, " + ex.ToString());
  1535             }
  1536             finally
  1537             {
  1538                 ns = null;
  1539                 store = null;
  1540                 stores = null;
  1541             }
  1542         }
  1543 
  1544         /// <summary>
  1545         /// Opens the pEp data store root folder and saves the reference for further use.
  1546         /// If none already exists, a new one is created.
  1547         /// </summary>
  1548         private void OpenPEPStoreRootFolder()
  1549         {
  1550             Outlook.Store pEpStore = null;
  1551             Outlook.Store store = null;
  1552             Outlook.Stores stores = null;
  1553             Outlook.NameSpace ns = null;
  1554 
  1555             try
  1556             {
  1557                 // The path to store the pEp store to
  1558                 string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "pEp", (Globals.PEP_DATA_FILE_NAME + ".pst"));
  1559                 
  1560                 /* For Outlook installations from the Windows Trusted Store the AddStoreEx function to add a store seems to
  1561                  * convert "%LOCALAPPDATA%" to "%LOCALAPPDATA\Packages\Microsoft.Office.Desktop_8wekyb3d8bbwe\LocalCache\Local\".
  1562                  * This is also confirmed on several sites/blogs. No official documentation has been found so far, though.
  1563                  * In any case, we also use the above mentioned path to search for the pEp store.
  1564                  */
  1565                 string winStorePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Packages", "Microsoft.Office.Desktop_8wekyb3d8bbwe", "LocalCache", "Local", "pEp", (Globals.PEP_DATA_FILE_NAME + ".pst"));
  1566 
  1567                 ns = this.Application.Session;
  1568                 stores = ns.Stores;
  1569 
  1570                 // Try to find an existing store based on file name
  1571                 for (int i = 1; i <= stores.Count; i++)
  1572                 {
  1573                     /* Note: accessing the stores can fail if the data file is missing or is in use by another program. 
  1574                      * This is usually OK as long as it isn't the pEp file.
  1575                      * However, here the assumption is made that any error is not the pEp file and execution will continue.
  1576                      * If for some reason the error prevents detecting an existing pEp.pst file, this will be caught in the next step.
  1577                      */
  1578                     try
  1579                     {
  1580                         store = stores[i];
  1581                     }
  1582                     catch (Exception ex)
  1583                     {
  1584                         Log.Warning("OpenPEPStoreRootFolder: Failed to get store, " + ex.ToString());
  1585                     }
  1586 
  1587                     if ((store?.FilePath?.Equals(path) == true) ||
  1588                         (store?.FilePath?.Equals(winStorePath) == true))
  1589                     {
  1590                         pEpStore = store;
  1591                         break;
  1592                     }
  1593 
  1594                     store = null;
  1595                 }
  1596 
  1597                 // If no store was found, create new 
  1598                 if (pEpStore == null)
  1599                 {
  1600                     /* Create the file and add it as a store, otherwise use the existing one.
  1601                      * This can throw an error if a user either modified the list of Outlook data stores
  1602                      * or the pEp.pst file itself.
  1603                      */
  1604                     try
  1605                     {
  1606                         ns.AddStoreEx(path, Outlook.OlStoreType.olStoreUnicode);
  1607                     }
  1608                     catch (Exception ex)
  1609                     {
  1610                         Log.Error("OpenPEPStoreRootFolder: Failed to add pEp store. " + ex.ToString());
  1611                     }
  1612 
  1613                     for (int i = 1; i <= stores.Count; i++)
  1614                     {
  1615                         /* Search again for the newly created store.
  1616                          * Note: As the creation itself might have failed, this is not guaranteed to work.
  1617                          * We then try again in the next step or throw an error if the store cannot be accessed.
  1618                          */
  1619                         try
  1620                         {
  1621                             store = stores[i];
  1622                         }
  1623                         catch (Exception ex)
  1624                         {
  1625                             Log.Warning("OpenPEPStoreRootFolder: Failed to get store, " + ex.ToString());
  1626                         }
  1627 
  1628                         if ((store?.FilePath?.Equals(path) == true) ||
  1629                             (store?.FilePath?.Equals(winStorePath) == true))
  1630                         {
  1631                             pEpStore = store;
  1632                             pEpStore.GetRootFolder().Name = Globals.PEP_DATA_FILE_NAME;
  1633                             break; // Break before releasing
  1634                         }
  1635 
  1636                         store = null;
  1637                     }
  1638                 }
  1639 
  1640                 if (pEpStore != null)
  1641                 {
  1642                     this._PEPStoreRootFolder = (Outlook.Folder)pEpStore.GetRootFolder();
  1643                 }
  1644                 else
  1645                 {
  1646                     // Try again using fallback solution for file paths with prefixes
  1647                     Log.Warning("OpenPEPStoreRootFolder: No pEp store found. Trying fallback. pEp path is " + path);
  1648 
  1649                     for (int i = 1; i <= stores.Count; i++)
  1650                     {
  1651                         try
  1652                         {
  1653                             store = stores[i];
  1654                             Log.Info("OpenPEPStoreRootFolder: file path of store " + i + " (" + (store?.DisplayName ?? "<null>") + "): " + store?.FilePath ?? "<null>");
  1655                         }
  1656                         catch (Exception ex)
  1657                         {
  1658                             Log.Warning("OpenPEPStoreRootFolder: Failed to get store, " + ex.ToString());
  1659                         }
  1660 
  1661                         // Custom comparison of file paths independently of their (known) prefixes
  1662                         if (Comparisons.FilePathsAreEqual(store?.FilePath, path) ||
  1663                             Comparisons.FilePathsAreEqual(store?.FilePath, winStorePath))
  1664                         {
  1665                             pEpStore = store;
  1666                             pEpStore.GetRootFolder().Name = Globals.PEP_DATA_FILE_NAME;
  1667                             break;
  1668                         }
  1669 
  1670                         store = null;
  1671                     }
  1672 
  1673                     // If pEp store was found, use it. Else throw error.
  1674                     if (pEpStore != null)
  1675                     {
  1676                         this._PEPStoreRootFolder = pEpStore.GetRootFolder() as Outlook.Folder;
  1677                     }
  1678                     else
  1679                     {
  1680                         throw new Exception("Cannot open required pEp.pst file.");
  1681                     }
  1682                 }
  1683             }
  1684             catch (Exception ex)
  1685             {
  1686                 Globals.StopAndSendCrashReport(ex);
  1687             }
  1688             finally
  1689             {
  1690                 ns = null;
  1691                 pEpStore = null;
  1692                 store = null;
  1693                 stores = null;
  1694             }
  1695         }
  1696 
  1697         /// <summary>
  1698         /// Resets the pEp data store.
  1699         /// This will delete all files.
  1700         /// </summary>
  1701         internal void ResetPEPStore()
  1702         {
  1703             Outlook.Folder deletedFolder = null;
  1704             Outlook.Folders folders = null;
  1705             Outlook.Items items = null;
  1706             Outlook.Store store = null;
  1707             Outlook.Folder contacts = null;
  1708             Outlook.Folders contactsFolders = null;
  1709 
  1710             try
  1711             {
  1712                 if (this._PEPStoreRootFolder != null)
  1713                 {
  1714                     store = this._PEPStoreRootFolder.Store;
  1715 
  1716                     // Move all folders to deleted folder
  1717                     folders = this._PEPStoreRootFolder.Folders;
  1718                     for (int i = folders.Count; i > 0; i--)
  1719                     {
  1720                         // Default folders cannot be deleted and are skipped
  1721                         try
  1722                         {
  1723                             folders[i].Delete();
  1724                         }
  1725                         catch { }
  1726                     }
  1727 
  1728                     if (folders != null)
  1729                     {
  1730                         // Marshal.ReleaseComObject(folders);
  1731                         folders = null;
  1732                     }
  1733 
  1734                     // Move any contact folders/contacts to the deleted folder
  1735                     contacts = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
  1736                     contactsFolders = contacts.Folders;
  1737 
  1738                     for (int i = contactsFolders.Count; i > 0; i--)
  1739                     {
  1740                         try
  1741                         {
  1742                             contactsFolders[i].Delete();
  1743                         }
  1744                         catch { }
  1745                     }
  1746 
  1747                     // Delete items from deleted folder
  1748                     deletedFolder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
  1749 
  1750                     // Permanently delete items
  1751                     items = deletedFolder.Items;
  1752                     for (int i = items.Count; i > 0; i--)
  1753                     {
  1754                         try
  1755                         {
  1756                             items[i].Delete();
  1757                         }
  1758                         catch { }
  1759                     }
  1760 
  1761                     items = null;
  1762 
  1763                     // Permanently delete folders
  1764                     folders = deletedFolder.Folders;
  1765                     for (int i = folders.Count; i > 0; i--)
  1766                     {
  1767                         try
  1768                         {
  1769                             folders[i].Delete();
  1770                         }
  1771                         catch { }
  1772                     }
  1773 
  1774                     folders = null;
  1775                 }
  1776             }
  1777             catch (Exception ex)
  1778             {
  1779                 Log.Error("ResetPEPStore: Error occured. " + ex.ToString());
  1780             }
  1781             finally
  1782             {
  1783                 contacts = null;
  1784                 contactsFolders = null;
  1785                 deletedFolder = null;
  1786                 folders = null;
  1787                 items = null;
  1788                 store = null;
  1789             }
  1790         }
  1791 
  1792         /// <summary>
  1793         /// Sets the visibility of the pEp data store in the navigation pane.
  1794         /// This works by carefully releasing and maintaining references outside of Outlook.
  1795         /// </summary>
  1796         /// <param name="visible">True if the pEp folder should be visible, otherwise false.</param>
  1797         private void SetPEPStoreRootFolderVisibility(bool visible)
  1798         {
  1799             Outlook.Folder folder = null;
  1800             Outlook.NameSpace ns = null;
  1801             Outlook.Store store = null;
  1802 
  1803             try
  1804             {
  1805                 // If the pEp store hasn't been opened already, try to open it
  1806                 if (this._PEPStoreRootFolder == null)
  1807                 {
  1808                     this.OpenPEPStoreRootFolder();
  1809                 }
  1810 
  1811                 // Check again if the store has been found
  1812                 if (this._PEPStoreRootFolder != null)
  1813                 {
  1814                     ns = this.Application.Session;
  1815                     store = this._PEPStoreRootFolder.Store;
  1816 
  1817                     // Never show the default 'system' folders
  1818                     foreach (Outlook.OlDefaultFolders defaultFolder in Enum.GetValues(typeof(Outlook.OlDefaultFolders)))
  1819                     {
  1820                         // Allow deleted items
  1821                         if (defaultFolder != Outlook.OlDefaultFolders.olFolderDeletedItems)
  1822                         {
  1823                             try
  1824                             {
  1825                                 folder = (Outlook.Folder)store.GetDefaultFolder(defaultFolder);
  1826                                 MapiHelper.SetProperty(folder, MapiProperty.PidTagAttributeHidden, true);
  1827                             }
  1828                             catch { }
  1829                             finally
  1830                             {
  1831                                 if (folder != null)
  1832                                 {
  1833                                     // Marshal.ReleaseComObject(folder);
  1834                                     folder = null;
  1835                                 }
  1836                             }
  1837                         }
  1838                     }
  1839 
  1840                     // Attempt to add/remove the store from the session which sets visibility
  1841                     if (visible)
  1842                     {
  1843                         try
  1844                         {
  1845                             // Release the temp folder before attempting an open/re-open
  1846                             //Marshal.ReleaseComObject(this._PEPStoreRootFolder);
  1847                             this._PEPStoreRootFolder = null;
  1848 
  1849                             // After opening it will always be visible
  1850                             this.OpenPEPStoreRootFolder();
  1851                         }
  1852                         catch (Exception ex)
  1853                         {
  1854                             Log.Warning("SetPEPStoreRootFolderVisibility: Failed to make pEp root folder visible. " + ex.ToString());
  1855                         }
  1856                     }
  1857                     else
  1858                     {
  1859                         /* Remove the store from the session which will also hide it in the navigation pane.
  1860                          * Importantly, the pEp store's root folder reference is not released.
  1861                          * This allows the application to continue to use the store.
  1862                          * 
  1863                          * Also note that this call to remove the store will fail if the store is already removed.
  1864                          * This can happen when the visibility is set to false more than once.
  1865                          * Therefore, just try to remove it although don't log any errors.
  1866                          */
  1867                         try
  1868                         {
  1869                             ns.RemoveStore(this._PEPStoreRootFolder);
  1870                         }
  1871                         catch { }
  1872                     }
  1873                 }
  1874                 else
  1875                 {
  1876                     Log.Error("SetPEPStoreRootFolderVisibility: Couldn't set visibility. Folder is null.");
  1877                 }
  1878             }
  1879             catch (Exception ex)
  1880             {
  1881                 Log.Error("SetPEPStoreRootFolderVisibility: Failed, " + ex.ToString());
  1882             }
  1883             finally
  1884             {
  1885                 // Release objects
  1886                 folder = null;
  1887                 ns = null;
  1888                 store = null;
  1889             }
  1890         }
  1891 
  1892         /// <summary>
  1893         /// Sets pEp rules and view filters for a given account.
  1894         /// <param name="account">The Outlook account for which to set rules and view
  1895         /// <param name="enable">Whether to enable or disable rules and view filters.</param>
  1896         /// filters.</param>
  1897         /// </summary>
  1898         internal void SetRulesAndViewFilters(Outlook.Account account,
  1899                                              bool enable)
  1900         {
  1901             // If a failure occured, do not mark first startup as completed (run again next time).
  1902             if ((this.SetRules(account, enable) == false) ||
  1903                  (this.SetInboxViewFilters(account, enable) == false))
  1904             {
  1905                 this.Settings.IsFirstStartupComplete = false;
  1906             }
  1907         }
  1908 
  1909         /// <summary>
  1910         /// Sets pEp rules and view filters for all accounts.
  1911         /// <param name="enable">Whether to enable or disable rules and view filters.</param>
  1912         /// filters.</param>
  1913         /// </summary>
  1914         internal void SetRulesAndViewFilters(bool enable)
  1915         {
  1916             // If a failure occured, do not mark first startup as completed (run again next time).
  1917             this.Settings.IsFirstStartupComplete = (this.SetRules(enable) && this.SetInboxViewFilters(enable));
  1918         }
  1919 
  1920         /// <summary>
  1921         /// Sets the rules to hide pEp internal category MailItems for the given account.
  1922         /// </summary>
  1923         /// <param name="account">The account to set the rules for.</param>
  1924         /// <param name="enable">Whether to enable or disable the rules.</param>
  1925         /// <returns>True, if the rules were correctly set for this account. Otherwise false.</returns>
  1926         internal bool SetRules(Outlook.Account account,
  1927                                bool enable)
  1928         {
  1929             bool success = false;
  1930             bool categoriesSet = true;
  1931             bool ruleExists = false;
  1932             Outlook.AssignToCategoryRuleAction action = null;
  1933             Outlook.Rules rules = null;
  1934             Outlook.Rule rule = null;
  1935             Outlook.Store deliveryStore = null;
  1936             Outlook.TextRuleCondition condition = null;
  1937 
  1938             Log.Verbose("SetRules: Setting rules for single account.");
  1939 
  1940             try
  1941             {
  1942                 // Getting delivery store can fail for new accounts when Outlook is not restarted
  1943                 try
  1944                 {
  1945                     deliveryStore = account.DeliveryStore;
  1946                 }
  1947                 catch
  1948                 {
  1949                     deliveryStore = null;
  1950                     Log.Warning("SetRules: Failure getting DeliveryStore");
  1951                 }
  1952 
  1953                 if (deliveryStore != null)
  1954                 {
  1955                     // Get rules
  1956                     try
  1957                     {
  1958                         rules = deliveryStore.GetRules();
  1959                     }
  1960                     catch
  1961                     {
  1962                         rules = null;
  1963                         Log.Warning("SetRules: Failure getting rules");
  1964                     }
  1965 
  1966                     // Adding rule to the rules collection
  1967                     if (rules != null)
  1968                     {
  1969                         try
  1970                         {
  1971                             // Check if rule already was created, create new otherwise (if needed)
  1972                             try
  1973                             {
  1974                                 rule = rules[Globals.PEP_INTERNAL_CATEGORY_NAME];
  1975                                 ruleExists = true;
  1976                                 success = true;
  1977                             }
  1978                             catch
  1979                             {
  1980                                 if (enable)
  1981                                 {
  1982                                     rule = rules.Create(Globals.PEP_INTERNAL_CATEGORY_NAME, Outlook.OlRuleType.olRuleReceive);
  1983                                 }
  1984                             }
  1985                         }
  1986                         catch (Exception ex)
  1987                         {
  1988                             rule = null;
  1989                             Log.Warning("SetRules: Failure creating rule. " + ex.ToString());
  1990                         }
  1991 
  1992                         // Create or remove rule
  1993                         if (enable)
  1994                         {
  1995                             // Define rule if it didn't exist previously
  1996                             if ((rule != null) &&
  1997                                 (ruleExists == false))
  1998                             {
  1999                                 // Condition: message header includes defined string
  2000                                 try
  2001                                 {
  2002                                     condition = rule.Conditions?.MessageHeader;
  2003                                     condition.Text = new string[] { PEPMessage.PR_PEP_AUTO_CONSUME_NAME.ToLower() };
  2004                                     condition.Enabled = true;
  2005                                 }
  2006                                 catch (Exception ex)
  2007                                 {
  2008                                     condition = null;
  2009                                     Log.Warning("SetRules: Failure setting condition. " + ex.ToString());
  2010                                 }
  2011 
  2012                                 if (condition != null)
  2013                                 {
  2014                                     // Action: assign "pEp internal" category
  2015                                     try
  2016                                     {
  2017                                         if (this.CreatePEPCategories() == false)
  2018                                         {
  2019                                             categoriesSet = false;
  2020                                         }
  2021 
  2022                                         action = rule.Actions.AssignToCategory;
  2023                                         action.Categories = new string[] { Globals.PEP_INTERNAL_CATEGORY_NAME };
  2024                                         action.Enabled = true;
  2025                                     }
  2026                                     catch (Exception ex)
  2027                                     {
  2028                                         action = null;
  2029                                         Log.Warning("SetRules: Failure adding category. " + ex.ToString());
  2030                                     }
  2031 
  2032                                     if ((condition != null) &&
  2033                                         (action != null))
  2034                                     {
  2035                                         rules.Save();
  2036                                         rule.Execute();
  2037                                         success = categoriesSet;
  2038                                     }
  2039                                 }
  2040                             }
  2041                         }
  2042                         else
  2043                         {
  2044                             if (ruleExists)
  2045                             {
  2046                                 rules.Remove(Globals.PEP_INTERNAL_CATEGORY_NAME);
  2047                                 rules.Save();
  2048                             }
  2049 
  2050                             success = true;
  2051                         }
  2052                     }
  2053                 }
  2054 
  2055                 Log.Verbose("SetRules: {0} processed {1}.", account?.SmtpAddress ?? "NULL", success ? "successfully" : "unsuccessfully");
  2056             }
  2057             catch (Exception ex)
  2058             {
  2059                 Log.Error("SetRules: Failure occured, " + ex.ToString());
  2060             }
  2061             finally
  2062             {
  2063                 action = null;
  2064                 condition = null;
  2065                 deliveryStore = null;
  2066                 rule = null;
  2067                 rules = null;
  2068             }
  2069 
  2070             return success;
  2071         }
  2072 
  2073         /// <summary>
  2074         /// Sets the rules for all accounts to hide pEp internal category MailItems.
  2075         /// </summary>
  2076         /// <param name="enable">Whether to enable or disable the rules.</param>
  2077         /// <returns>True, if the rules were correctly set. Otherwise false.</returns>
  2078         internal bool SetRules(bool enable)
  2079         {
  2080             bool success = true;
  2081             Outlook.Account account = null;
  2082             Outlook.Accounts accounts = null;
  2083             Outlook.NameSpace ns = null;
  2084 
  2085             Log.Verbose("SetRules: Setting rules for all accounts");
  2086 
  2087             try
  2088             {
  2089                 ns = this.Application.Session;
  2090                 accounts = ns.Accounts;
  2091 
  2092                 for (int i = 1; i <= accounts.Count; i++)
  2093                 {
  2094                     account = accounts[i];
  2095 
  2096                     if (account != null)
  2097                     {
  2098                         if (this.SetRules(account, enable) == false)
  2099                         {
  2100                             success = false;
  2101                         }
  2102 
  2103                         account = null;
  2104                     }
  2105                 }
  2106             }
  2107             catch (Exception ex)
  2108             {
  2109                 success = false;
  2110                 Log.Error("SetRules: Failure occured, " + ex.ToString());
  2111             }
  2112             finally
  2113             {
  2114                 account = null;
  2115                 accounts = null;
  2116                 ns = null;
  2117             }
  2118 
  2119             return success;
  2120         }
  2121 
  2122         /// <summary>
  2123         /// Sets the view filter settings of the inbox folder to hide pEp internal category MailItems for the given account.
  2124         /// </summary>
  2125         /// <param name="account">The account to set the inbox view filter for.</param>
  2126         /// <param name="enable">Whether to enable or disable the view filters.</param>
  2127         /// <returns>True, if the filters were correctly set for this account. Otherwise false.</returns>
  2128         internal bool SetInboxViewFilters(Outlook.Account account,
  2129                                           bool enable)
  2130         {
  2131             bool success = false;
  2132             string currentViewName = null;
  2133             Outlook.Store deliveryStore = null;
  2134             Outlook.Folder folder = null;
  2135             Outlook.View view = null;
  2136             Outlook.Views views = null;
  2137 
  2138             Log.Verbose("SetInboxViewFilters: Setting inbox view filter for single account");
  2139 
  2140             try
  2141             {
  2142                 // Getting delivery store can fail for new accounts when Outlook is not restarted
  2143                 try
  2144                 {
  2145                     deliveryStore = account.DeliveryStore;
  2146                 }
  2147                 catch
  2148                 {
  2149                     deliveryStore = null;
  2150                     Log.Warning("SetInboxViewFilters: Failure getting DeliveryStore");
  2151                 }
  2152 
  2153                 if (deliveryStore != null)
  2154                 {
  2155                     // Get the inbox
  2156                     try
  2157                     {
  2158                         folder = (Outlook.Folder)deliveryStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
  2159                     }
  2160                     catch
  2161                     {
  2162                         folder = null;
  2163                         Log.Warning("SetInboxViewFilters: Failure getting inbox folder");
  2164                     }
  2165 
  2166                     // Change the filter for all views in the inbox
  2167                     if (folder != null)
  2168                     {
  2169                         views = folder.Views;
  2170                         currentViewName = folder.CurrentView?.Name;
  2171 
  2172                         for (int j = 1; j <= views.Count; j++)
  2173                         {
  2174                             view = views[j];
  2175 
  2176                             try
  2177                             {
  2178                                 // Only set the filter on standard views, if the user creates their own don't modify it
  2179                                 if (view.Standard)
  2180                                 {
  2181                                     // Clear existing filter -- seems to work better
  2182                                     view.Filter = null;
  2183                                     view.Save();
  2184 
  2185                                     if ((currentViewName != null) &&
  2186                                         (string.Equals(view.Name, currentViewName, StringComparison.OrdinalIgnoreCase)))
  2187                                     {
  2188                                         view.Apply();
  2189                                     }
  2190 
  2191                                     if (enable)
  2192                                     {
  2193                                         // Set the filter
  2194                                         if (account.AccountType == Outlook.OlAccountType.olImap)
  2195                                         {
  2196                                             // (1) Hide any deleted IMAP items http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/85700003 = 0
  2197                                             // (2) Hide 'pEp internal' and "pEp processing' category items
  2198                                             view.Filter = "(\"" + MapiProperty.PidLidImapMarkedForDeletion.DaslName + "\" = 0" +
  2199                                                           " AND " +
  2200                                                           "\"urn:schemas-microsoft-com:office:office#Keywords\" <> '" + Globals.PEP_INTERNAL_CATEGORY_NAME + "'" +
  2201                                                           " AND " +
  2202                                                           "\"urn:schemas-microsoft-com:office:office#Keywords\" <> '" + Globals.PEP_PROCESSING_CATEGORY_NAME + "')";
  2203                                         }
  2204                                         else
  2205                                         {
  2206                                             // Hide 'pEp internal' and "pEp processing' category items
  2207                                             view.Filter = "(\"urn:schemas-microsoft-com:office:office#Keywords\" <> '" + Globals.PEP_INTERNAL_CATEGORY_NAME + "'" +
  2208                                                           " AND " +
  2209                                                           "\"urn:schemas-microsoft-com:office:office#Keywords\" <> '" + Globals.PEP_PROCESSING_CATEGORY_NAME + "')";
  2210                                         }
  2211 
  2212                                         if ((currentViewName != null) &&
  2213                                             (string.Equals(view.Name, currentViewName, StringComparison.OrdinalIgnoreCase)))
  2214                                         {
  2215                                             view.Save();
  2216                                             view.Apply();
  2217                                         }
  2218                                         else
  2219                                         {
  2220                                             view.Save();
  2221                                         }
  2222                                     }
  2223                                 }
  2224 
  2225                                 success = true;
  2226                             }
  2227                             catch (Exception ex)
  2228                             {
  2229                                 Log.Warning("SetInboxViewFilters: Failed to set view. " + ex.ToString());
  2230                             }
  2231 
  2232                             view = null;
  2233                         }
  2234                     }
  2235                 }
  2236             }
  2237             catch (Exception ex)
  2238             {
  2239                 Log.Error("SetInboxViewFilters: Failure occured, " + ex.ToString());
  2240             }
  2241             finally
  2242             {
  2243                 deliveryStore = null;
  2244                 folder = null;
  2245                 view = null;
  2246                 views = null;
  2247             }
  2248 
  2249             return success;
  2250         }
  2251 
  2252         /// <summary>
  2253         /// Sets the view filter settings of all account's inbox folders to hide pEp internal category MailItems.
  2254         /// </summary>
  2255         /// <param name="enable">Whether to enable or disable the view filters.</param>
  2256         /// <returns>True, if the filters were correctly set. Otherwise false.</returns>
  2257         internal bool SetInboxViewFilters(bool enable)
  2258         {
  2259             bool success = true;
  2260             Outlook.Account account = null;
  2261             Outlook.Accounts accounts = null;
  2262             Outlook.NameSpace ns = null;
  2263 
  2264             Log.Verbose("SetInboxViewFilters: Setting inbox view filter for all accounts");
  2265 
  2266             try
  2267             {
  2268                 ns = this.Application.Session;
  2269                 accounts = ns.Accounts;
  2270 
  2271                 for (int i = 1; i <= accounts.Count; i++)
  2272                 {
  2273                     account = accounts[i];
  2274 
  2275                     if (account != null)
  2276                     {
  2277                         if (this.SetInboxViewFilters(account, enable) == false)
  2278                         {
  2279                             success = false;
  2280                         }
  2281 
  2282                         account = null;
  2283                     }
  2284                 }
  2285             }
  2286             catch (Exception ex)
  2287             {
  2288                 success = false;
  2289                 Log.Error("SetInboxViewFilters: Failure occured, " + ex.ToString());
  2290             }
  2291             finally
  2292             {
  2293                 account = null;
  2294                 accounts = null;
  2295                 ns = null;
  2296             }
  2297 
  2298             return success;
  2299         }
  2300 
  2301         /// <summary>
  2302         /// Retrieves the pEp drafts folder and creates it if necessary.
  2303         /// </summary>
  2304         /// <returns>The pEp drafts folder or null if an error occurs.</returns>
  2305         internal Outlook.Folder GetPEPStoreDraftsFolder()
  2306         {
  2307             Outlook.Folder pEpDraftsFolder = null;
  2308             Outlook.Folders folders = null;
  2309 
  2310             try
  2311             {
  2312                 folders = PEPStoreRootFolder?.Folders;
  2313 
  2314                 try
  2315                 {
  2316                     pEpDraftsFolder = folders?[Globals.PEP_DRAFTS_FOLDER_NAME] as Outlook.Folder;
  2317                 }
  2318                 catch
  2319                 {
  2320                     pEpDraftsFolder = null;
  2321                 }
  2322 
  2323                 if (pEpDraftsFolder == null)
  2324                 {
  2325                     pEpDraftsFolder = folders?.Add(Globals.PEP_DRAFTS_FOLDER_NAME, Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
  2326                 }
  2327             }
  2328             catch (Exception ex)
  2329             {
  2330                 pEpDraftsFolder = null;
  2331                 Log.Error("Cannot create pEp drafts folder. " + ex.ToString());
  2332             }
  2333             finally
  2334             {
  2335                 folders = null;
  2336             }
  2337 
  2338             return pEpDraftsFolder;
  2339         }
  2340 
  2341         /// <summary>
  2342         /// Creates the pEp internal category for the specified account's store unless it already exists.
  2343         /// </summary>
  2344         internal bool CreatePEPCategories(Outlook.Store deliveryStore)
  2345         {
  2346             bool pEpInternalExists = false;
  2347             bool pEpProcessingExists = false;
  2348             Outlook.Category category = null;
  2349             Outlook.Categories categories = null;
  2350 
  2351             if (deliveryStore != null)
  2352             {
  2353                 try
  2354                 {
  2355                     categories = deliveryStore.Categories;
  2356 
  2357                     // Check if the categories already exists
  2358                     for (int i = 1; i <= categories?.Count; i++)
  2359                     {
  2360                         category = categories[i];
  2361 
  2362                         if (category?.Name?.Equals(Globals.PEP_INTERNAL_CATEGORY_NAME, StringComparison.OrdinalIgnoreCase) == true)
  2363                         {
  2364                             pEpInternalExists = true;
  2365                         }
  2366                         else if (category?.Name?.Equals(Globals.PEP_PROCESSING_CATEGORY_NAME, StringComparison.OrdinalIgnoreCase) == true)
  2367                         {
  2368                             pEpProcessingExists = true;
  2369                         }
  2370 
  2371                         category = null;
  2372 
  2373                         if (pEpInternalExists &&
  2374                             pEpProcessingExists)
  2375                         {
  2376                             break;
  2377                         }
  2378                     }
  2379                 }
  2380                 catch (Exception ex)
  2381                 {
  2382                     Log.Error("CreatePEPCategories: Error checking if category exists. " + ex.ToString());
  2383 
  2384                     // Just try to create it anyway, this will throw an exception if it already exists
  2385                     pEpInternalExists = false;
  2386                     pEpProcessingExists = false;
  2387                 }
  2388                 finally
  2389                 {
  2390                     category = null;
  2391                     categories = null;
  2392                 }
  2393 
  2394                 // If a category was not found, create and add it to account master list
  2395                 if (pEpInternalExists == false)
  2396                 {
  2397                     try
  2398                     {
  2399                         // Add category
  2400                         categories = deliveryStore.Categories;
  2401                         categories?.Add(Globals.PEP_INTERNAL_CATEGORY_NAME, Outlook.OlCategoryColor.olCategoryColorDarkGreen);
  2402                         pEpInternalExists = true;
  2403                     }
  2404                     catch (Exception ex)
  2405                     {
  2406                         Log.Error("CreatePEPCategories: Error setting pEp Internal category. " + ex.ToString());
  2407                     }
  2408                     finally
  2409                     {
  2410                         categories = null;
  2411                     }
  2412                 }
  2413 
  2414                 if (pEpProcessingExists == false)
  2415                 {
  2416                     try
  2417                     {
  2418                         // Add category
  2419                         categories = deliveryStore.Categories;
  2420                         categories?.Add(Globals.PEP_PROCESSING_CATEGORY_NAME, Outlook.OlCategoryColor.olCategoryColorDarkGreen);
  2421                         pEpProcessingExists = true;
  2422                     }
  2423                     catch (Exception ex)
  2424                     {
  2425                         Log.Error("CreatePEPCategories: Error settising pEp Processing. " + ex.ToString());
  2426                     }
  2427                     finally
  2428                     {
  2429                         categories = null;
  2430                     }
  2431                 }
  2432             }
  2433 
  2434             return (pEpInternalExists && pEpProcessingExists);
  2435         }
  2436 
  2437         /// <summary>
  2438         /// Creates the pEp internal category in Outlook for all accounts.
  2439         /// </summary>
  2440         internal bool CreatePEPCategories()
  2441         {
  2442             bool success = true;
  2443             Outlook.Account account = null;
  2444             Outlook.Accounts accounts = null;
  2445             Outlook.NameSpace ns = null;
  2446             Outlook.Store deliveryStore = null;
  2447 
  2448             try
  2449             {
  2450                 ns = this.Application.Session;
  2451                 accounts = ns?.Accounts;
  2452 
  2453                 // Set the pEp internal category for all accounts
  2454                 for (int i = 1; i <= accounts?.Count; i++)
  2455                 {
  2456                     try
  2457                     {
  2458                         account = accounts[i];
  2459 
  2460                         // If the account doesn't have pEp enabled, don't create category
  2461                         if ((account?.GetIsPEPEnabled() != true) || (account?.GetIsDecryptAlwaysEnabled() != true))
  2462                         {
  2463                             deliveryStore = account?.DeliveryStore;
  2464                             if ((deliveryStore == null) ||
  2465                                 (this.CreatePEPCategories(deliveryStore) == false))
  2466                             {
  2467                                 success = false;
  2468                             }
  2469                             deliveryStore = null;
  2470                         }
  2471                     }
  2472                     catch (Exception ex)
  2473                     {
  2474                         Log.Error("SetPEPInternalCategory: Error setting category for account. " + ex.ToString());
  2475                         success = false;
  2476                     }
  2477                     finally
  2478                     {
  2479                         account = null;
  2480                         deliveryStore = null;
  2481                     }
  2482                 }
  2483             }
  2484             catch (Exception ex)
  2485             {
  2486                 Log.Error("SetPEPInternalCategory: Failure occured, " + ex.ToString());
  2487                 success = false;
  2488             }
  2489             finally
  2490             {
  2491                 account = null;
  2492                 accounts = null;
  2493                 ns = null;
  2494                 deliveryStore = null;
  2495             }
  2496 
  2497             return success;
  2498         }
  2499 
  2500         /// <summary>
  2501         /// Detects the current UI culture in Outlook and returns it as a CultureInfo object.
  2502         /// This will return English as the default language (never null).
  2503         /// </summary>
  2504         /// <returns>The active UI culture in Outlook.</returns>
  2505         internal CultureInfo GetActiveUICulture()
  2506         {
  2507             CultureInfo outlookCulture = null;
  2508             CultureInfo pEpCulture = null;
  2509             Office.LanguageSettings lang = null;
  2510             string languageName = null;
  2511             const string defaultLanguageName = "en";
  2512 
  2513             // The current supported languages. Has to be synced with resources.
  2514             List<string> pEpLanguages = new List<string>
  2515             {
  2516                 "ca",
  2517                 "de",
  2518                 "en",
  2519                 "es",
  2520                 "fr",
  2521                 "hi",
  2522                 "it",
  2523                 "mr",
  2524                 "nl",
  2525                 "tr",
  2526                 "zh"
  2527              };
  2528 
  2529             try
  2530             {
  2531                 // Get Outlook culture
  2532                 lang = this.Application.LanguageSettings;
  2533                 outlookCulture = new CultureInfo(lang.LanguageID[Office.MsoAppLanguageID.msoLanguageIDUI]);
  2534 
  2535                 /* Get the two letter ISO language name.
  2536                  * This is needed because we have not yet country-specific localization.
  2537                  * If the language is supported, use it. Else, use default language.
  2538                  */
  2539                 languageName = outlookCulture.TwoLetterISOLanguageName;
  2540                 if (pEpLanguages.Contains(languageName))
  2541                 {
  2542                     pEpCulture = new CultureInfo(languageName);
  2543                 }
  2544                 else
  2545                 {
  2546                     pEpCulture = new CultureInfo(defaultLanguageName);
  2547                 }
  2548             }
  2549             catch (Exception ex)
  2550             {
  2551                 pEpCulture = new CultureInfo(defaultLanguageName);
  2552                 Log.Verbose("GetActiveUICulture: Failed to get UI culture, " + ex.ToString());
  2553             }
  2554             finally
  2555             {
  2556                 if (lang != null)
  2557                 {
  2558                     //Marshal.ReleaseComObject(lang);
  2559                     lang = null;
  2560                 }
  2561             }
  2562 
  2563             return (pEpCulture);
  2564         }
  2565 
  2566         /// <summary>
  2567         /// Formats the given text string as separated 4-character groups.
  2568         /// The intention is for use when showing fingerprints.
  2569         /// Optionally, five 4-character groups are put on each line.
  2570         /// Example: 49422235FC99585B891C --> 4942 2235 FC99 585B 891C
  2571         /// </summary>
  2572         /// <param name="text">The text to format in 4-character groups.</param>
  2573         /// <param name="insertNewLine">Whether to insert a newline after each group.</param>
  2574         /// <returns>The re-formatted string.</returns>
  2575         internal string ToQuadruple(string text, bool insertNewLine)
  2576         {
  2577             List<string> groups = new List<string>();
  2578             string result = "";
  2579 
  2580             // Separate in sections of 4 characters
  2581             if (text != null)
  2582             {
  2583                 for (int i = 0; i < text.Length; i += 4)
  2584                 {
  2585                     try
  2586                     {
  2587                         groups.Add(text.Substring(i, 4));
  2588                     }
  2589                     catch (ArgumentOutOfRangeException)
  2590                     {
  2591                         groups.Add(text.Substring(i));
  2592                         break;
  2593                     }
  2594                 }
  2595             }
  2596 
  2597             // Separate in lines of 5 groups
  2598             if (insertNewLine)
  2599             {
  2600                 for (int i = 0; i < groups.Count; i += 5)
  2601                 {
  2602                     if (string.IsNullOrEmpty(result))
  2603                     {
  2604                         try
  2605                         {
  2606                             result = String.Join(" ", groups.GetRange(i, 5));
  2607                         }
  2608                         catch
  2609                         {
  2610                             result = String.Join(" ", groups.GetRange(i, (groups.Count - i)));
  2611                         }
  2612                     }
  2613                     else
  2614                     {
  2615                         try
  2616                         {
  2617                             result += Environment.NewLine + String.Join(" ", groups.GetRange(i, 5));
  2618                         }
  2619                         catch
  2620                         {
  2621                             result += Environment.NewLine + String.Join(" ", groups.GetRange(i, (groups.Count - i)));
  2622                         }
  2623                     }
  2624                 }
  2625             }
  2626             else
  2627             {
  2628                 result = string.Join(" ", groups);
  2629             }
  2630 
  2631             return result;
  2632         }
  2633 
  2634         /// <summary>
  2635         /// Removes any formatting from the given fingerprint string.
  2636         /// Example: 0x3fa1 32ca -> 3FA132CA
  2637         /// Warning: Null can be returned if the given fingerprint is null (default return value is the input).
  2638         /// </summary>
  2639         /// <param name="fingerprint">The fingerprint string to remove formatting from.</param>
  2640         /// <returns>A fingerprint string without formatting, otherwise the original input.</returns>
  2641         internal string RemoveFprFormatting(string fingerprint)
  2642         {
  2643             string result = fingerprint;
  2644 
  2645             if (string.IsNullOrEmpty(fingerprint) == false)
  2646             {
  2647                 result = fingerprint.Trim();
  2648                 result = result.ToUpperInvariant();
  2649                 result = result.Replace(" ", "");
  2650                 result = result.Replace("\r\n", "");
  2651 
  2652                 if (result.StartsWith("0X"))
  2653                 {
  2654                     result = result.Substring(2, (result.Length - 2));
  2655                 }
  2656             }
  2657 
  2658             return (result);
  2659         }
  2660 
  2661         /**************************************************************
  2662          * 
  2663          * Event Handling
  2664          * 
  2665          *************************************************************/
  2666 
  2667         /// <summary>
  2668         /// Event handler for when the add-in is starting up.
  2669         /// This is the first user code to execute in the add-in.
  2670         /// See: https://msdn.microsoft.com/en-us/library/7xy91eax.aspx
  2671         /// </summary>
  2672         private void ThisAddIn_Startup(object sender, EventArgs e)
  2673         {
  2674             CultureInfo culture;
  2675 
  2676             // Disable GPGOL
  2677             Log.Info("ThisAddIn_Startup: Disable GPGOL");
  2678             this.DisableGpgOL();
  2679 
  2680             // Init global error handling
  2681             Log.Info("ThisAddIn_Startup: Connect Events");
  2682             Globals.ConnectEvents(true);
  2683 
  2684             // Connect custom ThisAddIn event
  2685             Log.Info("ThisAddIn_Startup: Connect ThisAddIn events");
  2686             this.FirstStartup += ThisAddIn_FirstStartup;
  2687 
  2688             /* Load settings from Registry and update accounts list. This must be done before RegisterMyself()
  2689              * to be able to set the not for sync flag if necessary.
  2690              */
  2691             Log.Info("ThisAddIn_Startup: Loading settings");
  2692             this._Settings = new PEPSettings();
  2693             this._Settings.LoadFromRegistry();
  2694             this.SyncAccountsList();
  2695 
  2696 #if !READER_RELEASE_MODE
  2697             // Connect callbacks, use PEPEngine property accessor in case the engine is not already initialized
  2698             Log.Info("ThisAddIn_Startup: Register callbacks");
  2699             this.adapterCallbacks = new AdapterCallbacks();
  2700             ThisAddIn.PEPEngine.RegisterCallbacks(this.adapterCallbacks);
  2701 #endif
  2702 
  2703             /* Register all accounts as own identities in the engine
  2704              * Warning: This must be done BEFORE synchronizing settings because SyncWithSettings() will use 
  2705              * the engine's OwnIdentitiesRetrieve list to synchronize own identity flags such as IsSyncEnabled.
  2706              * The OwnIdentitiesRetrieve list will depend on what identities have been passed to Myself().
  2707              */
  2708             Log.Info("ThisAddIn_Startup: Register myself");
  2709             this.RegisterMyself();
  2710 
  2711             // Process and sync settings (Warning: sequence is very important here)
  2712             Log.Info("ThisAddIn_Startup: Sync settings");
  2713             this.DetectChangesFromLastSettings(this._Settings);
  2714             this._Settings.SaveUpdaterConfigToRegistry();
  2715             this.SyncWithSettings();
  2716             this._Settings.PropertyChanged += Settings_PropertyChanged;
  2717 
  2718             // Set the UI culture for resource translation
  2719             Log.Info("ThisAddIn_Startup: Set UI language");
  2720             culture = this.GetActiveUICulture();
  2721             CultureInfo.DefaultThreadCurrentCulture = culture;
  2722             CultureInfo.DefaultThreadCurrentUICulture = culture;
  2723             Log.Info("ThisAddIn_Startup: " + culture.TwoLetterISOLanguageName + " language detected.");
  2724 
  2725             // Add reference to KeySyncWizard in order to start the dialog from the main thread
  2726             KeySyncWizard.Wizard = new KeySyncWizard();
  2727 
  2728             try
  2729             {
  2730                 /* Note: This is sensitive to time as pEp needs to start as fast as possible.
  2731                  * If there is too much delay, Outlook will automatically disable the add-in.
  2732                  * See: https://msdn.microsoft.com/en-us/library/office/jj228679.aspx#Anchor_7
  2733                  * 
  2734                  * If performance is proven to be an issue here, move to another location.
  2735                  */
  2736                 if (this.initialized == false)
  2737                 {
  2738                     // Get the Outlook options and set pEp required Outlook options
  2739                     Log.Info("ThisAddIn_Startup: Get Outlook options and set pEp required values.");
  2740                     this._OutlookOptions = new OutlookOptions();
  2741                     this._OutlookOptions.ReadOptionsFromRegistry();
  2742                     this._OutlookOptions.SetRegistryValues();
  2743 
  2744                     // Connect watched objects
  2745                     Log.Info("ThisAddIn_Startup: Connect Watched objects");
  2746                     this.ConnectWatchedFolders();
  2747                     this.ConnectWatchedExplorers(true);
  2748                     this.ConnectWatchedInspectors(true);
  2749 
  2750                     // Connect application events
  2751                     Log.Info("ThisAddIn_Startup: Connect Application Events");
  2752                     this.ConnectApplicationEvents(true);
  2753 
  2754                     // Initialize inbox cleaning timer
  2755                     this.ToggleInboxCleaning(true);
  2756 
  2757                     // Create the 'pEp Internal' and 'pEp Processing' categories
  2758                     this.CreatePEPCategories();
  2759 
  2760                     // Initialization complete
  2761                     Log.Info("ThisAddIn_Startup: Main program started.");
  2762                     this.initialized = true;
  2763                 }
  2764 
  2765                 // Startup active parts of engine
  2766                 ThisAddIn.PEPEngine.Startup();
  2767             }
  2768             catch (Exception ex)
  2769             {
  2770                 string summaryMessage = Properties.Resources.Message_InitError + " " +
  2771                                         Properties.Resources.Message_Reinstall;
  2772                 Globals.StopAndSendCrashReport(ex, summaryMessage, false);
  2773             }
  2774         }
  2775 
  2776         /// <summary>
  2777         /// Subscribes to application events or unsubscribes from them.
  2778         /// </summary>
  2779         /// <param name="subscribe">Whether to subscribe or unsubscribe</param>
  2780         private void ConnectApplicationEvents(bool subscribe)
  2781         {
  2782             if (this.Application != null)
  2783             {
  2784                 try
  2785                 {
  2786                     if (subscribe)
  2787                     {
  2788                         ((Outlook.ApplicationEvents_11_Event)this.Application).Startup += Application_Startup;
  2789                         ((Outlook.ApplicationEvents_11_Event)this.Application).Quit += Application_Quit;
  2790                         ((Outlook.ApplicationEvents_11_Event)this.Application).NewMailEx += Application_NewMailEx;
  2791                         ((Outlook.ApplicationEvents_11_Event)this.Application).ItemSend += Application_ItemSend;
  2792                     }
  2793                     else
  2794                     {
  2795                         ((Outlook.ApplicationEvents_11_Event)this.Application).Startup -= Application_Startup;
  2796                         ((Outlook.ApplicationEvents_11_Event)this.Application).Quit -= Application_Quit;
  2797                         ((Outlook.ApplicationEvents_11_Event)this.Application).NewMailEx -= Application_NewMailEx;
  2798                         ((Outlook.ApplicationEvents_11_Event)this.Application).ItemSend -= Application_ItemSend;
  2799                     }
  2800                 }
  2801                 catch (Exception ex)
  2802                 {
  2803                     Log.Error("ConnectApplicationEvents: Error occured. " + ex.ToString());
  2804                 }
  2805             }
  2806         }
  2807 
  2808         /// <summary>
  2809         /// Connects all explorers with their respective events and the Explorers collection
  2810         /// with the NewExplorer event.
  2811         /// <param name="connect">Whether to connect or disconnect the explorers.</param>
  2812         /// </summary>
  2813         private void ConnectWatchedExplorers(bool connect)
  2814         {
  2815             try
  2816             {
  2817                 if (connect)
  2818                 {
  2819                     this.explorers = this.Application.Explorers;
  2820 
  2821                     for (int i = 1; i <= this.explorers.Count; i++)
  2822                     {
  2823                         this.watchedExplorers.Add(new WatchedExplorer(this.explorers[i]));
  2824                     }
  2825 
  2826                     this.explorers.NewExplorer += Explorers_NewExplorer;
  2827                 }
  2828                 else
  2829                 {
  2830                     this.explorers.NewExplorer -= Explorers_NewExplorer;
  2831 
  2832                     for (int i = 0; i < this.watchedExplorers.Count; i++)
  2833                     {
  2834                         this.RemoveFromWatchedExplorers(this.watchedExplorers[i]);
  2835                         this.watchedExplorers[i].Dispose();
  2836                     }
  2837 
  2838                     this.explorers = null;
  2839                 }
  2840             }
  2841             catch (Exception ex)
  2842             {
  2843                 Log.Error("ConnectWatchedExplorers: Error occured. " + ex.ToString());
  2844             }
  2845         }
  2846 
  2847         /// <summary>
  2848         /// Event handler for when a new explorer is being opened and 
  2849         /// added to the Explorers collection.
  2850         /// </summary>
  2851         /// <param name="explorer">The newly opened explorer.</param>
  2852         private void Explorers_NewExplorer(Outlook.Explorer explorer)
  2853         {
  2854             this.AddToWatchedExplorers(new WatchedExplorer(explorer));
  2855         }
  2856 
  2857         /// <summary>
  2858         /// Connects all inspectors with their respective events and the Inspectors collection
  2859         /// with the Newinspector event.
  2860         /// <param name="connect">Whether to connect or disconnect the inspectors.</param>
  2861         /// </summary>
  2862         private void ConnectWatchedInspectors(bool connect)
  2863         {
  2864             try
  2865             {
  2866                 if (connect)
  2867                 {
  2868                     this.inspectors = this.Application.Inspectors;
  2869 
  2870                     for (int i = 1; i <= this.inspectors.Count; i++)
  2871                     {
  2872                         this.watchedInspectors.Add(new WatchedInspector(this.inspectors[i]));
  2873                     }
  2874 
  2875                     this.inspectors.NewInspector += Explorers_NewInspector;
  2876                 }
  2877                 else
  2878                 {
  2879                     this.inspectors.NewInspector -= Explorers_NewInspector;
  2880 
  2881                     for (int i = 0; i < this.watchedInspectors.Count; i++)
  2882                     {
  2883                         this.RemoveFromWatchedInspectors(this.watchedInspectors[i]);
  2884                         this.watchedInspectors[i].Dispose();
  2885                     }
  2886 
  2887                     this.inspectors = null;
  2888                 }
  2889             }
  2890             catch (Exception ex)
  2891             {
  2892                 Log.Error("ConnectWatchedInspectors: Error occured. " + ex.ToString());
  2893             }
  2894         }
  2895 
  2896         /// <summary>
  2897         /// Event handler for when a new inspector is being opened and 
  2898         /// added to the Inspectors collection.
  2899         /// </summary>
  2900         /// <param name="inspector">The newly opened inspector.</param>
  2901         private void Explorers_NewInspector(Outlook.Inspector inspector)
  2902         {
  2903             this.AddToWatchedInspectors(new WatchedInspector(inspector));
  2904         }
  2905 
  2906         /// <summary>
  2907         /// Enables or disables the automatic deletion of old autoconsume messages.
  2908         /// This gets automatically disabled again if no autoconsume messages are found in the inbox.
  2909         /// <param name="enable">Whether to enable or disable the automatic cleaning.</param>
  2910         /// <param name="runOnEnable">Whether to run the inbox cleaning once right away when it gets enabled.</param>
  2911         /// </summary>
  2912         internal void ToggleInboxCleaning(bool enable)
  2913         {
  2914             if ((enable) &&
  2915                 (inboxCleaner == null))
  2916             {
  2917                 // Only enable if not yet enabled
  2918                 inboxCleaner = new System.Windows.Forms.Timer
  2919                 {
  2920                     Interval = Globals.TIMEOUT_SYNC_MESSAGE
  2921                 };
  2922                 inboxCleaner.Tick += InboxCleaner_Tick;
  2923                 inboxCleaner.Start();
  2924                 Log.Verbose("ToggleInboxCleaning: Automatic inbox cleaning enabled");
  2925 
  2926                 // Run it once right away
  2927                 Task.Run(() =>
  2928                 {
  2929                     this.InboxCleaner_Tick(null, null);
  2930                 });
  2931             }
  2932             else if ((enable == false) &&
  2933                      (inboxCleaner != null))
  2934             {
  2935                 inboxCleaner.Stop();
  2936                 inboxCleaner.Dispose();
  2937                 inboxCleaner = null;
  2938                 Log.Verbose("ToggleInboxCleaning: Automatic inbox cleaning disabled");
  2939             }
  2940         }
  2941 
  2942         /// <summary>
  2943         /// Event handler for when the inbox cleaner timer has elapsed.
  2944         /// This searches in all inboxes for old keysync messages and deletes them.
  2945         /// </summary>
  2946         private void InboxCleaner_Tick(object sender, EventArgs e)
  2947         {
  2948             int messagesCounter = 0;
  2949             int deletedMessagesCounter = 0;
  2950             Outlook.Folder folder = null;
  2951             Outlook.NameSpace ns = null;
  2952             Outlook.Store store = null;
  2953             Outlook.Stores stores = null;
  2954 
  2955             Log.Verbose("InboxCleaner_Tick: Checking for messages to delete...");
  2956 
  2957             try
  2958             {
  2959                 ns = this.Application.Session;
  2960                 stores = ns?.Stores;
  2961 
  2962                 for (int i = 1; i <= stores?.Count; i++)
  2963                 {
  2964                     // Note: accessing the stores can fail if the data file is missing or is in use by another program. 
  2965                     try
  2966                     {
  2967                         store = stores[i];
  2968                     }
  2969                     catch (Exception ex)
  2970                     {
  2971                         store = null;
  2972                         Log.Warning("InboxCleaner_Tick: Failed to get store. " + ex.ToString());
  2973                     }
  2974 
  2975                     // Clean Inbox folder
  2976                     try
  2977                     {
  2978                         folder = store?.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
  2979 
  2980                         if (folder != null)
  2981                         {
  2982                             this.CleanFolder(store, folder, out int foundMessages, out int deletedMessages);
  2983                             messagesCounter += foundMessages;
  2984                             deletedMessagesCounter += deletedMessages;
  2985                         }
  2986                     }
  2987                     catch (Exception ex)
  2988                     {
  2989                         folder = null;
  2990                         Log.Warning("InboxCleaner_Tick: Failure getting inbox folder. " + ex.Message);
  2991                     }
  2992                     finally
  2993                     {
  2994                         folder = null;
  2995                     }
  2996 
  2997                     // Clean Deleted Items folder
  2998                     try
  2999                     {
  3000                         folder = store?.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems) as Outlook.Folder;
  3001 
  3002                         if (folder != null)
  3003                         {
  3004                             this.CleanFolder(store, folder, out int foundMessages, out int deletedMessages);
  3005                             messagesCounter += foundMessages;
  3006                             deletedMessagesCounter += deletedMessages;
  3007                         }
  3008                     }
  3009                     catch (Exception ex)
  3010                     {
  3011                         folder = null;
  3012                         Log.Warning("InboxCleaner_Tick: Failure getting deleted items folder. " + ex.Message);
  3013                     }
  3014                     finally
  3015                     {
  3016                         folder = null;
  3017                     }
  3018                 }
  3019             }
  3020             catch (Exception ex)
  3021             {
  3022                 Log.Error("InboxCleaner_Tick: Failure occured, " + ex.ToString());
  3023             }
  3024             finally
  3025             {
  3026                 folder = null;
  3027                 ns = null;
  3028                 store = null;
  3029                 stores = null;
  3030             }
  3031 
  3032             // If no keys sync messages were found, disable the automatic cleaning.
  3033             if (messagesCounter == 0)
  3034             {
  3035                 Log.Verbose("InboxCleaner_Tick: No more 'pEp Internal' messages were found in the inbox. Disabling cleaning...");
  3036                 Globals.ThisAddIn.ToggleInboxCleaning(false);
  3037             }
  3038 
  3039             Log.Verbose("InboxCleaner_Tick: Inbox cleaning finished. Deleted " + deletedMessagesCounter + " items.");
  3040         }
  3041 
  3042         /// <summary>
  3043         /// Deletes all timed-out pEp internal messages in a given folder.
  3044         /// </summary>
  3045         /// <param name="store">The store where this folder is located.</param>
  3046         /// <param name="folder">The folder to be cleaned.</param>
  3047         /// <param name="foundMessages">The pEp internal messages found in this folder.</param>
  3048         /// <param name="deletedMessages">The pEp internal messages that have been deleted.</param>
  3049         private void CleanFolder(Outlook.Store store, Outlook.Folder folder, out int foundMessages, out int deletedMessages)
  3050         {
  3051             deletedMessages = 0;
  3052             foundMessages = 0;
  3053             const string searchFilter = "[Categories] ='" + Globals.PEP_INTERNAL_CATEGORY_NAME + "' Or [Categories] ='" + Globals.PEP_PROCESSING_CATEGORY_NAME + "'";
  3054             Outlook.Items inboxItems = null;
  3055             Outlook.Items filteredInboxItems = null;
  3056             Outlook.MailItem mailItem = null;
  3057 
  3058             // Process all internal mail items again to check if consumed flag is set
  3059             try
  3060             {
  3061                 Log.Verbose("CleanFolder: Cleaning folder " + folder?.FolderPath);
  3062 
  3063                 inboxItems = folder?.Items as Outlook.Items;
  3064 
  3065                 if (inboxItems?.Count > 0)
  3066                 {
  3067                     // Get all mails with the "pEp Internal" category
  3068                     filteredInboxItems = inboxItems.Restrict(searchFilter) as Outlook.Items;
  3069                     Log.Verbose("CleanFolder: " + inboxItems.Count + " items found.");
  3070 
  3071                     if (filteredInboxItems != null)
  3072                     {
  3073                         foundMessages = filteredInboxItems.Count;
  3074                         Log.Verbose("CleanFolder: " + foundMessages + " 'pEp Internal' items found.");
  3075 
  3076                         for (int j = 1; j <= foundMessages; j++)
  3077                         {
  3078                             try
  3079                             {
  3080                                 mailItem = filteredInboxItems[j] as Outlook.MailItem;
  3081 
  3082                                 if (mailItem != null)
  3083                                 {
  3084                                     Log.Verbose("CleanFolder: Processing 'pEp Internal' item " + j + "...");
  3085 
  3086                                     // Check if auto consume message and delete if timed out or delete pEp Internal category
  3087                                     if (mailItem.GetIsAutoConsume())
  3088                                     {
  3089                                         if (DateTime.UtcNow - (mailItem.ReceivedTime.ToUniversalTime()) > TimeSpan.FromMilliseconds(Globals.TIMEOUT_SYNC_MESSAGE))
  3090                                         {
  3091                                             mailItem.PermanentlyDelete(store);
  3092                                             deletedMessages++;
  3093                                         }
  3094                                         else if (Globals.ThisAddIn.Settings.HideInternalMessages == false)
  3095                                         {
  3096                                             if (mailItem.RemoveCategories(Globals.PEP_INTERNAL_CATEGORY_NAME, Globals.PEP_PROCESSING_CATEGORY_NAME))
  3097                                             {
  3098                                                 mailItem.Save();
  3099                                             }
  3100                                         }
  3101                                     }
  3102                                     else
  3103                                     {
  3104                                         if (mailItem.RemovePEPProcessingCategory())
  3105                                         {
  3106                                             mailItem.Save();
  3107                                         }
  3108                                     }
  3109                                 }
  3110 
  3111                                 mailItem = null;
  3112                             }
  3113                             catch (Exception ex)
  3114                             {
  3115                                 Log.Error("CleanFolder: Error processing mail item. " + ex.Message);
  3116                             }
  3117                         }
  3118                     }
  3119                 }
  3120                 else
  3121                 {
  3122                     Log.Verbose("CleanFolder: No items were found or folder was null.");
  3123                 }
  3124             }
  3125             catch (Exception ex)
  3126             {
  3127                 Log.Warning("CleanFolder: Failure occured. " + ex.Message);
  3128             }
  3129             finally
  3130             {
  3131                 inboxItems = null;
  3132                 filteredInboxItems = null;
  3133                 mailItem = null;
  3134             }
  3135         }
  3136 
  3137         /// <summary>
  3138         /// Event handler for when the add-in is shutdown.
  3139         /// Importantly: In Outlook, The Shutdown event is raised only when the user 
  3140         /// disables the VSTO Add-in by using the COM Add-ins dialog box in Outlook. 
  3141         /// It is not raised when Outlook exits. This is why Application_Quit is used instead.
  3142         /// See: https://msdn.microsoft.com/en-us/library/7xy91eax.aspx
  3143         /// </summary>
  3144         private void ThisAddIn_Shutdown(object sender, EventArgs e)
  3145         {
  3146             return;
  3147         }
  3148 
  3149         /// <summary>
  3150         /// Event handler for when first startup of the add-in is detected.
  3151         /// This is a custom event.
  3152         /// </summary>
  3153         private void ThisAddIn_FirstStartup(object sender, EventArgs e)
  3154         {
  3155             Log.Info("ThisAddIn_FirstStartup: First startup detected");
  3156 
  3157             // Set rules and inbox view filters for all accounts
  3158             Task.Factory.StartNew(() =>
  3159             {
  3160                 this.SetRulesAndViewFilters(this._Settings?.HideInternalMessages ?? PEPSettings.HIDE_INTERNAL_MESSAGES_DEFAULT);
  3161             });
  3162         }
  3163 
  3164         /// <summary>
  3165         /// Event handler for when the application is starting up.
  3166         /// This occurs after all add-in programs have been loaded.
  3167         /// See: https://msdn.microsoft.com/en-us/library/ff869298.aspx
  3168         /// </summary>
  3169         private void Application_Startup()
  3170         {
  3171             /* Open the Reader splash screen if the user has not disabled it.
  3172              * The splash is opened with a Timer in order to keep it from slowing initialization on this thread.
  3173              */
  3174             if ((Globals.RELEASE_MODE == Globals.ReleaseMode.Reader) &&
  3175                 (this._Settings.IsReaderSplashEnabled == true))
  3176             {
  3177                 System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer
  3178                 {
  3179                     Interval = 6000 // Interval to ensure Outlook loads
  3180                 };
  3181                 timer.Tick += (s, ev) =>
  3182                 {
  3183                     var splashScreen = new FormReaderSplash();
  3184                     splashScreen.Show();
  3185                     timer.Stop();
  3186                     timer.Dispose();
  3187                 };
  3188                 timer.Start();
  3189             }
  3190         }
  3191 
  3192         /// <summary>
  3193         /// Event handler for when the application is quit.
  3194         /// This is the last user code to execute in the add-in.
  3195         /// See: https://msdn.microsoft.com/en-us/library/ff869760.aspx
  3196         /// </summary>
  3197         private void Application_Quit()
  3198         {
  3199             // Disconnect global events
  3200             Globals.ConnectEvents(false);
  3201 
  3202             // Disconnect application events
  3203             this.ConnectApplicationEvents(false);
  3204 
  3205             // Disconnect watched items
  3206             this.ConnectWatchedExplorers(false);
  3207             this.ConnectWatchedInspectors(false);
  3208 
  3209             // Save configuration
  3210             this._Settings.SaveToRegistry();
  3211             this._Settings.PropertyChanged -= Settings_PropertyChanged;
  3212 
  3213             // Disconnect custom ThisAddIn event
  3214             this.FirstStartup -= ThisAddIn_FirstStartup;
  3215 
  3216             // Log loaded items
  3217             // Log.Verbose("Application_Quit: Item loaded count=" + this.watchedMailItems.Count.ToString());
  3218 
  3219             if (ThisAddIn._PEPEngine != null)
  3220             {
  3221 #if !READER_RELEASE_MODE
  3222                 // Disconnect callbacks, DO NOT use the PEPEngine property accessor (only use existing instance)
  3223                 ThisAddIn._PEPEngine.UnregisterCallbacks();
  3224                 this.adapterCallbacks = null;
  3225 #endif
  3226                 // Release the pEp engine
  3227                 Marshal.FinalReleaseComObject(ThisAddIn._PEPEngine);
  3228                 ThisAddIn._PEPEngine = null;
  3229             }
  3230 
  3231             // Stop inbox cleaning timer
  3232             if (inboxCleaner != null)
  3233             {
  3234                 inboxCleaner.Stop();
  3235                 inboxCleaner.Dispose();
  3236             }
  3237 
  3238             Log.Archive();
  3239         }
  3240 
  3241         /// <summary>
  3242         /// Event handler for when one or more new mail items are received.
  3243         /// See: https://msdn.microsoft.com/en-us/library/office/ff869202.aspx
  3244         /// </summary>
  3245         /// <param name="entryIdCollection">A collection of EntryIDs (separated by ',')
  3246         /// for each new mail item.</param>
  3247         private void Application_NewMailEx(string entryIdCollection)
  3248         {
  3249             string[] idList;
  3250             Outlook.NameSpace ns = this.Application.Session;
  3251 
  3252             Log.Verbose("Application_NewMailEx: Started processing new items.");
  3253 
  3254             if (string.IsNullOrEmpty(entryIdCollection) == false)
  3255             {
  3256                 idList = entryIdCollection.Split(',');
  3257                 foreach (string eid in idList)
  3258                 {
  3259                     try
  3260                     {
  3261                         // Try to push to decryption stack
  3262                         ThisAddIn.DecryptionStack.TryPush(eid);
  3263                     }
  3264                     catch (Exception ex)
  3265                     {
  3266                         Log.Error("Application_NewMailEx: Error processing item entryId. " + ex.ToString());
  3267                     }
  3268                 }
  3269             }
  3270 
  3271             ns = null;
  3272             Log.Verbose("Application_NewMailEx: Complete (decryption likely ongoing in background threads).");
  3273 
  3274         }
  3275 
  3276         // NOTE 08/30/2017: Removed this handler again. Tests showed that this event is occasionally called very often
  3277         // and is not suitable to replace the Items_ItemAdd event. Removed due to possible performance overhead during
  3278         // connection of new account with lots of mails.
  3279         /// <summary>
  3280         /// This event handler was added to test when the event is called and if it's more reliable than NewMailEx.
  3281         /// </summary>
  3282         /// <param name="item"></param>
  3283         //private void Application_ItemLoad(object item)
  3284         //{
  3285         //    Log.Verbose("Application_ItemLoad called.");
  3286         //}
  3287 
  3288         /// <summary>
  3289         /// Event handler that occurs whenever an Outlook item is loaded into memory.
  3290         /// See: https://msdn.microsoft.com/en-us/library/office/ff868544.aspx
  3291         /// </summary>
  3292         /// <param name="Item">A weak object reference for the loaded Outlook item.</param>
  3293         //private void Application_ItemLoad(object item)
  3294         //{
  3295         //    WatchedMailItem newItem;
  3296 
  3297         //    if (item is Outlook.MailItem)
  3298         //    {
  3299         //        newItem = new WatchedMailItem(item as Outlook.MailItem);
  3300         //        newItem.Disposed += WatchedMailItem_Disposed;
  3301 
  3302         //        this.watchedMailItems.Add(newItem);
  3303         //    }
  3304 
  3305         //    return;
  3306         //}
  3307 
  3308         /// <summary>
  3309         /// Event handler for when the application is about to send an item.
  3310         /// This event is called before the mail item is sent and will encrypt the data as necessary.
  3311         /// See: https://msdn.microsoft.com/en-us/library/office/ff865076.aspx
  3312         /// </summary>
  3313         /// <param name="item">The outlook item being sent.</param>
  3314         /// <param name="cancel">Whether to cancel the item send.</param>
  3315         private void Application_ItemSend(object item, ref bool cancel)
  3316         {
  3317             Log.Verbose("Application_ItemSend: Send started");
  3318 
  3319             if ((this.isItemSendHandlerEnabled) &&
  3320                 (item is Outlook.MailItem omi))
  3321             {
  3322                 // Only process if pEp is enabled
  3323                 if (omi?.GetIsSendProcessingEnabled() == true)
  3324                 {
  3325                     // Check if a processing state has been set
  3326                     MailItemExtensions.ProcessingState? processingState = omi.GetProcessingState();
  3327 
  3328                     // If the message has already been processed, just send it out
  3329                     if (processingState == MailItemExtensions.ProcessingState.Processed)
  3330                     {
  3331                         Log.Verbose("Application_ItemSend: Message already processed. Sending directly...");
  3332                         return;
  3333                     }
  3334                     else if (processingState == MailItemExtensions.ProcessingState.ProcessedAvoidWinmailDat)
  3335                     {
  3336                         Log.Verbose("Application_ItemSend: Message already processed. Preventing Winmail.dat and sending directly...");
  3337                         omi.AvoidWinmailDatAttachment();
  3338                         return;
  3339                     }
  3340 
  3341                     // Check for special cases
  3342                     bool processMessage = true;
  3343 
  3344                     // If S/MIME is enabled, add pEp header and do not process
  3345                     if (omi.GetIsSMIMEEnabled())
  3346                     {
  3347                         omi.SetPEPProperty(MailItemExtensions.PEPProperty.PEPProtocolVersion, "2.0");
  3348                         processMessage = false;
  3349                     }
  3350                     else if (omi.GetIsForcefullyProtected())
  3351                     {
  3352                         // If ForceProtected, create special mail
  3353                         Log.Info("Application_ItemSend: Sending forcefully protected message.");
  3354 
  3355                         if (FPPMessage.ProcessOutgoing(omi) == Globals.ReturnStatus.Success)
  3356                         {
  3357                             Log.Verbose("Application_ItemSend: Successfully processed outgoing message.");
  3358                         }
  3359                         else
  3360                         {
  3361                             cancel = true;
  3362                             processMessage = false;
  3363                             Log.Error("Application_ItemSend: Error creating forcefully protected message.");
  3364                         }
  3365                     }
  3366 
  3367                     // If no special case was found, process normally
  3368                     if (processMessage)
  3369                     {
  3370                         string sendUnencryptedWarning = Properties.Resources.Message_SendError + Environment.NewLine + Environment.NewLine + Properties.Resources.Message_SendUnencryptedConfirmation;
  3371                         DialogResult result;
  3372                         Globals.ReturnStatus status;
  3373 
  3374                         try
  3375                         {
  3376                             Log.Verbose("Application_ItemSend: Starting encryption and message processing.");
  3377 
  3378                             status = PEPMessage.Create(omi, out PEPMessage message);
  3379                             if (status == Globals.ReturnStatus.Success)
  3380                             {
  3381                                 /* If the message was marked to be processed in the background, cancel the normal
  3382                                  * send process and process the message further in the dedicated method.
  3383                                  */
  3384                                 if (processingState == MailItemExtensions.ProcessingState.ProcessInBackground)
  3385                                 {
  3386                                     cancel = true;
  3387                                     Log.Verbose("Application_ItemSend: Canceling normal sending and initiating background processing.");
  3388                                     omi.ProcessAndSendMessageAsync(message);
  3389                                     return;
  3390                                 }
  3391                                 else
  3392                                 {
  3393                                     // Process outgoing message
  3394                                     Log.Verbose("Application_ItemSend: Normal processing.");
  3395 
  3396                                     MsgProcessor processor = new MsgProcessor();
  3397                                     if (processor.ProcessSentMessage(message, Globals.ThisAddIn.Settings.ExtraKeys, out PEPMessage processedMessage) != Globals.ReturnStatus.Success)
  3398                                     {
  3399                                         throw new Exception("Error processing message.");
  3400                                     }
  3401 
  3402                                     // Apply processed message to outgoing item
  3403                                     processedMessage.ApplyTo(omi, false, false, false);
  3404 
  3405                                     // Set Reply or forward icon on original message if needed
  3406                                     string originalEntryId = omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID) as string;
  3407                                     if (string.IsNullOrEmpty(originalEntryId) == false)
  3408                                     {
  3409                                         omi.AddReplyIconsToOriginal(originalEntryId);
  3410                                     }
  3411 
  3412                                     // Avoid creation of 'winmail.dat' attachment if needed
  3413                                     if (processedMessage.IsSecure == false)
  3414                                     {
  3415                                         omi.AvoidWinmailDatAttachment();
  3416                                     }
  3417                                 }
  3418                             }
  3419                             else if (status == Globals.ReturnStatus.FailureNoConnection)
  3420                             {
  3421                                 // Don't send the original message
  3422                                 cancel = true;
  3423 
  3424                                 if (omi?.GetIsAutoConsume() != true)
  3425                                 {
  3426                                     MessageBox.Show(Properties.Resources.Message_SendingNoConnection,
  3427                                                     Properties.Resources.Message_TitlePEPError,
  3428                                                     MessageBoxButtons.OK,
  3429                                                     MessageBoxIcon.Warning);
  3430                                 }
  3431                             }
  3432                             else
  3433                             {
  3434                                 // Throw the error out to the main catch
  3435                                 throw (new Exception("Failed to create PEPMessage"));
  3436                             }
  3437                         }
  3438                         catch (Exception ex)
  3439                         {
  3440                             Log.Error("Application_ItemSend: Send failure, " + ex.ToString());
  3441 
  3442                             if (processingState == MailItemExtensions.ProcessingState.ProcessInBackground)
  3443                             {
  3444                                 omi.Display();
  3445                             }
  3446 
  3447                             // Ask the user to continue (not for automatic messages)
  3448                             if (omi?.GetIsAutoConsume() != true)
  3449                             {
  3450                                 result = MessageBox.Show(sendUnencryptedWarning,
  3451                                                          Properties.Resources.Message_TitlePEPError,
  3452                                                          MessageBoxButtons.YesNo,
  3453                                                          MessageBoxIcon.Error);
  3454                                 cancel = (result != DialogResult.Yes);
  3455                             }
  3456 
  3457                             Log.Info("Application_ItemSend: Error during sending. " + (cancel ? "User aborted sending." : "user chose to send mail unencrypted."));
  3458                         }
  3459                     }
  3460                 }
  3461                 else if (omi != null)
  3462                 {
  3463                     Log.Info("Application_ItemSend: Item skipped because pEp is disabled or message is sent forcefully unencrypted.");
  3464 
  3465                     // Add disclaimer if needed
  3466                     omi.AddDisclaimer();
  3467 
  3468                     // Avoid creation of 'winmail.dat' attachment
  3469                     omi.AvoidWinmailDatAttachment();
  3470                 }
  3471                 else
  3472                 {
  3473                     Log.Error("Application_ItemSend: " + ((item == null) ? "item is null" : "error casting item to Outlook.MailItem"));
  3474                 }
  3475 
  3476                 omi = null;
  3477             }
  3478             else
  3479             {
  3480                 Log.Verbose("Application_ItemSend: Item is null, not a MailItem or item send handler is disabled.");
  3481             }
  3482 
  3483             Log.Verbose("Application_ItemSend: Completed. cancel=" + cancel.ToString());
  3484         }
  3485 
  3486         /// <summary>
  3487         /// Event handler for when a property changes within the active settings.
  3488         /// Warning: This code should be kept synchronized with the SyncWithSettings method.
  3489         /// </summary>
  3490         private void Settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
  3491         {
  3492             bool exists;
  3493             pEpIdentity[] ownIdentities;
  3494             PEPSettings settings = (PEPSettings)sender;
  3495             List<KeyValuePair<CultureInfo, string>> languages;
  3496 
  3497             switch (e.PropertyName)
  3498             {
  3499                 case (nameof(PEPSettings.IsKeyServerUsed)):
  3500                     {
  3501                         // Sync IsKeyServerUsed with engine
  3502                         if (settings.IsKeyServerUsed)
  3503                         {
  3504                             ThisAddIn.PEPEngine.StartKeyserverLookup();
  3505                         }
  3506                         else
  3507                         {
  3508                             ThisAddIn.PEPEngine.StopKeyserverLookup();
  3509                         }
  3510                         break;
  3511                     }
  3512                 case (nameof(PEPSettings.IsPassiveModeEnabled)):
  3513                     {
  3514                         // Sync IsPassiveModeEnabled with engine
  3515                         ThisAddIn.PEPEngine.PassiveMode(settings.IsPassiveModeEnabled);
  3516                         break;
  3517                     }
  3518                 case (nameof(PEPSettings.IsPEPFolderVisible)):
  3519                     {
  3520                         // Sync IsPEPFolderVisible with Outlook
  3521                         this.SetPEPStoreRootFolderVisibility(settings.IsPEPFolderVisible);
  3522                         break;
  3523                     }
  3524                 case (nameof(PEPSettings.IsUnencryptedSubjectEnabled)):
  3525                     {
  3526                         // Sync IsUnencryptedSubjectEnabled with engine
  3527                         ThisAddIn.PEPEngine.UnencryptedSubject(settings.IsUnencryptedSubjectEnabled);
  3528                         break;
  3529                     }
  3530                 case (nameof(PEPSettings.IsVerboseLoggingEnabled)):
  3531                     {
  3532                         // Sync IsVerboseLoggingEnabled with engine
  3533                         ThisAddIn.PEPEngine.VerboseLogging(settings.IsVerboseLoggingEnabled);
  3534                         break;
  3535                     }
  3536                 case (nameof(PEPSettings.TrustwordsCulture)):
  3537                     {
  3538                         // Sync TrustwordsCulture with engine
  3539                         if (this._Settings.TrustwordsCulture != null)
  3540                         {
  3541                             // Validate it exists in the engine list
  3542                             exists = false;
  3543                             languages = this.LanguageList;
  3544                             foreach (KeyValuePair<CultureInfo, string> entry in languages)
  3545                             {
  3546                                 if (entry.Key.LCID == this._Settings.TrustwordsCulture.LCID)
  3547                                 {
  3548                                     exists = true;
  3549                                     break;
  3550                                 }
  3551                             }
  3552 
  3553                             if (exists == false)
  3554                             {
  3555                                 // Reset to default
  3556                                 this._Settings.TrustwordsCulture = this.GetActiveUICulture();
  3557                                 Log.Warning("Settings_PropertyChanged: Invalid TrustwordsCulture detected, setting to default.");
  3558                             }
  3559                         }
  3560                         else
  3561                         {
  3562                             // Reset to default
  3563                             this._Settings.TrustwordsCulture = this.GetActiveUICulture();
  3564                         }
  3565                         break;
  3566                     }
  3567                 default:
  3568                     {
  3569                         // Account sync
  3570                         if (e.PropertyName.StartsWith("AccountSettingsList") &&
  3571                             e.PropertyName.EndsWith("IsSyncEnabled"))
  3572                         {
  3573                             /* Sync the account settings with the engine's own identity flags.
  3574                              * Warning: RegisterMyself() must already have been called so the engine has all own identities.
  3575                              * The engine can commonly have more own identities than what is in the accounts list.
  3576                              * This isn't a problem though and engine-only identities will not be changed here.
  3577                              */
  3578                             ownIdentities = ThisAddIn.PEPEngine.OwnIdentitiesRetrieve();
  3579                             foreach (PEPSettings.PEPAccountSettings acctSettings in this._Settings.AccountSettingsList)
  3580                             {
  3581                                 // Find the own identity that matches with the account settings
  3582                                 foreach (pEpIdentity ident in ownIdentities)
  3583                                 {
  3584                                     pEpIdentity ownIdent = ident;
  3585 
  3586                                     if (acctSettings.EqualsByAddress(ownIdent.Address))
  3587                                     {
  3588                                         // Sync the engine's own identity flags with the account settings
  3589                                         if (ownIdent.GetIsSyncEnabled() != acctSettings.IsSyncEnabled)
  3590                                         {
  3591                                             if (acctSettings.IsSyncEnabled)
  3592                                             {
  3593                                                 ThisAddIn.PEPEngine.UnsetIdentityFlags(ref ownIdent, pEpIdentityFlags.pEpIdfNotForSync);
  3594                                             }
  3595                                             else
  3596                                             {
  3597                                                 ThisAddIn.PEPEngine.SetIdentityFlags(ref ownIdent, pEpIdentityFlags.pEpIdfNotForSync);
  3598                                             }
  3599                                         }
  3600 
  3601                                         break;
  3602                                     }
  3603                                 }
  3604                             }
  3605                         }
  3606 
  3607                         break;
  3608                     }
  3609             }
  3610         }
  3611 
  3612         /// <summary>
  3613         /// Event handler that occurs whenever a watched mail item is being disposed.
  3614         /// </summary>
  3615         //private void WatchedMailItem_Disposed(object sender, EventArgs e)
  3616         //{
  3617         //    WatchedMailItem item = sender as WatchedMailItem;
  3618 
  3619         //    this.watchedMailItems.Remove(item);
  3620         //    item.Disposed -= WatchedMailItem_Disposed;
  3621 
  3622         //    return;
  3623         //}
  3624 
  3625         /**************************************************************
  3626          * 
  3627          * Sub-classes
  3628          * 
  3629          *************************************************************/
  3630 
  3631         /// <summary>
  3632         /// Stores a MailItem with connected events after it is loaded by Outlook.
  3633         /// </summary>
  3634         //private class WatchedMailItem : IDisposable
  3635         //{
  3636         //    /// <summary>
  3637         //    /// Occurs when the component is disposed by a call to the Dispose method.
  3638         //    /// </summary>
  3639         //    public event EventHandler Disposed;
  3640 
  3641         //    /// <summary>
  3642         //    /// Gets the MailItem object.
  3643         //    /// </summary>
  3644         //    private Outlook.MailItem mailItem;
  3645 
  3646         //    /**************************************************************
  3647         //     * 
  3648         //     * Constructors/Destructors
  3649         //     * 
  3650         //     *************************************************************/
  3651 
  3652         //    /// <summary>
  3653         //    /// Primary constructor.
  3654         //    /// </summary>
  3655         //    /// <param name="mailItem">The mail item to watch.</param>
  3656         //    public WatchedMailItem(Outlook.MailItem mailItem)
  3657         //    {
  3658         //        this.mailItem = mailItem;
  3659 
  3660         //        if (this.mailItem != null)
  3661         //        {
  3662         //            ((Outlook.ItemEvents_10_Event)this.mailItem).BeforeRead += MailItem_BeforeRead;
  3663         //            ((Outlook.ItemEvents_10_Event)this.mailItem).Unload += MailItem_Unload;
  3664         //            ((Outlook.ItemEvents_10_Event)this.mailItem).Write += MailItem_Write;
  3665         //        }
  3666         //    }
  3667 
  3668         //    /// <summary>
  3669         //    /// Destructor.
  3670         //    /// </summary>
  3671         //    ~WatchedMailItem()
  3672         //    {
  3673         //        this.Dispose();
  3674         //    }
  3675 
  3676         //    /**************************************************************
  3677         //     * 
  3678         //     * Methods
  3679         //     * 
  3680         //     *************************************************************/
  3681 
  3682         //    /// <summary>
  3683         //    /// Releases all resources and disconnects internal events.
  3684         //    /// </summary>
  3685         //    public void Dispose()
  3686         //    {
  3687         //        if (this.mailItem != null)
  3688         //        {
  3689         //            ((Outlook.ItemEvents_10_Event)this.mailItem).BeforeRead -= MailItem_BeforeRead;
  3690         //            ((Outlook.ItemEvents_10_Event)this.mailItem).Unload -= MailItem_Unload;
  3691         //            ((Outlook.ItemEvents_10_Event)this.mailItem).Write -= MailItem_Write;
  3692 
  3693         //            // Marshal.ReleaseComObject(this.mailItem);
  3694         //            this.mailItem = null;
  3695 
  3696         //            // Raise the disposed event
  3697         //            this.Disposed.Invoke(this, new EventArgs());
  3698         //        }
  3699 
  3700         //        return;
  3701         //    }
  3702 
  3703         //    /**************************************************************
  3704         //     * 
  3705         //     * Event Handling
  3706         //     * 
  3707         //     *************************************************************/
  3708 
  3709         //    /// <summary>
  3710         //    /// Event handler for when the mail item is unloaded from memory (programmatically or by user action).
  3711         //    /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.unload.aspx
  3712         //    /// </summary>
  3713         //    private void MailItem_Unload()
  3714         //    {
  3715         //        this.Dispose();
  3716         //        return;
  3717         //    }
  3718 
  3719         //    /// <summary>
  3720         //    /// Event handler that occurs before Outlook begins to read the properties for the mail item.
  3721         //    /// See: https://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook.itemevents_10_event.beforeread.aspx
  3722         //    /// </summary>
  3723         //    private void MailItem_BeforeRead()
  3724         //    {
  3725         //        return;
  3726         //    }
  3727 
  3728         //    /// <summary>
  3729         //    /// Event handler for when the mail item is saved.
  3730         //    /// See: https://msdn.microsoft.com/en-us/library/office/ff868664.aspx
  3731         //    /// </summary>
  3732         //    /// <param name="cancel">Whether to cancel the item write.</param>
  3733         //    private void MailItem_Write(ref bool cancel)
  3734         //    {
  3735         //        return;
  3736         //    }
  3737         //}
  3738 
  3739         /// <summary>
  3740         /// Stores an Outlook Folder with connected events.
  3741         /// </summary>
  3742         private class WatchedFolder : IDisposable
  3743         {
  3744             /// <summary>
  3745             /// Occurs when the component is disposed by a call to the Dispose method.
  3746             /// </summary>
  3747             public event EventHandler Disposed;
  3748 
  3749             private Outlook.OlAccountType       accountType;
  3750             private Outlook.OlDefaultFolders?   defaultFolder;
  3751             private Outlook.Folder              folder;
  3752             private Outlook.Items               items;
  3753 
  3754             /**************************************************************
  3755              * 
  3756              * Constructors/Destructors
  3757              * 
  3758              *************************************************************/
  3759 
  3760             /// <summary>
  3761             /// Primary constructor.
  3762             /// </summary>
  3763             /// <param name="folder">The folder to watch.</param>
  3764             /// <param name="defaultFolder">The default folder type (null if none).</param>
  3765             public WatchedFolder(Outlook.Folder folder,
  3766                                  Outlook.OlDefaultFolders? defaultFolder)
  3767             {
  3768                 this.folder = folder;
  3769                 this.defaultFolder = defaultFolder;
  3770                 this.items = this.folder?.Items;
  3771                 this.accountType = folder.GetAccountType();
  3772 
  3773                 if (this.folder != null)
  3774                 {
  3775                     this.folder.BeforeFolderMove += new Outlook.MAPIFolderEvents_12_BeforeFolderMoveEventHandler(Folder_BeforeFolderMove);
  3776                     this.folder.BeforeItemMove += new Outlook.MAPIFolderEvents_12_BeforeItemMoveEventHandler(Folder_BeforeItemMove);
  3777                 }
  3778 
  3779                 if (this.items != null)
  3780                 {
  3781                     this.items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(Items_ItemAdd);
  3782                 }
  3783             }
  3784 
  3785             /// <summary>
  3786             /// Destructor.
  3787             /// </summary>
  3788             ~WatchedFolder()
  3789             {
  3790                 this.Dispose();
  3791             }
  3792 
  3793             /**************************************************************
  3794              * 
  3795              * Methods
  3796              * 
  3797              *************************************************************/
  3798 
  3799             /// <summary>
  3800             /// Releases all resources and disconnects internal events.
  3801             /// </summary>
  3802             public void Dispose()
  3803             {
  3804                 if (this.folder != null)
  3805                 {
  3806                     this.folder.BeforeFolderMove -= Folder_BeforeFolderMove;
  3807                     this.folder.BeforeItemMove -= Folder_BeforeItemMove;
  3808 
  3809                     // Marshal.ReleaseComObject(this.folder);
  3810                     this.folder = null;
  3811                 }
  3812 
  3813                 if (this.items != null)
  3814                 {
  3815                     this.items.ItemAdd -= Items_ItemAdd;
  3816 
  3817                     // Marshal.ReleaseComObject(this.items);
  3818                     this.items = null;
  3819                 }
  3820 
  3821                 // Raise the disposed event
  3822                 if (this.Disposed != null)
  3823                     this.Disposed.Invoke(this, new EventArgs());
  3824             }
  3825 
  3826             /**************************************************************
  3827              * 
  3828              * Event Handling
  3829              * 
  3830              *************************************************************/
  3831 
  3832             /// <summary>
  3833             /// Event handler that occurs when an item is added to the folder items list.
  3834             /// Warning: This event does not run when a large number of items are added to the folder at once.
  3835             /// See: https://msdn.microsoft.com/en-us/library/office/ff869609.aspx
  3836             /// </summary>
  3837             private void Items_ItemAdd(object item)
  3838             {
  3839                 bool process = false;
  3840                 object propValue = null;
  3841                 Outlook.MailItem omi = null;
  3842                 Outlook.Attachments attachments = null;
  3843 
  3844                 try
  3845                 {
  3846                     Log.Verbose("Items_ItemAdd raised. Processing mail item...");
  3847 
  3848                     // This is also the check to see if it's a mail item
  3849                     omi = item as Outlook.MailItem;
  3850 
  3851                     if (omi != null)
  3852                     {
  3853                         string entryId = omi.EntryID;
  3854 
  3855                         // Check, if message is a beacon or keysync message in Sent folder and delete it in this case
  3856                         if ((this.defaultFolder != null) &&
  3857                             (this.defaultFolder == Outlook.OlDefaultFolders.olFolderSentMail))
  3858                         {
  3859                             omi.GetPEPProperty(MailItemExtensions.PEPProperty.AutoConsume, out propValue);
  3860                             if (propValue != null)
  3861                             {
  3862                                 omi.PermanentlyDelete();
  3863                                 Log.Verbose("Items_ItemAdd: pEp internal mail item in Sent folder was deleted.");
  3864                             }
  3865                             else if (MailItemExtensions.IsInCopiedItemsList(entryId) == false)
  3866                             {
  3867                                 process = true;
  3868                             }
  3869                         }
  3870                         /* Else, process the mail item and decrypt it. This is needed especially for Sent folders as sent mails are normally
  3871                          * not read and therefore remain encrypted and not searchable in this folder.
  3872                          * 
  3873                          * NOTE: Via debugging, it could be determined that the Copy() method called during the creation of a mirror item on
  3874                          * untrusted servers most likely raises internally the Items.ItemAdd event. Therefore, we add the copied item's EntryID
  3875                          * to a list of copied items during its processing and check here if the newly added mail item is in this list. If yes,
  3876                          * do not process it. However, if for whatever reason, the ItemAdd event for one of those copied items was to be raised 
  3877                          * at a later stage, we might run into problems with a loop of copied items that will be processed, copied during creation
  3878                          * of the mirror, raise an ItemAdd event for the new copy and so on.
  3879                          */
  3880                         else if (MailItemExtensions.IsInCopiedItemsList(entryId) == false)
  3881                         {
  3882                             process = true;
  3883                             Log.Verbose("Items_ItemAdd: mail item to be processed.");
  3884                         }
  3885 
  3886                         // If this item is to be processed, add to decryption stack
  3887                         if (process)
  3888                         {
  3889                             /* If potentially encrypted message, hide during processing.
  3890                              * Note: on IMAP, there seems to be some race condition that leads to a failure during the Save() method when removing
  3891                              * the 'pEp Processing' category. As this means that in those environments, this category doesn't get removed correctly
  3892                              * and the mail item remains hidden until a restart of Outlook. Therefore, don't hide messages on IMAP.
  3893                              */
  3894                             try
  3895                             {
  3896                                 if ((Globals.ThisAddIn.Settings.IsUXImprovementEnabled) &&
  3897                                     (this.accountType != Outlook.OlAccountType.olImap))
  3898                                 {
  3899                                     attachments = omi.Attachments;
  3900                                     if (attachments.Count == 2)
  3901                                     {
  3902                                         omi.AddPEPProcessingCategory();
  3903                                         omi.UnRead = false;
  3904                                         omi.Save();
  3905                                     }
  3906                                 }
  3907                             }
  3908                             catch (Exception ex)
  3909                             {
  3910                                 Log.Error("Items_ItemAdd. Error adding pEp processing category. " + ex.ToString());
  3911                             }
  3912                             finally
  3913                             {
  3914                                 attachments = null;
  3915                             }
  3916 
  3917                             ThisAddIn.DecryptionStack.TryPush(entryId);
  3918                         }
  3919                     }
  3920                 }
  3921                 catch (Exception ex)
  3922                 {
  3923                     Log.Error("Items_ItemAdd. Error occured. " + ex.ToString());
  3924                 }
  3925                 finally
  3926                 {
  3927                     omi = null;
  3928                 }
  3929             }
  3930 
  3931             /// <summary>
  3932             /// Event handler that occurs when an item is about to be moved or deleted from a folder, 
  3933             /// either as a result of user action or through program code.
  3934             /// See: https://msdn.microsoft.com/en-us/library/office/ff869445.aspx
  3935             /// </summary>
  3936             private void Folder_BeforeItemMove(object item, Outlook.MAPIFolder moveTo, ref bool cancel)
  3937             {
  3938                 return;
  3939             }
  3940 
  3941             /// <summary>
  3942             /// Event handler that accours when a folder is about to be moved or deleted, 
  3943             /// either as a result of user action or through program code.
  3944             /// See: https://msdn.microsoft.com/en-us/library/office/ff868895.aspx
  3945             /// </summary>
  3946             private void Folder_BeforeFolderMove(Outlook.MAPIFolder moveTo, ref bool cancel)
  3947             {
  3948                 return;
  3949             }
  3950         }
  3951     }
  3952 }