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