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