UI/FormRegionPrivacyStatus.cs
author Dean Looyengoed
Thu, 10 Mar 2016 18:03:36 +0100
changeset 641 58d9dbf575bb
parent 638 5d99a596d5b5
child 642 1a59435a585c
permissions -rw-r--r--
Show force unencrypted image next to identities whose Outlook contact is set to force unencrypted.
Dean@159
     1
´╗┐using pEpCOMServerAdapterLib;
Dean@159
     2
using System;
vb@133
     3
using System.Collections.Generic;
Dean@445
     4
using System.ComponentModel;
Dean@438
     5
using System.Drawing;
Dean@159
     6
using System.Runtime.InteropServices;
vb@133
     7
using System.Windows.Forms;
Dean@159
     8
using Color = System.Drawing.Color;
vb@133
     9
using Outlook = Microsoft.Office.Interop.Outlook;
vb@133
    10
vb@133
    11
namespace pEp
vb@133
    12
{
Dean@159
    13
    /// <summary>
Dean@312
    14
    /// Partial class for the privacy status form region that is displayed below every outlook message.
Dean@159
    15
    /// </summary>
Dean@312
    16
    partial class FormRegionPrivacyStatus
vb@133
    17
    {
vb@133
    18
        #region Form Region Factory
vb@133
    19
vb@133
    20
        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
Dean@312
    21
        [Microsoft.Office.Tools.Outlook.FormRegionName("pEp.FormRegionPrivacyStatus")]
Dean@312
    22
        public partial class FormRegionPrivacyStatusFactory
vb@133
    23
        {
vb@133
    24
            // Occurs before the form region is initialized.
vb@133
    25
            // To prevent the form region from appearing, set e.Cancel to true.
vb@133
    26
            // Use e.OutlookItem to get a reference to the current Outlook item.
Dean@312
    27
            private void FormRegionPrivacyStatus_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
vb@133
    28
            {
Dean@327
    29
                WindowFormRegionCollection formRegions;
Dean@327
    30
Dean@327
    31
                /* There is a Microsoft bug at least in Outlook 2013 and Windows 8.1
Dean@327
    32
                 * This bug causes multiple PrivacyStatus form regions to appear stacked on top of each other.
Dean@327
    33
                 * To trigger this bug, on an unencrypted server, click reply to compose an in-line response.
Dean@327
    34
                 * Then click to another tab such as People or Tasks. Then click back on the mail tab to view 
Dean@327
    35
                 * the original email again. Two form regions will be visible: 
Dean@327
    36
                 * (1) for the status during the in-line reply and 
Dean@327
    37
                 * (2) for the status of only the received message.
Dean@327
    38
                 * 
Dean@327
    39
                 * To fix this bug, any existing form regions are found and closed when initializing a new privacy status
Dean@327
    40
                 * form region.
Dean@327
    41
                 */
Dean@327
    42
Dean@327
    43
                try
Dean@327
    44
                {
Dean@327
    45
                    formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
Dean@327
    46
                    if (formRegions.FormRegionPrivacyStatus != null)
Dean@327
    47
                    {
Dean@327
    48
                        /* Note: there seems to be no way to actually close the form region.
Dean@327
    49
                         * Therefore, this is as close as possible to actually closing it.
Dean@327
    50
                         * The actual form regions will be cleaned up as soon as another email is selected.
Dean@327
    51
                         */
Dean@327
    52
                        formRegions.FormRegionPrivacyStatus.OutlookFormRegion.Visible = false;
Dean@327
    53
                    }
Dean@327
    54
                }
Dean@327
    55
                catch { }
Dean@327
    56
Dean@327
    57
                return;
vb@133
    58
            }
vb@133
    59
        }
vb@133
    60
vb@133
    61
        #endregion
vb@133
    62
Dean@159
    63
        /* Notes:
Dean@179
    64
         * 
Dean@159
    65
         * Use this.OutlookItem to get a reference to the current Outlook item.
Dean@159
    66
         * Use this.OutlookFormRegion to get a reference to the form region.
Dean@179
    67
         * 
Dean@179
    68
         * UI State Managment:
Dean@179
    69
         * 
Dean@179
    70
         * The UI state is almost entirely set from the associated mail item data.
Dean@179
    71
         * However, a separate state class is maintained to represent the UI as some separation is needed.
Dean@179
    72
         * This logical separation MUST be maintained throughout the code.
Dean@179
    73
         * Specific cases are noted where possible.
Dean@179
    74
         * 
Dean@356
    75
         * The separate privacy status manager form state is also managed here.
Dean@259
    76
         * 
Dean@159
    77
         */
Dean@159
    78
Dean@170
    79
        private CryptableMailItem associatedMailItem = null;
Dean@179
    80
        private bool              refreshOngoing     = false;
Dean@179
    81
        private bool              eventsAreConnected = false;
Dean@170
    82
Dean@313
    83
        private FormManagePrivacyStatus managerForm = null;
Dean@259
    84
Dean@250
    85
        // Data or controls not stored in the UI
Dean@179
    86
        private _pEp_color stateUIColorRating; // WARNING: Do NOT use this directly
vb@133
    87
Dean@159
    88
        /**************************************************************
Dean@159
    89
         * 
Dean@159
    90
         * Methods
Dean@159
    91
         * 
Dean@159
    92
         *************************************************************/
Dean@159
    93
Dean@171
    94
        /// <summary>
Dean@438
    95
        /// Determines if this form region is running in an inspector window.
Dean@438
    96
        /// If not true, it is assumed to be within an explorer window.
Dean@438
    97
        /// </summary>
Dean@438
    98
        /// <returns>True if an inspector window, false if within an explorer.</returns>
Dean@438
    99
        private bool IsWithinInspector()
Dean@438
   100
        {
Dean@438
   101
            bool isWithinInspector = false;
Dean@438
   102
            Outlook.Explorer temp = null;
Dean@438
   103
Dean@438
   104
            try
Dean@438
   105
            {
Dean@438
   106
                // Just try to cast to an explorer class
Dean@438
   107
                temp = (Outlook.Explorer)this.OutlookFormRegion.Parent;
Dean@438
   108
                isWithinInspector = false;
Dean@438
   109
            }
Dean@438
   110
            catch
Dean@438
   111
            {
Dean@438
   112
                isWithinInspector = true;
Dean@438
   113
            }
Dean@438
   114
            finally
Dean@438
   115
            {
Dean@438
   116
                if (temp != null)
Dean@438
   117
                {
Dean@438
   118
                    Marshal.ReleaseComObject(temp);
Dean@438
   119
                    temp = null;
Dean@438
   120
                }
Dean@438
   121
            }
Dean@438
   122
Dean@438
   123
            return (isWithinInspector);
Dean@438
   124
        }
Dean@438
   125
Dean@438
   126
        /// <summary>
Dean@170
   127
        /// Sets the cryptable mail item associated with this encryption status panel.
Dean@170
   128
        /// The associated mail item can then be accessed through its local variable.
Dean@170
   129
        /// </summary>
Dean@170
   130
        private void SetAssociatedMailItem()
Dean@170
   131
        {
Dean@170
   132
            bool errorOccurred = false;
Dean@170
   133
            Outlook.MailItem omi = null;
Dean@170
   134
Dean@170
   135
            // Null check
Dean@170
   136
            if (!errorOccurred)
Dean@170
   137
            {
Dean@170
   138
                try
Dean@170
   139
                {
Dean@170
   140
                    if (this.OutlookItem == null)
Dean@170
   141
                    {
Dean@170
   142
                        errorOccurred = true;
Dean@170
   143
                    }
Dean@170
   144
                }
Dean@170
   145
                catch (COMException)
Dean@170
   146
                {
Dean@170
   147
                    errorOccurred = true;
Dean@170
   148
                }
Dean@170
   149
            }
Dean@170
   150
Dean@170
   151
            // Attempt to get and cast the outlook mail item
Dean@170
   152
            if (!errorOccurred)
Dean@170
   153
            {
Dean@170
   154
                try
Dean@170
   155
                {
Dean@170
   156
                    omi = (Outlook.MailItem)this.OutlookItem;
Dean@170
   157
                }
Dean@170
   158
                catch
Dean@170
   159
                {
Dean@170
   160
                    errorOccurred = true;
Dean@170
   161
                }
Dean@170
   162
            }
Dean@170
   163
Dean@170
   164
            // Finally set the associated mail item
Dean@170
   165
            if ((errorOccurred) ||
Dean@170
   166
                (omi == null))
Dean@170
   167
            {
Dean@170
   168
                this.associatedMailItem = null;
Dean@170
   169
            }
Dean@170
   170
            else
Dean@170
   171
            {
Dean@170
   172
                // Check if the associated mail item has already been set
Dean@170
   173
                if (this.associatedMailItem != null)
Dean@170
   174
                {
Dean@170
   175
                    // Only re-set the mail item if the EntryID has changed
Dean@170
   176
                    if (this.associatedMailItem.EntryID != omi.EntryID)
Dean@170
   177
                    {
Dean@170
   178
                        this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   179
                    }
Dean@170
   180
                }
Dean@170
   181
                else
Dean@170
   182
                {
Dean@170
   183
                    this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   184
                }
Dean@170
   185
            }
Dean@170
   186
Dean@170
   187
            return;
Dean@170
   188
        }
Dean@170
   189
Dean@179
   190
        /// <summary>
Dean@290
   191
        /// Completes the handshake process when the identity of a partner was previously marked as compromised.
Dean@281
   192
        /// </summary>
Dean@281
   193
        /// <param name="identityPartner">The identity of the partner to complete the handshake with.</param>
Dean@384
   194
        private void DoHandshakeForCompromisedKey(PEPIdentity identityPartner)
Dean@281
   195
        {
Dean@281
   196
            DialogResult result;
Dean@281
   197
Dean@281
   198
            result = MessageBox.Show(this.ParentForm,
Dean@378
   199
                                     pEp.Properties.Resources.Message_WarningCompromisedKey,
Dean@378
   200
                                     pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@423
   201
                                     MessageBoxButtons.YesNo);
Dean@281
   202
Dean@423
   203
            if (result == DialogResult.Yes)
Dean@281
   204
            {
Dean@281
   205
                this.DoHandshake(identityPartner);
Dean@281
   206
            }
Dean@281
   207
Dean@281
   208
            return;
Dean@281
   209
        }
Dean@281
   210
Dean@281
   211
        /// <summary>
Dean@281
   212
        /// Completes the handshake process where the identity of a partner is confirmed.
Dean@179
   213
        /// </summary>
Dean@179
   214
        /// <param name="identityPartner">The identity of the partner to complete the handshake with.</param>
Dean@384
   215
        private void DoHandshake(PEPIdentity identityPartner)
vb@133
   216
        {
Dean@155
   217
            string ownFpr;
Dean@155
   218
            string partnerFpr;
Dean@363
   219
            string trustwordsShort;
Dean@363
   220
            string trustwordsFull;
Dean@155
   221
            string[] lines;
Dean@179
   222
            DialogResult result;
Dean@633
   223
            PEPIdentity myIdentity;
Dean@155
   224
            FormHandshake handshakeDialog;
Dean@155
   225
            FormHandshake.State state = new FormHandshake.State();
markus@201
   226
Dean@190
   227
            Globals.ThisAddIn.LogVerbose("doHandshake");
Dean@384
   228
            Globals.ThisAddIn.LogVerbose(identityPartner.Address);
vb@139
   229
Dean@363
   230
            // Process identities
Dean@384
   231
            if (identityPartner.Username == "")
Dean@363
   232
            {
Dean@384
   233
                identityPartner.Username = identityPartner.Address;
vb@133
   234
            }
vb@133
   235
Dean@501
   236
            identityPartner.UserID = Globals.ThisAddIn.GetUserID(identityPartner.Address);
vb@139
   237
Dean@633
   238
            myIdentity = this.associatedMailItem.Myself;
Dean@363
   239
Dean@363
   240
            // Calculate and add trustwords
Dean@633
   241
            this.CalcTrustwords(myIdentity, identityPartner, out trustwordsShort, out trustwordsFull);
Dean@633
   242
            state.Myself = myIdentity.Copy();
Dean@600
   243
            state.Partner = identityPartner.Copy();
Dean@363
   244
            state.TrustwordsShort = trustwordsShort;
Dean@363
   245
            state.TrustwordsFull = trustwordsFull;
Dean@363
   246
Dean@363
   247
            // Calculate and add fingerprint
Dean@633
   248
            ownFpr = this.ToQuadruple(myIdentity.Fingerprint);
Dean@384
   249
            partnerFpr = this.ToQuadruple(identityPartner.Fingerprint);
vb@133
   250
Dean@633
   251
            if (myIdentity.Fingerprint.CompareTo(identityPartner.Fingerprint) > 0)
vb@133
   252
            {
Dean@155
   253
                lines = new string[3];
Dean@378
   254
                lines[0] = pEp.Properties.Resources.PrivacyStatus_TrustwordsPartnerShortPartner + partnerFpr;
Dean@378
   255
                lines[2] = pEp.Properties.Resources.PrivacyStatus_TrustwordsPartnerShortMyself + ownFpr;
Dean@155
   256
                state.Fingerprint = lines;
vb@133
   257
            }
vb@133
   258
            else
vb@133
   259
            {
Dean@155
   260
                lines = new string[3];
Dean@378
   261
                lines[0] = pEp.Properties.Resources.PrivacyStatus_TrustwordsOwnShortMyself + ownFpr;
Dean@378
   262
                lines[2] = pEp.Properties.Resources.PrivacyStatus_TrustwordsOwnShortPartner + partnerFpr;
Dean@155
   263
                state.Fingerprint = lines;
vb@133
   264
            }
vb@133
   265
Dean@155
   266
            // Create and show handshake dialog
Dean@155
   267
            handshakeDialog = new FormHandshake(state);
Dean@179
   268
            handshakeDialog.StartPosition = FormStartPosition.CenterScreen;
Dean@179
   269
            result = handshakeDialog.ShowDialog(this);
Dean@155
   270
Dean@356
   271
            this.ProcessDoHandshakeResult(result, identityPartner);
Dean@356
   272
Dean@356
   273
            return;
Dean@356
   274
        }
Dean@356
   275
Dean@356
   276
        /// <summary>
Dean@356
   277
        /// Processes the result of the do handshake dialog after a user makes a selection.
Dean@356
   278
        /// </summary>
Dean@356
   279
        /// <param name="result">The result of the handshake dialog selection.</param>
Dean@356
   280
        /// <param name="partner">The identity of the partner to handshake with.</param>
Dean@356
   281
        private void ProcessDoHandshakeResult(DialogResult result,
Dean@384
   282
                                              PEPIdentity partner)
Dean@356
   283
        {
Dean@384
   284
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
vb@133
   285
vb@133
   286
            switch (result)
vb@133
   287
            {
vb@133
   288
                case DialogResult.Yes:
Dean@279
   289
                    {
Dean@290
   290
                        // Check if key was previously compromised -- warning for this must be displayed earlier
Dean@281
   291
                        if (identityPartner.comm_type == _pEp_comm_type.pEp_ct_compromized)
Dean@281
   292
                        {
Dean@281
   293
                            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@281
   294
                        }
Dean@281
   295
Dean@279
   296
                        identityPartner = ThisAddIn.pEp.trust_personal_key(ref identityPartner);
Dean@293
   297
                        this.associatedMailItem.ColorRating = _pEp_color.pEp_rating_trusted;
Dean@279
   298
Dean@279
   299
                        this.UpdateUIFromMailItem();
Dean@279
   300
Dean@279
   301
                        // Update the manager form state
Dean@279
   302
                        if (this.managerForm != null)
Dean@279
   303
                        {
Dean@279
   304
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   305
                        }
Dean@279
   306
Dean@279
   307
                        break;
Dean@279
   308
                    }
vb@133
   309
                case DialogResult.No:
Dean@279
   310
                    {
Dean@279
   311
                        ThisAddIn.pEp.key_compromized(ref identityPartner);
Dean@279
   312
                        identityPartner.comm_type = _pEp_comm_type.pEp_ct_compromized;
Dean@279
   313
                        identityPartner = ThisAddIn.pEp.update_identity(identityPartner);
Dean@293
   314
                        this.associatedMailItem.ColorRating = _pEp_color.pEp_rating_red;
Dean@279
   315
Dean@279
   316
                        this.UpdateUIFromMailItem();
Dean@279
   317
Dean@279
   318
                        // Update the manager form state
Dean@279
   319
                        if (this.managerForm != null)
Dean@279
   320
                        {
Dean@279
   321
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   322
                        }
Dean@279
   323
Dean@279
   324
                        break;
Dean@279
   325
                    }
vb@133
   326
            }
Dean@279
   327
Dean@279
   328
            return;
vb@133
   329
        }
vb@133
   330
Dean@179
   331
        /// <summary>
Dean@179
   332
        /// Reverses any past handshake confirmation by unconfirming the given identity partner.
Dean@179
   333
        /// </summary>
Dean@384
   334
        /// <param name="partner">The identity of the partner to unconfirm.</param>
Dean@384
   335
        private void UndoHandshake(PEPIdentity partner)
vb@133
   336
        {
Dean@384
   337
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
Dean@280
   338
            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@279
   339
Dean@179
   340
            this.UpdateUIFromMailItem();
Dean@279
   341
Dean@279
   342
            // Update the manager form state
Dean@279
   343
            if (this.managerForm != null)
Dean@279
   344
            {
Dean@279
   345
                this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   346
            }
Dean@279
   347
Dean@279
   348
            return;
vb@133
   349
        }
vb@133
   350
Dean@161
   351
        /// <summary>
Dean@363
   352
        /// Calculates both the short and full trustwords between the given personal identity and the identity partner.
Dean@363
   353
        /// </summary>
Dean@363
   354
        /// <param name="myIdentity">The personal identity.</param>
Dean@363
   355
        /// <param name="partnerIdentity">The identity of the partner.</param>
Dean@363
   356
        /// <param name="trustwordsShort">The short version of trustwords.</param>
Dean@363
   357
        /// <param name="trustwordsFull">The full/long version of trustwords.</param>
Dean@384
   358
        private void CalcTrustwords(PEPIdentity myIdentity,
Dean@384
   359
                                    PEPIdentity partnerIdentity,
Dean@363
   360
                                    out string trustwordsShort,
Dean@363
   361
                                    out string trustwordsFull)
Dean@363
   362
        {
Dean@363
   363
            string myShort;
Dean@363
   364
            string myLong;
Dean@363
   365
            string partnerShort;
Dean@363
   366
            string partnerLong;
Dean@363
   367
Dean@384
   368
            myShort = ThisAddIn.pEp.trustwords(myIdentity.Fingerprint, max_words: 5).ToLower();
Dean@384
   369
            myLong = ThisAddIn.pEp.trustwords(myIdentity.Fingerprint).ToLower();
Dean@384
   370
            partnerShort = ThisAddIn.pEp.trustwords(partnerIdentity.Fingerprint, max_words: 5).ToLower();
Dean@384
   371
            partnerLong = ThisAddIn.pEp.trustwords(partnerIdentity.Fingerprint).ToLower();
Dean@363
   372
Dean@384
   373
            if (myIdentity.Fingerprint.CompareTo(partnerIdentity.Fingerprint) > 0)
Dean@363
   374
            {
Dean@363
   375
                trustwordsShort = partnerShort + myShort;
Dean@363
   376
                trustwordsFull = partnerLong + myLong;
Dean@363
   377
            }
Dean@363
   378
            else
Dean@363
   379
            {
Dean@363
   380
                trustwordsShort = myShort + " " + partnerShort;
Dean@363
   381
                trustwordsFull = myLong + " " + partnerLong;
Dean@363
   382
            }
Dean@363
   383
Dean@363
   384
            return;
Dean@363
   385
        }
Dean@363
   386
Dean@363
   387
        /// <summary>
Dean@161
   388
        /// Formats the given text string as separated 4-character groups.
Dean@161
   389
        /// Example: 49422235FC99585B891C --> 4942 2235 FC99 585B 891C
Dean@161
   390
        /// </summary>
Dean@161
   391
        /// <param name="text">The text to format in 4-character groups.</param>
Dean@161
   392
        /// <returns>The re-formatted string.</returns>
Dean@161
   393
        private string ToQuadruple(string text)
Dean@159
   394
        {
Dean@159
   395
            List<string> result = new List<string>();
Dean@159
   396
Dean@161
   397
            if (text != null)
Dean@159
   398
            {
Dean@161
   399
                for (int i = 0; i < text.Length; i += 4)
Dean@159
   400
                {
Dean@161
   401
                    try
Dean@161
   402
                    {
Dean@161
   403
                        result.Add(text.Substring(i, 4));
Dean@161
   404
                    }
Dean@161
   405
                    catch (ArgumentOutOfRangeException)
Dean@161
   406
                    {
Dean@161
   407
                        result.Add(text.Substring(i));
Dean@161
   408
                        break;
Dean@161
   409
                    }
Dean@159
   410
                }
Dean@159
   411
            }
Dean@159
   412
Dean@159
   413
            return String.Join(" ", result);
Dean@159
   414
        }
markus@201
   415
Dean@196
   416
        /// <summary>
Dean@196
   417
        /// Makes the unencrypted preview form.
Dean@196
   418
        /// This gets the active form region then fills it's content.
Dean@196
   419
        /// </summary>
Dean@198
   420
        /// <returns>True if successful, otherwise false.</returns>
Dean@198
   421
        private bool MakePreview()
Dean@159
   422
        {
Dean@620
   423
            bool success = false;
Dean@198
   424
            bool isSuccessful;
Dean@198
   425
            byte[] rtfBody;
Dean@159
   426
            WindowFormRegionCollection formRegions;
Dean@620
   427
            PEPMessage mirror;
Dean@198
   428
            formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
Dean@159
   429
Dean@198
   430
            if ((formRegions != null) &&
Dean@198
   431
                (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@620
   432
                (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@198
   433
            {
Dean@620
   434
                formRegions.FormRegionPreviewUnencrypted.ClearMessage();
Dean@620
   435
                mirror = this.associatedMailItem.MirrorGet();
Dean@620
   436
Dean@620
   437
                if (mirror != null)
Dean@198
   438
                {
Dean@620
   439
                    // Attempt to the the RTF body
Dean@620
   440
                    isSuccessful = this.associatedMailItem.MirrorTryGetRTFBody(out rtfBody);
Dean@620
   441
                    if (isSuccessful == false)
Dean@620
   442
                    {
Dean@620
   443
                        return (false);
Dean@620
   444
                    }
Dean@620
   445
Dean@620
   446
                    formRegions.FormRegionPreviewUnencrypted.SetMessage(mirror);
Dean@620
   447
                    formRegions.FormRegionPreviewUnencrypted.SetRTFBody(System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length));
Dean@620
   448
                    success = true;
Dean@198
   449
                }
Dean@198
   450
            }
Dean@198
   451
Dean@198
   452
            return (success);
Dean@159
   453
        }
markus@201
   454
Dean@179
   455
        /// <summary>
Dean@279
   456
        /// Builds a new manager form state using this encryption state/mail item current state.
Dean@279
   457
        /// </summary>
Dean@279
   458
        /// <returns>A new manager form state.</returns>
Dean@313
   459
        private FormManagePrivacyStatus.State GetManagerState()
Dean@279
   460
        {
Dean@527
   461
            bool isMyself;
Dean@641
   462
            bool isContactSendUnencrypted;
Dean@364
   463
            string trustwordsShort;
Dean@364
   464
            string trustwordsFull;
Dean@384
   465
            List<PEPIdentity> identities;
Dean@384
   466
            PEPIdentity myIdentity;
Dean@384
   467
            PEPIdentity incomingIdent;
Dean@527
   468
            PEPIdentity[] myIdentities;
Dean@259
   469
            _pEp_color identityPartnerColor;
Dean@259
   470
            SelectionItem item;
Dean@312
   471
            PrivacyState state = this.CopyUIToState();
Dean@313
   472
            FormManagePrivacyStatus.State managerState = new FormManagePrivacyStatus.State();
Dean@259
   473
Dean@332
   474
            // Resolve all recipients -- this ensures the identities list is correctly populated
Dean@332
   475
            this.associatedMailItem.ResolveAllRecipients();
Dean@332
   476
Dean@279
   477
            managerState.VisualState = state.Copy();
Dean@279
   478
            managerState.IsIncoming = this.associatedMailItem.IsIncoming;
Dean@259
   479
Dean@259
   480
            if (this.associatedMailItem.IsIncoming)
Dean@259
   481
            {
Dean@384
   482
                identities = new List<PEPIdentity>();
Dean@259
   483
Dean@259
   484
                // Add only one identity
Dean@638
   485
                if (this.associatedMailItem.From != null)
Dean@638
   486
                {
Dean@638
   487
                    incomingIdent = new PEPIdentity();
Dean@638
   488
                    incomingIdent.Address = this.associatedMailItem.From.Address;
Dean@638
   489
                    incomingIdent.Username = this.associatedMailItem.From.Username;
Dean@638
   490
                    incomingIdent.UserID = Globals.ThisAddIn.GetUserID(incomingIdent.Address);
Dean@259
   491
Dean@638
   492
                    identities.Add(incomingIdent);
Dean@638
   493
                }
Dean@259
   494
            }
Dean@259
   495
            else
Dean@259
   496
            {
Dean@395
   497
                identities = this.associatedMailItem.Recipients;
Dean@259
   498
            }
Dean@259
   499
Dean@366
   500
            // Get my identity
Dean@633
   501
            myIdentity = this.associatedMailItem.Myself;
Dean@527
   502
            myIdentities = PEPIdentity.GetMyIdentities();
Dean@366
   503
Dean@279
   504
            // Add identities
Dean@394
   505
            identities = PEPIdentity.ToFlatList(identities);
Dean@279
   506
            managerState.Identities.Clear();
Dean@384
   507
            foreach (PEPIdentity ident in identities)
Dean@259
   508
            {
Dean@485
   509
                if (ident.IsValid())
Dean@485
   510
                {
Dean@485
   511
                    pEp_identity_s partnerIdentity_s = ThisAddIn.pEp.update_identity(ident.ToCOMType());
Dean@485
   512
                    PEPIdentity partnerIdentity = new PEPIdentity(partnerIdentity_s);
Dean@485
   513
                    identityPartnerColor = ThisAddIn.pEp.identity_color(partnerIdentity_s);
Dean@641
   514
                    isContactSendUnencrypted = Globals.ThisAddIn.ContactIsSendUnencryptedForced(partnerIdentity.Address);
Dean@259
   515
Dean@527
   516
                    // Check if identity is myself
Dean@527
   517
                    isMyself = false;
Dean@527
   518
                    foreach (PEPIdentity me in myIdentities)
Dean@527
   519
                    {
Dean@527
   520
                        if (partnerIdentity.EqualsByAddress(me))
Dean@527
   521
                        {
Dean@527
   522
                            isMyself = true;
Dean@527
   523
                            break;
Dean@527
   524
                        }
Dean@527
   525
                    }
Dean@527
   526
Dean@485
   527
                    item = new SelectionItem();
Dean@485
   528
                    item.TextLine1 = partnerIdentity.Username;
Dean@485
   529
                    item.TextLine2 = partnerIdentity.Address;
Dean@259
   530
Dean@485
   531
                    // Don't show both the user name and address if they are the same
Dean@485
   532
                    if ((item.TextLine1 != null) &&
Dean@485
   533
                        (item.TextLine2 != null) &&
Dean@485
   534
                        (item.TextLine1 == item.TextLine2))
Dean@485
   535
                    {
Dean@485
   536
                        item.IsTwoTextLinesVisible = false;
Dean@485
   537
                    }
Dean@332
   538
Dean@527
   539
                    // Calculate trustwords
Dean@527
   540
                    this.CalcTrustwords(myIdentity,
Dean@527
   541
                                        partnerIdentity,
Dean@527
   542
                                        out trustwordsShort,
Dean@527
   543
                                        out trustwordsFull);
Dean@527
   544
Dean@485
   545
                    // Set image
Dean@641
   546
                    if (isContactSendUnencrypted)
Dean@485
   547
                    {
Dean@641
   548
                        // Show the force unencrypted image indicating this is set by the user not the engine
Dean@641
   549
                        item.ItemImage = pEp.Properties.Resources.ImageRibbonForceUnencOpen;
Dean@641
   550
                    }
Dean@641
   551
                    else
Dean@641
   552
                    {
Dean@641
   553
                        switch (PrivacyState.ConvertRatingToPrivacyColor(identityPartnerColor))
Dean@641
   554
                        {
Dean@641
   555
                            case PrivacyState.PrivacyColor.Green:
Dean@641
   556
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusGreen;
Dean@641
   557
                                break;
Dean@641
   558
                            case PrivacyState.PrivacyColor.Yellow:
Dean@641
   559
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusYellow;
Dean@641
   560
                                break;
Dean@641
   561
                            case PrivacyState.PrivacyColor.Red:
Dean@641
   562
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusRed;
Dean@641
   563
                                break;
Dean@641
   564
                            case PrivacyState.PrivacyColor.NoColor:
Dean@641
   565
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusNoColor;
Dean@641
   566
                                break;
Dean@641
   567
                            default:
Dean@641
   568
                                item.ItemImage = null;
Dean@641
   569
                                break;
Dean@641
   570
                        }
Dean@485
   571
                    }
Dean@259
   572
Dean@485
   573
                    // Set button
Dean@641
   574
                    if ((isMyself == false) &&
Dean@641
   575
                        (isContactSendUnencrypted == false))
Dean@366
   576
                    {
Dean@485
   577
                        if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   578
                        {
Dean@485
   579
                            // Undo handshake
Dean@485
   580
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_StopTrusting;
Dean@485
   581
                            item.IsButtonVisible = true;
Dean@485
   582
                            item.ButtonOnClick = (x, y) => { this.UndoHandshake(partnerIdentity); };
Dean@356
   583
Dean@485
   584
                            item.IsExpandable = false;
Dean@485
   585
                        }
Dean@485
   586
                        else if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_unconfirmed_encryption &&
Dean@485
   587
                                 partnerIdentity.CommunicationType < _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   588
                        {
Dean@485
   589
                            // Do handshake
Dean@485
   590
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_HandshakeAdvanced;
Dean@485
   591
                            item.IsButtonVisible = true;
Dean@485
   592
                            item.ButtonOnClick = (x, y) => { this.DoHandshake(partnerIdentity); };
Dean@356
   593
Dean@485
   594
                            item.IsExpandable = true;
Dean@485
   595
                            item.ExpandedText = Properties.Resources.PrivacyStatus_TrustwordDesc + "\n\n" +
Dean@485
   596
                                                trustwordsShort;
Dean@447
   597
Dean@485
   598
                            item.ExpandedButton1Text = Properties.Resources.PrivacyStatus_SelectTrust;
Dean@485
   599
                            item.ExpandedButton1OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.Yes, partnerIdentity); };
Dean@485
   600
                            item.ExpandedButton1BackColor = PrivacyState.COLOR_GREEN;
Dean@485
   601
                            item.ExpandedButton1ForeColor = Color.White;
Dean@447
   602
Dean@485
   603
                            item.ExpandedButton2Text = Properties.Resources.PrivacyStatus_SelectMistrust;
Dean@485
   604
                            item.ExpandedButton2OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.No, partnerIdentity); };
Dean@485
   605
                            item.ExpandedButton2BackColor = PrivacyState.COLOR_RED;
Dean@485
   606
                            item.ExpandedButton2ForeColor = Color.White;
Dean@485
   607
                        }
Dean@485
   608
                        else if (partnerIdentity.CommunicationType == _pEp_comm_type.pEp_ct_compromized)
Dean@485
   609
                        {
Dean@485
   610
                            // Redo handshake with confirmation
Dean@485
   611
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@485
   612
                            item.IsButtonVisible = true;
Dean@485
   613
                            item.ButtonOnClick = (x, y) => { this.DoHandshakeForCompromisedKey(partnerIdentity); };
Dean@641
   614
Dean@641
   615
                            item.IsExpandable = false;
Dean@485
   616
                        }
Dean@485
   617
                        else
Dean@485
   618
                        {
Dean@485
   619
                            item.IsButtonVisible = false;
Dean@641
   620
                            item.IsExpandable = false;
Dean@485
   621
                        }
Dean@366
   622
                    }
Dean@366
   623
                    else
Dean@366
   624
                    {
Dean@366
   625
                        item.IsButtonVisible = false;
Dean@641
   626
                        item.IsExpandable = false;
Dean@366
   627
                    }
Dean@281
   628
                }
Dean@485
   629
                else // Invalid identity
Dean@259
   630
                {
Dean@485
   631
                    item = new SelectionItem();
Dean@485
   632
                    item.TextLine1 = ident.Username;
Dean@485
   633
                    item.TextLine2 = ident.Address;
Dean@485
   634
                    item.ItemImage = null;
Dean@485
   635
                    item.IsTwoTextLinesVisible = true;
Dean@259
   636
                    item.IsButtonVisible = false;
Dean@259
   637
                }
Dean@259
   638
Dean@279
   639
                managerState.Identities.Add(item);
Dean@259
   640
            }
Dean@259
   641
Dean@375
   642
            // Attempt to select the first identity requiring a handshake
Dean@375
   643
            for (int i = 0; i < managerState.Identities.Count; i++)
Dean@375
   644
            {
Dean@375
   645
                // Determine if it's a handshake identity by simply seeing if it's expandable
Dean@375
   646
                if (managerState.Identities[i].IsExpandable)
Dean@375
   647
                {
Dean@375
   648
                    managerState.SelectedIdentityIndex = i;
Dean@375
   649
                    break;
Dean@375
   650
                }
Dean@375
   651
            }
Dean@375
   652
Dean@279
   653
            return (managerState);
Dean@279
   654
        }
Dean@279
   655
Dean@279
   656
        /// <summary>
Dean@279
   657
        /// Builds the latest state of the encryption status manager then shows the UI.
Dean@279
   658
        /// </summary>
Dean@279
   659
        private void BuildAndShowManager()
Dean@279
   660
        {
Dean@279
   661
            DialogResult result;
Dean@313
   662
            FormManagePrivacyStatus form;
Dean@313
   663
            FormManagePrivacyStatus.State stateOut;
Dean@279
   664
Dean@483
   665
            try
Dean@483
   666
            {
Dean@483
   667
                // Show the form
Dean@483
   668
                form = new FormManagePrivacyStatus();
Dean@483
   669
                form.StartPosition = FormStartPosition.CenterScreen;
Dean@259
   670
Dean@483
   671
                this.managerForm = form;
Dean@483
   672
                result = form.ShowDialog(this.ParentForm, this.GetManagerState(), out stateOut); // Must show as dialog to block code
Dean@483
   673
            }
Dean@483
   674
            catch (Exception ex)
Dean@483
   675
            {
Dean@483
   676
                GlobalExceptionHandler.StopAndSendCrashReport(ex);
Dean@483
   677
            }
Dean@259
   678
Dean@259
   679
            return;
Dean@259
   680
        }
Dean@259
   681
Dean@259
   682
        /// <summary>
Dean@179
   683
        /// Updates the status of the UI state based on the associated mail item.
Dean@179
   684
        /// Any previous state changes in the UI are preserved.
Dean@179
   685
        /// </summary>
Dean@622
   686
        public void UpdateUIFromMailItem()
Dean@159
   687
        {
Dean@312
   688
            PrivacyState state;
Dean@342
   689
            bool? sendUnencryptedProperty;
Dean@159
   690
Dean@173
   691
            if (this.associatedMailItem != null)
Dean@159
   692
            {
Dean@342
   693
                sendUnencryptedProperty = this.associatedMailItem.SendUnencrypted;
Dean@342
   694
Dean@342
   695
                if ((sendUnencryptedProperty != null) &&
Dean@342
   696
                    ((bool)sendUnencryptedProperty == true))
Dean@159
   697
                {
Dean@342
   698
                    // Force unencrypted
Dean@312
   699
                    state = new PrivacyState(_pEp_color.pEp_rating_unencrypted);
Dean@159
   700
                }
Dean@159
   701
                else
Dean@159
   702
                {
Dean@312
   703
                    state = new PrivacyState(this.associatedMailItem.ColorRating);
Dean@159
   704
                }
Dean@179
   705
Dean@179
   706
                this.CopyStateToUI(state);
Dean@159
   707
            }
Dean@159
   708
Dean@179
   709
            return;
Dean@159
   710
        }
Dean@159
   711
Dean@172
   712
        #region StateMethods
Dean@172
   713
Dean@172
   714
        /// <summary>
Dean@172
   715
        /// Connects or disconnects all control events from the UI.
Dean@172
   716
        /// </summary>
Dean@172
   717
        /// <param name="connect">True to connect events, false to disconnect.</param>
Dean@172
   718
        private void ConnectEvents(bool connect)
Dean@172
   719
        {
Dean@172
   720
            // Connect events only if not already connected
markus@201
   721
            if ((connect == true) &&
Dean@172
   722
                (this.eventsAreConnected == false))
Dean@172
   723
            {
Dean@312
   724
                this.ButtonPrivacyStatus.Click += this.ButtonPrivacyStatus_Click;
Dean@312
   725
                this.ButtonPrivacyStatus.MouseUp += this.ButtonPrivacyStatus_MouseUp;
Dean@179
   726
Dean@172
   727
                this.eventsAreConnected = true;
Dean@172
   728
            }
Dean@172
   729
            // Always attempt to disconnect
Dean@172
   730
            else if (connect == false)
Dean@172
   731
            {
Dean@312
   732
                this.ButtonPrivacyStatus.Click -= this.ButtonPrivacyStatus_Click;
Dean@312
   733
                this.ButtonPrivacyStatus.MouseUp -= this.ButtonPrivacyStatus_MouseUp;
Dean@179
   734
Dean@172
   735
                this.eventsAreConnected = false;
Dean@172
   736
            }
Dean@172
   737
Dean@172
   738
            return;
Dean@172
   739
        }
Dean@172
   740
Dean@172
   741
        /// <summary>
Dean@172
   742
        /// Refreshes the UI by reloading the state.
Dean@172
   743
        /// </summary>
Dean@172
   744
        private void RefreshUI()
Dean@172
   745
        {
Dean@172
   746
            this.CopyStateToUI(this.CopyUIToState());
Dean@172
   747
            return;
Dean@172
   748
        }
Dean@172
   749
Dean@172
   750
        /// <summary>
Dean@172
   751
        /// Copies the given state to the UI.
Dean@172
   752
        /// Events are turned off until the process is complete.
Dean@172
   753
        /// </summary>
Dean@172
   754
        /// <param name="state">The state to set to the UI.</param>
Dean@312
   755
        private void CopyStateToUI(PrivacyState state)
Dean@172
   756
        {
Dean@172
   757
            this.ConnectEvents(false);
markus@201
   758
Dean@172
   759
            ///////////////////////////////////////////////////////////
Dean@172
   760
            // Set UI data
Dean@172
   761
            ///////////////////////////////////////////////////////////
Dean@172
   762
Dean@179
   763
            // Save UI state maintained outside of controls
Dean@312
   764
            this.stateUIColorRating = state.PrivacyStatus;
Dean@179
   765
Dean@312
   766
            this.ButtonPrivacyStatus.BackColor = state.BackgroundColor;
Dean@312
   767
            this.ButtonPrivacyStatus.ForeColor = state.ForegroundColor;
Dean@312
   768
            this.ButtonPrivacyStatus.Text = state.ShortText;
Dean@172
   769
Dean@172
   770
            this.ConnectEvents(true);
Dean@172
   771
Dean@172
   772
            return;
Dean@172
   773
        }
Dean@172
   774
Dean@172
   775
        /// <summary>
Dean@172
   776
        /// Copies the UI to a new state.
Dean@172
   777
        /// </summary>
Dean@172
   778
        /// <returns>The state of the UI.</returns>
Dean@312
   779
        private PrivacyState CopyUIToState()
Dean@172
   780
        {
Dean@312
   781
            return (new PrivacyState(this.stateUIColorRating));
Dean@172
   782
        }
Dean@172
   783
Dean@172
   784
        #endregion
Dean@172
   785
Dean@159
   786
        /**************************************************************
Dean@159
   787
         * 
Dean@159
   788
         * Event Handling
Dean@159
   789
         * 
Dean@159
   790
         *************************************************************/
Dean@159
   791
Dean@159
   792
        /// <summary>
Dean@159
   793
        /// Event handler that is called before the form region is displayed.
Dean@159
   794
        /// </summary>
Dean@312
   795
        private void FormRegionPrivacyStatus_FormRegionShowing(object sender, System.EventArgs e)
Dean@159
   796
        {
Dean@173
   797
            this.SetAssociatedMailItem();
Dean@173
   798
Dean@631
   799
            // Set background color for Office 2013
Dean@631
   800
            try
Dean@631
   801
            {
Dean@631
   802
                if (Globals.ThisAddIn.Application.Version.Substring(0, 2) == "15")
Dean@631
   803
                {
Dean@631
   804
                    if (this.IsWithinInspector())
Dean@631
   805
                    {
Dean@631
   806
                        this.BackColor = SystemColors.ButtonFace;
Dean@631
   807
                    }
Dean@631
   808
                    else
Dean@631
   809
                    {
Dean@631
   810
                        this.BackColor = SystemColors.Window;
Dean@631
   811
                    }
Dean@631
   812
                }
Dean@631
   813
            }
Dean@631
   814
            catch { }
Dean@631
   815
Dean@199
   816
            // Connect cryptable mail item events
Dean@189
   817
            if (this.associatedMailItem != null)
Dean@159
   818
            {
Dean@159
   819
                try
Dean@159
   820
                {
Dean@445
   821
                    this.associatedMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@179
   822
Dean@189
   823
                    if (this.associatedMailItem.IsInEncryptedStore &&
Dean@198
   824
                        this.associatedMailItem.IsPGPEncrypted)
Dean@159
   825
                    {
Dean@189
   826
                        this.associatedMailItem.Open += MailItem_Open;
Dean@159
   827
                    }
Dean@159
   828
                }
Dean@159
   829
                catch { }
Dean@179
   830
            }
Dean@159
   831
Dean@179
   832
            // Set the default UI state
Dean@312
   833
            this.CopyStateToUI(new PrivacyState());
Dean@179
   834
Dean@199
   835
            // Call the timer tick method manually to refresh data
Dean@199
   836
            this.TimerRefresh_Tick(null, new EventArgs());
Dean@179
   837
Dean@179
   838
            return;
Dean@159
   839
        }
Dean@159
   840
Dean@159
   841
        /// <summary>
Dean@159
   842
        /// Event handler for when the form region is closed.
Dean@159
   843
        /// </summary>
Dean@312
   844
        private void FormRegionPrivacyStatus_FormRegionClosed(object sender, System.EventArgs e)
Dean@159
   845
        {
Dean@199
   846
            // Disconnect cryptable mail item events
Dean@190
   847
            if (this.associatedMailItem != null)
Dean@179
   848
            {
Dean@179
   849
                try
Dean@179
   850
                {
Dean@445
   851
                    this.associatedMailItem.PropertyChanged -= MailItem_PropertyChanged;
markus@201
   852
                    this.associatedMailItem.Open -= MailItem_Open;
Dean@179
   853
                }
Dean@179
   854
                catch { }
Dean@179
   855
            }
Dean@179
   856
Dean@179
   857
            return;
Dean@179
   858
        }
Dean@179
   859
Dean@179
   860
        /// <summary>
Dean@179
   861
        /// Event handler called after the refresh timer has elapsed.
Dean@179
   862
        /// </summary>
Dean@179
   863
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
   864
        {
Dean@199
   865
            bool tryAgain = false;
Dean@199
   866
            bool isSuccessful;
Dean@179
   867
            this.TimerRefresh.Enabled = false; // Only once
markus@201
   868
Dean@179
   869
            // Ensure the tick method is not called more than once
Dean@179
   870
            if (refreshOngoing == false)
Dean@179
   871
            {
Dean@179
   872
                this.refreshOngoing = true;
Dean@179
   873
Dean@179
   874
                if (this.associatedMailItem != null)
Dean@179
   875
                {
Dean@179
   876
                    if (this.associatedMailItem.DownloadState == Outlook.OlDownloadState.olFullItem)
Dean@179
   877
                    {
Dean@179
   878
                        this.UpdateUIFromMailItem();
Dean@199
   879
Dean@199
   880
                        /* Create the unencrypted preview if the mail item is encrypted and
Dean@199
   881
                         * it is in an encrypted (untrusted) store
Dean@199
   882
                         * 
Dean@312
   883
                         * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Dean@199
   884
                         * it also is initialized after FormRegionPreviewUnencrypted.
Dean@199
   885
                         */
Dean@199
   886
                        if (this.associatedMailItem.IsInEncryptedStore &&
Dean@199
   887
                            this.associatedMailItem.IsPGPEncrypted)
Dean@199
   888
                        {
Dean@199
   889
                            isSuccessful = this.MakePreview();
Dean@199
   890
Dean@534
   891
                            // Disable try again as it never seems to recover in real-world testing
Dean@534
   892
                            /*if (isSuccessful == false)
Dean@199
   893
                            {
Dean@199
   894
                                tryAgain = true;
Dean@534
   895
                            }*/
Dean@199
   896
                        }
Dean@179
   897
                    }
Dean@179
   898
                    else
Dean@179
   899
                    {
Dean@179
   900
                        this.associatedMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Dean@199
   901
                        tryAgain = true;
Dean@179
   902
                    }
Dean@179
   903
                }
Dean@179
   904
Dean@199
   905
                // Set the timer to refresh again later automatically
Dean@199
   906
                if (tryAgain)
Dean@199
   907
                {
Dean@199
   908
                    this.TimerRefresh.Interval = 100;
Dean@199
   909
                    this.TimerRefresh.Enabled = true;
Dean@199
   910
                }
Dean@199
   911
Dean@179
   912
                this.refreshOngoing = false;
Dean@179
   913
            }
Dean@175
   914
Dean@159
   915
            return;
Dean@159
   916
        }
Dean@159
   917
Dean@169
   918
        /// <summary>
Dean@169
   919
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
   920
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
   921
        /// </summary>
Dean@169
   922
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
   923
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
   924
        /// and the inspector is not displayed.</param>
Dean@169
   925
        private void MailItem_Open(ref bool cancel)
Dean@159
   926
        {
Dean@173
   927
            if (this.associatedMailItem != null && this.associatedMailItem.MirrorDisplay())
Dean@169
   928
            {
Dean@169
   929
                cancel = true;
Dean@169
   930
            }
Dean@169
   931
Dean@169
   932
            return;
Dean@159
   933
        }
Dean@159
   934
Dean@169
   935
        /// <summary>
Dean@169
   936
        /// Event handler for when a mail item property is changed.
Dean@169
   937
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
   938
        /// </summary>
Dean@169
   939
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@445
   940
        private void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Dean@159
   941
        {
Dean@445
   942
            switch (e.PropertyName.ToUpper())
Dean@159
   943
            {
Dean@179
   944
                case "TO":
Dean@179
   945
                    // Start the refresh timer
Dean@179
   946
                    this.TimerRefresh.Enabled = true;
Dean@159
   947
                    break;
Dean@159
   948
                // Outlook bug: there are always both events, so one is enough
Dean@159
   949
                //case "CC":
Dean@179
   950
                //    // Start the refresh timer
Dean@179
   951
                //    this.TimerRefresh.Enabled = true;
Dean@159
   952
                //    break;
Dean@159
   953
            }
Dean@169
   954
Dean@169
   955
            return;
Dean@159
   956
        }
Dean@159
   957
Dean@179
   958
        /// <summary>
Dean@312
   959
        /// Event handler for when the privacy status button is clicked.
Dean@179
   960
        /// </summary>
Dean@312
   961
        private void ButtonPrivacyStatus_Click(object sender, EventArgs e)
vb@133
   962
        {
Dean@310
   963
            this.BuildAndShowManager();
Dean@179
   964
            return;
vb@133
   965
        }
vb@133
   966
Dean@179
   967
        /// <summary>
Dean@312
   968
        /// Event handler for when a mouse button is released over the privacy status button.
Dean@179
   969
        /// </summary>
Dean@312
   970
        private void ButtonPrivacyStatus_MouseUp(object sender, MouseEventArgs e)
vb@133
   971
        {
Dean@179
   972
            return;
vb@133
   973
        }
vb@133
   974
    }
vb@133
   975
}