UI/FormRegionPrivacyStatus.cs
author Dean Looyengoed
Mon, 13 Jun 2016 23:28:34 +0200
changeset 987 631109fd788e
parent 985 4697e8949bbe
child 988 00729aeeec59
permissions -rw-r--r--
Always get the FormRegions from the ActiveWindow instead of only the Explorer.
This supports both the inspector and explorer correctly.
Dean@159
     1
´╗┐using pEpCOMServerAdapterLib;
Dean@159
     2
using System;
vb@133
     3
using System.Collections.Generic;
Dean@445
     4
using System.ComponentModel;
Dean@859
     5
using System.Diagnostics;
Dean@438
     6
using System.Drawing;
Dean@854
     7
using System.Globalization;
Dean@159
     8
using System.Runtime.InteropServices;
vb@133
     9
using System.Windows.Forms;
vb@133
    10
using Outlook = Microsoft.Office.Interop.Outlook;
vb@133
    11
vb@133
    12
namespace pEp
vb@133
    13
{
Dean@159
    14
    /// <summary>
Dean@312
    15
    /// Partial class for the privacy status form region that is displayed below every outlook message.
Dean@159
    16
    /// </summary>
Dean@910
    17
    internal partial class FormRegionPrivacyStatus
vb@133
    18
    {
vb@133
    19
        #region Form Region Factory
vb@133
    20
vb@133
    21
        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
Dean@312
    22
        [Microsoft.Office.Tools.Outlook.FormRegionName("pEp.FormRegionPrivacyStatus")]
Dean@312
    23
        public partial class FormRegionPrivacyStatusFactory
vb@133
    24
        {
vb@133
    25
            // Occurs before the form region is initialized.
vb@133
    26
            // To prevent the form region from appearing, set e.Cancel to true.
vb@133
    27
            // Use e.OutlookItem to get a reference to the current Outlook item.
Dean@312
    28
            private void FormRegionPrivacyStatus_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
vb@133
    29
            {
Dean@985
    30
                //WindowFormRegionCollection formRegions;
Dean@327
    31
Dean@327
    32
                /* There is a Microsoft bug at least in Outlook 2013 and Windows 8.1
Dean@327
    33
                 * This bug causes multiple PrivacyStatus form regions to appear stacked on top of each other.
Dean@327
    34
                 * To trigger this bug, on an unencrypted server, click reply to compose an in-line response.
Dean@327
    35
                 * Then click to another tab such as People or Tasks. Then click back on the mail tab to view 
Dean@327
    36
                 * the original email again. Two form regions will be visible: 
Dean@327
    37
                 * (1) for the status during the in-line reply and 
Dean@327
    38
                 * (2) for the status of only the received message.
Dean@327
    39
                 * 
Dean@327
    40
                 * To fix this bug, any existing form regions are found and closed when initializing a new privacy status
Dean@327
    41
                 * form region.
Dean@327
    42
                 */
Dean@985
    43
                /*
Dean@327
    44
                try
Dean@327
    45
                {
Dean@987
    46
                    formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@327
    47
                    if (formRegions.FormRegionPrivacyStatus != null)
Dean@327
    48
                    {
Dean@985
    49
                        // Note: there seems to be no way to actually close the form region.
Dean@985
    50
                        // Therefore, this is as close as possible to actually closing it.
Dean@985
    51
                        // The actual form regions will be cleaned up as soon as another email is selected.
Dean@327
    52
                        formRegions.FormRegionPrivacyStatus.OutlookFormRegion.Visible = false;
Dean@327
    53
                    }
Dean@327
    54
                }
Dean@327
    55
                catch { }
Dean@985
    56
                */
Dean@327
    57
                return;
vb@133
    58
            }
vb@133
    59
        }
vb@133
    60
vb@133
    61
        #endregion
vb@133
    62
Dean@159
    63
        /* Notes:
Dean@179
    64
         * 
Dean@159
    65
         * Use this.OutlookItem to get a reference to the current Outlook item.
Dean@159
    66
         * Use this.OutlookFormRegion to get a reference to the form region.
Dean@179
    67
         * 
Dean@179
    68
         * UI State Managment:
Dean@179
    69
         * 
Dean@179
    70
         * The UI state is almost entirely set from the associated mail item data.
Dean@179
    71
         * However, a separate state class is maintained to represent the UI as some separation is needed.
Dean@179
    72
         * This logical separation MUST be maintained throughout the code.
Dean@179
    73
         * Specific cases are noted where possible.
Dean@179
    74
         * 
Dean@356
    75
         * The separate privacy status manager form state is also managed here.
Dean@259
    76
         * 
Dean@159
    77
         */
Dean@159
    78
Dean@758
    79
        private CryptableMailItem       associatedMailItem     = null;
Dean@758
    80
        private bool                    eventsAreConnected     = false;
Dean@758
    81
        private bool                    initialized            = false;
Dean@758
    82
        private FormManagePrivacyStatus managerForm            = null;
Dean@758
    83
        private bool                    refreshOngoing         = false;
Dean@758
    84
        private bool                    displayMirrorRequested = false;
Dean@259
    85
Dean@250
    86
        // Data or controls not stored in the UI
Dean@179
    87
        private _pEp_color stateUIColorRating; // WARNING: Do NOT use this directly
vb@133
    88
Dean@159
    89
        /**************************************************************
Dean@159
    90
         * 
Dean@159
    91
         * Methods
Dean@159
    92
         * 
Dean@159
    93
         *************************************************************/
Dean@159
    94
Dean@171
    95
        /// <summary>
Dean@438
    96
        /// Determines if this form region is running in an inspector window.
Dean@438
    97
        /// If not true, it is assumed to be within an explorer window.
Dean@438
    98
        /// </summary>
Dean@438
    99
        /// <returns>True if an inspector window, false if within an explorer.</returns>
Dean@438
   100
        private bool IsWithinInspector()
Dean@438
   101
        {
Dean@438
   102
            bool isWithinInspector = false;
Dean@895
   103
            Outlook.Inspector insp = null;
Dean@438
   104
Dean@438
   105
            try
Dean@438
   106
            {
Dean@895
   107
                /* There are two potential methods to determine if the item is within an inspector.
Dean@895
   108
                 * (1) Use this.OutlookFormRegion.Parent which will contain either the Explorer or an Inspector
Dean@895
   109
                 *     A cast could be tried to an Explorer of this parent and if it fails, it's assumed to be an inspector
Dean@895
   110
                 * (2) Use this.OutlookFormRegion.Inspector which will contain the Inspector if it exists.
Dean@895
   111
                 *     This will fail or return null if this form region is not running within it's own Inspector window.
Dean@895
   112
                 */
Dean@895
   113
                insp = this.OutlookFormRegion.Inspector;
Dean@895
   114
Dean@895
   115
                if (insp != null)
Dean@895
   116
                {
Dean@895
   117
                    isWithinInspector = true;
Dean@895
   118
                }
Dean@438
   119
            }
Dean@438
   120
            catch
Dean@438
   121
            {
Dean@895
   122
                isWithinInspector = false;
Dean@438
   123
            }
Dean@438
   124
            finally
Dean@438
   125
            {
Dean@895
   126
                if (insp != null)
Dean@438
   127
                {
Dean@895
   128
                    Marshal.ReleaseComObject(insp);
Dean@895
   129
                    insp = null;
Dean@438
   130
                }
Dean@438
   131
            }
Dean@438
   132
Dean@438
   133
            return (isWithinInspector);
Dean@438
   134
        }
Dean@438
   135
Dean@438
   136
        /// <summary>
Dean@170
   137
        /// Sets the cryptable mail item associated with this encryption status panel.
Dean@170
   138
        /// The associated mail item can then be accessed through its local variable.
Dean@170
   139
        /// </summary>
Dean@170
   140
        private void SetAssociatedMailItem()
Dean@170
   141
        {
Dean@170
   142
            bool errorOccurred = false;
Dean@170
   143
            Outlook.MailItem omi = null;
Dean@170
   144
Dean@170
   145
            // Null check
Dean@170
   146
            if (!errorOccurred)
Dean@170
   147
            {
Dean@170
   148
                try
Dean@170
   149
                {
Dean@170
   150
                    if (this.OutlookItem == null)
Dean@170
   151
                    {
Dean@170
   152
                        errorOccurred = true;
Dean@170
   153
                    }
Dean@170
   154
                }
Dean@170
   155
                catch (COMException)
Dean@170
   156
                {
Dean@170
   157
                    errorOccurred = true;
Dean@170
   158
                }
Dean@170
   159
            }
Dean@170
   160
Dean@170
   161
            // Attempt to get and cast the outlook mail item
Dean@170
   162
            if (!errorOccurred)
Dean@170
   163
            {
Dean@170
   164
                try
Dean@170
   165
                {
Dean@170
   166
                    omi = (Outlook.MailItem)this.OutlookItem;
Dean@170
   167
                }
Dean@170
   168
                catch
Dean@170
   169
                {
Dean@170
   170
                    errorOccurred = true;
Dean@170
   171
                }
Dean@170
   172
            }
Dean@170
   173
Dean@170
   174
            // Finally set the associated mail item
Dean@170
   175
            if ((errorOccurred) ||
Dean@170
   176
                (omi == null))
Dean@170
   177
            {
Dean@170
   178
                this.associatedMailItem = null;
Dean@170
   179
            }
Dean@170
   180
            else
Dean@170
   181
            {
Dean@170
   182
                // Check if the associated mail item has already been set
Dean@170
   183
                if (this.associatedMailItem != null)
Dean@170
   184
                {
Dean@170
   185
                    // Only re-set the mail item if the EntryID has changed
Dean@170
   186
                    if (this.associatedMailItem.EntryID != omi.EntryID)
Dean@170
   187
                    {
Dean@170
   188
                        this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   189
                    }
Dean@170
   190
                }
Dean@170
   191
                else
Dean@170
   192
                {
Dean@170
   193
                    this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   194
                }
Dean@170
   195
            }
Dean@170
   196
Dean@170
   197
            return;
Dean@170
   198
        }
Dean@170
   199
Dean@179
   200
        /// <summary>
Dean@672
   201
        /// Completes the handshake process when the identity of a partner was previously marked as mistrusted.
Dean@281
   202
        /// </summary>
Dean@646
   203
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   204
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@672
   205
        private void DoHandshakeForMistrustedKey(PEPIdentity myself,
Dean@672
   206
                                                 PEPIdentity partner)
Dean@281
   207
        {
Dean@281
   208
            DialogResult result;
Dean@281
   209
Dean@281
   210
            result = MessageBox.Show(this.ParentForm,
Dean@672
   211
                                     pEp.Properties.Resources.Message_WarningMistrustedKey,
Dean@378
   212
                                     pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@423
   213
                                     MessageBoxButtons.YesNo);
Dean@281
   214
Dean@423
   215
            if (result == DialogResult.Yes)
Dean@281
   216
            {
Dean@646
   217
                this.DoHandshake(myself, partner);
Dean@281
   218
            }
Dean@281
   219
Dean@281
   220
            return;
Dean@281
   221
        }
Dean@281
   222
Dean@281
   223
        /// <summary>
Dean@281
   224
        /// Completes the handshake process where the identity of a partner is confirmed.
Dean@179
   225
        /// </summary>
Dean@646
   226
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   227
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@646
   228
        private void DoHandshake(PEPIdentity myself,
Dean@646
   229
                                 PEPIdentity partner)
vb@133
   230
        {
Dean@179
   231
            DialogResult result;
Dean@155
   232
            FormHandshake handshakeDialog;
Dean@155
   233
            FormHandshake.State state = new FormHandshake.State();
markus@201
   234
Dean@860
   235
            Globals.LogVerbose("DoHandshake: Handshake started.");
vb@139
   236
Dean@155
   237
            // Create and show handshake dialog
Dean@914
   238
            state = new FormHandshake.State(myself, partner);
Dean@155
   239
            handshakeDialog = new FormHandshake(state);
Dean@179
   240
            handshakeDialog.StartPosition = FormStartPosition.CenterScreen;
Dean@179
   241
            result = handshakeDialog.ShowDialog(this);
Dean@155
   242
Dean@646
   243
            this.ProcessDoHandshakeResult(result, partner);
Dean@356
   244
Dean@356
   245
            return;
Dean@356
   246
        }
Dean@356
   247
Dean@356
   248
        /// <summary>
Dean@356
   249
        /// Processes the result of the do handshake dialog after a user makes a selection.
Dean@356
   250
        /// </summary>
Dean@356
   251
        /// <param name="result">The result of the handshake dialog selection.</param>
Dean@356
   252
        /// <param name="partner">The identity of the partner to handshake with.</param>
Dean@356
   253
        private void ProcessDoHandshakeResult(DialogResult result,
Dean@384
   254
                                              PEPIdentity partner)
Dean@356
   255
        {
Dean@384
   256
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
vb@133
   257
vb@133
   258
            switch (result)
vb@133
   259
            {
vb@133
   260
                case DialogResult.Yes:
Dean@279
   261
                    {
Dean@672
   262
                        // Check if key was previously mistrusted -- warning to user must be displayed earlier
Dean@672
   263
                        if (identityPartner.comm_type == _pEp_comm_type.pEp_ct_mistrusted)
Dean@281
   264
                        {
Dean@281
   265
                            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@281
   266
                        }
Dean@281
   267
Dean@279
   268
                        identityPartner = ThisAddIn.pEp.trust_personal_key(ref identityPartner);
Dean@279
   269
Dean@279
   270
                        this.UpdateUIFromMailItem();
Dean@279
   271
Dean@279
   272
                        // Update the manager form state
Dean@279
   273
                        if (this.managerForm != null)
Dean@279
   274
                        {
Dean@279
   275
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   276
                        }
Dean@279
   277
Dean@279
   278
                        break;
Dean@279
   279
                    }
vb@133
   280
                case DialogResult.No:
Dean@279
   281
                    {
Dean@279
   282
                        ThisAddIn.pEp.key_compromized(ref identityPartner);
Dean@279
   283
Dean@279
   284
                        this.UpdateUIFromMailItem();
Dean@279
   285
Dean@279
   286
                        // Update the manager form state
Dean@279
   287
                        if (this.managerForm != null)
Dean@279
   288
                        {
Dean@279
   289
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   290
                        }
Dean@279
   291
Dean@279
   292
                        break;
Dean@279
   293
                    }
vb@133
   294
            }
Dean@279
   295
Dean@860
   296
            Globals.LogVerbose("ProcessDoHandshakeResult: Handshake complete.");
Dean@740
   297
Dean@279
   298
            return;
vb@133
   299
        }
vb@133
   300
Dean@179
   301
        /// <summary>
Dean@179
   302
        /// Reverses any past handshake confirmation by unconfirming the given identity partner.
Dean@179
   303
        /// </summary>
Dean@384
   304
        /// <param name="partner">The identity of the partner to unconfirm.</param>
Dean@384
   305
        private void UndoHandshake(PEPIdentity partner)
vb@133
   306
        {
Dean@384
   307
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
Dean@280
   308
            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@279
   309
Dean@179
   310
            this.UpdateUIFromMailItem();
Dean@279
   311
Dean@279
   312
            // Update the manager form state
Dean@279
   313
            if (this.managerForm != null)
Dean@279
   314
            {
Dean@279
   315
                this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   316
            }
Dean@279
   317
Dean@279
   318
            return;
vb@133
   319
        }
vb@133
   320
Dean@161
   321
        /// <summary>
Dean@279
   322
        /// Builds a new manager form state using this encryption state/mail item current state.
Dean@279
   323
        /// </summary>
Dean@279
   324
        /// <returns>A new manager form state.</returns>
Dean@313
   325
        private FormManagePrivacyStatus.State GetManagerState()
Dean@279
   326
        {
Dean@737
   327
            int currIndex = 0;
Dean@527
   328
            bool isMyself;
Dean@364
   329
            string trustwordsShort;
Dean@364
   330
            string trustwordsFull;
Dean@384
   331
            List<PEPIdentity> identities;
Dean@384
   332
            PEPIdentity myIdentity;
Dean@259
   333
            _pEp_color identityPartnerColor;
Dean@259
   334
            SelectionItem item;
Dean@312
   335
            PrivacyState state = this.CopyUIToState();
Dean@313
   336
            FormManagePrivacyStatus.State managerState = new FormManagePrivacyStatus.State();
Dean@259
   337
Dean@769
   338
            /* Resolve all recipients -- this ensures the identities list is correctly populated
Dean@769
   339
             *
Dean@769
   340
             * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Dean@769
   341
             * This is because the resolve process can modify the contents of the mail item which triggers an event.
Dean@769
   342
             * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Dean@769
   343
             * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that 
Dean@769
   344
             * cannot be resolved (no address).
Dean@769
   345
             */
Dean@769
   346
            if (this.associatedMailItem != null)
Dean@769
   347
            {
Dean@769
   348
                this.associatedMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@769
   349
                this.associatedMailItem.ResolveAllRecipients();
Dean@769
   350
                this.associatedMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@769
   351
            }
Dean@332
   352
Dean@279
   353
            managerState.VisualState = state.Copy();
Dean@279
   354
            managerState.IsIncoming = this.associatedMailItem.IsIncoming;
Dean@259
   355
Dean@653
   356
            if (managerState.IsIncoming)
Dean@259
   357
            {
Dean@384
   358
                identities = new List<PEPIdentity>();
Dean@259
   359
Dean@259
   360
                // Add only one identity
Dean@638
   361
                if (this.associatedMailItem.From != null)
Dean@638
   362
                {
Dean@764
   363
                    identities.Add(this.associatedMailItem.From);
Dean@638
   364
                }
Dean@259
   365
            }
Dean@259
   366
            else
Dean@259
   367
            {
Dean@395
   368
                identities = this.associatedMailItem.Recipients;
Dean@259
   369
            }
Dean@259
   370
Dean@366
   371
            // Get my identity
Dean@633
   372
            myIdentity = this.associatedMailItem.Myself;
Dean@366
   373
Dean@279
   374
            // Add identities
Dean@394
   375
            identities = PEPIdentity.ToFlatList(identities);
Dean@279
   376
            managerState.Identities.Clear();
Dean@384
   377
            foreach (PEPIdentity ident in identities)
Dean@259
   378
            {
Dean@737
   379
                // Needed so index can be used within anonymous methods without getting into the 'outer variable trap' of currIndex
Dean@737
   380
                int index = currIndex;
Dean@737
   381
Dean@865
   382
                if (ident.IsAddressValid)
Dean@485
   383
                {
Dean@774
   384
                    // Update the partner identity to get a fingerprint, preserve IsForceUnencrypted
Dean@485
   385
                    pEp_identity_s partnerIdentity_s = ThisAddIn.pEp.update_identity(ident.ToCOMType());
Dean@485
   386
                    PEPIdentity partnerIdentity = new PEPIdentity(partnerIdentity_s);
Dean@774
   387
                    partnerIdentity.IsForceUnencrypted = ident.IsForceUnencrypted;
Dean@774
   388
Dean@485
   389
                    identityPartnerColor = ThisAddIn.pEp.identity_color(partnerIdentity_s);
Dean@910
   390
                    isMyself = PEPIdentity.GetIsOwnIdentity(partnerIdentity.Address);
Dean@724
   391
Dean@880
   392
                    // Calculate trustwords
Dean@880
   393
                    Globals.ThisAddIn.CalcTrustwords(myIdentity,
Dean@880
   394
                                                     partnerIdentity,
Dean@880
   395
                                                     out trustwordsShort,
Dean@880
   396
                                                     out trustwordsFull,
Dean@880
   397
                                                     Globals.CULTURE_CODE_DEFAULT);
Dean@880
   398
Dean@485
   399
                    item = new SelectionItem();
Dean@485
   400
                    item.TextLine1 = partnerIdentity.Username;
Dean@485
   401
                    item.TextLine2 = partnerIdentity.Address;
Dean@894
   402
                    item.Tag = (string.IsNullOrWhiteSpace(partnerIdentity.Fingerprint) ? null : trustwordsShort);
Dean@259
   403
Dean@485
   404
                    // Don't show both the user name and address if they are the same
Dean@485
   405
                    if ((item.TextLine1 != null) &&
Dean@485
   406
                        (item.TextLine2 != null) &&
Dean@485
   407
                        (item.TextLine1 == item.TextLine2))
Dean@485
   408
                    {
Dean@485
   409
                        item.IsTwoTextLinesVisible = false;
Dean@485
   410
                    }
Dean@332
   411
Dean@485
   412
                    // Set image
Dean@774
   413
                    if ((partnerIdentity.IsForceUnencryptedBool) &&
Dean@653
   414
                        (managerState.IsIncoming == false))
Dean@485
   415
                    {
Dean@641
   416
                        // Show the force unencrypted image indicating this is set by the user not the engine
Dean@642
   417
                        item.ItemImage = pEp.Properties.Resources.ImageForceUnencOn;
Dean@641
   418
                    }
Dean@641
   419
                    else
Dean@641
   420
                    {
Dean@641
   421
                        switch (PrivacyState.ConvertRatingToPrivacyColor(identityPartnerColor))
Dean@641
   422
                        {
Dean@641
   423
                            case PrivacyState.PrivacyColor.Green:
Dean@641
   424
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusGreen;
Dean@641
   425
                                break;
Dean@641
   426
                            case PrivacyState.PrivacyColor.Yellow:
Dean@641
   427
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusYellow;
Dean@641
   428
                                break;
Dean@641
   429
                            case PrivacyState.PrivacyColor.Red:
Dean@641
   430
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusRed;
Dean@641
   431
                                break;
Dean@641
   432
                            case PrivacyState.PrivacyColor.NoColor:
Dean@641
   433
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusNoColor;
Dean@641
   434
                                break;
Dean@641
   435
                            default:
Dean@641
   436
                                item.ItemImage = null;
Dean@641
   437
                                break;
Dean@641
   438
                        }
Dean@485
   439
                    }
Dean@259
   440
Dean@485
   441
                    // Set button
Dean@653
   442
                    if ((isMyself) ||
Dean@774
   443
                        ((partnerIdentity.IsForceUnencryptedBool) &&
Dean@653
   444
                         (managerState.IsIncoming == false)))
Dean@653
   445
                    {
Dean@653
   446
                        item.IsButtonVisible = false;
Dean@653
   447
                        item.IsExpandable = false;
Dean@653
   448
                    }
Dean@653
   449
                    else
Dean@366
   450
                    {
Dean@485
   451
                        if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   452
                        {
Dean@485
   453
                            // Undo handshake
Dean@485
   454
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_StopTrusting;
Dean@485
   455
                            item.IsButtonVisible = true;
Dean@646
   456
                            item.ButtonOnClick = (x, y) => { this.UndoHandshake(partnerIdentity.Copy()); };
Dean@356
   457
Dean@485
   458
                            item.IsExpandable = false;
Dean@485
   459
                        }
Dean@485
   460
                        else if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_unconfirmed_encryption &&
Dean@485
   461
                                 partnerIdentity.CommunicationType < _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   462
                        {
Dean@485
   463
                            // Do handshake
Dean@737
   464
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@485
   465
                            item.IsButtonVisible = true;
Dean@646
   466
                            item.ButtonOnClick = (x, y) => { this.DoHandshake(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@356
   467
Dean@485
   468
                            item.IsExpandable = true;
Dean@485
   469
                            item.ExpandedText = Properties.Resources.PrivacyStatus_TrustwordDesc + "\n\n" +
Dean@485
   470
                                                trustwordsShort;
Dean@447
   471
Dean@485
   472
                            item.ExpandedButton1Text = Properties.Resources.PrivacyStatus_SelectTrust;
Dean@646
   473
                            item.ExpandedButton1OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.Yes, partnerIdentity.Copy()); };
Dean@485
   474
                            item.ExpandedButton1BackColor = PrivacyState.COLOR_GREEN;
Dean@485
   475
                            item.ExpandedButton1ForeColor = Color.White;
Dean@447
   476
Dean@737
   477
                            item.ExpandedButton2Text = Properties.Resources.PrivacyStatus_SelectCancel;
Dean@737
   478
                            item.ExpandedButton2OnClick = (x, y) =>
Dean@737
   479
                                {
Dean@737
   480
                                    FormManagePrivacyStatus.State activeManagerState;
Dean@737
   481
Dean@737
   482
                                    if (this.managerForm != null)
Dean@737
   483
                                    {
Dean@737
   484
                                        activeManagerState = this.managerForm.CopyUIToState();
Dean@758
   485
Dean@737
   486
                                        if ((index >= 0) &&
Dean@737
   487
                                            (index < activeManagerState.Identities.Count))
Dean@737
   488
                                        {
Dean@737
   489
                                            item = activeManagerState.Identities[index];
Dean@758
   490
                                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@758
   491
                                            item.IsExpanded = false;
Dean@737
   492
                                            item.IsExpandable = false;
Dean@880
   493
Dean@880
   494
                                            this.managerForm.UpdateDisplayedTrustwords();
Dean@737
   495
                                        }
Dean@737
   496
                                    }
Dean@737
   497
                                };
Dean@737
   498
Dean@737
   499
                            item.ExpandedButton3Text = Properties.Resources.PrivacyStatus_SelectMistrust;
Dean@737
   500
                            item.ExpandedButton3OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.No, partnerIdentity.Copy()); };
Dean@737
   501
                            item.ExpandedButton3BackColor = PrivacyState.COLOR_RED;
Dean@737
   502
                            item.ExpandedButton3ForeColor = Color.White;
Dean@485
   503
                        }
Dean@672
   504
                        else if (partnerIdentity.CommunicationType == _pEp_comm_type.pEp_ct_mistrusted)
Dean@485
   505
                        {
Dean@485
   506
                            // Redo handshake with confirmation
Dean@485
   507
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@485
   508
                            item.IsButtonVisible = true;
Dean@672
   509
                            item.ButtonOnClick = (x, y) => { this.DoHandshakeForMistrustedKey(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@641
   510
Dean@641
   511
                            item.IsExpandable = false;
Dean@485
   512
                        }
Dean@485
   513
                        else
Dean@485
   514
                        {
Dean@485
   515
                            item.IsButtonVisible = false;
Dean@641
   516
                            item.IsExpandable = false;
Dean@485
   517
                        }
Dean@366
   518
                    }
Dean@281
   519
                }
Dean@485
   520
                else // Invalid identity
Dean@259
   521
                {
Dean@485
   522
                    item = new SelectionItem();
Dean@485
   523
                    item.TextLine1 = ident.Username;
Dean@485
   524
                    item.TextLine2 = ident.Address;
Dean@485
   525
                    item.ItemImage = null;
Dean@485
   526
                    item.IsTwoTextLinesVisible = true;
Dean@259
   527
                    item.IsButtonVisible = false;
Dean@259
   528
                }
Dean@259
   529
Dean@279
   530
                managerState.Identities.Add(item);
Dean@737
   531
                currIndex++;
Dean@259
   532
            }
Dean@259
   533
Dean@737
   534
            // Attempt to select and expand the first identity requiring a handshake
Dean@375
   535
            for (int i = 0; i < managerState.Identities.Count; i++)
Dean@375
   536
            {
Dean@737
   537
                // Determine if it's a handshake identity by checking if it's expandable
Dean@375
   538
                if (managerState.Identities[i].IsExpandable)
Dean@375
   539
                {
Dean@737
   540
                    managerState.Identities[i].TextButton = Properties.Resources.PrivacyStatus_HandshakeAdvanced;
Dean@737
   541
                    managerState.Identities[i].IsExpanded = true;
Dean@375
   542
                    managerState.SelectedIdentityIndex = i;
Dean@375
   543
                    break;
Dean@375
   544
                }
Dean@375
   545
            }
Dean@375
   546
Dean@279
   547
            return (managerState);
Dean@279
   548
        }
Dean@279
   549
Dean@279
   550
        /// <summary>
Dean@279
   551
        /// Builds the latest state of the encryption status manager then shows the UI.
Dean@279
   552
        /// </summary>
Dean@279
   553
        private void BuildAndShowManager()
Dean@279
   554
        {
Dean@279
   555
            DialogResult result;
Dean@313
   556
            FormManagePrivacyStatus form;
Dean@313
   557
            FormManagePrivacyStatus.State stateOut;
Dean@279
   558
Dean@483
   559
            try
Dean@483
   560
            {
Dean@483
   561
                // Show the form
Dean@483
   562
                form = new FormManagePrivacyStatus();
Dean@483
   563
                form.StartPosition = FormStartPosition.CenterScreen;
Dean@259
   564
Dean@483
   565
                this.managerForm = form;
Dean@483
   566
                result = form.ShowDialog(this.ParentForm, this.GetManagerState(), out stateOut); // Must show as dialog to block code
Dean@483
   567
            }
Dean@483
   568
            catch (Exception ex)
Dean@483
   569
            {
Dean@860
   570
                Globals.StopAndSendCrashReport(ex);
Dean@483
   571
            }
Dean@259
   572
Dean@259
   573
            return;
Dean@259
   574
        }
Dean@259
   575
Dean@259
   576
        /// <summary>
Dean@179
   577
        /// Updates the status of the UI state based on the associated mail item.
Dean@179
   578
        /// </summary>
Dean@622
   579
        public void UpdateUIFromMailItem()
Dean@159
   580
        {
Dean@312
   581
            PrivacyState state;
Dean@159
   582
Dean@860
   583
            Globals.LogVerbose("UpdateUIFromMailItem: Started.");
Dean@740
   584
Dean@173
   585
            if (this.associatedMailItem != null)
Dean@159
   586
            {
Dean@859
   587
                if (this.associatedMailItem.ForceUnencryptedBool == true)
Dean@159
   588
                {
Dean@342
   589
                    // Force unencrypted
Dean@312
   590
                    state = new PrivacyState(_pEp_color.pEp_rating_unencrypted);
Dean@680
   591
                    this.CopyStateToUI(state);
Dean@740
   592
Dean@860
   593
                    Globals.LogVerbose("UpdateUIFromMailItem: Force unencrypted detected.");
Dean@159
   594
                }
Dean@159
   595
                else
Dean@159
   596
                {
Dean@860
   597
                    Globals.LogVerbose("UpdateUIFromMailItem: Starting decryption.");
Dean@740
   598
Dean@680
   599
                    // Start the color rating calculation/decryption process
Dean@680
   600
                    this.associatedMailItem.StartDecryption();
Dean@159
   601
                }
Dean@159
   602
            }
Dean@159
   603
Dean@179
   604
            return;
Dean@159
   605
        }
Dean@159
   606
Dean@709
   607
        /// <summary>
Dean@709
   608
        /// Clears the associated unencrypted preview and displays the given note (if any).
Dean@709
   609
        /// </summary>
Dean@709
   610
        /// <param name="note">The note to diplsay.</param>
Dean@709
   611
        private void ClearPreview(string note = null)
Dean@709
   612
        {
Dean@987
   613
            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
   614
Dean@709
   615
            if ((formRegions != null) &&
Dean@709
   616
                (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@709
   617
                (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@709
   618
            {
Dean@709
   619
                formRegions.FormRegionPreviewUnencrypted.ClearMessage();
Dean@709
   620
                formRegions.FormRegionPreviewUnencrypted.SetNote(note);
Dean@709
   621
            }
Dean@709
   622
Dean@709
   623
            return;
Dean@709
   624
        }
Dean@709
   625
Dean@172
   626
        #region StateMethods
Dean@172
   627
Dean@172
   628
        /// <summary>
Dean@172
   629
        /// Connects or disconnects all control events from the UI.
Dean@172
   630
        /// </summary>
Dean@172
   631
        /// <param name="connect">True to connect events, false to disconnect.</param>
Dean@172
   632
        private void ConnectEvents(bool connect)
Dean@172
   633
        {
Dean@172
   634
            // Connect events only if not already connected
markus@201
   635
            if ((connect == true) &&
Dean@172
   636
                (this.eventsAreConnected == false))
Dean@172
   637
            {
Dean@312
   638
                this.ButtonPrivacyStatus.Click += this.ButtonPrivacyStatus_Click;
Dean@312
   639
                this.ButtonPrivacyStatus.MouseUp += this.ButtonPrivacyStatus_MouseUp;
Dean@859
   640
                this.LinkLabelUpgrade.LinkClicked += LinkLabelUpgrade_LinkClicked;
Dean@179
   641
Dean@172
   642
                this.eventsAreConnected = true;
Dean@172
   643
            }
Dean@172
   644
            // Always attempt to disconnect
Dean@172
   645
            else if (connect == false)
Dean@172
   646
            {
Dean@312
   647
                this.ButtonPrivacyStatus.Click -= this.ButtonPrivacyStatus_Click;
Dean@312
   648
                this.ButtonPrivacyStatus.MouseUp -= this.ButtonPrivacyStatus_MouseUp;
Dean@859
   649
                this.LinkLabelUpgrade.LinkClicked -= LinkLabelUpgrade_LinkClicked;
Dean@179
   650
Dean@172
   651
                this.eventsAreConnected = false;
Dean@172
   652
            }
Dean@172
   653
Dean@172
   654
            return;
Dean@172
   655
        }
Dean@172
   656
Dean@172
   657
        /// <summary>
Dean@172
   658
        /// Copies the given state to the UI.
Dean@172
   659
        /// Events are turned off until the process is complete.
Dean@172
   660
        /// </summary>
Dean@172
   661
        /// <param name="state">The state to set to the UI.</param>
Dean@312
   662
        private void CopyStateToUI(PrivacyState state)
Dean@172
   663
        {
Dean@172
   664
            this.ConnectEvents(false);
markus@201
   665
Dean@172
   666
            ///////////////////////////////////////////////////////////
Dean@172
   667
            // Set UI data
Dean@172
   668
            ///////////////////////////////////////////////////////////
Dean@172
   669
Dean@179
   670
            // Save UI state maintained outside of controls
Dean@312
   671
            this.stateUIColorRating = state.PrivacyStatus;
Dean@179
   672
Dean@312
   673
            this.ButtonPrivacyStatus.BackColor = state.BackgroundColor;
Dean@312
   674
            this.ButtonPrivacyStatus.ForeColor = state.ForegroundColor;
Dean@312
   675
            this.ButtonPrivacyStatus.Text = state.ShortText;
Dean@172
   676
Dean@670
   677
            // Update the manager form state
Dean@670
   678
            if (this.managerForm != null)
Dean@670
   679
            {
Dean@670
   680
                this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@670
   681
            }
Dean@670
   682
Dean@859
   683
            ///////////////////////////////////////////////////////////
Dean@859
   684
            // Set UI control visibility
Dean@859
   685
            ///////////////////////////////////////////////////////////
Dean@859
   686
Dean@894
   687
#if READER_RELEASE_MODE
Dean@894
   688
            this.LinkLabelUpgrade.Visible = true;
Dean@894
   689
#else
Dean@894
   690
            this.LinkLabelUpgrade.Visible = false;
Dean@894
   691
#endif
Dean@859
   692
Dean@172
   693
            this.ConnectEvents(true);
Dean@172
   694
Dean@172
   695
            return;
Dean@172
   696
        }
Dean@172
   697
Dean@172
   698
        /// <summary>
Dean@172
   699
        /// Copies the UI to a new state.
Dean@172
   700
        /// </summary>
Dean@172
   701
        /// <returns>The state of the UI.</returns>
Dean@312
   702
        private PrivacyState CopyUIToState()
Dean@172
   703
        {
Dean@312
   704
            return (new PrivacyState(this.stateUIColorRating));
Dean@172
   705
        }
Dean@172
   706
Dean@172
   707
        #endregion
Dean@172
   708
Dean@159
   709
        /**************************************************************
Dean@159
   710
         * 
Dean@159
   711
         * Event Handling
Dean@159
   712
         * 
Dean@159
   713
         *************************************************************/
Dean@159
   714
Dean@159
   715
        /// <summary>
Dean@680
   716
        /// Event handler that is called when the form region is displayed.
Dean@680
   717
        /// This is called each time the form region looses then regains visiblity 
Dean@680
   718
        /// (for example an other email is selected then back to this one).
Dean@159
   719
        /// </summary>
Dean@312
   720
        private void FormRegionPrivacyStatus_FormRegionShowing(object sender, System.EventArgs e)
Dean@159
   721
        {
Dean@680
   722
            // Do not allow initialization more than once
Dean@680
   723
            if (initialized == false)
Dean@680
   724
            {
Dean@680
   725
                this.SetAssociatedMailItem();
Dean@173
   726
Dean@680
   727
                // Set background color for Office 2013
Dean@159
   728
                try
Dean@159
   729
                {
Dean@680
   730
                    if (Globals.ThisAddIn.Application.Version.Substring(0, 2) == "15")
Dean@159
   731
                    {
Dean@680
   732
                        if (this.IsWithinInspector())
Dean@680
   733
                        {
Dean@680
   734
                            this.BackColor = SystemColors.ButtonFace;
Dean@680
   735
                        }
Dean@680
   736
                        else
Dean@680
   737
                        {
Dean@680
   738
                            this.BackColor = SystemColors.Window;
Dean@680
   739
                        }
Dean@159
   740
                    }
Dean@159
   741
                }
Dean@159
   742
                catch { }
Dean@680
   743
Dean@680
   744
                // Connect cryptable mail item events
Dean@680
   745
                if (this.associatedMailItem != null)
Dean@680
   746
                {
Dean@680
   747
                    try
Dean@680
   748
                    {
Dean@680
   749
                        this.associatedMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@680
   750
                        this.associatedMailItem.DecryptionComplete += MailItem_DecryptionComplete;
Dean@709
   751
                        this.associatedMailItem.GetMirrorComplete += MailItem_GetMirrorComplete;
Dean@682
   752
                        this.associatedMailItem.Send += MailItem_Send;
Dean@680
   753
Dean@680
   754
                        if (this.associatedMailItem.IsInEncryptedStore &&
Dean@927
   755
                            this.associatedMailItem.IsEncrypted)
Dean@680
   756
                        {
Dean@680
   757
                            this.associatedMailItem.Open += MailItem_Open;
Dean@680
   758
                        }
Dean@680
   759
                    }
Dean@680
   760
                    catch { }
Dean@680
   761
                }
Dean@680
   762
Dean@807
   763
                // Connect static events
Dean@807
   764
                CryptableMailItem.EncryptedConversationCacheUpdated += CryptableMailItem_EncryptedConversationCacheUpdated;
Dean@807
   765
Dean@680
   766
                this.CopyStateToUI(new PrivacyState());
Dean@683
   767
                this.TimerRefresh.Tick += TimerRefresh_Tick;
Dean@680
   768
                this.initialized = true;
Dean@179
   769
            }
Dean@159
   770
Dean@683
   771
            // Call the timer tick method manually to refresh data with no delay
Dean@199
   772
            this.TimerRefresh_Tick(null, new EventArgs());
Dean@179
   773
Dean@179
   774
            return;
Dean@159
   775
        }
Dean@159
   776
Dean@159
   777
        /// <summary>
Dean@159
   778
        /// Event handler for when the form region is closed.
Dean@159
   779
        /// </summary>
Dean@312
   780
        private void FormRegionPrivacyStatus_FormRegionClosed(object sender, System.EventArgs e)
Dean@159
   781
        {
Dean@199
   782
            // Disconnect cryptable mail item events
Dean@190
   783
            if (this.associatedMailItem != null)
Dean@179
   784
            {
Dean@179
   785
                try
Dean@179
   786
                {
Dean@445
   787
                    this.associatedMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@680
   788
                    this.associatedMailItem.DecryptionComplete -= MailItem_DecryptionComplete;
Dean@709
   789
                    this.associatedMailItem.GetMirrorComplete -= MailItem_GetMirrorComplete;
markus@201
   790
                    this.associatedMailItem.Open -= MailItem_Open;
Dean@682
   791
                    this.associatedMailItem.Send -= MailItem_Send;
Dean@179
   792
                }
Dean@179
   793
                catch { }
Dean@179
   794
            }
Dean@179
   795
Dean@807
   796
            // Disconnect static events
Dean@807
   797
            CryptableMailItem.EncryptedConversationCacheUpdated -= CryptableMailItem_EncryptedConversationCacheUpdated;
Dean@807
   798
Dean@682
   799
            // Stop and disconnect the refresh timer
Dean@682
   800
            this.TimerRefresh.Stop();
Dean@682
   801
            this.TimerRefresh.Enabled = false;
Dean@682
   802
            this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@682
   803
Dean@179
   804
            return;
Dean@179
   805
        }
Dean@179
   806
Dean@179
   807
        /// <summary>
Dean@179
   808
        /// Event handler called after the refresh timer has elapsed.
Dean@179
   809
        /// </summary>
Dean@179
   810
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
   811
        {
Dean@199
   812
            bool tryAgain = false;
Dean@684
   813
            bool markForDownload = false;
Dean@179
   814
            this.TimerRefresh.Enabled = false; // Only once
Dean@684
   815
            Outlook.OlDownloadState dlState;
markus@201
   816
Dean@709
   817
            /* The Refresh/UI_Update process is a little more complicated here than other forms.
Dean@709
   818
             * There are the following components:
Dean@709
   819
             *   1. TimerRefresh_Tick
Dean@709
   820
             *        This is the main timer tick event handler called any time
Dean@709
   821
             *        a refresh was requested and hasn't been run yet. A refresh
Dean@709
   822
             *        is requested either at initialization or when a property changes
Dean@709
   823
             *        (such as MailItem_PropertyChanged). It is on a timer as many 
Dean@709
   824
             *        property change events could occur rapidy, but only one refresh should
Dean@709
   825
             *        occur for performance reasons.
Dean@709
   826
             * 
Dean@709
   827
             *   2. UpdateUIFromMailItem
Dean@709
   828
             *        This will re-calculate the mail item's color rating and then update the UI.
Dean@709
   829
             *        However, if a mail item is not forcefully unencrypted, it will just call StartDecryption.
Dean@709
   830
             * 
Dean@709
   831
             *   3. MailItem_DecryptionComplete
Dean@709
   832
             *        When decryption of the mail item is complete, this even handler will be called.
Dean@709
   833
             *        This will update the UI with the latest color rating then call StartGetMirror.
Dean@709
   834
             *        The CopyStateToUI method is used which means any open privacy status form will also
Dean@709
   835
             *        be updated.
Dean@709
   836
             * 
Dean@709
   837
             *   4. MailItem_GetMirrorComplete
Dean@709
   838
             *        This is the final step in updating the UI, after a mirror is located, it's contents
Dean@709
   839
             *        will be shown to the unencrypted preview.
Dean@709
   840
             * 
Dean@709
   841
             * The general calling sequence is as shown above 1->4 with each component calling the next.
Dean@709
   842
             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
Dean@709
   843
             */
Dean@709
   844
Dean@179
   845
            // Ensure the tick method is not called more than once
Dean@179
   846
            if (refreshOngoing == false)
Dean@179
   847
            {
Dean@179
   848
                this.refreshOngoing = true;
Dean@179
   849
Dean@179
   850
                if (this.associatedMailItem != null)
Dean@179
   851
                {
Dean@684
   852
                    // Attempt to get the download state
Dean@684
   853
                    try
Dean@684
   854
                    {
Dean@684
   855
                        dlState = this.associatedMailItem.DownloadState;
Dean@684
   856
                    }
Dean@684
   857
                    catch (Exception ex)
Dean@684
   858
                    {
Dean@860
   859
                        Globals.Log("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
Dean@684
   860
Dean@684
   861
                        // Assume everything is downloaded, but try to download again as well
Dean@684
   862
                        dlState = Outlook.OlDownloadState.olFullItem;
Dean@684
   863
                        markForDownload = true;
Dean@684
   864
                    }
Dean@684
   865
Dean@684
   866
                    if (dlState == Outlook.OlDownloadState.olFullItem)
Dean@179
   867
                    {
Dean@709
   868
                        // Clear any existing preview and update
Dean@709
   869
                        this.ClearPreview(Properties.Resources.Message_Opening);
Dean@179
   870
                        this.UpdateUIFromMailItem();
Dean@179
   871
                    }
Dean@179
   872
                    else
Dean@179
   873
                    {
Dean@684
   874
                        markForDownload = true;
Dean@684
   875
                    }
Dean@684
   876
Dean@684
   877
                    if (markForDownload)
Dean@684
   878
                    {
Dean@684
   879
                        // Try to mark the message for full download
Dean@684
   880
                        try
Dean@684
   881
                        {
Dean@684
   882
                            this.associatedMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Dean@684
   883
                            tryAgain = true;
Dean@684
   884
                        }
Dean@684
   885
                        catch (Exception ex)
Dean@684
   886
                        {
Dean@860
   887
                            Globals.Log("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
Dean@684
   888
                        }
Dean@179
   889
                    }
Dean@179
   890
                }
Dean@179
   891
Dean@199
   892
                // Set the timer to refresh again later automatically
Dean@199
   893
                if (tryAgain)
Dean@199
   894
                {
Dean@199
   895
                    this.TimerRefresh.Interval = 100;
Dean@199
   896
                    this.TimerRefresh.Enabled = true;
Dean@199
   897
                }
Dean@199
   898
Dean@179
   899
                this.refreshOngoing = false;
Dean@179
   900
            }
Dean@175
   901
Dean@159
   902
            return;
Dean@159
   903
        }
Dean@159
   904
Dean@169
   905
        /// <summary>
Dean@680
   906
        /// Event handler for when the decryption process is completed in the associated mail item.
Dean@709
   907
        /// This will then update the form region UI and the privacy status window as needed.
Dean@680
   908
        /// </summary>
Dean@704
   909
        private void MailItem_DecryptionComplete(object sender, CryptableMailItem.DecryptionEventArgs e)
Dean@680
   910
        {
Dean@860
   911
            Globals.LogVerbose("MailItem_DecryptionComplete: Decryption completed.");
Dean@740
   912
Dean@680
   913
            try
Dean@680
   914
            {
Dean@680
   915
                // Marshal code back to UI thread as necessary
Dean@680
   916
                this.Invoke(new Action(() =>
Dean@680
   917
                    {
Dean@680
   918
                        this.CopyStateToUI(new PrivacyState(e.ColorRating));
Dean@709
   919
Dean@709
   920
                        /* Create the unencrypted preview if the mail item is encrypted and
Dean@709
   921
                         * it is in an encrypted (untrusted) store
Dean@709
   922
                         * 
Dean@709
   923
                         * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Dean@709
   924
                         * it also is initialized after FormRegionPreviewUnencrypted.
Dean@709
   925
                         */
Dean@747
   926
                        try
Dean@709
   927
                        {
Dean@747
   928
                            if (this.associatedMailItem.IsInEncryptedStore &&
Dean@927
   929
                                this.associatedMailItem.IsEncrypted)
Dean@747
   930
                            {
Dean@860
   931
                                Globals.LogVerbose("MailItem_DecryptionComplete: Starting mirror location.");
Dean@747
   932
                                this.associatedMailItem.StartGetMirror();
Dean@747
   933
                            }
Dean@747
   934
                            else
Dean@747
   935
                            {
Dean@747
   936
                                this.ClearPreview();
Dean@747
   937
                            }
Dean@709
   938
                        }
Dean@747
   939
                        catch (Exception ex)
Dean@719
   940
                        {
Dean@747
   941
                            // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
Dean@747
   942
                            // While rare, just log the issue and stop the process
Dean@860
   943
                            Globals.Log("MailItem_DecryptionComplete: Failed to start mirror location, " + ex.ToString());
Dean@719
   944
                        }
Dean@680
   945
                    }));
Dean@680
   946
            }
Dean@680
   947
            catch (Exception ex)
Dean@680
   948
            {
Dean@860
   949
                Globals.Log("MailItem_DecryptionComplete: Error setting UI state, " + ex.ToString());
Dean@680
   950
            }
Dean@680
   951
Dean@680
   952
            return;
Dean@680
   953
        }
Dean@680
   954
Dean@680
   955
        /// <summary>
Dean@709
   956
        /// Event handler for when the get mirror locating process is complete for the associated mail item.
Dean@709
   957
        /// This will then update the unencrypted preview in the UI.
Dean@709
   958
        /// </summary>
Dean@709
   959
        private void MailItem_GetMirrorComplete(object sender, CryptableMailItem.GetMirrorEventArgs e)
Dean@709
   960
        {
Dean@709
   961
            try
Dean@709
   962
            {
Dean@709
   963
                // Marshal code back to UI thread as necessary
Dean@709
   964
                this.Invoke(new Action(() =>
Dean@709
   965
                    {
Dean@987
   966
                        WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
   967
Dean@910
   968
                        if ((e.Mirror == null) &&
Dean@910
   969
                            (this.associatedMailItem.DecryptionNoConnectionFailure))
Dean@709
   970
                        {
Dean@910
   971
                            this.ClearPreview(Properties.Resources.Message_DecryptionNoConnection);
Dean@910
   972
                            Globals.LogVerbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
Dean@910
   973
                        }
Dean@910
   974
                        else
Dean@910
   975
                        {
Dean@910
   976
                            if ((formRegions != null) &&
Dean@910
   977
                                (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@910
   978
                                (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@910
   979
                            {
Dean@910
   980
                                formRegions.FormRegionPreviewUnencrypted.SetMessage(e.Mirror);
Dean@910
   981
                                Globals.LogVerbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
Dean@910
   982
                            }
Dean@709
   983
                        }
Dean@758
   984
Dean@758
   985
                        // Display the mirror if necessary
Dean@758
   986
                        if ((this.associatedMailItem != null) &&
Dean@758
   987
                            (this.displayMirrorRequested))
Dean@758
   988
                        {
Dean@758
   989
                            this.associatedMailItem.DisplayMirror();
Dean@758
   990
                            this.displayMirrorRequested = false;
Dean@758
   991
                        }
Dean@709
   992
                    }));
Dean@709
   993
            }
Dean@709
   994
            catch (Exception ex)
Dean@709
   995
            {
Dean@860
   996
                Globals.Log("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
Dean@709
   997
            }
Dean@709
   998
Dean@709
   999
            return;
Dean@709
  1000
        }
Dean@709
  1001
Dean@709
  1002
        /// <summary>
Dean@807
  1003
        /// Event handler for the static mail item encrypted conversation cache updated.
Dean@807
  1004
        /// This event is fired after the conversation cache has been updated with parent information following a
Dean@807
  1005
        /// forward or reply mail item event (on a different, likely parent, mail item).
Dean@807
  1006
        /// </summary>
Dean@807
  1007
        private void CryptableMailItem_EncryptedConversationCacheUpdated(object sender, EventArgs e)
Dean@807
  1008
        {
Dean@807
  1009
            // Process the mail item now that the cache is updated
Dean@807
  1010
            this.associatedMailItem.SetIsOriginallyEncryptedByCache();
Dean@807
  1011
Dean@807
  1012
            // Remove the event handler -- this can only be processed once because it's timing dependent
Dean@807
  1013
            CryptableMailItem.EncryptedConversationCacheUpdated -= CryptableMailItem_EncryptedConversationCacheUpdated;
Dean@807
  1014
Dean@807
  1015
            return;
Dean@807
  1016
        }
Dean@807
  1017
Dean@807
  1018
        /// <summary>
Dean@169
  1019
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
  1020
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
  1021
        /// </summary>
Dean@169
  1022
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
  1023
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
  1024
        /// and the inspector is not displayed.</param>
Dean@169
  1025
        private void MailItem_Open(ref bool cancel)
Dean@159
  1026
        {
Dean@758
  1027
            bool result;
Dean@758
  1028
Dean@758
  1029
            if (this.associatedMailItem != null &&
Dean@901
  1030
                this.associatedMailItem.IsInEncryptedStore &&
Dean@927
  1031
                this.associatedMailItem.IsEncrypted)
Dean@169
  1032
            {
Dean@758
  1033
                // Try to open the mirror
Dean@758
  1034
                result = this.associatedMailItem.DisplayMirror();
Dean@758
  1035
Dean@758
  1036
                if (result == false)
Dean@758
  1037
                {
Dean@758
  1038
                    // Set flag to open after decryption/mirror location
Dean@758
  1039
                    this.displayMirrorRequested = true;
Dean@758
  1040
                }
Dean@758
  1041
Dean@758
  1042
                // Always cancel opening the original
Dean@169
  1043
                cancel = true;
Dean@169
  1044
            }
Dean@169
  1045
Dean@169
  1046
            return;
Dean@159
  1047
        }
Dean@159
  1048
Dean@169
  1049
        /// <summary>
Dean@682
  1050
        /// Event handler for when a mail item is sent.
Dean@682
  1051
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
Dean@682
  1052
        /// </summary>
Dean@682
  1053
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@682
  1054
        /// If the event procedure sets this argument to True, the send operation is not completed 
Dean@682
  1055
        /// and the inspector is left open.</param>
Dean@682
  1056
        private void MailItem_Send(ref bool cancel)
Dean@682
  1057
        {
Dean@807
  1058
            DialogResult result;
Dean@807
  1059
            PrivacyState state = this.CopyUIToState();
Dean@807
  1060
Dean@807
  1061
            if ((this.associatedMailItem.IsOriginallyEncrypted) &&
Dean@807
  1062
                (state.PrivacyStatus < _pEp_color.pEp_rating_unreliable))
Dean@807
  1063
            {
Dean@807
  1064
                result = MessageBox.Show(this.ParentForm,
Dean@807
  1065
                                         pEp.Properties.Resources.Message_WarningPreviouslyEncrypted,
Dean@807
  1066
                                         pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@807
  1067
                                         MessageBoxButtons.YesNo);
Dean@807
  1068
Dean@807
  1069
                if (result == DialogResult.No)
Dean@807
  1070
                {
Dean@807
  1071
                    // Cancel sending
Dean@807
  1072
                    cancel = true;
Dean@807
  1073
                }
Dean@807
  1074
            }
Dean@807
  1075
Dean@682
  1076
            // Stop and disconnect the refresh timer
Dean@682
  1077
            // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
Dean@807
  1078
            if (cancel == false)
Dean@807
  1079
            {
Dean@807
  1080
                this.TimerRefresh.Stop();
Dean@807
  1081
                this.TimerRefresh.Enabled = false;
Dean@807
  1082
                this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@807
  1083
            }
Dean@682
  1084
Dean@682
  1085
            return;
Dean@682
  1086
        }
Dean@682
  1087
Dean@682
  1088
        /// <summary>
Dean@169
  1089
        /// Event handler for when a mail item property is changed.
Dean@169
  1090
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
  1091
        /// </summary>
Dean@169
  1092
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@445
  1093
        private void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Dean@159
  1094
        {
Dean@445
  1095
            switch (e.PropertyName.ToUpper())
Dean@159
  1096
            {
Dean@179
  1097
                case "TO":
Dean@179
  1098
                    // Start the refresh timer
Dean@179
  1099
                    this.TimerRefresh.Enabled = true;
Dean@159
  1100
                    break;
Dean@159
  1101
                // Outlook bug: there are always both events, so one is enough
Dean@159
  1102
                //case "CC":
Dean@179
  1103
                //    // Start the refresh timer
Dean@179
  1104
                //    this.TimerRefresh.Enabled = true;
Dean@159
  1105
                //    break;
Dean@159
  1106
            }
Dean@169
  1107
Dean@169
  1108
            return;
Dean@159
  1109
        }
Dean@159
  1110
Dean@179
  1111
        /// <summary>
Dean@312
  1112
        /// Event handler for when the privacy status button is clicked.
Dean@179
  1113
        /// </summary>
Dean@312
  1114
        private void ButtonPrivacyStatus_Click(object sender, EventArgs e)
vb@133
  1115
        {
Dean@310
  1116
            this.BuildAndShowManager();
Dean@179
  1117
            return;
vb@133
  1118
        }
vb@133
  1119
Dean@179
  1120
        /// <summary>
Dean@312
  1121
        /// Event handler for when a mouse button is released over the privacy status button.
Dean@179
  1122
        /// </summary>
Dean@312
  1123
        private void ButtonPrivacyStatus_MouseUp(object sender, MouseEventArgs e)
vb@133
  1124
        {
Dean@179
  1125
            return;
vb@133
  1126
        }
Dean@859
  1127
Dean@859
  1128
        /// <summary>
Dean@859
  1129
        /// Event handler for when the pEp website hyperlink is clicked.
Dean@859
  1130
        /// </summary>
Dean@859
  1131
        private void LinkLabelUpgrade_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
Dean@859
  1132
        {
Dean@966
  1133
            try
Dean@966
  1134
            {
Dean@966
  1135
                Process.Start(Globals.PEP_WEBSITE_LINK);
Dean@966
  1136
            }
Dean@966
  1137
            catch (Exception ex)
Dean@966
  1138
            {
Dean@966
  1139
                Globals.Log("LinkLabelPEP_LinkClicked: Unable to open website link, " + ex.ToString());
Dean@966
  1140
            }
Dean@966
  1141
Dean@859
  1142
            return;
Dean@859
  1143
        }
vb@133
  1144
    }
vb@133
  1145
}