Wrappers/WatchedWindow.cs
author Thomas
Thu, 06 Sep 2018 09:29:19 +0200
branchOUT-497
changeset 2359 0e6191d039e4
child 2360 f01523e581fa
permissions -rw-r--r--
Major restructuration:
- Remove FormRegionPrivacyStatus
- Create new WatchedWindow as base class for WatchedExplorers and WatchedInspectors
- Move all logic from FormRegionPrivacy to WatchedWindow
- Use Explorer.SelectionChanged and Inspectors.Newinspector events instead of FormRegionPrivacyStatus.FormRegionShowing to detect opening of mail item.
- Rework of RibbonCustomizations. State of pEp button now stored in WatchedWindow instead of FormRegionPrivacyStatus
Thomas@2359
     1
´╗┐using pEp.UI;
Thomas@2359
     2
using pEpCOMServerAdapterLib;
Thomas@2359
     3
using System;
Thomas@2359
     4
using System.ComponentModel;
Thomas@2359
     5
using System.Windows.Forms;
Thomas@2359
     6
using Outlook = Microsoft.Office.Interop.Outlook;
Thomas@2359
     7
Thomas@2359
     8
namespace pEp
Thomas@2359
     9
{
Thomas@2359
    10
    /// <summary>
Thomas@2359
    11
    /// Stores an Outlook Window with connected events.
Thomas@2359
    12
    /// </summary>
Thomas@2359
    13
    public abstract class WatchedWindow : IDisposable
Thomas@2359
    14
    {
Thomas@2359
    15
        private CryptableMailItem               cryptableMailItem           = null;
Thomas@2359
    16
        private bool                            displayMirrorRequested      = false;
Thomas@2359
    17
        private HandshakeDialog                 handshakeDialog             = null;
Thomas@2359
    18
        private bool                            isEnabled                   = true;
Thomas@2359
    19
        private bool                            isStarted                   = false;
Thomas@2359
    20
        private bool                            processingOngoing           = false;
Thomas@2359
    21
        private bool                            refreshOngoing              = false;
Thomas@2359
    22
        private bool                            repeatProcessing            = false;
Thomas@2359
    23
        private int                             repeatCounter               = 0;
Thomas@2359
    24
        private const int                       maxRepeatCount              = 5;
Thomas@2359
    25
Thomas@2359
    26
        private Outlook.MailItem                _CurrentMailItem            = null;
Thomas@2359
    27
Thomas@2359
    28
        public enum WindowTypes
Thomas@2359
    29
        {
Thomas@2359
    30
            Undefined,
Thomas@2359
    31
            Inspector,
Thomas@2359
    32
            Explorer
Thomas@2359
    33
        }
Thomas@2359
    34
Thomas@2359
    35
        #region Properties
Thomas@2359
    36
        /// <summary>
Thomas@2359
    37
        /// The rating of the currently selected message.
Thomas@2359
    38
        /// </summary>
Thomas@2359
    39
        private pEpRating _Rating = pEpRating.pEpRatingUndefined;
Thomas@2359
    40
Thomas@2359
    41
        /// <summary>
Thomas@2359
    42
        /// The mail item that is connected to this Inspector/Explorer window.
Thomas@2359
    43
        /// </summary>
Thomas@2359
    44
        public Outlook.MailItem CurrentMailItem
Thomas@2359
    45
        {
Thomas@2359
    46
            get
Thomas@2359
    47
            {
Thomas@2359
    48
                return this._CurrentMailItem;
Thomas@2359
    49
            }
Thomas@2359
    50
            protected set
Thomas@2359
    51
            {
Thomas@2359
    52
                this._CurrentMailItem = value;
Thomas@2359
    53
            }
Thomas@2359
    54
        }
Thomas@2359
    55
Thomas@2359
    56
        /// <summary>
Thomas@2359
    57
        /// Gets or sets whether to disable the Force Protection option.
Thomas@2359
    58
        /// </summary>
Thomas@2359
    59
        public bool DisableForceProtection { get; set; } = false;
Thomas@2359
    60
Thomas@2359
    61
        /// <summary>
Thomas@2359
    62
        /// Gets or sets whether to send this message forcefully protected.
Thomas@2359
    63
        /// </summary>
Thomas@2359
    64
        public bool ForceProtection { get; set; } = false;
Thomas@2359
    65
Thomas@2359
    66
        /// <summary>
Thomas@2359
    67
        /// Gets or sets whether to send this message forcefully unencrypted.
Thomas@2359
    68
        /// </summary>
Thomas@2359
    69
        public bool ForceUnencrypted { get; set; } = false;
Thomas@2359
    70
Thomas@2359
    71
        /// <summary>
Thomas@2359
    72
        /// Gets or sets whether the message is a draft message.
Thomas@2359
    73
        /// </summary>
Thomas@2359
    74
        public bool IsDraft { get; set; } = false;
Thomas@2359
    75
Thomas@2359
    76
        /// <summary>
Thomas@2359
    77
        /// Gets or sets whether to always store this message as if on an untrusted server.
Thomas@2359
    78
        /// </summary>
Thomas@2359
    79
        public bool NeverUnsecure { get; set; } = false;
Thomas@2359
    80
Thomas@2359
    81
        /// <summary>
Thomas@2359
    82
        /// Gets the rating of this message.
Thomas@2359
    83
        /// </summary>
Thomas@2359
    84
        public pEpRating Rating
Thomas@2359
    85
        {
Thomas@2359
    86
            get { return this._Rating; }
Thomas@2359
    87
        }
Thomas@2359
    88
Thomas@2359
    89
        /// <summary>
Thomas@2359
    90
        /// Gets the associated Explorer/Inspector window. To be overwritten by child class.
Thomas@2359
    91
        /// </summary>
Thomas@2359
    92
        public abstract dynamic Window { get; }
Thomas@2359
    93
Thomas@2359
    94
        /// <summary>
Thomas@2359
    95
        /// Sets the rating of this message and updates the UI.
Thomas@2359
    96
        /// </summary>
Thomas@2359
    97
        /// <param name="rating">The message rating.</param>
Thomas@2359
    98
        public void SetRating(pEpRating rating)
Thomas@2359
    99
        {
Thomas@2359
   100
            this._Rating = rating;
Thomas@2359
   101
            RibbonCustomizations.Invalidate();
Thomas@2359
   102
        }
Thomas@2359
   103
Thomas@2359
   104
        /// <summary>
Thomas@2359
   105
        /// The timer that schedules the updates of this window.
Thomas@2359
   106
        /// </summary>
Thomas@2359
   107
        public System.Windows.Forms.Timer TimerRefresh { get; set; } = new System.Windows.Forms.Timer();
Thomas@2359
   108
        #endregion
Thomas@2359
   109
Thomas@2359
   110
        #region Constructors / Destructors
Thomas@2359
   111
Thomas@2359
   112
        /// <summary>
Thomas@2359
   113
        /// Destructor.
Thomas@2359
   114
        /// </summary>
Thomas@2359
   115
        ~WatchedWindow()
Thomas@2359
   116
        {
Thomas@2359
   117
            this.Dispose(true);
Thomas@2359
   118
        }
Thomas@2359
   119
        #endregion
Thomas@2359
   120
Thomas@2359
   121
        #region Methods
Thomas@2359
   122
        /**************************************************************
Thomas@2359
   123
         * 
Thomas@2359
   124
         * Methods
Thomas@2359
   125
         * 
Thomas@2359
   126
         *************************************************************/
Thomas@2359
   127
Thomas@2359
   128
        /// <summary>
Thomas@2359
   129
        /// Releases all resources and disconnects internal events.
Thomas@2359
   130
        /// </summary>
Thomas@2359
   131
        public void Dispose()
Thomas@2359
   132
        {
Thomas@2359
   133
            this.Dispose(true);
Thomas@2359
   134
        }
Thomas@2359
   135
Thomas@2359
   136
        /// <summary>
Thomas@2359
   137
        /// Clean up any resources being used.
Thomas@2359
   138
        /// </summary>
Thomas@2359
   139
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
Thomas@2359
   140
        protected virtual void Dispose(bool disposing)
Thomas@2359
   141
        {
Thomas@2359
   142
            if (disposing)
Thomas@2359
   143
            {
Thomas@2359
   144
                // Set Outlook objects to null
Thomas@2359
   145
                this._CurrentMailItem = null;
Thomas@2359
   146
            }
Thomas@2359
   147
        }
Thomas@2359
   148
              
Thomas@2359
   149
        /// <summary>
Thomas@2359
   150
        /// Builds the latest state of the encryption status manager then shows the UI.
Thomas@2359
   151
        /// </summary>
Thomas@2359
   152
        public void BuildAndShowManager()
Thomas@2359
   153
        {
Thomas@2359
   154
            /* Resolve all recipients -- this ensures the identities list is correctly populated
Thomas@2359
   155
             * 
Thomas@2359
   156
             * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Thomas@2359
   157
             * This is because the resolve process can modify the contents of the mail item which triggers an event.
Thomas@2359
   158
             * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Thomas@2359
   159
             * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
Thomas@2359
   160
             * cannot be resolved (no address).
Thomas@2359
   161
             */
Thomas@2359
   162
            try
Thomas@2359
   163
            {
Thomas@2359
   164
                this.ResolveAllRecipients();
Thomas@2359
   165
            }
Thomas@2359
   166
            catch (Exception ex)
Thomas@2359
   167
            {
Thomas@2359
   168
                Log.Verbose("BuildAndShowManager: Error resolving recipients. " + ex.ToString());
Thomas@2359
   169
            }
Thomas@2359
   170
Thomas@2359
   171
            // Build the dialog
Thomas@2359
   172
            try
Thomas@2359
   173
            {
Thomas@2359
   174
                // The PEPMessage to build the dialog with
Thomas@2359
   175
                PEPMessage message = null;
Thomas@2359
   176
Thomas@2359
   177
                // The own identity to build the dialog with
Thomas@2359
   178
                PEPIdentity myself = this.cryptableMailItem?.Myself;
Thomas@2359
   179
Thomas@2359
   180
                // If message is a draft, create it directly from the Outlook mail item
Thomas@2359
   181
                if (this.IsDraft)
Thomas@2359
   182
                {
Thomas@2359
   183
                    Log.Verbose("BuildAndShowManager: Creating PEPMessage from draft.");
Thomas@2359
   184
Thomas@2359
   185
                    if (PEPMessage.Create(this._CurrentMailItem, out message) != Globals.ReturnStatus.Success)
Thomas@2359
   186
                    {
Thomas@2359
   187
                        Log.Error("BuildAndShowManager: Error creating PEPMessage from draft.");
Thomas@2359
   188
                        message = null;
Thomas@2359
   189
                    }
Thomas@2359
   190
                    else
Thomas@2359
   191
                    {
Thomas@2359
   192
                        // Calculate rating
Thomas@2359
   193
                        message.Rating = message.GetOutgoingRating();
Thomas@2359
   194
Thomas@2359
   195
                        // If Force Protection is set, assign a random GUID
Thomas@2359
   196
                        if ((this.ForceProtection) &&
Thomas@2359
   197
                            (this.DisableForceProtection == false))
Thomas@2359
   198
                        {
Thomas@2359
   199
                            message.ForceProtectionId = Guid.NewGuid().ToString();
Thomas@2359
   200
                        }
Thomas@2359
   201
Thomas@2359
   202
                        // If message is Force Unencrypted, assign it
Thomas@2359
   203
                        message.ForceUnencrypted = this.ForceUnencrypted;
Thomas@2359
   204
                    }
Thomas@2359
   205
                }
Thomas@2359
   206
                else
Thomas@2359
   207
                {
Thomas@2359
   208
                    // Else, use either the cryptable mail item's associated mirror or message
Thomas@2359
   209
                    message = this.cryptableMailItem?.Mirror ?? this.cryptableMailItem?.Message;
Thomas@2359
   210
                    Log.Verbose(string.Format("BuildAndShowManager: Message {0} retrieved from CryptableMailItem", ((message != null) ? "successfully" : "could not be")));
Thomas@2359
   211
Thomas@2359
   212
                    // As fallback, if we don't have a message yet, create it
Thomas@2359
   213
                    if (message == null)
Thomas@2359
   214
                    {
Thomas@2359
   215
                        Log.Verbose("BuildAndShowManager: Using fallback method to get message.");
Thomas@2359
   216
Thomas@2359
   217
                        Outlook.MailItem mirror = null;
Thomas@2359
   218
Thomas@2359
   219
                        try
Thomas@2359
   220
                        {
Thomas@2359
   221
                            // For securely stored mails, try to look up mirror
Thomas@2359
   222
                            if (this._CurrentMailItem?.GetIsSecurelyStored() == true)
Thomas@2359
   223
                            {
Thomas@2359
   224
                                mirror = this._CurrentMailItem?.GetMirror();
Thomas@2359
   225
Thomas@2359
   226
                                if (mirror != null)
Thomas@2359
   227
                                {
Thomas@2359
   228
                                    // If mirror is found, use it to create PEPMessage
Thomas@2359
   229
                                    Log.Verbose("BuildAndShowManager: Mirror found.");
Thomas@2359
   230
Thomas@2359
   231
                                    if (PEPMessage.Create(mirror, out message) != Globals.ReturnStatus.Success)
Thomas@2359
   232
                                    {
Thomas@2359
   233
                                        message = null;
Thomas@2359
   234
                                        Log.Error("BuildAndShowManager: Error creating PEPMessage.");
Thomas@2359
   235
                                    }
Thomas@2359
   236
                                    else
Thomas@2359
   237
                                    {
Thomas@2359
   238
                                        message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
Thomas@2359
   239
                                    }
Thomas@2359
   240
                                }
Thomas@2359
   241
                                else
Thomas@2359
   242
                                {
Thomas@2359
   243
                                    // If no mirror is found, decrypt message and use decrypted one (do not 
Thomas@2359
   244
                                    // decrypt forcefully protected messages).
Thomas@2359
   245
                                    if ((PEPMessage.Create(this._CurrentMailItem, out message) == Globals.ReturnStatus.Success) &&
Thomas@2359
   246
                                        (string.IsNullOrEmpty(message.ForceProtectionId)))
Thomas@2359
   247
                                    {
Thomas@2359
   248
                                        var msgProcessor = new MsgProcessor();
Thomas@2359
   249
                                        PEPMessage decryptedMsg = null;
Thomas@2359
   250
                                        string[] keyList;
Thomas@2359
   251
                                        pEpDecryptFlags flags = pEpDecryptFlags.pEpDecryptFlagsNone;
Thomas@2359
   252
                                        pEpRating rating = msgProcessor.Decrypt(ref message, out decryptedMsg, out keyList, ref flags);
Thomas@2359
   253
                                        if (decryptedMsg != null)
Thomas@2359
   254
                                        {
Thomas@2359
   255
                                            message = decryptedMsg;
Thomas@2359
   256
                                        }
Thomas@2359
   257
                                        message.Rating = rating;
Thomas@2359
   258
                                    }
Thomas@2359
   259
                                    else
Thomas@2359
   260
                                    {
Thomas@2359
   261
                                        message = null;
Thomas@2359
   262
                                        Log.Error("BuildAndShowManager: Error creating PEPMessage from mirror.");
Thomas@2359
   263
                                    }
Thomas@2359
   264
                                }
Thomas@2359
   265
                            }
Thomas@2359
   266
Thomas@2359
   267
                            // If we don't have a PEPMessage yet, create it
Thomas@2359
   268
                            if (message == null)
Thomas@2359
   269
                            {
Thomas@2359
   270
                                Log.Verbose("BuildAndShowManager: Creating PEPMessage.");
Thomas@2359
   271
Thomas@2359
   272
                                if (PEPMessage.Create(this._CurrentMailItem, out message) != Globals.ReturnStatus.Success)
Thomas@2359
   273
                                {
Thomas@2359
   274
                                    message = null;
Thomas@2359
   275
                                    Log.Error("BuildAndShowManager: Error creating PEPMessage.");
Thomas@2359
   276
                                }
Thomas@2359
   277
                                else
Thomas@2359
   278
                                {
Thomas@2359
   279
                                    message.Rating = AdapterExtensions.ReevaluateMessageRating(message);
Thomas@2359
   280
                                }
Thomas@2359
   281
                            }
Thomas@2359
   282
Thomas@2359
   283
                            // Get myself identiy if we don't have it yet
Thomas@2359
   284
                            if (myself == null)
Thomas@2359
   285
                            {
Thomas@2359
   286
                                myself = this._CurrentMailItem.GetMyselfIdentity();
Thomas@2359
   287
                            }
Thomas@2359
   288
                        }
Thomas@2359
   289
                        catch (Exception ex)
Thomas@2359
   290
                        {
Thomas@2359
   291
                            Log.Error("FormRegionPrivacyStatus.Message: Error converting message. " + ex.ToString());
Thomas@2359
   292
                        }
Thomas@2359
   293
                        finally
Thomas@2359
   294
                        {
Thomas@2359
   295
                            mirror = null;
Thomas@2359
   296
                        }
Thomas@2359
   297
                    }
Thomas@2359
   298
                }
Thomas@2359
   299
Thomas@2359
   300
                // Build dialog
Thomas@2359
   301
                if (message != null)
Thomas@2359
   302
                {
Thomas@2359
   303
                    handshakeDialog = new HandshakeDialog(message, myself, this.IsDraft);
Thomas@2359
   304
                    handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
Thomas@2359
   305
                    handshakeDialog.Closed += HandshakeDialog_Closed;
Thomas@2359
   306
                    handshakeDialog.Show();
Thomas@2359
   307
                }
Thomas@2359
   308
                else
Thomas@2359
   309
                {
Thomas@2359
   310
                    throw new Exception("Could not build handshake dialog. Message is null.");
Thomas@2359
   311
                }
Thomas@2359
   312
            }
Thomas@2359
   313
            catch (Exception ex)
Thomas@2359
   314
            {
Thomas@2359
   315
                Globals.StopAndSendCrashReport(ex);
Thomas@2359
   316
            }
Thomas@2359
   317
        }
Thomas@2359
   318
Thomas@2359
   319
        /// <summary>
Thomas@2359
   320
        /// Schedules for the pEp rating and UI (including displayed mirror) to be updated.
Thomas@2359
   321
        /// This can be called many times with no issue as the update is only run every n milliseconds.
Thomas@2359
   322
        /// </summary>
Thomas@2359
   323
        public void RequestRatingAndUIUpdate()
Thomas@2359
   324
        {
Thomas@2359
   325
            if (this.isEnabled)
Thomas@2359
   326
            {
Thomas@2359
   327
                this.TimerRefresh.Enabled = true;
Thomas@2359
   328
            }
Thomas@2359
   329
        }
Thomas@2359
   330
Thomas@2359
   331
        /// <summary>
Thomas@2359
   332
        /// Immediately starts the update of UI rating based on the associated mail item.
Thomas@2359
   333
        /// This will start decryption as necessary and also will update the displayed mirror.
Thomas@2359
   334
        /// This method by-passes the refresh timer completely.
Thomas@2359
   335
        /// WARNING: This method assumes the message is fully downloaded already.
Thomas@2359
   336
        /// </summary>
Thomas@2359
   337
        private void ImmediateRatingAndUIUpdate()
Thomas@2359
   338
        {
Thomas@2359
   339
            if ((this.isEnabled) &&
Thomas@2359
   340
                (this.cryptableMailItem != null))
Thomas@2359
   341
            {
Thomas@2359
   342
                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
Thomas@2359
   343
Thomas@2359
   344
                // Start the rating calculation/decryption process
Thomas@2359
   345
                this.cryptableMailItem.StartProcessing();
Thomas@2359
   346
                this.processingOngoing = true;
Thomas@2359
   347
            }
Thomas@2359
   348
        }
Thomas@2359
   349
Thomas@2359
   350
        /// <summary>
Thomas@2359
   351
        /// Resets the Enabled status of this form region and recalculates the rating if necessary.
Thomas@2359
   352
        /// </summary>
Thomas@2359
   353
        /// <param name="enable">Whether to enable the form region.</param>
Thomas@2359
   354
        public void UpdateFormRegion(bool enable)
Thomas@2359
   355
        {
Thomas@2359
   356
            this.SetIsEnabled(enable);
Thomas@2359
   357
Thomas@2359
   358
            // Refresh the UI
Thomas@2359
   359
            if (enable)
Thomas@2359
   360
            {
Thomas@2359
   361
                this.ResolveAllRecipients();
Thomas@2359
   362
                this.RequestRatingAndUIUpdate();
Thomas@2359
   363
            }
Thomas@2359
   364
        }
Thomas@2359
   365
Thomas@2359
   366
        /// <summary>
Thomas@2359
   367
        /// Workaround method to update the current inspector window. This is done by moving the mail item
Thomas@2359
   368
        /// to a temporary folder first and then back to the current folder. Both folders CANNOT be the same.
Thomas@2359
   369
        /// As a fallback, the mail item stays in the temporary folder if moving back to the current folder
Thomas@2359
   370
        /// fails.
Thomas@2359
   371
        /// </summary>
Thomas@2359
   372
        private void UpdateInspector()
Thomas@2359
   373
        {
Thomas@2359
   374
            Outlook.Application application = null;
Thomas@2359
   375
            Outlook.Folder currentFolder = null;
Thomas@2359
   376
            Outlook.Folder tempFolder = null;
Thomas@2359
   377
            Outlook.Inspector currentInspector = null;
Thomas@2359
   378
            Outlook.Inspector newInspector = null;
Thomas@2359
   379
            Outlook.MailItem tempMailItem = null;
Thomas@2359
   380
            Outlook.Store store = null;
Thomas@2359
   381
            Outlook.MailItem omi = this.CurrentMailItem;
Thomas@2359
   382
Thomas@2359
   383
            if (omi != null)
Thomas@2359
   384
            {
Thomas@2359
   385
                try
Thomas@2359
   386
                {
Thomas@2359
   387
                    application = omi.Application;
Thomas@2359
   388
                    currentInspector = omi.GetInspector;
Thomas@2359
   389
                    currentFolder = omi.Parent as Outlook.Folder;
Thomas@2359
   390
Thomas@2359
   391
                    if ((currentInspector != null) &&
Thomas@2359
   392
                        (application != null) &&
Thomas@2359
   393
                        (currentFolder != null))
Thomas@2359
   394
                    {
Thomas@2359
   395
                        var left = currentInspector.Left;
Thomas@2359
   396
                        var top = currentInspector.Top;
Thomas@2359
   397
                        var width = currentInspector.Width;
Thomas@2359
   398
                        var height = currentInspector.Height;
Thomas@2359
   399
                        var windowState = currentInspector.WindowState;
Thomas@2359
   400
Thomas@2359
   401
                        /* Check, if in trusted store. In that case, use the default drafts folder
Thomas@2359
   402
                         * as temporary folder. If the store is untrusted, use the pEp drafts folder.
Thomas@2359
   403
                         */
Thomas@2359
   404
                        store = currentFolder.Store;
Thomas@2359
   405
                        if (store?.GetIsSecureStorageEnabled() ?? false)
Thomas@2359
   406
                        {
Thomas@2359
   407
                            tempFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
Thomas@2359
   408
                        }
Thomas@2359
   409
                        else
Thomas@2359
   410
                        {
Thomas@2359
   411
                            tempFolder = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
Thomas@2359
   412
                        }
Thomas@2359
   413
Thomas@2359
   414
                        if (tempFolder != null)
Thomas@2359
   415
                        {
Thomas@2359
   416
                            tempMailItem = omi.Move(tempFolder) as Outlook.MailItem;
Thomas@2359
   417
Thomas@2359
   418
                            if (tempMailItem != null)
Thomas@2359
   419
                            {
Thomas@2359
   420
                                try
Thomas@2359
   421
                                {
Thomas@2359
   422
                                    omi = tempMailItem.Move(currentFolder) as Outlook.MailItem;
Thomas@2359
   423
                                }
Thomas@2359
   424
                                catch
Thomas@2359
   425
                                {
Thomas@2359
   426
                                    omi = tempMailItem.Copy();
Thomas@2359
   427
                                }
Thomas@2359
   428
Thomas@2359
   429
                                newInspector = application.Inspectors.Add(omi);
Thomas@2359
   430
Thomas@2359
   431
                                if (windowState == Outlook.OlWindowState.olNormalWindow)
Thomas@2359
   432
                                {
Thomas@2359
   433
                                    newInspector.Left = left;
Thomas@2359
   434
                                    newInspector.Top = top;
Thomas@2359
   435
                                    newInspector.Width = width;
Thomas@2359
   436
                                    newInspector.Height = height;
Thomas@2359
   437
                                }
Thomas@2359
   438
Thomas@2359
   439
                                newInspector.Display();
Thomas@2359
   440
                                newInspector.WindowState = windowState;
Thomas@2359
   441
Thomas@2359
   442
                                repeatProcessing = false;
Thomas@2359
   443
                            }
Thomas@2359
   444
                        }
Thomas@2359
   445
                        else
Thomas@2359
   446
                        {
Thomas@2359
   447
                            Log.Error("UpdateInspector: Cannot get temporary folder.");
Thomas@2359
   448
                        }
Thomas@2359
   449
                    }
Thomas@2359
   450
                    else
Thomas@2359
   451
                    {
Thomas@2359
   452
                        Log.Verbose("UpdateInspector: Error retrieving inspector window or application.");
Thomas@2359
   453
                    }
Thomas@2359
   454
                }
Thomas@2359
   455
                catch (Exception ex)
Thomas@2359
   456
                {
Thomas@2359
   457
                    Log.Verbose("UpdateInspector: Error updating inspector window. " + ex.ToString());
Thomas@2359
   458
                }
Thomas@2359
   459
                finally
Thomas@2359
   460
                {
Thomas@2359
   461
                    application = null;
Thomas@2359
   462
                    currentInspector = null;
Thomas@2359
   463
                    newInspector = null;
Thomas@2359
   464
                    omi = null;
Thomas@2359
   465
                    tempMailItem = null;
Thomas@2359
   466
                }
Thomas@2359
   467
            }
Thomas@2359
   468
        }
Thomas@2359
   469
Thomas@2359
   470
        /// <summary>
Thomas@2359
   471
        /// Clears the associated unencrypted preview and displays the given note (if any).
Thomas@2359
   472
        /// </summary>
Thomas@2359
   473
        /// <param name="note">The note to display.</param>
Thomas@2359
   474
        private void SetNote(string note = null)
Thomas@2359
   475
        {
Thomas@2359
   476
            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Thomas@2359
   477
Thomas@2359
   478
            if ((formRegions != null) &&
Thomas@2359
   479
                (string.IsNullOrEmpty(note) == false))
Thomas@2359
   480
            {
Thomas@2359
   481
                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Thomas@2359
   482
                    (formRegions.FormRegionPreviewUnencrypted.Visible))
Thomas@2359
   483
                {
Thomas@2359
   484
                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetNote(note);
Thomas@2359
   485
                }
Thomas@2359
   486
            }
Thomas@2359
   487
        }
Thomas@2359
   488
Thomas@2359
   489
        /// <summary>
Thomas@2359
   490
        /// Sets whether processing of the mail item is enabled.
Thomas@2359
   491
        /// This should commonly be set from the .GetIsPEPEnabled() value.
Thomas@2359
   492
        /// </summary>
Thomas@2359
   493
        private void SetIsEnabled(bool enabled)
Thomas@2359
   494
        {
Thomas@2359
   495
            PEPIdentity currIdent;
Thomas@2359
   496
            Globals.ReturnStatus sts;
Thomas@2359
   497
            Outlook.Recipient currUser = null;
Thomas@2359
   498
            Outlook.Account currAccount = null;
Thomas@2359
   499
            Outlook.Account sendingAccount = null;
Thomas@2359
   500
            Outlook.NameSpace ns = null;
Thomas@2359
   501
Thomas@2359
   502
            this.isEnabled = enabled;
Thomas@2359
   503
Thomas@2359
   504
            if (enabled)
Thomas@2359
   505
            {
Thomas@2359
   506
                // Do not allow initialization more than once
Thomas@2359
   507
                if (this.isStarted == false)
Thomas@2359
   508
                {
Thomas@2359
   509
                    /* It's possible for new draft MailItems to be created outside the context of an account.
Thomas@2359
   510
                     * In this situation the SendUsingAccount will always be null which of course breaks several pEp operations.
Thomas@2359
   511
                     * The operations themselves cannot make the assumption about what account information to use.
Thomas@2359
   512
                     * Therefore, the situation is detected here and for draft mail items a null SendUsingAccount will be 
Thomas@2359
   513
                     * set with the session's default account.
Thomas@2359
   514
                     */
Thomas@2359
   515
                    try
Thomas@2359
   516
                    {
Thomas@2359
   517
                        ns = Globals.ThisAddIn.Application.Session;
Thomas@2359
   518
Thomas@2359
   519
                        if (this.IsDraft)
Thomas@2359
   520
                        {
Thomas@2359
   521
                            sendingAccount = this._CurrentMailItem.SendUsingAccount;
Thomas@2359
   522
                            currUser = ns.CurrentUser;
Thomas@2359
   523
Thomas@2359
   524
                            if (sendingAccount == null)
Thomas@2359
   525
                            {
Thomas@2359
   526
                                sts = PEPIdentity.Create(currUser, out currIdent);
Thomas@2359
   527
Thomas@2359
   528
                                if (sts == Globals.ReturnStatus.Success)
Thomas@2359
   529
                                {
Thomas@2359
   530
                                    sendingAccount = AccountExtensions.GetDefaultAccount(Outlook.OlDefaultFolders.olFolderDrafts);
Thomas@2359
   531
                                    if (sendingAccount != null)
Thomas@2359
   532
                                    {
Thomas@2359
   533
                                        this._CurrentMailItem.SendUsingAccount = currAccount;
Thomas@2359
   534
                                    }
Thomas@2359
   535
                                }
Thomas@2359
   536
                            }
Thomas@2359
   537
Thomas@2359
   538
                            // Check if account is already registered in pEp list and add it if necessary
Thomas@2359
   539
                            var acctSettings = Globals.ThisAddIn.Settings.GetAccountSettings(sendingAccount?.SmtpAddress);
Thomas@2359
   540
                            if (acctSettings == null)
Thomas@2359
   541
                            {
Thomas@2359
   542
                                Log.Verbose("SetIsEnabled: New account detected. Creating pEp settings.");
Thomas@2359
   543
Thomas@2359
   544
                                // Create pEp settings for the new account
Thomas@2359
   545
                                acctSettings = sendingAccount.CreatePEPSettings();
Thomas@2359
   546
Thomas@2359
   547
                                // Add account to list
Thomas@2359
   548
                                Globals.ThisAddIn.Settings.AccountsAddedWhileRunningList.Add(acctSettings?.SmtpAddress);
Thomas@2359
   549
                                Log.Verbose("SetIsEnabled: New account registered in pEp settings.");
Thomas@2359
   550
Thomas@2359
   551
                                // Generate key
Thomas@2359
   552
                                Globals.ThisAddIn.RegisterMyself(acctSettings);
Thomas@2359
   553
                                Log.Verbose("SetIsEnabled: Myself registered.");
Thomas@2359
   554
Thomas@2359
   555
                                // Set rules and view filters
Thomas@2359
   556
                                Globals.ThisAddIn.SetRulesAndViewFilters(sendingAccount);
Thomas@2359
   557
                            }
Thomas@2359
   558
                        }
Thomas@2359
   559
                    }
Thomas@2359
   560
                    catch (Exception ex)
Thomas@2359
   561
                    {
Thomas@2359
   562
                        Log.Error("SetIsEnabled: Error occured. " + ex.ToString());
Thomas@2359
   563
                    }
Thomas@2359
   564
                    finally
Thomas@2359
   565
                    {
Thomas@2359
   566
                        currAccount = null;
Thomas@2359
   567
                        currUser = null;
Thomas@2359
   568
                        ns = null;
Thomas@2359
   569
                        sendingAccount = null;
Thomas@2359
   570
                    }
Thomas@2359
   571
Thomas@2359
   572
                    // Connect refresh timer
Thomas@2359
   573
                    this.TimerRefresh.Tick += TimerRefresh_Tick;
Thomas@2359
   574
                    this.isStarted = true;
Thomas@2359
   575
                }
Thomas@2359
   576
            }
Thomas@2359
   577
            else
Thomas@2359
   578
            {
Thomas@2359
   579
                // Stop and disconnect the refresh timer
Thomas@2359
   580
                this.TimerRefresh.Stop();
Thomas@2359
   581
                this.TimerRefresh.Enabled = false;
Thomas@2359
   582
                this.TimerRefresh.Tick -= TimerRefresh_Tick;
Thomas@2359
   583
Thomas@2359
   584
                this.isStarted = false;
Thomas@2359
   585
            }
Thomas@2359
   586
        }
Thomas@2359
   587
Thomas@2359
   588
        /// <summary>
Thomas@2359
   589
        /// Resolves all recipients of the Outlook mail item.
Thomas@2359
   590
        /// </summary>
Thomas@2359
   591
        private void ResolveAllRecipients()
Thomas@2359
   592
        {
Thomas@2359
   593
            if ((this.isEnabled) &&
Thomas@2359
   594
                (this.cryptableMailItem != null))
Thomas@2359
   595
            {
Thomas@2359
   596
                /*
Thomas@2359
   597
                 * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Thomas@2359
   598
                 * This is because the resolve process can modify the contents of the mail item which triggers an event.
Thomas@2359
   599
                 * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Thomas@2359
   600
                 * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
Thomas@2359
   601
                 * cannot be resolved(no address).
Thomas@2359
   602
                 */
Thomas@2359
   603
                try
Thomas@2359
   604
                {
Thomas@2359
   605
                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Thomas@2359
   606
                    this.cryptableMailItem.ResolveAllRecipients();
Thomas@2359
   607
                    this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Thomas@2359
   608
                }
Thomas@2359
   609
                catch (Exception ex)
Thomas@2359
   610
                {
Thomas@2359
   611
                    Log.Error("Error resolving recipients. " + ex.ToString());
Thomas@2359
   612
                }
Thomas@2359
   613
            }
Thomas@2359
   614
        }
Thomas@2359
   615
        #endregion
Thomas@2359
   616
Thomas@2359
   617
        #region Event Handling
Thomas@2359
   618
        /**************************************************************
Thomas@2359
   619
         * 
Thomas@2359
   620
         * Event Handling
Thomas@2359
   621
         * 
Thomas@2359
   622
         *************************************************************/
Thomas@2359
   623
Thomas@2359
   624
        protected void InitializeMailItem(bool isInlineResponse = false)
Thomas@2359
   625
        {
Thomas@2359
   626
            bool enableFormRegion = false;
Thomas@2359
   627
            bool cancelOpenEvent = false;
Thomas@2359
   628
            bool isSecureAttachedMail = false;
Thomas@2359
   629
            string messageId = null;
Thomas@2359
   630
Thomas@2359
   631
            try
Thomas@2359
   632
            {      
Thomas@2359
   633
                // Check if draft
Thomas@2359
   634
                this.IsDraft = this._CurrentMailItem.GetIsDraft();
Thomas@2359
   635
Thomas@2359
   636
                /* Set immediately a provisional rating in order to have a less flickery
Thomas@2359
   637
                 * UI experience.
Thomas@2359
   638
                 * The provisional rating is either a stored rating or, in case we have a
Thomas@2359
   639
                 * reply message, the rating of the original (the item we reply to).
Thomas@2359
   640
                 * This provisional rating will be replace with the real one once the full
Thomas@2359
   641
                 * processing is complete.
Thomas@2359
   642
                 */
Thomas@2359
   643
                pEpRating provisionalRating = pEpRating.pEpRatingUndefined;
Thomas@2359
   644
Thomas@2359
   645
                // Try to get an original rating (in case of reply messages)
Thomas@2359
   646
                if ((this.IsDraft) &&
Thomas@2359
   647
                    (this._CurrentMailItem?.Recipients?.Count > 0))
Thomas@2359
   648
                {
Thomas@2359
   649
                    string originalRatingString = this._CurrentMailItem.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING) as string;
Thomas@2359
   650
Thomas@2359
   651
                    // If we have an original rating, parse it and set it.
Thomas@2359
   652
                    if (string.IsNullOrEmpty(originalRatingString) == false)
Thomas@2359
   653
                    {
Thomas@2359
   654
                        provisionalRating = AdapterExtensions.ParseRatingString(originalRatingString);
Thomas@2359
   655
                    }
Thomas@2359
   656
                }
Thomas@2359
   657
                else
Thomas@2359
   658
                {
Thomas@2359
   659
                    // Try to get rating from db
Thomas@2359
   660
                    provisionalRating = PEPDatabase.GetRating(this._CurrentMailItem.EntryID);
Thomas@2359
   661
Thomas@2359
   662
                    // If there is no rating in the db, use stored or default rating
Thomas@2359
   663
                    if (provisionalRating == pEpRating.pEpRatingUndefined)
Thomas@2359
   664
                    {
Thomas@2359
   665
                        provisionalRating = this._CurrentMailItem.GetStoredRating() ?? pEpRating.pEpRatingUndefined;
Thomas@2359
   666
                    }
Thomas@2359
   667
                }
Thomas@2359
   668
Thomas@2359
   669
                // Only set rating if one has been retrieved
Thomas@2359
   670
                if (provisionalRating != pEpRating.pEpRatingUndefined)
Thomas@2359
   671
                {
Thomas@2359
   672
                    this.SetRating(provisionalRating);
Thomas@2359
   673
                    Log.Verbose("FormRegionPrivacyStatus_FormRegionShowing: Provisional rating {0} shown.", Enum.GetName(typeof(pEpRating), provisionalRating));
Thomas@2359
   674
                }
Thomas@2359
   675
Thomas@2359
   676
Thomas@2359
   677
                // Do not process S/MIME messages
Thomas@2359
   678
                if (this._CurrentMailItem.GetIsSMIMEEnabled())
Thomas@2359
   679
                {
Thomas@2359
   680
                    Log.Verbose("FormRegionPrivacyStatus_FormRegionShowing: S/MIME message detected. Won't be processed.");
Thomas@2359
   681
Thomas@2359
   682
                    // Set unencrypted rating
Thomas@2359
   683
                    this.SetRating(pEpRating.pEpRatingUnencrypted);
Thomas@2359
   684
Thomas@2359
   685
                    // Set icon(s) if necessary     
Thomas@2359
   686
                    if ((IsDraft == false) &&
Thomas@2359
   687
                        (this._CurrentMailItem.SetEncryptionIcons()))
Thomas@2359
   688
                    {
Thomas@2359
   689
                        try
Thomas@2359
   690
                        {
Thomas@2359
   691
                            this._CurrentMailItem.Save();
Thomas@2359
   692
                        }
Thomas@2359
   693
                        catch (Exception ex)
Thomas@2359
   694
                        {
Thomas@2359
   695
                            Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error saving message after changing icon. " + ex.ToString());
Thomas@2359
   696
                        }
Thomas@2359
   697
                    }
Thomas@2359
   698
Thomas@2359
   699
                    return;
Thomas@2359
   700
                }
Thomas@2359
   701
Thomas@2359
   702
                /* Check if item is attached mail. For performance reasons,
Thomas@2359
   703
                 * only do the whole check if an item has been loaded to the
Thomas@2359
   704
                 * cache of attached mails and if item might be secure.
Thomas@2359
   705
                 */
Thomas@2359
   706
                if ((PEPAttachment.AttachedMailsCache.Count > 0) &&
Thomas@2359
   707
                    (this._CurrentMailItem.Attachments?.Count == 2))
Thomas@2359
   708
                {
Thomas@2359
   709
                    try
Thomas@2359
   710
                    {
Thomas@2359
   711
                        // Check if mail item is an attached mail
Thomas@2359
   712
                        if (this._CurrentMailItem.GetIsAttachedMail(out messageId))
Thomas@2359
   713
                        {
Thomas@2359
   714
                            Outlook.MailItem mirror = null;
Thomas@2359
   715
                            PEPMessage pEpMessage;
Thomas@2359
   716
Thomas@2359
   717
                            // Try to get the mirror
Thomas@2359
   718
                            mirror = this._CurrentMailItem.GetMirror(messageId);
Thomas@2359
   719
Thomas@2359
   720
                            // If mirror was not found, decrypt and create mirror
Thomas@2359
   721
                            if (mirror != null)
Thomas@2359
   722
                            {
Thomas@2359
   723
                                isSecureAttachedMail = true;
Thomas@2359
   724
                            }
Thomas@2359
   725
                            else
Thomas@2359
   726
                            {
Thomas@2359
   727
                                if ((PEPMessage.Create(this._CurrentMailItem, out pEpMessage) == Globals.ReturnStatus.Success) &&
Thomas@2359
   728
                                    (pEpMessage.IsSecure))
Thomas@2359
   729
                                {
Thomas@2359
   730
                                    PEPMessage decryptedMessage;
Thomas@2359
   731
                                    MsgProcessor msgProcessor = new MsgProcessor();
Thomas@2359
   732
                                    if (msgProcessor.Decrypt(pEpMessage, out decryptedMessage))
Thomas@2359
   733
                                    {
Thomas@2359
   734
                                        isSecureAttachedMail = true;
Thomas@2359
   735
                                        mirror = this._CurrentMailItem.CreateMirrorOMI(messageId);
Thomas@2359
   736
                                        decryptedMessage.ApplyTo(mirror, true, false);
Thomas@2359
   737
                                        mirror?.Save();
Thomas@2359
   738
                                    }
Thomas@2359
   739
                                    else
Thomas@2359
   740
                                    {
Thomas@2359
   741
                                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Decryption of attached mail was not successful.");
Thomas@2359
   742
                                    }
Thomas@2359
   743
                                }
Thomas@2359
   744
                            }
Thomas@2359
   745
Thomas@2359
   746
                            // Check if attachment is being opened or if only the preview is needed
Thomas@2359
   747
                            if (CryptableMailItem.PreviewAttachedMailId?.Equals(messageId) != true)
Thomas@2359
   748
                            {
Thomas@2359
   749
                                // Display mirror and cancel opening of original
Thomas@2359
   750
                                cancelOpenEvent = true;
Thomas@2359
   751
                                mirror?.Display();
Thomas@2359
   752
                            }
Thomas@2359
   753
Thomas@2359
   754
                            // Not needed anymore after this point
Thomas@2359
   755
                            CryptableMailItem.PreviewAttachedMailId = null;
Thomas@2359
   756
                        }
Thomas@2359
   757
                    }
Thomas@2359
   758
                    catch (Exception ex)
Thomas@2359
   759
                    {
Thomas@2359
   760
                        messageId = null;
Thomas@2359
   761
                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error checking for attached mail. " + ex.ToString());
Thomas@2359
   762
                    }
Thomas@2359
   763
                }
Thomas@2359
   764
Thomas@2359
   765
                this.cryptableMailItem = new CryptableMailItem(this._CurrentMailItem, provisionalRating);
Thomas@2359
   766
Thomas@2359
   767
                // Set inline response property
Thomas@2359
   768
                this.cryptableMailItem.IsInlineResponse = isInlineResponse;
Thomas@2359
   769
Thomas@2359
   770
                // Set properties for encrypted attached mail
Thomas@2359
   771
                if (isSecureAttachedMail)
Thomas@2359
   772
                {
Thomas@2359
   773
                    this.cryptableMailItem.MessageId = messageId;
Thomas@2359
   774
                    this.cryptableMailItem.IsSecureAttachedMail = true;
Thomas@2359
   775
                }
Thomas@2359
   776
Thomas@2359
   777
                // Connect cryptable mail item events
Thomas@2359
   778
                if (this.cryptableMailItem != null)
Thomas@2359
   779
                {
Thomas@2359
   780
                    // If we don't open the original, set property and return
Thomas@2359
   781
                    if (cancelOpenEvent)
Thomas@2359
   782
                    {
Thomas@2359
   783
                        this.cryptableMailItem.Open += MailItem_Open;
Thomas@2359
   784
                        this.cryptableMailItem.CancelOpen = true;
Thomas@2359
   785
                        return;
Thomas@2359
   786
                    }
Thomas@2359
   787
                    else
Thomas@2359
   788
                    {
Thomas@2359
   789
                        try
Thomas@2359
   790
                        {
Thomas@2359
   791
                            this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Thomas@2359
   792
                            this.cryptableMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
Thomas@2359
   793
                            this.cryptableMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
Thomas@2359
   794
                            this.cryptableMailItem.Send += MailItem_Send;
Thomas@2359
   795
Thomas@2359
   796
                            if (this.cryptableMailItem.IsSecurelyStored)
Thomas@2359
   797
                            {
Thomas@2359
   798
                                this.cryptableMailItem.Open += MailItem_Open;
Thomas@2359
   799
                            }
Thomas@2359
   800
                        }
Thomas@2359
   801
                        catch (Exception ex)
Thomas@2359
   802
                        {
Thomas@2359
   803
                            Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error occured. " + ex.ToString());
Thomas@2359
   804
                        }
Thomas@2359
   805
Thomas@2359
   806
                        if (this._CurrentMailItem.GetIsPEPEnabled())
Thomas@2359
   807
                        {
Thomas@2359
   808
                            // If pEp is enabled, show the form region
Thomas@2359
   809
                            enableFormRegion = true;
Thomas@2359
   810
                        }
Thomas@2359
   811
                        else
Thomas@2359
   812
                        {
Thomas@2359
   813
                            /* If pEp is disabled, process item and show form region in the following cases:
Thomas@2359
   814
                             * 1. Incoming items: if decrypt always option is set
Thomas@2359
   815
                             * 2. Outgoing items: if EnableProtection option is set
Thomas@2359
   816
                             *                    Note: if this property isn't set, subscribe to originally 
Thomas@2359
   817
                             *                          encrypted status update event handler in case the 
Thomas@2359
   818
                             *                          current code runs before CryptableMailItem.MailItem_Reply
Thomas@2359
   819
                             *                          or CryptableMailItem.MailItem_Forward.
Thomas@2359
   820
                             */
Thomas@2359
   821
                            if (this.IsDraft)
Thomas@2359
   822
                            {
Thomas@2359
   823
                                enableFormRegion = true;
Thomas@2359
   824
                                this.cryptableMailItem.OriginallyEncryptedStatusUpdated += CryptableMailItem_OriginallyEncryptedStatusUpdated;
Thomas@2359
   825
                            }
Thomas@2359
   826
                            else
Thomas@2359
   827
                            {
Thomas@2359
   828
                                enableFormRegion = this._CurrentMailItem.GetIsDecryptAlwaysEnabled();
Thomas@2359
   829
                            }
Thomas@2359
   830
                        }
Thomas@2359
   831
                    }
Thomas@2359
   832
                }
Thomas@2359
   833
Thomas@2359
   834
                // Update pEp enabled status
Thomas@2359
   835
                this.SetIsEnabled(enableFormRegion);
Thomas@2359
   836
Thomas@2359
   837
                if (this.isEnabled)
Thomas@2359
   838
                {
Thomas@2359
   839
                    // If forcefully protected, run dedicated decryption
Thomas@2359
   840
                    if (this._CurrentMailItem.GetIsForcefullyProtected())
Thomas@2359
   841
                    {
Thomas@2359
   842
                        FPPMessage fppMessage = new FPPMessage(this._CurrentMailItem);
Thomas@2359
   843
                        if ((fppMessage?.GetMessageType() != null) ||
Thomas@2359
   844
                            (fppMessage?.CurrentMessage?.IsSecure == true))
Thomas@2359
   845
                        {
Thomas@2359
   846
                            fppMessage.ProcessIncoming(true);
Thomas@2359
   847
                        }
Thomas@2359
   848
                        else
Thomas@2359
   849
                        {
Thomas@2359
   850
                            this.TimerRefresh_Tick(null, new EventArgs());
Thomas@2359
   851
                        }
Thomas@2359
   852
                    }
Thomas@2359
   853
                    else
Thomas@2359
   854
                    {
Thomas@2359
   855
                        // Call the timer tick method manually to refresh data with no delay
Thomas@2359
   856
                        this.TimerRefresh_Tick(null, new EventArgs());
Thomas@2359
   857
                    }
Thomas@2359
   858
                }
Thomas@2359
   859
            }
Thomas@2359
   860
            catch (Exception e)
Thomas@2359
   861
            {
Thomas@2359
   862
                Log.Error("Window_SelectionChange: Error. " + e.Message);
Thomas@2359
   863
            }
Thomas@2359
   864
        }
Thomas@2359
   865
Thomas@2359
   866
        /// <summary>
Thomas@2359
   867
        /// Event handler for when the form region is closed.
Thomas@2359
   868
        /// </summary>
Thomas@2359
   869
        protected void FormRegionPrivacyStatus_FormRegionClosed(object sender, EventArgs e)
Thomas@2359
   870
        {
Thomas@2359
   871
            // Disconnect cryptable mail item
Thomas@2359
   872
            if (this.cryptableMailItem != null)
Thomas@2359
   873
            {
Thomas@2359
   874
                try
Thomas@2359
   875
                {
Thomas@2359
   876
                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Thomas@2359
   877
                    this.cryptableMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
Thomas@2359
   878
                    this.cryptableMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
Thomas@2359
   879
                    this.cryptableMailItem.Open -= MailItem_Open;
Thomas@2359
   880
                    this.cryptableMailItem.Send -= MailItem_Send;
Thomas@2359
   881
                    this.cryptableMailItem.OriginallyEncryptedStatusUpdated -= CryptableMailItem_OriginallyEncryptedStatusUpdated;
Thomas@2359
   882
                }
Thomas@2359
   883
                catch { }
Thomas@2359
   884
Thomas@2359
   885
                this.cryptableMailItem.Dispose();
Thomas@2359
   886
                this.cryptableMailItem = null;
Thomas@2359
   887
            }
Thomas@2359
   888
Thomas@2359
   889
            // Disconnect other
Thomas@2359
   890
            this.SetIsEnabled(false);
Thomas@2359
   891
        }
Thomas@2359
   892
Thomas@2359
   893
        /// <summary>
Thomas@2359
   894
        /// Event handler for when the processing is completed in the associated mail item.
Thomas@2359
   895
        /// This will then update the form region UI and the privacy status window as needed.
Thomas@2359
   896
        /// </summary>
Thomas@2359
   897
        private void MailItem_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
Thomas@2359
   898
        {
Thomas@2359
   899
            Log.Verbose("MailItem_ProcessingComplete: Decryption completed.");
Thomas@2359
   900
Thomas@2359
   901
            try
Thomas@2359
   902
            {
Thomas@2359
   903
                // Marshal code back to UI thread as necessary
Thomas@2359
   904
                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
Thomas@2359
   905
                {
Thomas@2359
   906
                    if (this.isEnabled)
Thomas@2359
   907
                    {
Thomas@2359
   908
                        try
Thomas@2359
   909
                        {
Thomas@2359
   910
                            this.SetRating(e.ProcessedRating);
Thomas@2359
   911
Thomas@2359
   912
                            // Set MAPI properties if needed
Thomas@2359
   913
                            if (e.PropertiesToSet?.Count > 0)
Thomas@2359
   914
                            {
Thomas@2359
   915
                                this._CurrentMailItem?.SetMAPIProperties(e.PropertiesToSet);
Thomas@2359
   916
                            }
Thomas@2359
   917
                            Log.Verbose("MailItem_ProcessingComplete: Status bar updated with rating " + Enum.GetName(typeof(pEpRating), e.ProcessedRating));
Thomas@2359
   918
                        }
Thomas@2359
   919
                        catch (Exception ex)
Thomas@2359
   920
                        {
Thomas@2359
   921
                            Log.Verbose("MailItem_ProcessingComplete: Error. " + ex.ToString());
Thomas@2359
   922
                        }
Thomas@2359
   923
Thomas@2359
   924
                        if (repeatProcessing &&
Thomas@2359
   925
                            (repeatCounter++ < maxRepeatCount))
Thomas@2359
   926
                        {
Thomas@2359
   927
                            repeatProcessing = false;
Thomas@2359
   928
                            this.RequestRatingAndUIUpdate();
Thomas@2359
   929
                        }
Thomas@2359
   930
                        else
Thomas@2359
   931
                        {
Thomas@2359
   932
                            /* Check if the mail item is in Outbox and update the inspector window if possible.
Thomas@2359
   933
                             * This is the case when a submitted, but not yet sent email is opened again when working 
Thomas@2359
   934
                             * offline or without internet connection. Without this update, Outlook removes the message class 
Thomas@2359
   935
                             * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
Thomas@2359
   936
                             * opened again (i.e. is lost).
Thomas@2359
   937
                             */
Thomas@2359
   938
                            try
Thomas@2359
   939
                            {
Thomas@2359
   940
                                if ((this._CurrentMailItem?.GetIsSubmitted() == true) &&
Thomas@2359
   941
                                    (this.IsDraft))
Thomas@2359
   942
                                {
Thomas@2359
   943
                                    UpdateInspector();
Thomas@2359
   944
                                }
Thomas@2359
   945
                            }
Thomas@2359
   946
                            catch (Exception ex)
Thomas@2359
   947
                            {
Thomas@2359
   948
                                Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
Thomas@2359
   949
                            }
Thomas@2359
   950
Thomas@2359
   951
                            /* Create the unencrypted preview if the mail item is encrypted and
Thomas@2359
   952
                             * it is in an encrypted (untrusted) store
Thomas@2359
   953
                             * 
Thomas@2359
   954
                             * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Thomas@2359
   955
                             * it also is initialized after FormRegionPreviewUnencrypted.
Thomas@2359
   956
                             */
Thomas@2359
   957
                            try
Thomas@2359
   958
                            {
Thomas@2359
   959
                                if (this.cryptableMailItem.IsSecurelyStored || this.cryptableMailItem.IsSecureAttachedMail)
Thomas@2359
   960
                                {
Thomas@2359
   961
                                    Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
Thomas@2359
   962
                                    this.cryptableMailItem.StartGetMirror(this.cryptableMailItem.MessageId);
Thomas@2359
   963
                                }
Thomas@2359
   964
                                else
Thomas@2359
   965
                                {
Thomas@2359
   966
                                    this.SetNote();
Thomas@2359
   967
                                }
Thomas@2359
   968
                            }
Thomas@2359
   969
                            catch (Exception ex)
Thomas@2359
   970
                            {
Thomas@2359
   971
                                // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
Thomas@2359
   972
                                // While rare, just log the issue and stop the process
Thomas@2359
   973
                                Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
Thomas@2359
   974
                            }
Thomas@2359
   975
Thomas@2359
   976
                            /* OUT-470: Workaround until this is implemented in the engine:
Thomas@2359
   977
                             * Only enable Force Protection if all recipients are grey
Thomas@2359
   978
                             */
Thomas@2359
   979
                            if (this.IsDraft)
Thomas@2359
   980
                            {
Thomas@2359
   981
                                bool disableForceProtection = false;
Thomas@2359
   982
                                Outlook.Recipients recipients = null;
Thomas@2359
   983
                                Outlook.Recipient recipient = null;
Thomas@2359
   984
                                PEPIdentity pEpIdentity = null;
Thomas@2359
   985
Thomas@2359
   986
                                try
Thomas@2359
   987
                                {
Thomas@2359
   988
                                    recipients = this._CurrentMailItem?.Recipients;
Thomas@2359
   989
                                    if (recipients?.Count > 0)
Thomas@2359
   990
                                    {
Thomas@2359
   991
                                        for (int i = 1; i <= recipients.Count; i++)
Thomas@2359
   992
                                        {
Thomas@2359
   993
                                            recipient = recipients[i];
Thomas@2359
   994
                                            if ((PEPIdentity.Create(recipient, out pEpIdentity, false) == Globals.ReturnStatus.Success) &&
Thomas@2359
   995
                                                ((PEPIdentity.GetIsOwnIdentity(pEpIdentity.Address) ||
Thomas@2359
   996
                                                 (ThisAddIn.PEPEngine.IdentityRating(pEpIdentity.ToCOMType()) >= pEpRating.pEpRatingReliable))))
Thomas@2359
   997
                                            {
Thomas@2359
   998
                                                disableForceProtection = true;
Thomas@2359
   999
                                                Log.Verbose("ToggleButtonForceProtection_GetEnabled: Secure recipient found. Disabling force protection.");
Thomas@2359
  1000
                                                break;
Thomas@2359
  1001
                                            }
Thomas@2359
  1002
                                        }
Thomas@2359
  1003
                                    }
Thomas@2359
  1004
                                    else
Thomas@2359
  1005
                                    {
Thomas@2359
  1006
                                        // If there aren't any recipients (anymore), reset values
Thomas@2359
  1007
                                        this.DisableForceProtection = false;
Thomas@2359
  1008
                                        this.ForceProtection = false;
Thomas@2359
  1009
                                        this.NeverUnsecure = false;
Thomas@2359
  1010
                                        this.ForceUnencrypted = false;
Thomas@2359
  1011
                                    }
Thomas@2359
  1012
                                }
Thomas@2359
  1013
                                catch (Exception ex)
Thomas@2359
  1014
                                {
Thomas@2359
  1015
                                    Log.Error("ToggleButtonForceProtection_GetEnabled: Error occured. " + ex.ToString());
Thomas@2359
  1016
                                }
Thomas@2359
  1017
                                finally
Thomas@2359
  1018
                                {
Thomas@2359
  1019
                                    recipient = null;
Thomas@2359
  1020
                                    recipients = null;
Thomas@2359
  1021
                                }
Thomas@2359
  1022
Thomas@2359
  1023
                                this.DisableForceProtection = disableForceProtection;
Thomas@2359
  1024
                            }
Thomas@2359
  1025
                        }
Thomas@2359
  1026
                    }
Thomas@2359
  1027
                }));
Thomas@2359
  1028
            }
Thomas@2359
  1029
            catch (Exception ex)
Thomas@2359
  1030
            {
Thomas@2359
  1031
                Log.Error("MailItem_ProcessingComplete: Error setting UI state, " + ex.ToString());
Thomas@2359
  1032
            }
Thomas@2359
  1033
Thomas@2359
  1034
            this.processingOngoing = false;
Thomas@2359
  1035
        }
Thomas@2359
  1036
Thomas@2359
  1037
        /// <summary>
Thomas@2359
  1038
        /// Event handler for when the get mirror locating process is complete for the associated mail item.
Thomas@2359
  1039
        /// This will then update the unencrypted preview in the UI.
Thomas@2359
  1040
        /// </summary>
Thomas@2359
  1041
        private void MailItem_GetMirrorCompleted(object sender, CryptableMailItem.GetMirrorCompletedEventArgs e)
Thomas@2359
  1042
        {
Thomas@2359
  1043
            try
Thomas@2359
  1044
            {
Thomas@2359
  1045
                // Marshal code back to UI thread as necessary
Thomas@2359
  1046
                KeySyncWizard.Wizard.Dispatcher.Invoke(new Action(() =>
Thomas@2359
  1047
                {
Thomas@2359
  1048
                    if (this.isEnabled)
Thomas@2359
  1049
                    {
Thomas@2359
  1050
                        WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Thomas@2359
  1051
Thomas@2359
  1052
                        // If the message was forcefully protected, there is no mirror and we show the actual message
Thomas@2359
  1053
                        if ((e.Mirror == null) &&
Thomas@2359
  1054
                            (this._CurrentMailItem?.GetIsForcefullyProtected() == true))
Thomas@2359
  1055
                        {
Thomas@2359
  1056
                            PEPMessage mirror = null;
Thomas@2359
  1057
                            if (PEPMessage.Create(this._CurrentMailItem, out mirror) == Globals.ReturnStatus.Success)
Thomas@2359
  1058
                            {
Thomas@2359
  1059
                                e.Mirror = mirror;
Thomas@2359
  1060
                            }
Thomas@2359
  1061
                        }
Thomas@2359
  1062
Thomas@2359
  1063
                        if ((e.Mirror == null) &&
Thomas@2359
  1064
                            (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.Failure))
Thomas@2359
  1065
                        {
Thomas@2359
  1066
                            this.SetNote(Properties.Resources.Message_OpenError);
Thomas@2359
  1067
                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, failure during decryption.");
Thomas@2359
  1068
                        }
Thomas@2359
  1069
                        else if ((e.Mirror == null) &&
Thomas@2359
  1070
                                 (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
Thomas@2359
  1071
                        {
Thomas@2359
  1072
                            this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
Thomas@2359
  1073
                            Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
Thomas@2359
  1074
                        }
Thomas@2359
  1075
                        else
Thomas@2359
  1076
                        {
Thomas@2359
  1077
                            if (formRegions != null)
Thomas@2359
  1078
                            {
Thomas@2359
  1079
                                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Thomas@2359
  1080
                                    (formRegions.FormRegionPreviewUnencrypted.Visible))
Thomas@2359
  1081
                                {
Thomas@2359
  1082
                                    formRegions.FormRegionPreviewUnencrypted.DisplayState.OriginalEntryId = this._CurrentMailItem?.EntryID;
Thomas@2359
  1083
                                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
Thomas@2359
  1084
                                }
Thomas@2359
  1085
Thomas@2359
  1086
                                Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
Thomas@2359
  1087
                            }
Thomas@2359
  1088
                        }
Thomas@2359
  1089
Thomas@2359
  1090
                        // Display the mirror if necessary
Thomas@2359
  1091
                        if ((this.cryptableMailItem != null) &&
Thomas@2359
  1092
                            (this.displayMirrorRequested))
Thomas@2359
  1093
                        {
Thomas@2359
  1094
                            this.cryptableMailItem.DisplayMirror();
Thomas@2359
  1095
                            this.displayMirrorRequested = false;
Thomas@2359
  1096
                        }
Thomas@2359
  1097
                    }
Thomas@2359
  1098
                }));
Thomas@2359
  1099
            }
Thomas@2359
  1100
            catch (Exception ex)
Thomas@2359
  1101
            {
Thomas@2359
  1102
                Log.Error("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
Thomas@2359
  1103
            }
Thomas@2359
  1104
        }
Thomas@2359
  1105
Thomas@2359
  1106
        /// <summary>
Thomas@2359
  1107
        /// Event handler for the mail item originally encrypted status updated.
Thomas@2359
  1108
        /// This event is fired after the status has been updated with parent information following a
Thomas@2359
  1109
        /// forward or reply mail item event (on a different, likely parent, mail item).
Thomas@2359
  1110
        /// </summary>
Thomas@2359
  1111
        protected void CryptableMailItem_OriginallyEncryptedStatusUpdated(object sender, EventArgs e)
Thomas@2359
  1112
        {
Thomas@2359
  1113
            // Process the mail item now that the cache is updated
Thomas@2359
  1114
            if (this.cryptableMailItem.IsOriginallyEncrypted)
Thomas@2359
  1115
            {
Thomas@2359
  1116
                this.cryptableMailItem.StartProcessing();
Thomas@2359
  1117
            }
Thomas@2359
  1118
        }
Thomas@2359
  1119
Thomas@2359
  1120
        /// <summary>
Thomas@2359
  1121
        /// Event handler for when a mail item is being opened in an inspector.
Thomas@2359
  1122
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Thomas@2359
  1123
        /// </summary>
Thomas@2359
  1124
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Thomas@2359
  1125
        /// If the event procedure sets this argument to True, the open operation is not completed 
Thomas@2359
  1126
        /// and the inspector is not displayed.</param>
Thomas@2359
  1127
        protected void MailItem_Open(ref bool cancel)
Thomas@2359
  1128
        {
Thomas@2359
  1129
            bool result;
Thomas@2359
  1130
Thomas@2359
  1131
            if ((this.isEnabled) &&
Thomas@2359
  1132
                (this.cryptableMailItem != null))
Thomas@2359
  1133
            {
Thomas@2359
  1134
                // If cryptable mail item is not to be opened, cancel opening
Thomas@2359
  1135
                if (this.cryptableMailItem.CancelOpen)
Thomas@2359
  1136
                {
Thomas@2359
  1137
                    cancel = true;
Thomas@2359
  1138
                }
Thomas@2359
  1139
                else if ((this.cryptableMailItem.IsSecurelyStored) &&
Thomas@2359
  1140
                         (this.cryptableMailItem.IsIncoming || this.cryptableMailItem.IsOriginallyEncrypted || !this.cryptableMailItem.IsDraft))
Thomas@2359
  1141
                {
Thomas@2359
  1142
                    // Try to open the mirror
Thomas@2359
  1143
                    result = this.cryptableMailItem.DisplayMirror();
Thomas@2359
  1144
Thomas@2359
  1145
                    if (result == false)
Thomas@2359
  1146
                    {
Thomas@2359
  1147
                        // Set flag to open after decryption/mirror location
Thomas@2359
  1148
                        this.displayMirrorRequested = true;
Thomas@2359
  1149
                    }
Thomas@2359
  1150
Thomas@2359
  1151
                    // Always cancel opening the original
Thomas@2359
  1152
                    cancel = true;
Thomas@2359
  1153
                }
Thomas@2359
  1154
            }
Thomas@2359
  1155
        }
Thomas@2359
  1156
Thomas@2359
  1157
        /// <summary>
Thomas@2359
  1158
        /// Event handler for when a mail item is sent.
Thomas@2359
  1159
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
Thomas@2359
  1160
        /// </summary>
Thomas@2359
  1161
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Thomas@2359
  1162
        /// If the event procedure sets this argument to True, the send operation is not completed 
Thomas@2359
  1163
        /// and the inspector is left open.</param>
Thomas@2359
  1164
        protected void MailItem_Send(ref bool cancel)
Thomas@2359
  1165
        {
Thomas@2359
  1166
            DialogResult result;
Thomas@2359
  1167
Thomas@2359
  1168
            if (this.isEnabled)
Thomas@2359
  1169
            {
Thomas@2359
  1170
                if ((this.cryptableMailItem.IsBeingProcessed) ||
Thomas@2359
  1171
                    (this.processingOngoing))
Thomas@2359
  1172
                {
Thomas@2359
  1173
                    Log.Verbose("MailItem_Send cancelled. Mail item still being processed.");
Thomas@2359
  1174
                    cancel = true;
Thomas@2359
  1175
                    return;
Thomas@2359
  1176
                }
Thomas@2359
  1177
Thomas@2359
  1178
                // Show warning message if needed
Thomas@2359
  1179
                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
Thomas@2359
  1180
                    (this.Rating < pEpRating.pEpRatingUnreliable) &&
Thomas@2359
  1181
                    (this.cryptableMailItem.IsOriginallyEncrypted))
Thomas@2359
  1182
                {
Thomas@2359
  1183
Thomas@2359
  1184
#if READER_RELEASE_MODE
Thomas@2359
  1185
                    FormReaderSplash warningMessage = new FormReaderSplash(true);
Thomas@2359
  1186
                    result = warningMessage.ShowDialog();
Thomas@2359
  1187
Thomas@2359
  1188
                    if (result != DialogResult.OK)
Thomas@2359
  1189
                    {
Thomas@2359
  1190
                        // Cancel sending
Thomas@2359
  1191
                        cancel = true;
Thomas@2359
  1192
                    }
Thomas@2359
  1193
#else
Thomas@2359
  1194
                    result = MessageBox.Show(Properties.Resources.Message_WarningSecurityLoss,
Thomas@2359
  1195
                                             Properties.Resources.Message_TitleConfirmOperation,
Thomas@2359
  1196
                                             MessageBoxButtons.YesNo,
Thomas@2359
  1197
                                             MessageBoxIcon.Warning);
Thomas@2359
  1198
Thomas@2359
  1199
                    if (result == DialogResult.No)
Thomas@2359
  1200
                    {
Thomas@2359
  1201
                        // Cancel sending
Thomas@2359
  1202
                        cancel = true;
Thomas@2359
  1203
                    }
Thomas@2359
  1204
#endif
Thomas@2359
  1205
                }
Thomas@2359
  1206
Thomas@2359
  1207
                if (cancel == false)
Thomas@2359
  1208
                {
Thomas@2359
  1209
                    // Set pEp options if needed
Thomas@2359
  1210
                    if ((this.ForceProtection) &&
Thomas@2359
  1211
                        (this.DisableForceProtection == false))
Thomas@2359
  1212
                    {
Thomas@2359
  1213
                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceProtection, Guid.NewGuid().ToString());
Thomas@2359
  1214
                    }
Thomas@2359
  1215
                    else if (this.ForceUnencrypted)
Thomas@2359
  1216
                    {
Thomas@2359
  1217
                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, true);
Thomas@2359
  1218
                    }
Thomas@2359
  1219
Thomas@2359
  1220
                    if (this.NeverUnsecure)
Thomas@2359
  1221
                    {
Thomas@2359
  1222
                        this._CurrentMailItem?.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, true);
Thomas@2359
  1223
                    }
Thomas@2359
  1224
Thomas@2359
  1225
                    // Stop and disconnect the refresh timer
Thomas@2359
  1226
                    // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
Thomas@2359
  1227
                    this.TimerRefresh.Stop();
Thomas@2359
  1228
                    this.TimerRefresh.Enabled = false;
Thomas@2359
  1229
                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
Thomas@2359
  1230
                }
Thomas@2359
  1231
            }
Thomas@2359
  1232
        }
Thomas@2359
  1233
Thomas@2359
  1234
        /// <summary>
Thomas@2359
  1235
        /// Event handler for when a mail item property is changed.
Thomas@2359
  1236
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Thomas@2359
  1237
        /// </summary>
Thomas@2359
  1238
        /// <param name="propertyName">The name of the property that was changed.</param>
Thomas@2359
  1239
        protected void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Thomas@2359
  1240
        {
Thomas@2359
  1241
            switch (e.PropertyName.ToUpperInvariant())
Thomas@2359
  1242
            {
Thomas@2359
  1243
                case "BCC":
Thomas@2359
  1244
                    {
Thomas@2359
  1245
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Thomas@2359
  1246
                        break;
Thomas@2359
  1247
                    }
Thomas@2359
  1248
                case "CC":
Thomas@2359
  1249
                    {
Thomas@2359
  1250
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Thomas@2359
  1251
                        break;
Thomas@2359
  1252
                    }
Thomas@2359
  1253
                case "SENTONBEHALFOFNAME":
Thomas@2359
  1254
                    {
Thomas@2359
  1255
                        // Always fired with "SENDUSINGACCOUNT" so is ignored
Thomas@2359
  1256
                        break;
Thomas@2359
  1257
                    }
Thomas@2359
  1258
                case "SENDUSINGACCOUNT":
Thomas@2359
  1259
                    {
Thomas@2359
  1260
                        // Update pEp enabled status
Thomas@2359
  1261
                        this.isStarted = false;
Thomas@2359
  1262
                        this.SetIsEnabled((this.CurrentMailItem)?.GetEnableFormRegion() ?? false);
Thomas@2359
  1263
Thomas@2359
  1264
                        // Refresh the UI
Thomas@2359
  1265
                        this.ResolveAllRecipients();
Thomas@2359
  1266
                        this.RequestRatingAndUIUpdate();
Thomas@2359
  1267
                        RibbonCustomizations.Invalidate();
Thomas@2359
  1268
Thomas@2359
  1269
                        break;
Thomas@2359
  1270
                    }
Thomas@2359
  1271
                case "TO":
Thomas@2359
  1272
                    {
Thomas@2359
  1273
                        if (this.isEnabled)
Thomas@2359
  1274
                        {
Thomas@2359
  1275
                            this.RequestRatingAndUIUpdate();
Thomas@2359
  1276
                        }
Thomas@2359
  1277
                        break;
Thomas@2359
  1278
                    }
Thomas@2359
  1279
            }
Thomas@2359
  1280
        }
Thomas@2359
  1281
Thomas@2359
  1282
        /// <summary>
Thomas@2359
  1283
        /// Event handler for when a handshake dialog was updated.
Thomas@2359
  1284
        /// </summary>
Thomas@2359
  1285
        protected void HandshakeDialog_Updated(object sender, EventArgs e)
Thomas@2359
  1286
        {
Thomas@2359
  1287
            // Update current form region
Thomas@2359
  1288
            this.RequestRatingAndUIUpdate();
Thomas@2359
  1289
            
Thomas@2359
  1290
            /* If a handshake is performed while having the same message open both in an inspector
Thomas@2359
  1291
             * and an Window window, the one that didn't trigger the handshake won't get updated
Thomas@2359
  1292
             * automatically. Therefore, after a handshake, we also update all other open windows.
Thomas@2359
  1293
             */
Thomas@2359
  1294
            try
Thomas@2359
  1295
            {
Thomas@2359
  1296
                Globals.ThisAddIn.RecalculateAllWindows(this);                
Thomas@2359
  1297
            }
Thomas@2359
  1298
            catch (Exception ex)
Thomas@2359
  1299
            {
Thomas@2359
  1300
                Log.Error("HandshakeDialog_Updated: Error updating other windows. " + ex.Message);
Thomas@2359
  1301
            }
Thomas@2359
  1302
        }
Thomas@2359
  1303
Thomas@2359
  1304
        /// <summary>
Thomas@2359
  1305
        /// Event handler for when a handshake dialog was closed.
Thomas@2359
  1306
        /// </summary>
Thomas@2359
  1307
        protected void HandshakeDialog_Closed(object sender, EventArgs e)
Thomas@2359
  1308
        {
Thomas@2359
  1309
            if (this.handshakeDialog != null)
Thomas@2359
  1310
            {
Thomas@2359
  1311
                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
Thomas@2359
  1312
                this.handshakeDialog.Closed -= HandshakeDialog_Closed;
Thomas@2359
  1313
                this.handshakeDialog = null;
Thomas@2359
  1314
            }
Thomas@2359
  1315
        }
Thomas@2359
  1316
Thomas@2359
  1317
        /// <summary>
Thomas@2359
  1318
        /// Event handler called after the refresh timer has elapsed.
Thomas@2359
  1319
        /// </summary>
Thomas@2359
  1320
        private void TimerRefresh_Tick(object sender, EventArgs e)
Thomas@2359
  1321
        {
Thomas@2359
  1322
            bool tryAgain = false;
Thomas@2359
  1323
#pragma warning disable 219
Thomas@2359
  1324
            bool markForDownload = false;
Thomas@2359
  1325
#pragma warning restore 219
Thomas@2359
  1326
            this.TimerRefresh.Enabled = false; // Only once
Thomas@2359
  1327
            Outlook.OlDownloadState dlState;
Thomas@2359
  1328
Thomas@2359
  1329
            /* The Refresh/UI_Update process:
Thomas@2359
  1330
             * There are the following components:
Thomas@2359
  1331
             *   1. TimerRefresh_Tick
Thomas@2359
  1332
             *        This is the main timer tick event handler called any time
Thomas@2359
  1333
             *        a refresh was requested (RequestRatingAndUIUpdate) and hasn't been run yet. 
Thomas@2359
  1334
             *        A refresh is requested either at initialization or when a property changes
Thomas@2359
  1335
             *        (such as MailItem_PropertyChanged). It is on a timer as many 
Thomas@2359
  1336
             *        property change events could occur rapidy, but only one refresh should
Thomas@2359
  1337
             *        occur for performance reasons.
Thomas@2359
  1338
             * 
Thomas@2359
  1339
             *   2. ImmediateRatingAndUIUpdate
Thomas@2359
  1340
             *        This will re-calculate the mail item's rating.
Thomas@2359
  1341
             *        This internally just calls CryptableMailItem.StartProcessing.
Thomas@2359
  1342
             * 
Thomas@2359
  1343
             *   3. MailItem_ProcessingCompleted
Thomas@2359
  1344
             *        When processing of the mail item is complete, this even handler will be called.
Thomas@2359
  1345
             *        This will update the UI with the latest rating then call StartGetMirror.
Thomas@2359
  1346
             *        The CopyStateToUI method is used which means any open privacy status form will also
Thomas@2359
  1347
             *        be updated.
Thomas@2359
  1348
             * 
Thomas@2359
  1349
             *   4. MailItem_GetMirrorComplete
Thomas@2359
  1350
             *        This is the final step in updating the UI, after a mirror is located, it's contents
Thomas@2359
  1351
             *        will be shown in the unencrypted preview.
Thomas@2359
  1352
             * 
Thomas@2359
  1353
             * The general calling sequence is as shown above 1->4 with each component calling the next.
Thomas@2359
  1354
             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
Thomas@2359
  1355
             */
Thomas@2359
  1356
Thomas@2359
  1357
            // Ensure the tick method is not called more than once
Thomas@2359
  1358
            if ((this.isEnabled) &&
Thomas@2359
  1359
                (refreshOngoing == false))
Thomas@2359
  1360
            {
Thomas@2359
  1361
                this.refreshOngoing = true;
Thomas@2359
  1362
Thomas@2359
  1363
                if ((this.cryptableMailItem != null) &&
Thomas@2359
  1364
                    (this.cryptableMailItem.IsBeingProcessed == false))
Thomas@2359
  1365
                {
Thomas@2359
  1366
                    // Attempt to get the download state
Thomas@2359
  1367
                    try
Thomas@2359
  1368
                    {
Thomas@2359
  1369
                        dlState = this.cryptableMailItem.DownloadState;
Thomas@2359
  1370
                    }
Thomas@2359
  1371
                    catch (Exception ex)
Thomas@2359
  1372
                    {
Thomas@2359
  1373
                        Log.Warning("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
Thomas@2359
  1374
Thomas@2359
  1375
                        // Assume everything is downloaded, but try to download again as well
Thomas@2359
  1376
                        dlState = Outlook.OlDownloadState.olFullItem;
Thomas@2359
  1377
                        markForDownload = true;
Thomas@2359
  1378
                    }
Thomas@2359
  1379
Thomas@2359
  1380
                    if (dlState == Outlook.OlDownloadState.olFullItem)
Thomas@2359
  1381
                    {
Thomas@2359
  1382
                        this.ImmediateRatingAndUIUpdate();
Thomas@2359
  1383
                    }
Thomas@2359
  1384
                    else
Thomas@2359
  1385
                    {
Thomas@2359
  1386
                        markForDownload = true;
Thomas@2359
  1387
                    }
Thomas@2359
  1388
Thomas@2359
  1389
                    /* 12/16/2016: It could be verified via testing that setting the MarkForDownload property
Thomas@2359
  1390
                     * can be a way to crash Outlook under certain circumstances (e.g. with IMAP on Outlook 2010 or on Windows 7). 
Thomas@2359
  1391
                     * This then is not caught by a try/catch block and therefore has to be considered an Outlook bug.
Thomas@2359
  1392
                     * It seems that in newer versions of Outlook/Windows, they fixed it, causing exceptions, if at all.
Thomas@2359
  1393
                     * For now, the following is commented out to prevent a crash. If at any point we see that header-only
Thomas@2359
  1394
                     * messages cause bigger issues, this decision has to be reevaluated.
Thomas@2359
  1395
                     */
Thomas@2359
  1396
                    //if (markForDownload)
Thomas@2359
  1397
                    //{
Thomas@2359
  1398
                    //    // Try to mark the message for full download
Thomas@2359
  1399
                    //    try
Thomas@2359
  1400
                    //    {
Thomas@2359
  1401
                    //        this.cryptableMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Thomas@2359
  1402
                    //        tryAgain = true;
Thomas@2359
  1403
                    //    }
Thomas@2359
  1404
                    //    catch (Exception ex)
Thomas@2359
  1405
                    //    {
Thomas@2359
  1406
                    //        Log.Warning("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
Thomas@2359
  1407
                    //    }
Thomas@2359
  1408
                    //}
Thomas@2359
  1409
                }
Thomas@2359
  1410
                else
Thomas@2359
  1411
                {
Thomas@2359
  1412
                    repeatProcessing = true;
Thomas@2359
  1413
                }
Thomas@2359
  1414
Thomas@2359
  1415
                // Set the timer to refresh again later automatically
Thomas@2359
  1416
                if (tryAgain)
Thomas@2359
  1417
                {
Thomas@2359
  1418
                    this.TimerRefresh.Interval = 100;
Thomas@2359
  1419
                    this.TimerRefresh.Enabled = true;
Thomas@2359
  1420
                }
Thomas@2359
  1421
Thomas@2359
  1422
                this.refreshOngoing = false;
Thomas@2359
  1423
            }
Thomas@2359
  1424
        }
Thomas@2359
  1425
Thomas@2359
  1426
        #endregion
Thomas@2359
  1427
    }
Thomas@2359
  1428
}