UI/FormRegionPrivacyStatus.cs
author Thomas
Wed, 23 Aug 2017 12:28:09 +0200
branchOUT-294
changeset 1799 caba7a4fb829
parent 1797 804480ce0270
child 1801 a084017b0fcb
permissions -rw-r--r--
Update the FormRegionPrivacyStatus after ForceProtection status change
Dean@1069
     1
´╗┐using pEp.UI;
Dean@1069
     2
using pEpCOMServerAdapterLib;
Dean@159
     3
using System;
Dean@445
     4
using System.ComponentModel;
Dean@859
     5
using System.Diagnostics;
vb@133
     6
using System.Windows.Forms;
vb@133
     7
using Outlook = Microsoft.Office.Interop.Outlook;
vb@133
     8
vb@133
     9
namespace pEp
vb@133
    10
{
Dean@159
    11
    /// <summary>
Dean@312
    12
    /// Partial class for the privacy status form region that is displayed below every outlook message.
Dean@159
    13
    /// </summary>
Dean@910
    14
    internal partial class FormRegionPrivacyStatus
vb@133
    15
    {
vb@133
    16
        #region Form Region Factory
vb@133
    17
vb@133
    18
        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
Dean@312
    19
        [Microsoft.Office.Tools.Outlook.FormRegionName("pEp.FormRegionPrivacyStatus")]
Dean@312
    20
        public partial class FormRegionPrivacyStatusFactory
vb@133
    21
        {
vb@133
    22
            // Occurs before the form region is initialized.
vb@133
    23
            // To prevent the form region from appearing, set e.Cancel to true.
vb@133
    24
            // Use e.OutlookItem to get a reference to the current Outlook item.
Dean@312
    25
            private void FormRegionPrivacyStatus_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
vb@133
    26
            {
Dean@1138
    27
                Outlook.MailItem omi;
Dean@1138
    28
Dean@1138
    29
                try
Dean@1138
    30
                {
Dean@1138
    31
                    omi = (Outlook.MailItem)e.OutlookItem;
Dean@1138
    32
                }
Dean@1138
    33
                catch
Dean@1138
    34
                {
Dean@1138
    35
                    // Never load if it's not a MailItem
Dean@1138
    36
                    e.Cancel = true;
Dean@1138
    37
                    return;
Dean@1138
    38
                }
Dean@1138
    39
Dean@985
    40
                //WindowFormRegionCollection formRegions;
Dean@327
    41
Dean@327
    42
                /* There is a Microsoft bug at least in Outlook 2013 and Windows 8.1
Dean@327
    43
                 * This bug causes multiple PrivacyStatus form regions to appear stacked on top of each other.
Dean@327
    44
                 * To trigger this bug, on an unencrypted server, click reply to compose an in-line response.
Dean@327
    45
                 * Then click to another tab such as People or Tasks. Then click back on the mail tab to view 
Dean@327
    46
                 * the original email again. Two form regions will be visible: 
Dean@327
    47
                 * (1) for the status during the in-line reply and 
Dean@327
    48
                 * (2) for the status of only the received message.
Dean@327
    49
                 * 
Dean@327
    50
                 * To fix this bug, any existing form regions are found and closed when initializing a new privacy status
Dean@327
    51
                 * form region.
Dean@327
    52
                 */
Dean@985
    53
                /*
Dean@327
    54
                try
Dean@327
    55
                {
Dean@987
    56
                    formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@327
    57
                    if (formRegions.FormRegionPrivacyStatus != null)
Dean@327
    58
                    {
Dean@985
    59
                        // Note: there seems to be no way to actually close the form region.
Dean@985
    60
                        // Therefore, this is as close as possible to actually closing it.
Dean@985
    61
                        // The actual form regions will be cleaned up as soon as another email is selected.
Dean@327
    62
                        formRegions.FormRegionPrivacyStatus.OutlookFormRegion.Visible = false;
Dean@327
    63
                    }
Dean@327
    64
                }
Dean@327
    65
                catch { }
Dean@985
    66
                */
Dean@1169
    67
Dean@327
    68
                return;
vb@133
    69
            }
vb@133
    70
        }
vb@133
    71
vb@133
    72
        #endregion
vb@133
    73
Dean@159
    74
        /* Notes:
Dean@179
    75
         * 
Dean@159
    76
         * Use this.OutlookItem to get a reference to the current Outlook item.
Dean@159
    77
         * Use this.OutlookFormRegion to get a reference to the form region.
Dean@179
    78
         * 
Dean@179
    79
         * UI State Managment:
Dean@179
    80
         * 
Dean@179
    81
         * The UI state is almost entirely set from the associated mail item data.
Dean@179
    82
         * However, a separate state class is maintained to represent the UI as some separation is needed.
Dean@179
    83
         * This logical separation MUST be maintained throughout the code.
Dean@179
    84
         * Specific cases are noted where possible.
Dean@179
    85
         * 
Dean@356
    86
         * The separate privacy status manager form state is also managed here.
Dean@159
    87
         */
Dean@159
    88
Dean@1384
    89
        /// <summary>
Dean@1384
    90
        /// Event for when the form region is expanded or collapsed.
Dean@1384
    91
        /// </summary>
Dean@1384
    92
        public event EventHandler Expanded;
Dean@1384
    93
Dean@1390
    94
        private CryptableMailItem       cryptableMailItem      = null;
Dean@1390
    95
        private bool                    displayMirrorRequested = false;
Thomas@1587
    96
        private HandshakeDialog         handshakeDialog        = null;
Dean@1390
    97
        private bool                    isEnabled              = true;
Dean@1384
    98
        private bool?                   isExpandedPrevious     = null;
Dean@1390
    99
        private bool                    isManagerFormEnabled   = true;
Dean@1390
   100
        private bool                    isStarted              = false;
Dean@758
   101
        private FormManagePrivacyStatus managerForm            = null;
Thomas@1505
   102
        private bool                    processingOngoing      = false;
Dean@1402
   103
        private bool                    refreshOngoing         = false;
Thomas@1419
   104
        private bool                    repeatProcessing       = false;
Thomas@1547
   105
        private int                     repeatCounter          = 0;
Thomas@1547
   106
        private const int               maxRepeatCount         = 5;
Dean@259
   107
Dean@159
   108
        /**************************************************************
Dean@159
   109
         * 
Dean@1375
   110
         * Property Accessors
Dean@1375
   111
         * 
Dean@1375
   112
         *************************************************************/
Dean@1375
   113
Dean@1375
   114
        /// <summary>
Dean@1377
   115
        /// Gets or sets the displayed state.
Dean@1375
   116
        /// </summary>
Dean@1377
   117
        public FormControlPrivacyStatus.State DisplayState
Dean@1375
   118
        {
Dean@1377
   119
            get { return (this.FormControlPrivacyStatusChild.DisplayState); }
Dean@1377
   120
            set { this.FormControlPrivacyStatusChild.DisplayState = value; }
Dean@1375
   121
        }
Dean@1375
   122
Dean@1375
   123
        /**************************************************************
Dean@1375
   124
         * 
Dean@159
   125
         * Methods
Dean@159
   126
         * 
Dean@159
   127
         *************************************************************/
Dean@159
   128
Dean@171
   129
        /// <summary>
Dean@438
   130
        /// Determines if this form region is running in an inspector window.
Dean@438
   131
        /// If not true, it is assumed to be within an explorer window.
Dean@438
   132
        /// </summary>
Dean@438
   133
        /// <returns>True if an inspector window, false if within an explorer.</returns>
Dean@438
   134
        private bool IsWithinInspector()
Dean@438
   135
        {
Dean@438
   136
            bool isWithinInspector = false;
Dean@895
   137
            Outlook.Inspector insp = null;
Dean@438
   138
Dean@438
   139
            try
Dean@438
   140
            {
Dean@895
   141
                /* There are two potential methods to determine if the item is within an inspector.
Dean@895
   142
                 * (1) Use this.OutlookFormRegion.Parent which will contain either the Explorer or an Inspector
Dean@895
   143
                 *     A cast could be tried to an Explorer of this parent and if it fails, it's assumed to be an inspector
Dean@895
   144
                 * (2) Use this.OutlookFormRegion.Inspector which will contain the Inspector if it exists.
Dean@895
   145
                 *     This will fail or return null if this form region is not running within it's own Inspector window.
Dean@895
   146
                 */
Dean@895
   147
                insp = this.OutlookFormRegion.Inspector;
Dean@895
   148
Dean@895
   149
                if (insp != null)
Dean@895
   150
                {
Dean@895
   151
                    isWithinInspector = true;
Dean@895
   152
                }
Dean@438
   153
            }
Dean@438
   154
            catch
Dean@438
   155
            {
Dean@895
   156
                isWithinInspector = false;
Dean@438
   157
            }
Dean@438
   158
            finally
Dean@438
   159
            {
Dean@895
   160
                if (insp != null)
Dean@438
   161
                {
vb@1516
   162
                    // Marshal.ReleaseComObject(insp);
Dean@895
   163
                    insp = null;
Dean@438
   164
                }
Dean@438
   165
            }
Dean@438
   166
Dean@438
   167
            return (isWithinInspector);
Dean@438
   168
        }
Dean@438
   169
Dean@438
   170
        /// <summary>
Dean@279
   171
        /// Builds the latest state of the encryption status manager then shows the UI.
Dean@279
   172
        /// </summary>
Dean@279
   173
        private void BuildAndShowManager()
Dean@279
   174
        {
Thomas@1583
   175
            /* Resolve all recipients -- this ensures the identities list is correctly populated
Thomas@1583
   176
             * 
Thomas@1583
   177
             * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Thomas@1583
   178
             * This is because the resolve process can modify the contents of the mail item which triggers an event.
Thomas@1583
   179
             * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Thomas@1583
   180
             * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
Thomas@1583
   181
             * cannot be resolved (no address).
Thomas@1583
   182
             */
Dean@483
   183
            try
Dean@483
   184
            {
Thomas@1583
   185
                this.ResolveAllRecipients();
Dean@483
   186
            }
Thomas@1583
   187
            catch (Exception e)
Dean@483
   188
            {
Thomas@1583
   189
                Log.Verbose("BuildAndShowManager: Error resolving recipients. " + e.Message);
Dean@483
   190
            }
Dean@259
   191
Thomas@1587
   192
            // Build the dialog
Thomas@1583
   193
            try
Thomas@1583
   194
            {
Thomas@1587
   195
                handshakeDialog = new HandshakeDialog(this.cryptableMailItem.Myself,
Thomas@1594
   196
                                                      this.cryptableMailItem.From,
Thomas@1594
   197
                                                      this.cryptableMailItem.Recipients,
Thomas@1648
   198
                                                      this.cryptableMailItem.IsIncoming,
Thomas@1648
   199
                                                      this.cryptableMailItem.LastProcessedRating);
Thomas@1587
   200
                handshakeDialog.OnUpdateStatus += HandshakeDialog_Updated;
Thomas@1587
   201
                handshakeDialog.Closed += HandshakeDialog_Closed;
Thomas@1587
   202
                handshakeDialog.ShowDialog();
Thomas@1551
   203
            }
Thomas@1583
   204
            catch (Exception e)
Thomas@1551
   205
            {
Thomas@1583
   206
                Globals.StopAndSendCrashReport(e);
Thomas@1551
   207
            }
Dean@259
   208
        }
Dean@259
   209
Dean@259
   210
        /// <summary>
Dean@1130
   211
        /// Schedules for the pEp rating and UI (including displayed mirror) to be updated.
Dean@1001
   212
        /// This can be called many times with no issue as the update is only run every n milliseconds.
Dean@179
   213
        /// </summary>
Dean@1130
   214
        public void RequestRatingAndUIUpdate()
Dean@1001
   215
        {
Dean@1390
   216
            if (this.isEnabled)
Dean@1390
   217
            {
Dean@1390
   218
                this.TimerRefresh.Enabled = true;
Dean@1390
   219
            }
Dean@1001
   220
            return;
Dean@1001
   221
        }
Dean@1001
   222
Dean@1001
   223
        /// <summary>
Dean@1130
   224
        /// Immediately starts the update of UI rating based on the associated mail item.
Dean@1001
   225
        /// This will start decryption as necessary and also will update the displayed mirror.
Dean@1001
   226
        /// This method by-passes the refresh timer completely.
Dean@1001
   227
        /// WARNING: This method assumes the message is fully downloaded already.
Dean@1001
   228
        /// </summary>
Dean@1130
   229
        private void ImmediateRatingAndUIUpdate()
Dean@159
   230
        {
Dean@1390
   231
            if ((this.isEnabled) &&
Dean@1390
   232
                (this.cryptableMailItem != null))
Dean@159
   233
            {
Dean@1301
   234
                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
Dean@740
   235
Dean@1301
   236
                // Start the rating calculation/decryption process
Dean@1390
   237
                this.cryptableMailItem.StartProcessing();
Thomas@1505
   238
                this.processingOngoing = true;
Dean@159
   239
            }
Dean@159
   240
Dean@179
   241
            return;
Dean@159
   242
        }
Dean@159
   243
Dean@709
   244
        /// <summary>
Thomas@1799
   245
        /// Resets the Enabled status of this form region and recalculates the rating if necessary.
Thomas@1799
   246
        /// </summary>
Thomas@1799
   247
        /// <param name="enable">Whether to enable the form region.</param>
Thomas@1799
   248
        public void UpdateFormRegion(bool enable)
Thomas@1799
   249
        {
Thomas@1799
   250
            this.SetIsEnabled(enable);
Thomas@1799
   251
Thomas@1799
   252
            // Refresh the UI
Thomas@1799
   253
            if (enable)
Thomas@1799
   254
            {
Thomas@1799
   255
                this.ResolveAllRecipients();
Thomas@1799
   256
                this.RequestRatingAndUIUpdate();
Thomas@1799
   257
                RibbonCustomizations.Invalidate();
Thomas@1799
   258
            }
Thomas@1799
   259
        }
Thomas@1799
   260
Thomas@1799
   261
        /// <summary>
Thomas@1458
   262
        /// Workaround method to update the current inspector window. This is done by moving the mail item
Thomas@1458
   263
        /// to a temporary folder first and then back to the current folder. Both folders CANNOT be the same.
Thomas@1458
   264
        /// As a fallback, the mail item stays in the temporary folder if moving back to the current folder
Thomas@1458
   265
        /// fails.
Thomas@1458
   266
        /// </summary>
Thomas@1547
   267
        private void UpdateInspector()
Thomas@1458
   268
        {
Thomas@1458
   269
            Outlook.Application application = null;
Thomas@1547
   270
            Outlook.Folder currentFolder = null;
Thomas@1547
   271
            Outlook.Folder tempFolder = null;
Thomas@1458
   272
            Outlook.Inspector currentInspector = null;
Thomas@1458
   273
            Outlook.Inspector newInspector = null;
Thomas@1458
   274
            Outlook.MailItem omi = null;
Thomas@1458
   275
            Outlook.MailItem tempMailItem = null;
Thomas@1547
   276
            Outlook.Store store = null;
Thomas@1458
   277
Thomas@1458
   278
            omi = this.OutlookItem as Outlook.MailItem;
Thomas@1458
   279
Thomas@1458
   280
            if (omi != null)
Thomas@1458
   281
            {
Thomas@1458
   282
                try
Thomas@1458
   283
                {
Thomas@1458
   284
                    application = omi.Application;
Thomas@1458
   285
                    currentInspector = omi.GetInspector;
Thomas@1547
   286
                    currentFolder = omi.Parent as Outlook.Folder;
Thomas@1458
   287
Thomas@1458
   288
                    if ((currentInspector != null) &&
Thomas@1547
   289
                        (application != null) &&
Thomas@1547
   290
                        (currentFolder != null))
Thomas@1458
   291
                    {
Thomas@1458
   292
                        var left = currentInspector.Left;
Thomas@1458
   293
                        var top = currentInspector.Top;
Thomas@1458
   294
                        var width = currentInspector.Width;
Thomas@1458
   295
                        var height = currentInspector.Height;
Thomas@1458
   296
                        var windowState = currentInspector.WindowState;
Thomas@1458
   297
Thomas@1547
   298
                        /* Check, if in trusted store. In that case, use the default drafts folder
Thomas@1547
   299
                         * as temporary folder. If the store is untrusted, use the pEp drafts folder.
Thomas@1547
   300
                         */
Thomas@1547
   301
                        store = currentFolder.Store;
Thomas@1547
   302
                        if (store?.GetIsSecureStorageEnabled() ?? false)
Thomas@1547
   303
                        {
Thomas@1547
   304
                            tempFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
Thomas@1547
   305
                        }
Thomas@1547
   306
                        else
Thomas@1547
   307
                        {
Thomas@1547
   308
                            tempFolder = store.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
Thomas@1547
   309
                        }
Thomas@1458
   310
Thomas@1547
   311
                        if (tempFolder != null)
Thomas@1458
   312
                        {
Thomas@1547
   313
                            tempMailItem = omi.Move(tempFolder) as Outlook.MailItem;
Thomas@1547
   314
Thomas@1547
   315
                            if (tempMailItem != null)
Thomas@1458
   316
                            {
Thomas@1547
   317
                                try
Thomas@1547
   318
                                {
Thomas@1547
   319
                                    omi = tempMailItem.Move(currentFolder) as Outlook.MailItem;
Thomas@1547
   320
                                }
Thomas@1547
   321
                                catch
Thomas@1547
   322
                                {
Thomas@1547
   323
                                    omi = tempMailItem.Copy();
Thomas@1547
   324
                                }
Thomas@1547
   325
Thomas@1547
   326
                                newInspector = application.Inspectors.Add(omi);
Thomas@1547
   327
Thomas@1547
   328
                                if (windowState == Outlook.OlWindowState.olNormalWindow)
Thomas@1547
   329
                                {
Thomas@1547
   330
                                    newInspector.Left = left;
Thomas@1547
   331
                                    newInspector.Top = top;
Thomas@1547
   332
                                    newInspector.Width = width;
Thomas@1547
   333
                                    newInspector.Height = height;
Thomas@1547
   334
                                }
Thomas@1547
   335
Thomas@1547
   336
                                newInspector.Display();
Thomas@1547
   337
                                newInspector.WindowState = windowState;
Thomas@1547
   338
Thomas@1547
   339
                                repeatProcessing = false;
Thomas@1458
   340
                            }
Thomas@1547
   341
                        }
Thomas@1547
   342
                        else
Thomas@1547
   343
                        {
Thomas@1547
   344
                            Log.Error("UpdateInspector: Cannot get temporary folder.");
Thomas@1458
   345
                        }
Thomas@1458
   346
                    }
Thomas@1458
   347
                    else
Thomas@1458
   348
                    {
Thomas@1458
   349
                        Log.Verbose("UpdateInspector: Error retrieving inspector window or application.");
Thomas@1458
   350
                    }
Thomas@1458
   351
                }
Thomas@1458
   352
                catch (Exception e)
Thomas@1458
   353
                {
Thomas@1458
   354
                    Log.Verbose("UpdateInspector: Error updating inspector window. " + e.Message);
Thomas@1458
   355
                }
Thomas@1458
   356
                finally
Thomas@1458
   357
                {
Thomas@1458
   358
                    if (application != null)
Thomas@1458
   359
                    {
vb@1507
   360
                        //Marshal.ReleaseComObject(application);
Thomas@1458
   361
                        application = null;
Thomas@1458
   362
                    }
Thomas@1458
   363
Thomas@1458
   364
                    if (currentInspector != null)
Thomas@1458
   365
                    {
vb@1516
   366
                        // Marshal.ReleaseComObject(currentInspector);
Thomas@1458
   367
                        currentInspector = null;
Thomas@1458
   368
                    }
Thomas@1458
   369
Thomas@1458
   370
                    if (newInspector != null)
Thomas@1458
   371
                    {
vb@1516
   372
                        // Marshal.ReleaseComObject(newInspector);
Thomas@1458
   373
                        newInspector = null;
Thomas@1458
   374
                    }
Thomas@1458
   375
Thomas@1458
   376
                    if (tempMailItem != null)
Thomas@1458
   377
                    {
vb@1516
   378
                        // Marshal.ReleaseComObject(tempMailItem);
Thomas@1458
   379
                        tempMailItem = null;
Thomas@1458
   380
                    }
Thomas@1458
   381
Thomas@1458
   382
                    if (omi != null)
Thomas@1458
   383
                    {
vb@1516
   384
                        // Marshal.ReleaseComObject(omi);
Thomas@1458
   385
                        omi = null;
Thomas@1458
   386
                    }
Thomas@1458
   387
                }
Thomas@1458
   388
            }
Thomas@1458
   389
Thomas@1458
   390
            return;
Thomas@1458
   391
        }
Thomas@1458
   392
Thomas@1458
   393
        /// <summary>
Dean@1117
   394
        /// Immediately update the manage privacy status form display state.
Dean@1117
   395
        /// This by default will completely rebuild the display state.
Dean@1117
   396
        /// </summary>
Thomas@1583
   397
        private void UpdateManagePrivacyStatusForm()
Dean@1117
   398
        {
Dean@1117
   399
            if (this.managerForm != null)
Dean@1117
   400
            {
Thomas@1583
   401
                // Only update the message rating
Thomas@1583
   402
                this.managerForm.DisplayState.Rating = this.FormControlPrivacyStatusChild.DisplayState.Rating;
Dean@1117
   403
            }
Dean@1117
   404
Dean@1117
   405
            return;
Dean@1117
   406
        }
Dean@1117
   407
Dean@1117
   408
        /// <summary>
Dean@709
   409
        /// Clears the associated unencrypted preview and displays the given note (if any).
Dean@709
   410
        /// </summary>
Dean@709
   411
        /// <param name="note">The note to diplsay.</param>
Dean@1483
   412
        private void SetNote(string note = null)
Dean@709
   413
        {
Dean@987
   414
            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
   415
Dean@1476
   416
            if (formRegions != null)
Dean@709
   417
            {
Dean@1476
   418
                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@1476
   419
                    (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@1476
   420
                {
Dean@1483
   421
                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetNote(note);
Dean@1476
   422
                }
Dean@709
   423
            }
Dean@709
   424
Dean@709
   425
            return;
Dean@709
   426
        }
Dean@709
   427
Dean@1390
   428
        /// <summary>
Dean@1390
   429
        /// Sets whether processing of the mail item is enabled.
Dean@1390
   430
        /// This should commonly be set from the .GetIsPEPEnabled() value.
Dean@1390
   431
        /// </summary>
Dean@1390
   432
        private void SetIsEnabled(bool enabled)
Dean@1390
   433
        {
Dean@1390
   434
            PEPIdentity currIdent;
Dean@1390
   435
            Globals.ReturnStatus sts;
Dean@1390
   436
            Outlook.MailItem omi = null;
Dean@1390
   437
            Outlook.Recipient currUser = null;
Dean@1390
   438
            Outlook.Account currAccount = null;
Dean@1390
   439
            Outlook.Account sendingAccount = null;
Dean@1390
   440
            Outlook.NameSpace ns = null;
Dean@1390
   441
Dean@1390
   442
            this.OutlookFormRegion.Visible = enabled;
Dean@1390
   443
            this.isEnabled = enabled;
Dean@1390
   444
Dean@1390
   445
            if (enabled)
Dean@1390
   446
            {
Dean@1390
   447
                // Do not allow initialization more than once
Dean@1390
   448
                if (this.isStarted == false)
Dean@1390
   449
                {
Dean@1390
   450
                    /* It's possible for new draft MailItems to be created outside the context of an account.
Dean@1390
   451
                     * In this situation the SendUsingAccount will always be null which of course breaks several pEp operations.
Dean@1390
   452
                     * The operations themselves cannot make the assumption about what account information to use.
Dean@1390
   453
                     * Therefore, the situation is detected here and for draft mail items a null SendUsingAccount will be 
Dean@1390
   454
                     * set with the session's default account.
Dean@1390
   455
                     */
Dean@1390
   456
                    try
Dean@1390
   457
                    {
Dean@1390
   458
                        ns = Globals.ThisAddIn.Application.Session;
Dean@1390
   459
Dean@1390
   460
                        if ((this.OutlookItem is Outlook.MailItem) &&
Dean@1390
   461
                            ((Outlook.MailItem)this.OutlookItem).GetIsDraft())
Dean@1390
   462
                        {
Dean@1390
   463
                            omi = this.OutlookItem as Outlook.MailItem;
Dean@1390
   464
                            sendingAccount = omi.SendUsingAccount;
Dean@1390
   465
                            currUser = ns.CurrentUser;
Dean@1390
   466
Dean@1390
   467
                            if (sendingAccount == null)
Dean@1390
   468
                            {
Dean@1390
   469
                                sts = PEPIdentity.Create(currUser, out currIdent);
Dean@1390
   470
Dean@1390
   471
                                if (sts == Globals.ReturnStatus.Success)
Dean@1390
   472
                                {
Dean@1390
   473
                                    currAccount = PEPIdentity.GetOwnAccount(currIdent.Address);
Dean@1390
   474
                                    omi.SendUsingAccount = currAccount;
Dean@1390
   475
                                }
Dean@1390
   476
                            }
Dean@1390
   477
                        }
Dean@1390
   478
                    }
Dean@1390
   479
                    catch { }
Dean@1390
   480
                    finally
Dean@1390
   481
                    {
Dean@1390
   482
                        if (omi != null)
Dean@1390
   483
                        {
vb@1516
   484
                            // Marshal.ReleaseComObject(omi);
Dean@1390
   485
                            omi = null;
Dean@1390
   486
                        }
Dean@1390
   487
Dean@1390
   488
                        if (currUser != null)
Dean@1390
   489
                        {
vb@1507
   490
                            //Marshal.ReleaseComObject(currUser);
Dean@1390
   491
                            currUser = null;
Dean@1390
   492
                        }
Dean@1390
   493
Dean@1390
   494
                        if (currAccount != null)
Dean@1390
   495
                        {
vb@1507
   496
                            //Marshal.ReleaseComObject(currAccount);
Dean@1390
   497
                            currAccount = null;
Dean@1390
   498
                        }
Dean@1390
   499
Dean@1390
   500
                        if (sendingAccount != null)
Dean@1390
   501
                        {
vb@1507
   502
                            //Marshal.ReleaseComObject(sendingAccount);
Dean@1390
   503
                            sendingAccount = null;
Dean@1390
   504
                        }
Dean@1390
   505
Dean@1390
   506
                        if (ns != null)
Dean@1390
   507
                        {
vb@1507
   508
                            //Marshal.ReleaseComObject(ns);
Dean@1390
   509
                            ns = null;
Dean@1390
   510
                        }
Dean@1390
   511
                    }
Dean@1390
   512
Dean@1390
   513
                    // Set reader upgrade link visibility
Dean@1390
   514
                    if ((Globals.RELEASE_MODE == Globals.ReleaseMode.Reader) &&
Dean@1390
   515
                        (this.cryptableMailItem != null) &&
Dean@1390
   516
                        (this.cryptableMailItem.IsDraft))
Dean@1390
   517
                    {
Dean@1390
   518
                        this.FormControlPrivacyStatusChild.DisplayState.UpgradeLinkIsVisible = true;
Dean@1390
   519
                    }
Dean@1390
   520
                    else
Dean@1390
   521
                    {
Dean@1390
   522
                        this.FormControlPrivacyStatusChild.DisplayState.UpgradeLinkIsVisible = false;
Dean@1390
   523
                    }
Dean@1390
   524
Dean@1390
   525
                    // Connect events
Dean@1390
   526
                    this.FormControlPrivacyStatusChild.PrivacyViewClick += FormControlPrivacyStatusChild_PrivacyViewClick;
Dean@1390
   527
                    this.Expanded += FormRegionPrivacyStatus_Expanded;
Dean@1390
   528
Dean@1390
   529
                    this.TimerRefresh.Tick += TimerRefresh_Tick;
Dean@1390
   530
                    this.isStarted = true;
Dean@1390
   531
                }
Dean@1390
   532
            }
Dean@1390
   533
            else
Dean@1390
   534
            {
Dean@1390
   535
                // Disconnect events
Dean@1390
   536
                this.FormControlPrivacyStatusChild.PrivacyViewClick -= FormControlPrivacyStatusChild_PrivacyViewClick;
Dean@1390
   537
                this.Expanded -= FormRegionPrivacyStatus_Expanded;
Dean@1390
   538
Dean@1390
   539
                // Stop and disconnect the refresh timer
Dean@1390
   540
                this.TimerRefresh.Stop();
Dean@1390
   541
                this.TimerRefresh.Enabled = false;
Dean@1390
   542
                this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@1390
   543
Dean@1390
   544
                this.isStarted = false;
Dean@1390
   545
            }
Dean@1390
   546
Dean@1390
   547
            return;
Dean@1390
   548
        }
Dean@1390
   549
Dean@1390
   550
        /// <summary>
Dean@1390
   551
        /// Resolves all recipients of the Outlook mail item.
Dean@1390
   552
        /// </summary>
Dean@1390
   553
        private void ResolveAllRecipients()
Dean@1390
   554
        {
Dean@1390
   555
            if ((this.isEnabled) &&
Dean@1390
   556
                (this.cryptableMailItem != null))
Dean@1390
   557
            {
Dean@1390
   558
                /*
Dean@1390
   559
                 * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Dean@1390
   560
                 * This is because the resolve process can modify the contents of the mail item which triggers an event.
Dean@1390
   561
                 * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Dean@1390
   562
                 * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
Dean@1390
   563
                 * cannot be resolved(no address).
Dean@1390
   564
                 */
Thomas@1551
   565
                try
Thomas@1551
   566
                {
Thomas@1551
   567
                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Thomas@1551
   568
                    this.cryptableMailItem.ResolveAllRecipients();
Thomas@1551
   569
                    this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Thomas@1551
   570
                }
Thomas@1551
   571
                catch (Exception e)
Thomas@1551
   572
                {
Thomas@1551
   573
                    Log.Error("Error resolving recipients. " + e.Message);
Thomas@1551
   574
                }
Dean@1390
   575
            }
Dean@1390
   576
Dean@1390
   577
            return;
Dean@1390
   578
        }
Dean@1390
   579
Dean@159
   580
        /**************************************************************
Dean@159
   581
         * 
Dean@159
   582
         * Event Handling
Dean@159
   583
         * 
Dean@159
   584
         *************************************************************/
Dean@159
   585
Dean@159
   586
        /// <summary>
Dean@680
   587
        /// Event handler that is called when the form region is displayed.
Thomas@1795
   588
        /// This is called each time the form region loses then regains visibility 
Dean@680
   589
        /// (for example an other email is selected then back to this one).
Dean@159
   590
        /// </summary>
Dean@1461
   591
        private void FormRegionPrivacyStatus_FormRegionShowing(object sender, EventArgs e)
Dean@159
   592
        {
Thomas@1797
   593
            bool enableFormRegion = false;
Thomas@1797
   594
            Outlook.MailItem omi = null;
Thomas@1797
   595
Dean@1390
   596
            // Set mail item
Thomas@1797
   597
            omi = this.OutlookItem as Outlook.MailItem;
Thomas@1797
   598
Thomas@1797
   599
            if (omi != null)
Dean@1390
   600
            {
Thomas@1797
   601
                this.cryptableMailItem = new CryptableMailItem(omi);
Thomas@1797
   602
Thomas@1797
   603
                // Connect cryptable mail item events
Thomas@1797
   604
                if (this.cryptableMailItem != null)
Thomas@1797
   605
                {
Thomas@1797
   606
                    try
Thomas@1797
   607
                    {
Thomas@1797
   608
                        this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Thomas@1797
   609
                        this.cryptableMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
Thomas@1797
   610
                        this.cryptableMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
Thomas@1797
   611
                        this.cryptableMailItem.Send += MailItem_Send;
Thomas@1797
   612
                        this.cryptableMailItem.Open += MailItem_Open;
Thomas@1797
   613
                    }
Thomas@1797
   614
                    catch (Exception ex)
Thomas@1797
   615
                    {
Thomas@1797
   616
                        Log.Error("FormRegionPrivacyStatus_FormRegionShowing: Error occured. " + ex.ToString());
Thomas@1797
   617
                    }
Thomas@1797
   618
Thomas@1797
   619
                    // If pEp is enabled, show the form region
Thomas@1797
   620
                    if (omi.GetIsPEPEnabled())
Thomas@1797
   621
                    {
Thomas@1797
   622
                        enableFormRegion = true;
Thomas@1797
   623
                    }
Thomas@1797
   624
                    else
Thomas@1797
   625
                    {
Thomas@1797
   626
                        /* If pEp is disabled, process item and show form region in the following cases:
Thomas@1797
   627
                         * 1. Incoming items: if decrypt always option is set
Thomas@1797
   628
                         * 2. Outgoing items: if ForceProtection option is set
Thomas@1797
   629
                         *                    Note: if this property isn't set, subscribe to originally 
Thomas@1797
   630
                         *                          encrypted status update event handler in case the 
Thomas@1797
   631
                         *                          current code runs before CryptableMailItem.MailItem_Reply
Thomas@1797
   632
                         *                          or CryptableMailItem.MailItem_Forward.
Thomas@1797
   633
                         */
Thomas@1797
   634
                        if (omi.GetIsIncoming())
Thomas@1797
   635
                        {
Thomas@1797
   636
                            enableFormRegion = omi.GetIsDecryptAlwaysEnabled();
Thomas@1797
   637
                        }
Thomas@1797
   638
                        else
Thomas@1797
   639
                        {
Thomas@1797
   640
                            enableFormRegion = omi.GetForceProtection();
Thomas@1797
   641
Thomas@1797
   642
                            if (enableFormRegion == false)
Thomas@1797
   643
                            {
Thomas@1797
   644
                                this.cryptableMailItem.OriginallyEncryptedStatusUpdated += CryptableMailItem_OriginallyEncryptedStatusUpdated;
Thomas@1797
   645
                            }
Thomas@1797
   646
                        }
Thomas@1797
   647
                    }
Thomas@1797
   648
                }
Thomas@1797
   649
Thomas@1797
   650
                // Update pEp enabled status
Thomas@1797
   651
                this.SetIsEnabled(enableFormRegion);
Thomas@1797
   652
Thomas@1797
   653
                if (this.isEnabled)
Thomas@1797
   654
                {
Thomas@1797
   655
                    // Call the timer tick method manually to refresh data with no delay
Thomas@1797
   656
                    this.TimerRefresh_Tick(null, new EventArgs());
Thomas@1797
   657
                }
Dean@1390
   658
            }
Dean@159
   659
        }
Dean@159
   660
Dean@159
   661
        /// <summary>
Dean@159
   662
        /// Event handler for when the form region is closed.
Dean@159
   663
        /// </summary>
Thomas@1795
   664
        private void FormRegionPrivacyStatus_FormRegionClosed(object sender, EventArgs e)
Dean@159
   665
        {
Dean@1390
   666
            // Disconnect cryptable mail item
Dean@1390
   667
            if (this.cryptableMailItem != null)
Dean@179
   668
            {
Dean@179
   669
                try
Dean@179
   670
                {
Dean@1390
   671
                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@1390
   672
                    this.cryptableMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
Dean@1390
   673
                    this.cryptableMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
Dean@1390
   674
                    this.cryptableMailItem.Open -= MailItem_Open;
Dean@1390
   675
                    this.cryptableMailItem.Send -= MailItem_Send;
Dean@179
   676
                }
Dean@179
   677
                catch { }
Dean@1390
   678
Dean@1390
   679
                this.cryptableMailItem.Dispose();
Dean@1390
   680
                this.cryptableMailItem = null;
Dean@179
   681
            }
Dean@179
   682
Dean@1390
   683
            // Disconnect other
Dean@1390
   684
            this.SetIsEnabled(false);
Dean@682
   685
Dean@179
   686
            return;
Dean@179
   687
        }
Dean@179
   688
Dean@179
   689
        /// <summary>
Dean@1384
   690
        /// Event handler for when the form region is expanded or collapsed.
Dean@1384
   691
        /// </summary>
Dean@1384
   692
        private void FormRegionPrivacyStatus_Expanded(object sender, EventArgs e)
Dean@1384
   693
        {
Dean@1385
   694
            /* This Outlook form region has a bug where clicking the '+' button to expand will also
Dean@1385
   695
             * raise a click event on the privacy status button. Basically, Outlook would fire the click event 
Dean@1385
   696
             * (FormControlPrivacyStatusChild_PrivacyViewClick) immediately after the region is expanded even though at 
Dean@1385
   697
             * the time it was clicked it was collapsed and the click already captured by the expander '+' button.
Dean@1385
   698
             * This code here works around that issue by disabling the manager form when the form region is collapsed.
Dean@1385
   699
             * Since the click event occurs BEFORE the expanded event, this will disable opening the manage privacy status
Dean@1385
   700
             * form in this situation.
Dean@1385
   701
             */
Dean@1390
   702
            this.isManagerFormEnabled = this.OutlookFormRegion.IsExpanded;
Dean@1384
   703
Dean@1384
   704
            return;
Dean@1384
   705
        }
Dean@1384
   706
Dean@1384
   707
        /// <summary>
Dean@1384
   708
        /// Event handler called after the monitor timer has elapsed.
Dean@1384
   709
        /// This should be used only for quick polling of changes in Outlook or the UI state.
Dean@1384
   710
        /// </summary>
Dean@1384
   711
        private void TimerMonitor_Tick(object sender, EventArgs e)
Dean@1384
   712
        {
Dean@1384
   713
            bool isExpandedCurrent;
Dean@1384
   714
Dean@1384
   715
            // Check for IsExpanded changes
Dean@1384
   716
            isExpandedCurrent = this.OutlookFormRegion.IsExpanded;
Dean@1384
   717
            if ((this.isExpandedPrevious == null) ||
Dean@1384
   718
                ((bool)this.isExpandedPrevious != isExpandedCurrent))
Dean@1384
   719
            {
Dean@1384
   720
                this.Expanded?.Invoke(this, new EventArgs());
Dean@1384
   721
            }
Dean@1384
   722
            this.isExpandedPrevious = isExpandedCurrent;
Dean@1384
   723
Dean@1384
   724
            return;
Dean@1384
   725
        }
Dean@1384
   726
Dean@1384
   727
        /// <summary>
Dean@179
   728
        /// Event handler called after the refresh timer has elapsed.
Dean@179
   729
        /// </summary>
Dean@179
   730
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
   731
        {
Dean@1402
   732
            bool tryAgain = false;
Thomas@1547
   733
#pragma warning disable 219
Dean@1402
   734
            bool markForDownload = false;
Thomas@1547
   735
#pragma warning restore 219
Dean@179
   736
            this.TimerRefresh.Enabled = false; // Only once
Dean@1402
   737
            Outlook.OlDownloadState dlState;
markus@201
   738
Dean@709
   739
            /* The Refresh/UI_Update process is a little more complicated here than other forms.
Dean@709
   740
             * There are the following components:
Dean@709
   741
             *   1. TimerRefresh_Tick
Dean@709
   742
             *        This is the main timer tick event handler called any time
Dean@1130
   743
             *        a refresh was requested (RequestRatingAndUIUpdate) and hasn't been run yet. 
Dean@1001
   744
             *        A refresh is requested either at initialization or when a property changes
Dean@709
   745
             *        (such as MailItem_PropertyChanged). It is on a timer as many 
Dean@709
   746
             *        property change events could occur rapidy, but only one refresh should
Dean@709
   747
             *        occur for performance reasons.
Dean@709
   748
             * 
Dean@1130
   749
             *   2. ImmediateRatingAndUIUpdate
Dean@1307
   750
             *        This will re-calculate the mail item's rating.
Dean@1307
   751
             *        This internally just calls CryptableMailItem.StartProcessing.
Dean@709
   752
             * 
Dean@1130
   753
             *   3. MailItem_ProcessingCompleted
Dean@1307
   754
             *        When processing of the mail item is complete, this even handler will be called.
Dean@1130
   755
             *        This will update the UI with the latest rating then call StartGetMirror.
Dean@709
   756
             *        The CopyStateToUI method is used which means any open privacy status form will also
Dean@709
   757
             *        be updated.
Dean@709
   758
             * 
Dean@709
   759
             *   4. MailItem_GetMirrorComplete
Dean@1402
   760
             *        This is the final step in updating the UI, after a mirror is located, it's contents
Dean@1307
   761
             *        will be shown in the unencrypted preview.
Dean@709
   762
             * 
Dean@709
   763
             * The general calling sequence is as shown above 1->4 with each component calling the next.
Dean@709
   764
             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
Dean@709
   765
             */
Dean@709
   766
Dean@179
   767
            // Ensure the tick method is not called more than once
Dean@1390
   768
            if ((this.isEnabled) &&
Dean@1402
   769
                (refreshOngoing == false))
Dean@179
   770
            {
Dean@1402
   771
                this.refreshOngoing = true;
Dean@1402
   772
Thomas@1419
   773
                if ((this.cryptableMailItem != null) &&
Thomas@1419
   774
                    (this.cryptableMailItem.IsBeingProcessed == false))
Dean@1402
   775
                {
Dean@1402
   776
                    // Attempt to get the download state
Dean@1402
   777
                    try
Dean@1402
   778
                    {
Dean@1402
   779
                        dlState = this.cryptableMailItem.DownloadState;
Dean@1402
   780
                    }
Dean@1402
   781
                    catch (Exception ex)
Dean@1402
   782
                    {
Dean@1402
   783
                        Log.Warning("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
Dean@1402
   784
Dean@1402
   785
                        // Assume everything is downloaded, but try to download again as well
Dean@1402
   786
                        dlState = Outlook.OlDownloadState.olFullItem;
Dean@1402
   787
                        markForDownload = true;
Dean@1402
   788
                    }
Dean@1402
   789
Dean@1402
   790
                    if (dlState == Outlook.OlDownloadState.olFullItem)
Dean@1402
   791
                    {
Dean@1402
   792
                        this.ImmediateRatingAndUIUpdate();
Dean@1402
   793
                    }
Dean@1402
   794
                    else
Dean@1402
   795
                    {
Dean@1402
   796
                        markForDownload = true;
Dean@1402
   797
                    }
Dean@1402
   798
Thomas@1529
   799
                    /* 12/16/2016: It could be verified via testing that setting the MarkForDownload property
Thomas@1529
   800
                     * can be a way to crash Outlook under certain circumstances (e.g. with IMAP on Outlook 2010 or on Windows 7). 
Thomas@1529
   801
                     * This then is not caught by a try/catch block and therefore has to be considered an Outlook bug.
Thomas@1529
   802
                     * It seems that in newer versions of Outlook/Windows, they fixed it, causing exceptions, if at all.
Thomas@1529
   803
                     * For now, the following is commented out to prevent a crash. If at any point we see that header-only
Thomas@1529
   804
                     * messages cause bigger issues, this decision has to be reevaluated.
Thomas@1529
   805
                     */
Thomas@1529
   806
                    //if (markForDownload)
Thomas@1529
   807
                    //{
Thomas@1529
   808
                    //    // Try to mark the message for full download
Thomas@1529
   809
                    //    try
Thomas@1529
   810
                    //    {
Thomas@1529
   811
                    //        this.cryptableMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Thomas@1529
   812
                    //        tryAgain = true;
Thomas@1529
   813
                    //    }
Thomas@1529
   814
                    //    catch (Exception ex)
Thomas@1529
   815
                    //    {
Thomas@1529
   816
                    //        Log.Warning("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
Thomas@1529
   817
                    //    }
Thomas@1529
   818
                    //}
Dean@1402
   819
                }
Thomas@1419
   820
                else
Thomas@1419
   821
                {
Thomas@1419
   822
                    repeatProcessing = true;
Thomas@1419
   823
                }
Dean@1402
   824
Dean@1402
   825
                // Set the timer to refresh again later automatically
Dean@1402
   826
                if (tryAgain)
Dean@1402
   827
                {
Dean@1402
   828
                    this.TimerRefresh.Interval = 100;
Dean@1402
   829
                    this.TimerRefresh.Enabled = true;
Dean@1402
   830
                }
Dean@1402
   831
Dean@1402
   832
                this.refreshOngoing = false;
Dean@179
   833
            }
Dean@175
   834
Dean@159
   835
            return;
Dean@159
   836
        }
Dean@159
   837
Dean@169
   838
        /// <summary>
Dean@1096
   839
        /// Event handler for when the processing is completed in the associated mail item.
Dean@709
   840
        /// This will then update the form region UI and the privacy status window as needed.
Dean@680
   841
        /// </summary>
Dean@1461
   842
        private void MailItem_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
Dean@680
   843
        {
Dean@1249
   844
            Log.Verbose("MailItem_ProcessingComplete: Decryption completed.");
Dean@740
   845
Dean@680
   846
            try
Dean@680
   847
            {
Dean@680
   848
                // Marshal code back to UI thread as necessary
Dean@680
   849
                this.Invoke(new Action(() =>
Dean@680
   850
                    {
Dean@1390
   851
                        if (this.isEnabled)
Dean@1390
   852
                        {
Thomas@1505
   853
                            try
Thomas@1505
   854
                            {
Thomas@1505
   855
                                this.FormControlPrivacyStatusChild.DisplayState.Rating = e.ProcessedRating;
Thomas@1505
   856
                                RibbonCustomizations.Invalidate();
Thomas@1583
   857
                                this.UpdateManagePrivacyStatusForm(); // Only update the rating
Thomas@1505
   858
                            }
Thomas@1505
   859
                            catch (Exception ex)
Thomas@1505
   860
                            {
Thomas@1505
   861
                                Log.Verbose("MailItem_ProcessingComplete: Error. " + ex.ToString());
Thomas@1505
   862
                            }
Dean@709
   863
Thomas@1547
   864
                            if (repeatProcessing &&
Thomas@1547
   865
                                (repeatCounter++ < maxRepeatCount))
Dean@747
   866
                            {
Thomas@1419
   867
                                repeatProcessing = false;
Thomas@1419
   868
                                this.RequestRatingAndUIUpdate();
Thomas@1419
   869
                            }
Thomas@1419
   870
                            else
Thomas@1419
   871
                            {
Thomas@1470
   872
                                /* Check if the mail item is in Outbox and update the inspector window if possible.
Thomas@1470
   873
                                 * This is the case when a submitted, but not yet sent email is opened again when working 
Thomas@1470
   874
                                 * offline or without internet connection. Without this update, Outlook removes the message class 
Thomas@1470
   875
                                 * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
Thomas@1470
   876
                                 * opened again (i.e. is lost).
Thomas@1458
   877
                                 */
Thomas@1458
   878
                                try
Thomas@1458
   879
                                {
Thomas@1458
   880
                                    Outlook.MailItem omi = this.OutlookItem as Outlook.MailItem;
Thomas@1458
   881
Thomas@1458
   882
                                    if ((omi != null) &&
Thomas@1458
   883
                                        (omi.GetIsSubmitted()) &&
Thomas@1458
   884
                                        (omi.GetIsDraft()))
Thomas@1458
   885
                                    {
Thomas@1458
   886
                                        var insp = this.OutlookFormRegion.Inspector;
Thomas@1458
   887
Thomas@1458
   888
                                        if (insp != null)
Thomas@1458
   889
                                        {
Thomas@1547
   890
                                            UpdateInspector();
Thomas@1458
   891
                                        }
Thomas@1458
   892
                                    }
Thomas@1458
   893
                                }
Thomas@1458
   894
                                catch (Exception ex)
Thomas@1458
   895
                                {
Thomas@1505
   896
                                    Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
Thomas@1458
   897
                                }
Thomas@1458
   898
Thomas@1419
   899
                                /* Create the unencrypted preview if the mail item is encrypted and
Thomas@1419
   900
                                 * it is in an encrypted (untrusted) store
Thomas@1419
   901
                                 * 
Thomas@1419
   902
                                 * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Thomas@1419
   903
                                 * it also is initialized after FormRegionPreviewUnencrypted.
Thomas@1419
   904
                                 */
Thomas@1419
   905
                                try
Dean@1390
   906
                                {
Thomas@1419
   907
                                    if (this.cryptableMailItem.IsSecurelyStored)
Thomas@1419
   908
                                    {
Thomas@1419
   909
                                        Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
Thomas@1419
   910
                                        this.cryptableMailItem.StartGetMirror();
Thomas@1419
   911
                                    }
Thomas@1419
   912
                                    else
Thomas@1419
   913
                                    {
Dean@1483
   914
                                        this.SetNote();
Thomas@1419
   915
                                    }
Dean@1390
   916
                                }
Thomas@1419
   917
                                catch (Exception ex)
Dean@1390
   918
                                {
Thomas@1419
   919
                                    // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
Thomas@1419
   920
                                    // While rare, just log the issue and stop the process
Thomas@1419
   921
                                    Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
Dean@1390
   922
                                }
Dean@747
   923
                            }
Dean@709
   924
                        }
Dean@680
   925
                    }));
Dean@680
   926
            }
Dean@680
   927
            catch (Exception ex)
Dean@680
   928
            {
Dean@1249
   929
                Log.Error("MailItem_ProcessingComplete: Error setting UI state, " + ex.ToString());
Dean@680
   930
            }
Dean@680
   931
Thomas@1505
   932
            this.processingOngoing = false;
Thomas@1505
   933
Dean@680
   934
            return;
Dean@680
   935
        }
Dean@680
   936
Dean@680
   937
        /// <summary>
Dean@709
   938
        /// Event handler for when the get mirror locating process is complete for the associated mail item.
Dean@709
   939
        /// This will then update the unencrypted preview in the UI.
Dean@709
   940
        /// </summary>
Dean@1096
   941
        private void MailItem_GetMirrorCompleted(object sender, CryptableMailItem.GetMirrorCompletedEventArgs e)
Dean@709
   942
        {
Dean@709
   943
            try
Dean@709
   944
            {
Dean@709
   945
                // Marshal code back to UI thread as necessary
Dean@709
   946
                this.Invoke(new Action(() =>
Dean@709
   947
                    {
Dean@1390
   948
                        if (this.isEnabled)
Dean@1390
   949
                        {
Dean@1390
   950
                            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
   951
Dean@1390
   952
                            if ((e.Mirror == null) &&
Dean@1390
   953
                                (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.Failure))
Dean@910
   954
                            {
Dean@1483
   955
                                this.SetNote(Properties.Resources.Message_OpenError);
Dean@1390
   956
                                Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, failure during decryption.");
Dean@910
   957
                            }
Dean@1390
   958
                            else if ((e.Mirror == null) &&
Dean@1390
   959
                                     (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
Dean@1390
   960
                            {
Dean@1483
   961
                                this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
Dean@1390
   962
                                Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
Dean@1390
   963
                            }
Dean@1390
   964
                            else
Dean@1390
   965
                            {
Dean@1476
   966
                                if (formRegions != null)
Dean@1390
   967
                                {
Dean@1476
   968
                                    if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@1476
   969
                                        (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@1476
   970
                                    {
Dean@1483
   971
                                        formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
Dean@1476
   972
                                    }
Dean@1476
   973
Dean@1390
   974
                                    Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
Dean@1390
   975
                                }
Dean@1390
   976
                            }
Dean@758
   977
Dean@1390
   978
                            // Display the mirror if necessary
Dean@1390
   979
                            if ((this.cryptableMailItem != null) &&
Dean@1390
   980
                                (this.displayMirrorRequested))
Dean@1390
   981
                            {
Dean@1390
   982
                                this.cryptableMailItem.DisplayMirror();
Dean@1390
   983
                                this.displayMirrorRequested = false;
Dean@1390
   984
                            }
Dean@758
   985
                        }
Dean@709
   986
                    }));
Dean@709
   987
            }
Dean@709
   988
            catch (Exception ex)
Dean@709
   989
            {
Dean@1249
   990
                Log.Error("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
Dean@709
   991
            }
Dean@709
   992
Dean@709
   993
            return;
Dean@709
   994
        }
Dean@709
   995
Dean@709
   996
        /// <summary>
Thomas@1797
   997
        /// Event handler for the mail item originally encrypted status updated.
Thomas@1797
   998
        /// This event is fired after the status has been updated with parent information following a
Dean@807
   999
        /// forward or reply mail item event (on a different, likely parent, mail item).
Dean@807
  1000
        /// </summary>
Thomas@1797
  1001
        private void CryptableMailItem_OriginallyEncryptedStatusUpdated(object sender, EventArgs e)
Dean@807
  1002
        {
Thomas@1797
  1003
            // Process the mail item now that the cache is updated
Thomas@1797
  1004
            if (this.isEnabled == false &&
Thomas@1797
  1005
                this.cryptableMailItem.IsOriginallyEncrypted)
Dean@1390
  1006
            {
Thomas@1797
  1007
                this.isEnabled = true;
Thomas@1797
  1008
                this.TimerRefresh_Tick(null, new EventArgs());
Dean@1390
  1009
            }
Dean@807
  1010
Dean@807
  1011
            return;
Dean@807
  1012
        }
Dean@807
  1013
Dean@807
  1014
        /// <summary>
Dean@169
  1015
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
  1016
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
  1017
        /// </summary>
Dean@169
  1018
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
  1019
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
  1020
        /// and the inspector is not displayed.</param>
Dean@169
  1021
        private void MailItem_Open(ref bool cancel)
Dean@159
  1022
        {
Dean@758
  1023
            bool result;
Dean@758
  1024
Thomas@1797
  1025
            if ((this.isEnabled)
Thomas@1797
  1026
                && (this.cryptableMailItem != null)
markus@1582
  1027
                && (this.cryptableMailItem.IsSecurelyStored)
markus@1582
  1028
                && (this.cryptableMailItem.IsIncoming || this.cryptableMailItem.IsOriginallyEncrypted || !this.cryptableMailItem.IsDraft))
Dean@169
  1029
            {
Dean@758
  1030
                // Try to open the mirror
Dean@1390
  1031
                result = this.cryptableMailItem.DisplayMirror();
Dean@758
  1032
Dean@758
  1033
                if (result == false)
Dean@758
  1034
                {
Dean@758
  1035
                    // Set flag to open after decryption/mirror location
Dean@758
  1036
                    this.displayMirrorRequested = true;
Dean@758
  1037
                }
Dean@758
  1038
Dean@758
  1039
                // Always cancel opening the original
Dean@169
  1040
                cancel = true;
Dean@169
  1041
            }
Dean@169
  1042
Dean@169
  1043
            return;
Dean@159
  1044
        }
Dean@159
  1045
Dean@169
  1046
        /// <summary>
Dean@682
  1047
        /// Event handler for when a mail item is sent.
Dean@682
  1048
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
Dean@682
  1049
        /// </summary>
Dean@682
  1050
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@682
  1051
        /// If the event procedure sets this argument to True, the send operation is not completed 
Dean@682
  1052
        /// and the inspector is left open.</param>
Dean@682
  1053
        private void MailItem_Send(ref bool cancel)
Dean@682
  1054
        {
Dean@807
  1055
            DialogResult result;
Dean@807
  1056
Dean@1390
  1057
            if (this.isEnabled)
Dean@807
  1058
            {
Thomas@1505
  1059
                if ((this.cryptableMailItem.IsBeingProcessed) ||
Thomas@1505
  1060
                    (this.processingOngoing))
Thomas@1505
  1061
                {
Thomas@1505
  1062
                    Log.Verbose("MailItem_Send cancelled. Mail item still being processed.");
Thomas@1505
  1063
                    cancel = true;
Thomas@1505
  1064
                    return;
Thomas@1505
  1065
                }
Thomas@1505
  1066
Dean@1390
  1067
                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
Dean@1390
  1068
                    (this.cryptableMailItem.IsOriginallyEncrypted) &&
Dean@1390
  1069
                    (this.FormControlPrivacyStatusChild.DisplayState.Rating < pEpRating.pEpRatingUnreliable))
Dean@1390
  1070
                {
Thomas@1318
  1071
Thomas@1318
  1072
#if READER_RELEASE_MODE
Dean@1390
  1073
                    FormReaderSplash warningMessage = new FormReaderSplash(true);
Dean@1390
  1074
                    result = warningMessage.ShowDialog();
Thomas@1318
  1075
Dean@1390
  1076
                    if (result != DialogResult.OK)
Dean@1390
  1077
                    {
Dean@1390
  1078
                        // Cancel sending
Dean@1390
  1079
                        cancel = true;
Dean@1390
  1080
                    }
Dean@1390
  1081
#else
Dean@1390
  1082
                    result = System.Windows.Forms.MessageBox.Show(this.ParentForm,
Dean@1390
  1083
                                                                  pEp.Properties.Resources.Message_WarningSecurityLoss,
Dean@1390
  1084
                                                                  pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@1390
  1085
                                                                  MessageBoxButtons.YesNo,
Dean@1390
  1086
                                                                  MessageBoxIcon.Warning);
Dean@1390
  1087
Dean@1390
  1088
                    if (result == DialogResult.No)
Dean@1390
  1089
                    {
Dean@1390
  1090
                        // Cancel sending
Dean@1390
  1091
                        cancel = true;
Dean@1390
  1092
                    }
Dean@1390
  1093
#endif
Dean@1390
  1094
                }
Dean@1390
  1095
Dean@1390
  1096
                // Stop and disconnect the refresh timer
Dean@1390
  1097
                // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
Dean@1390
  1098
                if (cancel == false)
Thomas@1318
  1099
                {
Dean@1390
  1100
                    this.TimerRefresh.Stop();
Dean@1390
  1101
                    this.TimerRefresh.Enabled = false;
Dean@1390
  1102
                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
Thomas@1318
  1103
                }
Dean@807
  1104
            }
Dean@682
  1105
Dean@682
  1106
            return;
Dean@682
  1107
        }
Dean@682
  1108
Dean@682
  1109
        /// <summary>
Dean@169
  1110
        /// Event handler for when a mail item property is changed.
Dean@169
  1111
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
  1112
        /// </summary>
Dean@169
  1113
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@445
  1114
        private void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Dean@159
  1115
        {
Dean@1349
  1116
            switch (e.PropertyName.ToUpperInvariant())
Dean@159
  1117
            {
Dean@1390
  1118
                case "BCC":
Dean@1390
  1119
                    {
Dean@1390
  1120
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Dean@1390
  1121
                        break;
Dean@1390
  1122
                    }
Dean@1390
  1123
                case "CC":
Dean@1390
  1124
                    {
Dean@1390
  1125
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Dean@1390
  1126
                        break;
Dean@1390
  1127
                    }
Dean@1390
  1128
                case "SENTONBEHALFOFNAME":
Dean@1390
  1129
                    {
Dean@1390
  1130
                        // Always fired with "SENDUSINGACCOUNT" so is ignored
Dean@1390
  1131
                        break;
Dean@1390
  1132
                    }
Dean@1390
  1133
                case "SENDUSINGACCOUNT":
Dean@1390
  1134
                    {
Dean@1390
  1135
                        // Update pEp enabled status
Thomas@1795
  1136
                        this.SetIsEnabled((this.OutlookItem as Outlook.MailItem)?.GetEnableFormRegion() ?? false);
Dean@1390
  1137
Dean@1390
  1138
                        // Refresh the UI
Dean@1390
  1139
                        this.ResolveAllRecipients();
Dean@1390
  1140
                        this.RequestRatingAndUIUpdate();
Dean@1390
  1141
                        RibbonCustomizations.Invalidate();
Dean@1390
  1142
Dean@1390
  1143
                        break;
Dean@1390
  1144
                    }
Dean@179
  1145
                case "TO":
Dean@1390
  1146
                    {
Dean@1390
  1147
                        if (this.isEnabled)
Dean@1390
  1148
                        {
Dean@1390
  1149
                            this.RequestRatingAndUIUpdate();
Dean@1390
  1150
                        }
Dean@1390
  1151
                        break;
Dean@1390
  1152
                    }
Dean@159
  1153
            }
Dean@169
  1154
Dean@169
  1155
            return;
Dean@159
  1156
        }
Dean@159
  1157
Dean@179
  1158
        /// <summary>
Thomas@1587
  1159
        /// Event handler for when a handshake dialog was updated.
Thomas@1583
  1160
        /// </summary>
Thomas@1587
  1161
        private void HandshakeDialog_Updated(object sender, EventArgs e)
Thomas@1583
  1162
        {
Thomas@1633
  1163
            // Update current form region
Thomas@1587
  1164
            this.RequestRatingAndUIUpdate();
Thomas@1633
  1165
Thomas@1633
  1166
            /* If a handshake is performed while having the same message open both in an inspector
Thomas@1633
  1167
             * and an explorer window, the one that didn't trigger the handshake won't get updated
Thomas@1633
  1168
             * automatically. Therefore, after a handshake, we perform a search for all form regions
Thomas@1633
  1169
             * of type FormRegionPrivacyStatus and update the associated cryptable mail items.
Thomas@1633
  1170
             */
Thomas@1633
  1171
            try
Thomas@1633
  1172
            {
Thomas@1633
  1173
                // Get all form regions
Thomas@1633
  1174
                var formRegions = Globals.FormRegions;
Thomas@1633
  1175
Thomas@1633
  1176
                foreach (var formRegion in formRegions)
Thomas@1633
  1177
                {
Thomas@1633
  1178
                    var fr = formRegion as FormRegionPrivacyStatus;
Thomas@1633
  1179
Thomas@1633
  1180
                    if (fr != null)
Thomas@1633
  1181
                    {
Thomas@1633
  1182
                        // Only process the ones that differ from the one that triggered the update.
Thomas@1633
  1183
                        if (fr.cryptableMailItem.Equals(this.cryptableMailItem) == false)
Thomas@1633
  1184
                        {
Thomas@1633
  1185
                            fr.cryptableMailItem.StartProcessing();
Thomas@1633
  1186
                        }
Thomas@1633
  1187
                    }
Thomas@1633
  1188
                }
Thomas@1633
  1189
            }
Thomas@1633
  1190
            catch (Exception ex)
Thomas@1633
  1191
            {
Thomas@1633
  1192
                Log.Error("HandshakeDialog_Updated: Error updating form regions. " + ex.Message);
Thomas@1633
  1193
            }
Thomas@1587
  1194
        }
Thomas@1587
  1195
Thomas@1587
  1196
        /// <summary>
Thomas@1587
  1197
        /// Event handler for when a handshake dialog was closed.
Thomas@1587
  1198
        /// </summary>
Thomas@1587
  1199
        private void HandshakeDialog_Closed(object sender, EventArgs e)
Thomas@1587
  1200
        {
Thomas@1587
  1201
            if (this.handshakeDialog != null)
Thomas@1587
  1202
            {
Thomas@1587
  1203
                this.handshakeDialog.OnUpdateStatus -= HandshakeDialog_Updated;
Thomas@1587
  1204
                this.handshakeDialog.Closed -= HandshakeDialog_Closed;
Thomas@1587
  1205
                this.handshakeDialog = null;
Thomas@1587
  1206
            }
Thomas@1583
  1207
        }
Thomas@1583
  1208
Thomas@1583
  1209
        /// <summary>
Dean@1021
  1210
        /// Event handler for when the manager form is closed.
Dean@1021
  1211
        /// </summary>
Dean@1021
  1212
        private void ManagerForm_FormClosed(object sender, FormClosedEventArgs e)
Dean@1021
  1213
        {
Dean@1021
  1214
            // Remove the reference held in the FormRegionPrivacyStatus so it stops getting updated
Dean@1021
  1215
            if (this.managerForm != null)
Dean@1021
  1216
            {
Dean@1021
  1217
                this.managerForm.FormClosed -= ManagerForm_FormClosed;
Dean@1021
  1218
                this.managerForm = null;
Dean@1021
  1219
            }
Dean@1021
  1220
Dean@1021
  1221
            return;
Dean@1021
  1222
        }
Dean@1021
  1223
Dean@1021
  1224
        /// <summary>
Dean@859
  1225
        /// Event handler for when the pEp website hyperlink is clicked.
Dean@859
  1226
        /// </summary>
Dean@859
  1227
        private void LinkLabelUpgrade_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
Dean@859
  1228
        {
Dean@966
  1229
            try
Dean@966
  1230
            {
Dean@1007
  1231
                Process.Start(Globals.PEP_WEBSITE_UPGRADE_LINK);
Dean@966
  1232
            }
Dean@966
  1233
            catch (Exception ex)
Dean@966
  1234
            {
Dean@1249
  1235
                Log.Error("LinkLabelUpgrade_LinkClicked: Unable to open website link, " + ex.ToString());
Dean@966
  1236
            }
Dean@966
  1237
Dean@859
  1238
            return;
Dean@859
  1239
        }
Dean@1047
  1240
Dean@1047
  1241
        /// <summary>
Dean@1086
  1242
        /// Event handler for when the privacy view button is clicked within the form control.
Dean@1047
  1243
        /// </summary>
Dean@1086
  1244
        private void FormControlPrivacyStatusChild_PrivacyViewClick(object sender, System.Windows.RoutedEventArgs e)
Dean@1047
  1245
        {
Dean@1390
  1246
            if (this.isManagerFormEnabled)
Dean@1384
  1247
            {
Dean@1384
  1248
                this.RequestRatingAndUIUpdate();
Dean@1384
  1249
                this.BuildAndShowManager();
Dean@1384
  1250
            }
Dean@1384
  1251
Dean@1047
  1252
            return;
Dean@1047
  1253
        }
vb@133
  1254
    }
vb@133
  1255
}