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