Fix draft protection for inline messages OUT-473
authorThomas
Fri, 13 Jul 2018 14:18:27 +0200
branchOUT-473
changeset 22932dd69aea9675
parent 2288 f8d4e72e617f
child 2294 9be4bcec40f0
Fix draft protection for inline messages
CryptableMailItem.cs
ThisAddIn.cs
UI/FormRegionPrivacyStatus.cs
Wrappers/WatchedExplorer.cs
pEpForOutlook.csproj
     1.1 --- a/CryptableMailItem.cs	Wed Jul 11 15:28:31 2018 +0200
     1.2 +++ b/CryptableMailItem.cs	Fri Jul 13 14:18:27 2018 +0200
     1.3 @@ -106,6 +106,7 @@
     1.4          private BackgroundWorker                  mirrorLocator;
     1.5          private BackgroundWorker                  processor;
     1.6  
     1.7 +        private string                            draftEntryId          = null;
     1.8          private string                            draftFileName         = null;
     1.9          private object                            mutexMailItem         = new object();
    1.10          private static object                     mutexConversation     = new object();
    1.11 @@ -113,25 +114,41 @@
    1.12          private static List<OriginalMailItem>     conversationCache     = new List<OriginalMailItem>();
    1.13          private static Dictionary<string, string> decryptionList        = new Dictionary<string, string>();
    1.14  
    1.15 -        /* Stores the message id of an attached mail item if it is loaded into the preview. 
    1.16 -         * See comments below in MailItem_BeforeAttachmentPreview event handler.
    1.17 -         */
    1.18 -        public static string    PreviewAttachedMailId = null;
    1.19 +        /// <summary>
    1.20 +        /// Stores the message id of an attached mail item if it is loaded into the preview.
    1.21 +        /// See comments below in MailItem_BeforeAttachmentPreview event handler.
    1.22 +        /// </summary>
    1.23 +        public static string PreviewAttachedMailId = null;
    1.24  
    1.25 -        // Whether to cancel the opening event of the internal mail item. Default is false.
    1.26 -        public bool         CancelOpen              { get; set; } = false;
    1.27 +        /// <summary>
    1.28 +        /// Whether to cancel the opening event of the internal mail item. Default is false.
    1.29 +        /// </summary>
    1.30 +        public bool CancelOpen { get; set; } = false;
    1.31  
    1.32 -        // The messageId of the internal mail item. Only needed for special cases like attached mails.
    1.33 -        public string       MessageId               { get; set; } = null;
    1.34 +        /// <summary>
    1.35 +        /// The messageId of the internal mail item. Only needed for special cases like attached mails.
    1.36 +        /// </summary>
    1.37 +        public string MessageId { get; set; } = null;
    1.38  
    1.39 -        // Whether the internal mail item is an attached mail
    1.40 -        public bool         IsSecureAttachedMail    { get; set; } = false;
    1.41 +        /// <summary>
    1.42 +        /// Whether the internal mail item is an inline response
    1.43 +        /// </summary>
    1.44 +        public bool IsInlineResponse { get; set; } = false;
    1.45  
    1.46 -        // The mirror of the internal mail item stored as PEPMessage
    1.47 -        public PEPMessage   Mirror                  { get; set; } = null;
    1.48 +        /// <summary>
    1.49 +        /// Whether the internal mail item is an attached mail.
    1.50 +        /// </summary>
    1.51 +        public bool IsSecureAttachedMail { get; set; } = false;
    1.52  
    1.53 -        // The PEPMessage of this mail item
    1.54 -        public PEPMessage   Message                 { get; set; } = null;
    1.55 +        /// <summary>
    1.56 +        /// The mirror of the internal mail item stored as PEPMessage.
    1.57 +        /// </summary>
    1.58 +        public PEPMessage Mirror { get; set; } = null;
    1.59 +
    1.60 +        /// <summary>
    1.61 +        /// The PEPMessage of this mail item.
    1.62 +        /// </summary>
    1.63 +        public PEPMessage Message { get; set; } = null;
    1.64  
    1.65          /**************************************************************
    1.66           * 
    1.67 @@ -379,6 +396,7 @@
    1.68               * First we try to save it to a custom drafts folder in the pEp store
    1.69               * and make this store visible in the favorites.
    1.70               * If this fails, as a fallback solution, we offer to save as a message file.
    1.71 +             * Note: Inline responses need to be processed differently.
    1.72               */
    1.73              if ((this.HasBeenSent == false) &&
    1.74                  (this.IsPEPMessage == false) &&
    1.75 @@ -386,6 +404,7 @@
    1.76                  ((this.internalMailItem.GetIsInSecureStore() || this.internalMailItem.GetNeverUnsecure())))
    1.77              {
    1.78                  bool useFallback = false;
    1.79 +                Outlook.Folder parentFolder = null;
    1.80                  Outlook.Folder pEpDraftsFolder = null;
    1.81                  Outlook.Inspector currentInspector = null;
    1.82                  Outlook.Inspector newInspector = null;
    1.83 @@ -402,48 +421,90 @@
    1.84  
    1.85                  try
    1.86                  {
    1.87 +                    // Get the pEp drafts folder and the current mail item's folder
    1.88                      pEpDraftsFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
    1.89  
    1.90 -                    // Save to pEp drafts folder if available
    1.91 -                    if (pEpDraftsFolder != null)
    1.92 +                    /* Inline responses need a special treatment.
    1.93 +                     * We cannot just intercept the Write event and check, if the item
    1.94 +                     * is in the pEp folder, as it gets synced to the server anyhow if we
    1.95 +                     * don't cancel the event.
    1.96 +                     * So, we look up if the mail item is already present in pEp drafts and overwrite it 
    1.97 +                     * with the current state if possible. If the item isn't there yet, create new item, 
    1.98 +                     * move to pEp drafts folder and save current state.
    1.99 +                     */
   1.100 +                    if (this.IsInlineResponse)
   1.101                      {
   1.102 -                        // Cancel the Write event for inline responses
   1.103 -                        app = Globals.ThisAddIn.Application;
   1.104 -                        activeExplorer = app?.ActiveExplorer();
   1.105 -                        cancel = (activeExplorer?.ActiveInlineResponse != null);
   1.106 +                        Outlook.Items items = null;
   1.107 +                        Outlook.MailItem draft = null;
   1.108  
   1.109 -                        // Try to move mail item to pEp drafts folder, if it's
   1.110 -                        // not already there.
   1.111 -                        var parent = this.internalMailItem.Parent as Outlook.Folder;
   1.112 -                        if (parent != pEpDraftsFolder // identity comparison of folders does not work
   1.113 -                            && parent.FullFolderPath != pEpDraftsFolder.FullFolderPath)
   1.114 +                        try
   1.115                          {
   1.116 -                            try
   1.117 +                            // Always cancel
   1.118 +                            cancel = true;
   1.119 +
   1.120 +                            // Try to find the draft (if existing)
   1.121 +                            if (string.IsNullOrEmpty(this.draftEntryId) == false)
   1.122                              {
   1.123 -                                omi = this.internalMailItem.Move(pEpDraftsFolder);
   1.124 -                            }
   1.125 -                            catch (Exception ex)
   1.126 -                            {
   1.127 -                                Log.Error("MailItem_Write: Error during moving to pEpDraftsFolder: " + ex.ToString());
   1.128 -                                omi = null;
   1.129 +                                // Get all items in the pEp drafts folder with the same subject as the current draft
   1.130 +                                items = pEpDraftsFolder?.Items?.Restrict(string.Format("[Subject] = '{0}'", this.internalMailItem?.Subject));
   1.131 +
   1.132 +                                for (int i = 1; i <= items?.Count; i++)
   1.133 +                                {
   1.134 +                                    draft = items[i] as Outlook.MailItem;
   1.135 +
   1.136 +                                    if (draftEntryId.Equals(draft?.EntryID) == true)
   1.137 +                                    {
   1.138 +                                        // Draft found. Just break and continue.
   1.139 +                                        break;
   1.140 +                                    }
   1.141 +
   1.142 +                                    draft = null;
   1.143 +                                }
   1.144 +
   1.145 +                                items = null;
   1.146                              }
   1.147  
   1.148 -                            // OUT-473: Workaround for "This method can't be used with an inline response mail item" exception
   1.149 -                            if (omi == null)
   1.150 -                            {                                                                
   1.151 -                                PEPMessage createdMessage = null;
   1.152 -                                if (PEPMessage.Create(this.internalMailItem, out createdMessage) == Globals.ReturnStatus.Success)
   1.153 +                            PEPMessage createdMessage = null;
   1.154 +                            if (PEPMessage.Create(this.internalMailItem, out createdMessage) == Globals.ReturnStatus.Success)
   1.155 +                            {
   1.156 +                                if (draft == null)
   1.157                                  {
   1.158 -                                    omi = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
   1.159 -                                    createdMessage.ApplyTo(omi, true, true);
   1.160 -                                    this.internalMailItem = omi.Move(pEpDraftsFolder);
   1.161 -                                    this.internalMailItem.Save();
   1.162 -                                    cancel = true;
   1.163 -                                    this.Write?.Invoke(ref cancel);
   1.164 -                                    return;
   1.165 +                                    draft = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
   1.166 +                                    createdMessage.ApplyTo(draft, true, true);
   1.167 +                                    draft = draft.Move(pEpDraftsFolder);
   1.168 +                                    draft.Save();
   1.169 +                                    this.draftEntryId = draft.EntryID;
   1.170 +                                }
   1.171 +                                else
   1.172 +                                {
   1.173 +                                    createdMessage.ApplyTo(draft, true, true);
   1.174 +                                    draft.Save();
   1.175                                  }
   1.176                              }
   1.177 +                            else
   1.178 +                            {
   1.179 +                                Log.Error("MailItem_Write: Error creating PEPMessage.");
   1.180 +                            }
   1.181 +                        }
   1.182 +                        catch (Exception ex)
   1.183 +                        {
   1.184 +                            Log.Error("MailItem_Write: Error saving inline item. " + ex.ToString());
   1.185 +                        }
   1.186 +                        finally
   1.187 +                        {
   1.188 +                            items = null;
   1.189 +                            omi = null;
   1.190 +                        }
   1.191 +                    }
   1.192 +                    else
   1.193 +                    {
   1.194 +                        // Get the mail item's parent folder
   1.195 +                        parentFolder = this.internalMailItem.Parent as Outlook.Folder;
   1.196  
   1.197 +                        // Save to pEp folder if not already there
   1.198 +                        if (pEpDraftsFolder?.FullFolderPath?.Equals(parentFolder?.FullFolderPath) == false)
   1.199 +                        {
   1.200 +                            omi = this.internalMailItem.Move(pEpDraftsFolder);
   1.201                              currentInspector = this.internalMailItem.GetInspector;
   1.202  
   1.203                              if (currentInspector != null)
   1.204 @@ -507,45 +568,45 @@
   1.205  
   1.206                              cancel = true;
   1.207                          }
   1.208 +                    }
   1.209  
   1.210 -                        /* Add the pEp drafts folder to favorites.
   1.211 -                         * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
   1.212 -                         * To make this more secure, we only proceed if the pEp store is already visible at this point.
   1.213 -                         * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
   1.214 -                         * to the favorites next time.
   1.215 +                    /* Add the pEp drafts folder to favorites.
   1.216 +                     * This is dangerous, as the Add() method crashes Outlook if the pEp store is not visible.
   1.217 +                     * To make this more secure, we only proceed if the pEp store is already visible at this point.
   1.218 +                     * Otherwise, we just set the pEp store's visibility to true and try to add the drafts folder
   1.219 +                     * to the favorites next time.
   1.220 +                     */
   1.221 +                    if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
   1.222 +                    {
   1.223 +                        // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
   1.224 +                        app = Globals.ThisAddIn?.Application;
   1.225 +                        activeExplorer = app?.ActiveExplorer();
   1.226 +                        navPane = activeExplorer?.NavigationPane;
   1.227 +                        navModules = navPane?.Modules;
   1.228 +                        mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
   1.229 +                        navGroups = mailModule?.NavigationGroups;
   1.230 +                        navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
   1.231 +                        navFolders = navGroup?.NavigationFolders;
   1.232 +
   1.233 +                        /* Check, if pEp drafts folder is already in favorites
   1.234 +                         * WARNING: If for whatever reason, the pEp store is not visible
   1.235 +                         * at this point, the Add() method crashes Outlook!
   1.236                           */
   1.237 -                        if (Globals.ThisAddIn.Settings.IsPEPFolderVisible)
   1.238 +                        if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
   1.239                          {
   1.240 -                            // Get favorite folders group. See: https://msdn.microsoft.com/en-us/library/office/ff865603.aspx
   1.241 -                            app = Globals.ThisAddIn?.Application;
   1.242 -                            activeExplorer = app?.ActiveExplorer();
   1.243 -                            navPane = activeExplorer?.NavigationPane;
   1.244 -                            navModules = navPane?.Modules;
   1.245 -                            mailModule = navModules?.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleMail) as Outlook.MailModule;
   1.246 -                            navGroups = mailModule?.NavigationGroups;
   1.247 -                            navGroup = navGroups?.GetDefaultNavigationGroup(Outlook.OlGroupType.olFavoriteFoldersGroup);
   1.248 -                            navFolders = navGroup?.NavigationFolders;
   1.249 -
   1.250 -                            /* Check, if pEp drafts folder is already in favorites
   1.251 -                             * WARNING: If for whatever reason, the pEp store is not visible
   1.252 -                             * at this point, the Add() method crashes Outlook!
   1.253 -                             */
   1.254 -                            if (navFolders[Globals.PEP_DRAFTS_FOLDER_NAME] == null)
   1.255 +                            if (navFolders != null)
   1.256                              {
   1.257 -                                if (navFolders != null)
   1.258 -                                {
   1.259 -                                    navFolders.Add(pEpDraftsFolder);
   1.260 -                                }
   1.261 -                                else
   1.262 -                                {
   1.263 -                                    Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
   1.264 -                                }
   1.265 +                                navFolders.Add(pEpDraftsFolder);
   1.266 +                            }
   1.267 +                            else
   1.268 +                            {
   1.269 +                                Log.Error("Cannot add pEp drafts folder to favorites because the folder could not be retrieved.");
   1.270                              }
   1.271                          }
   1.272 -                        else
   1.273 -                        {
   1.274 -                            Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
   1.275 -                        }
   1.276 +                    }
   1.277 +                    else
   1.278 +                    {
   1.279 +                        Globals.ThisAddIn.Settings.IsPEPFolderVisible = true;
   1.280                      }
   1.281                  }
   1.282                  catch (Exception ex)
   1.283 @@ -556,6 +617,7 @@
   1.284                  finally
   1.285                  {
   1.286                      currentInspector = null;
   1.287 +                    parentFolder = null;
   1.288                      pEpDraftsFolder = null;
   1.289                      omi = null;
   1.290  
     2.1 --- a/ThisAddIn.cs	Wed Jul 11 15:28:31 2018 +0200
     2.2 +++ b/ThisAddIn.cs	Fri Jul 13 14:18:27 2018 +0200
     2.3 @@ -54,12 +54,16 @@
     2.4          private AdapterCallbacks adapterCallbacks = null;
     2.5  #endif
     2.6  
     2.7 -        private bool                       initialized               = false;
     2.8 -        private bool                       isItemSendHandlerEnabled  = true;
     2.9 -        private FormControlOptions.State   lastOptionsState          = null;
    2.10 -        private Dictionary<string, string> userIdCache               = new Dictionary<string, string>();
    2.11 -        private List<WatchedFolder>        watchedFolders            = new List<WatchedFolder>();
    2.12 -        private System.Windows.Forms.Timer inboxCleaner              = null;
    2.13 +        private bool                        initialized                 = false;
    2.14 +        private bool                        isItemSendHandlerEnabled    = true;
    2.15 +        private FormControlOptions.State    lastOptionsState            = null;
    2.16 +        private Dictionary<string, string>  userIdCache                 = new Dictionary<string, string>();
    2.17 +        private List<WatchedFolder>         watchedFolders              = new List<WatchedFolder>();
    2.18 +        private System.Windows.Forms.Timer  inboxCleaner                = null;
    2.19 +
    2.20 +        private List<WatchedExplorer>       watchedExplorers            = new List<WatchedExplorer>();
    2.21 +        private object                      mutexWatchedExplorers       = new object();
    2.22 +        private Outlook.Explorers           explorers                   = null;
    2.23  
    2.24          /**************************************************************
    2.25           * 
    2.26 @@ -212,6 +216,30 @@
    2.27          }
    2.28  
    2.29          /// <summary>
    2.30 +        /// Adds a new WatchedExplorer to the list of watched explorers.
    2.31 +        /// </summary>
    2.32 +        /// <param name="watchedExplorer">The WatchedExplorer to add.</param>
    2.33 +        internal void AddToWatchedExplorers(WatchedExplorer watchedExplorer)
    2.34 +        {
    2.35 +            lock (mutexWatchedExplorers)
    2.36 +            {
    2.37 +                this.watchedExplorers.Add(watchedExplorer);
    2.38 +            }
    2.39 +        }
    2.40 +
    2.41 +        /// <summary>
    2.42 +        /// Removes a WatchedExplorer from the list of watched explorers.
    2.43 +        /// </summary>
    2.44 +        /// <param name="watchedExplorer">The WatchedExplorer to remove.</param>
    2.45 +        internal void RemoveFromWatchedExplorers(WatchedExplorer watchedExplorer)
    2.46 +        {
    2.47 +            lock (mutexWatchedExplorers)
    2.48 +            {
    2.49 +                this.watchedExplorers.Remove(watchedExplorer);
    2.50 +            }
    2.51 +        }
    2.52 +
    2.53 +        /// <summary>
    2.54          /// This updates the accounts list in pEp settings with the ones found in Outlook, adding new accounts and removing
    2.55          /// all accounts that are not there anymore.
    2.56          /// </summary>
    2.57 @@ -2784,6 +2812,10 @@
    2.58                      Log.Info("ThisAddIn_Startup: Connect Watched folders");
    2.59                      this.ConnectWatchedFolders();
    2.60  
    2.61 +                    // Connect watched explorers
    2.62 +                    Log.Info("ThisAddIn_Startup: Connect Watched explorers");
    2.63 +                    this.ConnectWatchedExplorers(true);
    2.64 +
    2.65                      // Connect application events
    2.66                      Log.Info("ThisAddIn_Startup: Connect Application Events");
    2.67                      this.ConnectApplicationEvents(true);
    2.68 @@ -2842,6 +2874,64 @@
    2.69          }
    2.70  
    2.71          /// <summary>
    2.72 +        /// Connects all explorers with their respective events and the Explorers collection
    2.73 +        /// with the NewExplorer event.
    2.74 +        /// <param name="connect">Whether to connect or disconnect the explorers.</param>
    2.75 +        /// </summary>
    2.76 +        private void ConnectWatchedExplorers(bool connect)
    2.77 +        {
    2.78 +            try
    2.79 +            {
    2.80 +                if (connect)
    2.81 +                {
    2.82 +                    this.explorers = this.Application.Explorers;
    2.83 +
    2.84 +                    for (int i = 1; i <= this.explorers.Count; i++)
    2.85 +                    {
    2.86 +                        this.watchedExplorers.Add(new WatchedExplorer(this.explorers[i]));
    2.87 +                    }
    2.88 +
    2.89 +                    this.explorers.NewExplorer += Explorers_NewExplorer;
    2.90 +                }
    2.91 +                else
    2.92 +                {
    2.93 +                    this.explorers.NewExplorer -= Explorers_NewExplorer;
    2.94 +
    2.95 +                    for (int i = 0; i < this.watchedExplorers.Count; i++)
    2.96 +                    {
    2.97 +                        this.RemoveFromWatchedExplorers(this.watchedExplorers[i]);
    2.98 +                        this.watchedExplorers[i].Dispose();
    2.99 +                    }
   2.100 +
   2.101 +                    this.explorers = null;
   2.102 +                }
   2.103 +            }
   2.104 +            catch (Exception ex)
   2.105 +            {
   2.106 +                Log.Error("ConnectWatchedExplorers: Error occured. " + ex.ToString());
   2.107 +            }        
   2.108 +        }
   2.109 +
   2.110 +        /// <summary>
   2.111 +        /// Disconnects all explorer events.
   2.112 +        /// </summary>
   2.113 +        private void DisconnectWatchedExplorers()
   2.114 +        {
   2.115 +            this.explorers.NewExplorer -= Explorers_NewExplorer;
   2.116 +            this.explorers = null;
   2.117 +        }
   2.118 +
   2.119 +        /// <summary>
   2.120 +        /// Event handler for when a new explorer is being opened and 
   2.121 +        /// added to the Explorers collection.
   2.122 +        /// </summary>
   2.123 +        /// <param name="Explorer">The newly opened explorer.</param>
   2.124 +        private void Explorers_NewExplorer(Outlook.Explorer explorer)
   2.125 +        {
   2.126 +            this.AddToWatchedExplorers(new WatchedExplorer(explorer));
   2.127 +        }
   2.128 +
   2.129 +        /// <summary>
   2.130          /// Enables or disables the automatic deletion of old autoconsume messages.
   2.131          /// This gets automatically disabled again if no autoconsume messages are found in the inbox.
   2.132          /// <param name="enable">Whether to enable or disable the automatic cleaning.</param>
   2.133 @@ -3170,6 +3260,9 @@
   2.134              // Disconnect application events
   2.135              this.ConnectApplicationEvents(false);
   2.136  
   2.137 +            // Disconnect watched items
   2.138 +            this.ConnectWatchedExplorers(false);
   2.139 +
   2.140              // Save configuration
   2.141              this._Settings.SaveToRegistry();
   2.142              this._Settings.PropertyChanged -= Settings_PropertyChanged;
     3.1 --- a/UI/FormRegionPrivacyStatus.cs	Wed Jul 11 15:28:31 2018 +0200
     3.2 +++ b/UI/FormRegionPrivacyStatus.cs	Fri Jul 13 14:18:27 2018 +0200
     3.3 @@ -769,7 +769,7 @@
     3.4                   * reply message, the rating of the original (the item we reply to).
     3.5                   * This provisional rating will be replace with the real one once the full
     3.6                   * processing is complete.
     3.7 -                 */ 
     3.8 +                 */
     3.9                  pEpRating provisionalRating = pEpRating.pEpRatingUndefined;
    3.10  
    3.11                  // Try to get an original rating (in case of reply messages)
    3.12 @@ -857,7 +857,30 @@
    3.13                      }
    3.14                  }
    3.15  
    3.16 -                this.cryptableMailItem = new CryptableMailItem(this.OutlookItem as Outlook.MailItem, provisionalRating);
    3.17 +                this.cryptableMailItem = new CryptableMailItem(omi, provisionalRating);
    3.18 +
    3.19 +                // Check if inline response
    3.20 +                if (omi.GetIsDraft())
    3.21 +                {
    3.22 +                    Outlook.Explorer explorer = null;
    3.23 +                    Outlook.MailItem inlineResponse = null;
    3.24 +
    3.25 +                    try
    3.26 +                    {
    3.27 +                        explorer = this.OutlookFormRegion?.Parent as Outlook.Explorer;
    3.28 +                        inlineResponse = explorer?.ActiveInlineResponse as Outlook.MailItem;
    3.29 +                        this.cryptableMailItem.IsInlineResponse = omi.Equals(inlineResponse);
    3.30 +                    }
    3.31 +                    catch (Exception ex)
    3.32 +                    {
    3.33 +                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error determining whether it's an inline response. " + ex.ToString());
    3.34 +                    }
    3.35 +                    finally
    3.36 +                    {
    3.37 +                        explorer = null;
    3.38 +                        inlineResponse = null;
    3.39 +                    }
    3.40 +                }
    3.41  
    3.42                  if (isSecureAttachedMail)
    3.43                  {
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/Wrappers/WatchedExplorer.cs	Fri Jul 13 14:18:27 2018 +0200
     4.3 @@ -0,0 +1,153 @@
     4.4 +´╗┐using System;
     4.5 +using Outlook = Microsoft.Office.Interop.Outlook;
     4.6 +
     4.7 +namespace pEp
     4.8 +{
     4.9 +    /// <summary>
    4.10 +    /// Stores an Outlook Explorer with connected events.
    4.11 +    /// </summary>
    4.12 +    public class WatchedExplorer : IDisposable
    4.13 +    {
    4.14 +        private Outlook.Explorer                explorer                   = null;
    4.15 +        private CryptableMailItem               inlineResponseItem         = null;
    4.16 +
    4.17 +        /**************************************************************
    4.18 +         * 
    4.19 +         * Constructors/Destructors
    4.20 +         * 
    4.21 +         *************************************************************/
    4.22 +
    4.23 +        /// <summary>
    4.24 +        /// Primary constructor.
    4.25 +        /// </summary>
    4.26 +        /// <param name="explorer">The explorer to watch.</param>
    4.27 +        public WatchedExplorer(Outlook.Explorer explorer)
    4.28 +        {
    4.29 +            this.explorer = explorer;
    4.30 +
    4.31 +            if (this.explorer != null)
    4.32 +            {
    4.33 +                this.ConnectWatchedExplorerEvents(true);
    4.34 +            }
    4.35 +        }
    4.36 +
    4.37 +        /// <summary>
    4.38 +        /// Destructor.
    4.39 +        /// </summary>
    4.40 +        ~WatchedExplorer()
    4.41 +        {
    4.42 +            this.Dispose(true);
    4.43 +        }
    4.44 +
    4.45 +        #region Methods
    4.46 +        /**************************************************************
    4.47 +         * 
    4.48 +         * Methods
    4.49 +         * 
    4.50 +         *************************************************************/
    4.51 +
    4.52 +        /// <summary>
    4.53 +        /// Releases all resources and disconnects internal events.
    4.54 +        /// </summary>
    4.55 +        public void Dispose()
    4.56 +        {
    4.57 +            this.Dispose(true);
    4.58 +        }
    4.59 +
    4.60 +        /// <summary>
    4.61 +        /// Clean up any resources being used.
    4.62 +        /// </summary>
    4.63 +        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    4.64 +        protected virtual void Dispose(bool disposing)
    4.65 +        {
    4.66 +            if (disposing)
    4.67 +            {
    4.68 +                // Disconnect all events
    4.69 +                this.ConnectWatchedExplorerEvents(false);
    4.70 +
    4.71 +                // Set Outlook objects to null
    4.72 +                this.explorer = null;
    4.73 +                this.inlineResponseItem?.Dispose();
    4.74 +                this.inlineResponseItem = null;
    4.75 +            }
    4.76 +        }
    4.77 +
    4.78 +        /// <summary>
    4.79 +        /// Connects the events for this watched explorer.
    4.80 +        /// <param name="connect">Whether to connect or disconnect the events.</param>
    4.81 +        /// </summary>
    4.82 +        private void ConnectWatchedExplorerEvents(bool connect)
    4.83 +        {
    4.84 +            try
    4.85 +            {
    4.86 +                if (connect)
    4.87 +                {
    4.88 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close += Explorer_Close;
    4.89 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).InlineResponseClose += Explorer_InlineResponseClose;
    4.90 +                }
    4.91 +                else
    4.92 +                {
    4.93 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).Close -= Explorer_Close;
    4.94 +                    ((Outlook.ExplorerEvents_10_Event)this.explorer).InlineResponseClose -= Explorer_InlineResponseClose;
    4.95 +                }
    4.96 +            }
    4.97 +            catch (Exception ex)
    4.98 +            {
    4.99 +                Log.Error("ConnectWatchedExplorerEvents: Error occured. " + ex.ToString());
   4.100 +            }
   4.101 +        }
   4.102 +
   4.103 +        #endregion
   4.104 +
   4.105 +        #region Event Handling
   4.106 +        /**************************************************************
   4.107 +         * 
   4.108 +         * Event Handling
   4.109 +         * 
   4.110 +         *************************************************************/
   4.111 +
   4.112 +        /// <summary>
   4.113 +        /// Event handler for when a watched explorer is being closed.
   4.114 +        /// </summary>
   4.115 +        private void Explorer_Close()
   4.116 +        {
   4.117 +            Globals.ThisAddIn.RemoveFromWatchedExplorers(this);
   4.118 +            this.Dispose();
   4.119 +        }
   4.120 +
   4.121 +        /// <summary>
   4.122 +        /// Event handler for when an inline response is being closed.
   4.123 +        /// </summary>
   4.124 +        private void Explorer_InlineResponseClose()
   4.125 +        {
   4.126 +            Outlook.MailItem omi = null;
   4.127 +
   4.128 +            /* Create a new CryptableMailItem. This is needed so that its
   4.129 +             * MailItem_Write event gets called and the message will get saved
   4.130 +             * securely instead of to the server's draft folder.
   4.131 +             * Note: the form region's CMI is already disposed at this point,
   4.132 +             * so that its Write event will never be called.
   4.133 +             */ 
   4.134 +            try
   4.135 +            {
   4.136 +                omi = this.explorer?.ActiveInlineResponse as Outlook.MailItem;
   4.137 +
   4.138 +                if (omi != null)
   4.139 +                {
   4.140 +                    this.inlineResponseItem = new CryptableMailItem(omi, null, false);
   4.141 +                    this.inlineResponseItem.IsInlineResponse = true;
   4.142 +                }
   4.143 +            }
   4.144 +            catch (Exception ex)
   4.145 +            {
   4.146 +                Log.Error("WatchedExplorer_InlineResponseClose: Error setting new inline response item. " + ex.ToString());
   4.147 +            }
   4.148 +            finally
   4.149 +            {
   4.150 +                omi = null;
   4.151 +            }
   4.152 +        }
   4.153 +
   4.154 +        #endregion
   4.155 +    }
   4.156 +}
     5.1 --- a/pEpForOutlook.csproj	Wed Jul 11 15:28:31 2018 +0200
     5.2 +++ b/pEpForOutlook.csproj	Fri Jul 13 14:18:27 2018 +0200
     5.3 @@ -443,6 +443,7 @@
     5.4        <DependentUpon>FormControlManagePrivacyStatus.xaml</DependentUpon>
     5.5      </Compile>
     5.6      <Compile Include="UI\ValueConverters.cs" />
     5.7 +    <Compile Include="Wrappers\WatchedExplorer.cs" />
     5.8      <EmbeddedResource Include="Properties\Resources.hi.resx">
     5.9        <Generator>PublicResXFileCodeGenerator</Generator>
    5.10        <LastGenOutput>Resources.hi.Designer.cs</LastGenOutput>