UI/FormRegionPrivacyStatus.cs
author Dean Looyengoed
Mon, 21 Mar 2016 21:12:51 +0100
changeset 709 beb17ca67621
parent 704 0218918dda31
child 713 0035e6809ef2
permissions -rw-r--r--
Revise the UI update process for the FormRegionPrivacyStatus.
This now implements the background thread to GetMirror and update the preview.
Indication is now given in the UI for 'Opening' and it's generally more responsive.
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@680
    79
        private CryptableMailItem       associatedMailItem = null;
Dean@680
    80
        private bool                    eventsAreConnected = false;
Dean@680
    81
        private bool                    initialized        = false;
Dean@680
    82
        private FormManagePrivacyStatus managerForm        = null;
Dean@680
    83
        private bool                    refreshOngoing     = false;
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@672
   191
        /// Completes the handshake process when the identity of a partner was previously marked as mistrusted.
Dean@281
   192
        /// </summary>
Dean@646
   193
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   194
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@672
   195
        private void DoHandshakeForMistrustedKey(PEPIdentity myself,
Dean@672
   196
                                                 PEPIdentity partner)
Dean@281
   197
        {
Dean@281
   198
            DialogResult result;
Dean@281
   199
Dean@281
   200
            result = MessageBox.Show(this.ParentForm,
Dean@672
   201
                                     pEp.Properties.Resources.Message_WarningMistrustedKey,
Dean@378
   202
                                     pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@423
   203
                                     MessageBoxButtons.YesNo);
Dean@281
   204
Dean@423
   205
            if (result == DialogResult.Yes)
Dean@281
   206
            {
Dean@646
   207
                this.DoHandshake(myself, partner);
Dean@281
   208
            }
Dean@281
   209
Dean@281
   210
            return;
Dean@281
   211
        }
Dean@281
   212
Dean@281
   213
        /// <summary>
Dean@281
   214
        /// Completes the handshake process where the identity of a partner is confirmed.
Dean@179
   215
        /// </summary>
Dean@646
   216
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   217
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@646
   218
        private void DoHandshake(PEPIdentity myself,
Dean@646
   219
                                 PEPIdentity partner)
vb@133
   220
        {
Dean@155
   221
            string ownFpr;
Dean@155
   222
            string partnerFpr;
Dean@363
   223
            string trustwordsShort;
Dean@363
   224
            string trustwordsFull;
Dean@155
   225
            string[] lines;
Dean@179
   226
            DialogResult result;
Dean@155
   227
            FormHandshake handshakeDialog;
Dean@155
   228
            FormHandshake.State state = new FormHandshake.State();
markus@201
   229
Dean@660
   230
            Global.AddToLog("DoHandshake: handshake started.");
vb@139
   231
Dean@363
   232
            // Process identities
Dean@646
   233
            if (partner.Username == "")
Dean@363
   234
            {
Dean@646
   235
                partner.Username = partner.Address;
vb@133
   236
            }
Dean@646
   237
            partner.UserID = Globals.ThisAddIn.GetUserID(partner.Address);
Dean@363
   238
Dean@363
   239
            // Calculate and add trustwords
Dean@646
   240
            this.CalcTrustwords(myself, partner, out trustwordsShort, out trustwordsFull);
Dean@646
   241
            state.Myself = myself.Copy();
Dean@646
   242
            state.Partner = partner.Copy();
Dean@363
   243
            state.TrustwordsShort = trustwordsShort;
Dean@363
   244
            state.TrustwordsFull = trustwordsFull;
Dean@363
   245
Dean@363
   246
            // Calculate and add fingerprint
Dean@646
   247
            ownFpr = this.ToQuadruple(myself.Fingerprint);
Dean@646
   248
            partnerFpr = this.ToQuadruple(partner.Fingerprint);
vb@133
   249
Dean@646
   250
            if (myself.Fingerprint.CompareTo(partner.Fingerprint) > 0)
vb@133
   251
            {
Dean@155
   252
                lines = new string[3];
Dean@378
   253
                lines[0] = pEp.Properties.Resources.PrivacyStatus_TrustwordsPartnerShortPartner + partnerFpr;
Dean@378
   254
                lines[2] = pEp.Properties.Resources.PrivacyStatus_TrustwordsPartnerShortMyself + ownFpr;
Dean@155
   255
                state.Fingerprint = lines;
vb@133
   256
            }
vb@133
   257
            else
vb@133
   258
            {
Dean@155
   259
                lines = new string[3];
Dean@378
   260
                lines[0] = pEp.Properties.Resources.PrivacyStatus_TrustwordsOwnShortMyself + ownFpr;
Dean@378
   261
                lines[2] = pEp.Properties.Resources.PrivacyStatus_TrustwordsOwnShortPartner + partnerFpr;
Dean@155
   262
                state.Fingerprint = lines;
vb@133
   263
            }
vb@133
   264
Dean@155
   265
            // Create and show handshake dialog
Dean@155
   266
            handshakeDialog = new FormHandshake(state);
Dean@179
   267
            handshakeDialog.StartPosition = FormStartPosition.CenterScreen;
Dean@179
   268
            result = handshakeDialog.ShowDialog(this);
Dean@155
   269
Dean@646
   270
            this.ProcessDoHandshakeResult(result, partner);
Dean@356
   271
Dean@356
   272
            return;
Dean@356
   273
        }
Dean@356
   274
Dean@356
   275
        /// <summary>
Dean@356
   276
        /// Processes the result of the do handshake dialog after a user makes a selection.
Dean@356
   277
        /// </summary>
Dean@356
   278
        /// <param name="result">The result of the handshake dialog selection.</param>
Dean@356
   279
        /// <param name="partner">The identity of the partner to handshake with.</param>
Dean@356
   280
        private void ProcessDoHandshakeResult(DialogResult result,
Dean@384
   281
                                              PEPIdentity partner)
Dean@356
   282
        {
Dean@384
   283
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
vb@133
   284
vb@133
   285
            switch (result)
vb@133
   286
            {
vb@133
   287
                case DialogResult.Yes:
Dean@279
   288
                    {
Dean@672
   289
                        // Check if key was previously mistrusted -- warning to user must be displayed earlier
Dean@672
   290
                        if (identityPartner.comm_type == _pEp_comm_type.pEp_ct_mistrusted)
Dean@281
   291
                        {
Dean@281
   292
                            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@281
   293
                        }
Dean@281
   294
Dean@279
   295
                        identityPartner = ThisAddIn.pEp.trust_personal_key(ref identityPartner);
Dean@279
   296
Dean@279
   297
                        this.UpdateUIFromMailItem();
Dean@279
   298
Dean@279
   299
                        // Update the manager form state
Dean@279
   300
                        if (this.managerForm != null)
Dean@279
   301
                        {
Dean@279
   302
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   303
                        }
Dean@279
   304
Dean@279
   305
                        break;
Dean@279
   306
                    }
vb@133
   307
                case DialogResult.No:
Dean@279
   308
                    {
Dean@279
   309
                        ThisAddIn.pEp.key_compromized(ref identityPartner);
Dean@279
   310
Dean@279
   311
                        this.UpdateUIFromMailItem();
Dean@279
   312
Dean@279
   313
                        // Update the manager form state
Dean@279
   314
                        if (this.managerForm != null)
Dean@279
   315
                        {
Dean@279
   316
                            this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   317
                        }
Dean@279
   318
Dean@279
   319
                        break;
Dean@279
   320
                    }
vb@133
   321
            }
Dean@279
   322
Dean@279
   323
            return;
vb@133
   324
        }
vb@133
   325
Dean@179
   326
        /// <summary>
Dean@179
   327
        /// Reverses any past handshake confirmation by unconfirming the given identity partner.
Dean@179
   328
        /// </summary>
Dean@384
   329
        /// <param name="partner">The identity of the partner to unconfirm.</param>
Dean@384
   330
        private void UndoHandshake(PEPIdentity partner)
vb@133
   331
        {
Dean@384
   332
            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(partner.ToCOMType());
Dean@280
   333
            ThisAddIn.pEp.key_reset_trust(ref identityPartner);
Dean@279
   334
Dean@179
   335
            this.UpdateUIFromMailItem();
Dean@279
   336
Dean@279
   337
            // Update the manager form state
Dean@279
   338
            if (this.managerForm != null)
Dean@279
   339
            {
Dean@279
   340
                this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@279
   341
            }
Dean@279
   342
Dean@279
   343
            return;
vb@133
   344
        }
vb@133
   345
Dean@161
   346
        /// <summary>
Dean@363
   347
        /// Calculates both the short and full trustwords between the given personal identity and the identity partner.
Dean@363
   348
        /// </summary>
Dean@646
   349
        /// <param name="myself">The personal identity.</param>
Dean@646
   350
        /// <param name="partner">The identity of the partner.</param>
Dean@363
   351
        /// <param name="trustwordsShort">The short version of trustwords.</param>
Dean@363
   352
        /// <param name="trustwordsFull">The full/long version of trustwords.</param>
Dean@646
   353
        private void CalcTrustwords(PEPIdentity myself,
Dean@646
   354
                                    PEPIdentity partner,
Dean@363
   355
                                    out string trustwordsShort,
Dean@363
   356
                                    out string trustwordsFull)
Dean@363
   357
        {
Dean@363
   358
            string myShort;
Dean@363
   359
            string myLong;
Dean@363
   360
            string partnerShort;
Dean@363
   361
            string partnerLong;
Dean@363
   362
Dean@674
   363
            myShort = ThisAddIn.pEp.trustwords(myself.Fingerprint, max_words: 5);
Dean@674
   364
            myLong = ThisAddIn.pEp.trustwords(myself.Fingerprint);
Dean@674
   365
            partnerShort = ThisAddIn.pEp.trustwords(partner.Fingerprint, max_words: 5);
Dean@674
   366
            partnerLong = ThisAddIn.pEp.trustwords(partner.Fingerprint);
Dean@363
   367
Dean@646
   368
            if (myself.Fingerprint.CompareTo(partner.Fingerprint) > 0)
Dean@363
   369
            {
Dean@363
   370
                trustwordsShort = partnerShort + myShort;
Dean@363
   371
                trustwordsFull = partnerLong + myLong;
Dean@363
   372
            }
Dean@363
   373
            else
Dean@363
   374
            {
Dean@673
   375
                trustwordsShort = myShort + partnerShort;
Dean@673
   376
                trustwordsFull = myLong + partnerLong;
Dean@363
   377
            }
Dean@363
   378
Dean@363
   379
            return;
Dean@363
   380
        }
Dean@363
   381
Dean@363
   382
        /// <summary>
Dean@161
   383
        /// Formats the given text string as separated 4-character groups.
Dean@161
   384
        /// Example: 49422235FC99585B891C --> 4942 2235 FC99 585B 891C
Dean@161
   385
        /// </summary>
Dean@161
   386
        /// <param name="text">The text to format in 4-character groups.</param>
Dean@161
   387
        /// <returns>The re-formatted string.</returns>
Dean@161
   388
        private string ToQuadruple(string text)
Dean@159
   389
        {
Dean@159
   390
            List<string> result = new List<string>();
Dean@159
   391
Dean@161
   392
            if (text != null)
Dean@159
   393
            {
Dean@161
   394
                for (int i = 0; i < text.Length; i += 4)
Dean@159
   395
                {
Dean@161
   396
                    try
Dean@161
   397
                    {
Dean@161
   398
                        result.Add(text.Substring(i, 4));
Dean@161
   399
                    }
Dean@161
   400
                    catch (ArgumentOutOfRangeException)
Dean@161
   401
                    {
Dean@161
   402
                        result.Add(text.Substring(i));
Dean@161
   403
                        break;
Dean@161
   404
                    }
Dean@159
   405
                }
Dean@159
   406
            }
Dean@159
   407
Dean@159
   408
            return String.Join(" ", result);
Dean@159
   409
        }
markus@201
   410
Dean@196
   411
        /// <summary>
Dean@279
   412
        /// Builds a new manager form state using this encryption state/mail item current state.
Dean@279
   413
        /// </summary>
Dean@279
   414
        /// <returns>A new manager form state.</returns>
Dean@313
   415
        private FormManagePrivacyStatus.State GetManagerState()
Dean@279
   416
        {
Dean@527
   417
            bool isMyself;
Dean@664
   418
            bool forceUnencrypted;
Dean@364
   419
            string trustwordsShort;
Dean@364
   420
            string trustwordsFull;
Dean@384
   421
            List<PEPIdentity> identities;
Dean@384
   422
            PEPIdentity myIdentity;
Dean@384
   423
            PEPIdentity incomingIdent;
Dean@527
   424
            PEPIdentity[] myIdentities;
Dean@259
   425
            _pEp_color identityPartnerColor;
Dean@259
   426
            SelectionItem item;
Dean@312
   427
            PrivacyState state = this.CopyUIToState();
Dean@313
   428
            FormManagePrivacyStatus.State managerState = new FormManagePrivacyStatus.State();
Dean@259
   429
Dean@332
   430
            // Resolve all recipients -- this ensures the identities list is correctly populated
Dean@332
   431
            this.associatedMailItem.ResolveAllRecipients();
Dean@332
   432
Dean@279
   433
            managerState.VisualState = state.Copy();
Dean@279
   434
            managerState.IsIncoming = this.associatedMailItem.IsIncoming;
Dean@259
   435
Dean@653
   436
            if (managerState.IsIncoming)
Dean@259
   437
            {
Dean@384
   438
                identities = new List<PEPIdentity>();
Dean@259
   439
Dean@259
   440
                // Add only one identity
Dean@638
   441
                if (this.associatedMailItem.From != null)
Dean@638
   442
                {
Dean@638
   443
                    incomingIdent = new PEPIdentity();
Dean@638
   444
                    incomingIdent.Address = this.associatedMailItem.From.Address;
Dean@638
   445
                    incomingIdent.Username = this.associatedMailItem.From.Username;
Dean@638
   446
                    incomingIdent.UserID = Globals.ThisAddIn.GetUserID(incomingIdent.Address);
Dean@259
   447
Dean@638
   448
                    identities.Add(incomingIdent);
Dean@638
   449
                }
Dean@259
   450
            }
Dean@259
   451
            else
Dean@259
   452
            {
Dean@395
   453
                identities = this.associatedMailItem.Recipients;
Dean@259
   454
            }
Dean@259
   455
Dean@366
   456
            // Get my identity
Dean@633
   457
            myIdentity = this.associatedMailItem.Myself;
Dean@527
   458
            myIdentities = PEPIdentity.GetMyIdentities();
Dean@366
   459
Dean@279
   460
            // Add identities
Dean@394
   461
            identities = PEPIdentity.ToFlatList(identities);
Dean@279
   462
            managerState.Identities.Clear();
Dean@384
   463
            foreach (PEPIdentity ident in identities)
Dean@259
   464
            {
Dean@648
   465
                if (ident.IsValid)
Dean@485
   466
                {
Dean@485
   467
                    pEp_identity_s partnerIdentity_s = ThisAddIn.pEp.update_identity(ident.ToCOMType());
Dean@485
   468
                    PEPIdentity partnerIdentity = new PEPIdentity(partnerIdentity_s);
Dean@485
   469
                    identityPartnerColor = ThisAddIn.pEp.identity_color(partnerIdentity_s);
Dean@664
   470
                    forceUnencrypted = Globals.ThisAddIn.ContactIsForceUnencrypted(partnerIdentity.Address);
Dean@259
   471
Dean@527
   472
                    // Check if identity is myself
Dean@527
   473
                    isMyself = false;
Dean@527
   474
                    foreach (PEPIdentity me in myIdentities)
Dean@527
   475
                    {
Dean@527
   476
                        if (partnerIdentity.EqualsByAddress(me))
Dean@527
   477
                        {
Dean@527
   478
                            isMyself = true;
Dean@527
   479
                            break;
Dean@527
   480
                        }
Dean@527
   481
                    }
Dean@527
   482
Dean@485
   483
                    item = new SelectionItem();
Dean@485
   484
                    item.TextLine1 = partnerIdentity.Username;
Dean@485
   485
                    item.TextLine2 = partnerIdentity.Address;
Dean@259
   486
Dean@485
   487
                    // Don't show both the user name and address if they are the same
Dean@485
   488
                    if ((item.TextLine1 != null) &&
Dean@485
   489
                        (item.TextLine2 != null) &&
Dean@485
   490
                        (item.TextLine1 == item.TextLine2))
Dean@485
   491
                    {
Dean@485
   492
                        item.IsTwoTextLinesVisible = false;
Dean@485
   493
                    }
Dean@332
   494
Dean@527
   495
                    // Calculate trustwords
Dean@527
   496
                    this.CalcTrustwords(myIdentity,
Dean@527
   497
                                        partnerIdentity,
Dean@527
   498
                                        out trustwordsShort,
Dean@527
   499
                                        out trustwordsFull);
Dean@527
   500
Dean@485
   501
                    // Set image
Dean@664
   502
                    if ((forceUnencrypted) &&
Dean@653
   503
                        (managerState.IsIncoming == false))
Dean@485
   504
                    {
Dean@641
   505
                        // Show the force unencrypted image indicating this is set by the user not the engine
Dean@642
   506
                        item.ItemImage = pEp.Properties.Resources.ImageForceUnencOn;
Dean@641
   507
                    }
Dean@641
   508
                    else
Dean@641
   509
                    {
Dean@641
   510
                        switch (PrivacyState.ConvertRatingToPrivacyColor(identityPartnerColor))
Dean@641
   511
                        {
Dean@641
   512
                            case PrivacyState.PrivacyColor.Green:
Dean@641
   513
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusGreen;
Dean@641
   514
                                break;
Dean@641
   515
                            case PrivacyState.PrivacyColor.Yellow:
Dean@641
   516
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusYellow;
Dean@641
   517
                                break;
Dean@641
   518
                            case PrivacyState.PrivacyColor.Red:
Dean@641
   519
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusRed;
Dean@641
   520
                                break;
Dean@641
   521
                            case PrivacyState.PrivacyColor.NoColor:
Dean@641
   522
                                item.ItemImage = pEp.Properties.Resources.ImagePrivacyStatusNoColor;
Dean@641
   523
                                break;
Dean@641
   524
                            default:
Dean@641
   525
                                item.ItemImage = null;
Dean@641
   526
                                break;
Dean@641
   527
                        }
Dean@485
   528
                    }
Dean@259
   529
Dean@485
   530
                    // Set button
Dean@653
   531
                    if ((isMyself) ||
Dean@664
   532
                        ((forceUnencrypted) &&
Dean@653
   533
                         (managerState.IsIncoming == false)))
Dean@653
   534
                    {
Dean@653
   535
                        item.IsButtonVisible = false;
Dean@653
   536
                        item.IsExpandable = false;
Dean@653
   537
                    }
Dean@653
   538
                    else
Dean@366
   539
                    {
Dean@485
   540
                        if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   541
                        {
Dean@485
   542
                            // Undo handshake
Dean@485
   543
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_StopTrusting;
Dean@485
   544
                            item.IsButtonVisible = true;
Dean@646
   545
                            item.ButtonOnClick = (x, y) => { this.UndoHandshake(partnerIdentity.Copy()); };
Dean@356
   546
Dean@485
   547
                            item.IsExpandable = false;
Dean@485
   548
                        }
Dean@485
   549
                        else if (partnerIdentity.CommunicationType >= _pEp_comm_type.pEp_ct_unconfirmed_encryption &&
Dean@485
   550
                                 partnerIdentity.CommunicationType < _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@485
   551
                        {
Dean@485
   552
                            // Do handshake
Dean@485
   553
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_HandshakeAdvanced;
Dean@485
   554
                            item.IsButtonVisible = true;
Dean@646
   555
                            item.ButtonOnClick = (x, y) => { this.DoHandshake(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@356
   556
Dean@485
   557
                            item.IsExpandable = true;
Dean@485
   558
                            item.ExpandedText = Properties.Resources.PrivacyStatus_TrustwordDesc + "\n\n" +
Dean@485
   559
                                                trustwordsShort;
Dean@447
   560
Dean@485
   561
                            item.ExpandedButton1Text = Properties.Resources.PrivacyStatus_SelectTrust;
Dean@646
   562
                            item.ExpandedButton1OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.Yes, partnerIdentity.Copy()); };
Dean@485
   563
                            item.ExpandedButton1BackColor = PrivacyState.COLOR_GREEN;
Dean@485
   564
                            item.ExpandedButton1ForeColor = Color.White;
Dean@447
   565
Dean@485
   566
                            item.ExpandedButton2Text = Properties.Resources.PrivacyStatus_SelectMistrust;
Dean@646
   567
                            item.ExpandedButton2OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.No, partnerIdentity.Copy()); };
Dean@485
   568
                            item.ExpandedButton2BackColor = PrivacyState.COLOR_RED;
Dean@485
   569
                            item.ExpandedButton2ForeColor = Color.White;
Dean@485
   570
                        }
Dean@672
   571
                        else if (partnerIdentity.CommunicationType == _pEp_comm_type.pEp_ct_mistrusted)
Dean@485
   572
                        {
Dean@485
   573
                            // Redo handshake with confirmation
Dean@485
   574
                            item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@485
   575
                            item.IsButtonVisible = true;
Dean@672
   576
                            item.ButtonOnClick = (x, y) => { this.DoHandshakeForMistrustedKey(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@641
   577
Dean@641
   578
                            item.IsExpandable = false;
Dean@485
   579
                        }
Dean@485
   580
                        else
Dean@485
   581
                        {
Dean@485
   582
                            item.IsButtonVisible = false;
Dean@641
   583
                            item.IsExpandable = false;
Dean@485
   584
                        }
Dean@366
   585
                    }
Dean@281
   586
                }
Dean@485
   587
                else // Invalid identity
Dean@259
   588
                {
Dean@485
   589
                    item = new SelectionItem();
Dean@485
   590
                    item.TextLine1 = ident.Username;
Dean@485
   591
                    item.TextLine2 = ident.Address;
Dean@485
   592
                    item.ItemImage = null;
Dean@485
   593
                    item.IsTwoTextLinesVisible = true;
Dean@259
   594
                    item.IsButtonVisible = false;
Dean@259
   595
                }
Dean@259
   596
Dean@279
   597
                managerState.Identities.Add(item);
Dean@259
   598
            }
Dean@259
   599
Dean@375
   600
            // Attempt to select the first identity requiring a handshake
Dean@375
   601
            for (int i = 0; i < managerState.Identities.Count; i++)
Dean@375
   602
            {
Dean@375
   603
                // Determine if it's a handshake identity by simply seeing if it's expandable
Dean@375
   604
                if (managerState.Identities[i].IsExpandable)
Dean@375
   605
                {
Dean@375
   606
                    managerState.SelectedIdentityIndex = i;
Dean@375
   607
                    break;
Dean@375
   608
                }
Dean@375
   609
            }
Dean@375
   610
Dean@279
   611
            return (managerState);
Dean@279
   612
        }
Dean@279
   613
Dean@279
   614
        /// <summary>
Dean@279
   615
        /// Builds the latest state of the encryption status manager then shows the UI.
Dean@279
   616
        /// </summary>
Dean@279
   617
        private void BuildAndShowManager()
Dean@279
   618
        {
Dean@279
   619
            DialogResult result;
Dean@313
   620
            FormManagePrivacyStatus form;
Dean@313
   621
            FormManagePrivacyStatus.State stateOut;
Dean@279
   622
Dean@483
   623
            try
Dean@483
   624
            {
Dean@483
   625
                // Show the form
Dean@483
   626
                form = new FormManagePrivacyStatus();
Dean@483
   627
                form.StartPosition = FormStartPosition.CenterScreen;
Dean@259
   628
Dean@483
   629
                this.managerForm = form;
Dean@483
   630
                result = form.ShowDialog(this.ParentForm, this.GetManagerState(), out stateOut); // Must show as dialog to block code
Dean@483
   631
            }
Dean@483
   632
            catch (Exception ex)
Dean@483
   633
            {
Dean@660
   634
                Global.StopAndSendCrashReport(ex);
Dean@483
   635
            }
Dean@259
   636
Dean@259
   637
            return;
Dean@259
   638
        }
Dean@259
   639
Dean@259
   640
        /// <summary>
Dean@179
   641
        /// Updates the status of the UI state based on the associated mail item.
Dean@179
   642
        /// </summary>
Dean@622
   643
        public void UpdateUIFromMailItem()
Dean@159
   644
        {
Dean@312
   645
            PrivacyState state;
Dean@664
   646
            bool? forceUnencryptedProperty;
Dean@159
   647
Dean@173
   648
            if (this.associatedMailItem != null)
Dean@159
   649
            {
Dean@664
   650
                forceUnencryptedProperty = this.associatedMailItem.ForceUnencrypted;
Dean@342
   651
Dean@664
   652
                if ((forceUnencryptedProperty != null) &&
Dean@664
   653
                    ((bool)forceUnencryptedProperty == true))
Dean@159
   654
                {
Dean@342
   655
                    // Force unencrypted
Dean@312
   656
                    state = new PrivacyState(_pEp_color.pEp_rating_unencrypted);
Dean@680
   657
                    this.CopyStateToUI(state);
Dean@159
   658
                }
Dean@159
   659
                else
Dean@159
   660
                {
Dean@680
   661
                    // Start the color rating calculation/decryption process
Dean@680
   662
                    this.associatedMailItem.StartDecryption();
Dean@159
   663
                }
Dean@159
   664
            }
Dean@159
   665
Dean@179
   666
            return;
Dean@159
   667
        }
Dean@159
   668
Dean@709
   669
        /// <summary>
Dean@709
   670
        /// Clears the associated unencrypted preview and displays the given note (if any).
Dean@709
   671
        /// </summary>
Dean@709
   672
        /// <param name="note">The note to diplsay.</param>
Dean@709
   673
        private void ClearPreview(string note = null)
Dean@709
   674
        {
Dean@709
   675
            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
Dean@709
   676
Dean@709
   677
            if ((formRegions != null) &&
Dean@709
   678
                (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@709
   679
                (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@709
   680
            {
Dean@709
   681
                formRegions.FormRegionPreviewUnencrypted.ClearMessage();
Dean@709
   682
                formRegions.FormRegionPreviewUnencrypted.SetNote(note);
Dean@709
   683
            }
Dean@709
   684
Dean@709
   685
            return;
Dean@709
   686
        }
Dean@709
   687
Dean@172
   688
        #region StateMethods
Dean@172
   689
Dean@172
   690
        /// <summary>
Dean@172
   691
        /// Connects or disconnects all control events from the UI.
Dean@172
   692
        /// </summary>
Dean@172
   693
        /// <param name="connect">True to connect events, false to disconnect.</param>
Dean@172
   694
        private void ConnectEvents(bool connect)
Dean@172
   695
        {
Dean@172
   696
            // Connect events only if not already connected
markus@201
   697
            if ((connect == true) &&
Dean@172
   698
                (this.eventsAreConnected == false))
Dean@172
   699
            {
Dean@312
   700
                this.ButtonPrivacyStatus.Click += this.ButtonPrivacyStatus_Click;
Dean@312
   701
                this.ButtonPrivacyStatus.MouseUp += this.ButtonPrivacyStatus_MouseUp;
Dean@179
   702
Dean@172
   703
                this.eventsAreConnected = true;
Dean@172
   704
            }
Dean@172
   705
            // Always attempt to disconnect
Dean@172
   706
            else if (connect == false)
Dean@172
   707
            {
Dean@312
   708
                this.ButtonPrivacyStatus.Click -= this.ButtonPrivacyStatus_Click;
Dean@312
   709
                this.ButtonPrivacyStatus.MouseUp -= this.ButtonPrivacyStatus_MouseUp;
Dean@179
   710
Dean@172
   711
                this.eventsAreConnected = false;
Dean@172
   712
            }
Dean@172
   713
Dean@172
   714
            return;
Dean@172
   715
        }
Dean@172
   716
Dean@172
   717
        /// <summary>
Dean@172
   718
        /// Copies the given state to the UI.
Dean@172
   719
        /// Events are turned off until the process is complete.
Dean@172
   720
        /// </summary>
Dean@172
   721
        /// <param name="state">The state to set to the UI.</param>
Dean@312
   722
        private void CopyStateToUI(PrivacyState state)
Dean@172
   723
        {
Dean@172
   724
            this.ConnectEvents(false);
markus@201
   725
Dean@172
   726
            ///////////////////////////////////////////////////////////
Dean@172
   727
            // Set UI data
Dean@172
   728
            ///////////////////////////////////////////////////////////
Dean@172
   729
Dean@179
   730
            // Save UI state maintained outside of controls
Dean@312
   731
            this.stateUIColorRating = state.PrivacyStatus;
Dean@179
   732
Dean@312
   733
            this.ButtonPrivacyStatus.BackColor = state.BackgroundColor;
Dean@312
   734
            this.ButtonPrivacyStatus.ForeColor = state.ForegroundColor;
Dean@312
   735
            this.ButtonPrivacyStatus.Text = state.ShortText;
Dean@172
   736
Dean@670
   737
            // Update the manager form state
Dean@670
   738
            if (this.managerForm != null)
Dean@670
   739
            {
Dean@670
   740
                this.managerForm.CopyStateToUI(this.GetManagerState());
Dean@670
   741
            }
Dean@670
   742
Dean@172
   743
            this.ConnectEvents(true);
Dean@172
   744
Dean@172
   745
            return;
Dean@172
   746
        }
Dean@172
   747
Dean@172
   748
        /// <summary>
Dean@172
   749
        /// Copies the UI to a new state.
Dean@172
   750
        /// </summary>
Dean@172
   751
        /// <returns>The state of the UI.</returns>
Dean@312
   752
        private PrivacyState CopyUIToState()
Dean@172
   753
        {
Dean@312
   754
            return (new PrivacyState(this.stateUIColorRating));
Dean@172
   755
        }
Dean@172
   756
Dean@172
   757
        #endregion
Dean@172
   758
Dean@159
   759
        /**************************************************************
Dean@159
   760
         * 
Dean@159
   761
         * Event Handling
Dean@159
   762
         * 
Dean@159
   763
         *************************************************************/
Dean@159
   764
Dean@159
   765
        /// <summary>
Dean@680
   766
        /// Event handler that is called when the form region is displayed.
Dean@680
   767
        /// This is called each time the form region looses then regains visiblity 
Dean@680
   768
        /// (for example an other email is selected then back to this one).
Dean@159
   769
        /// </summary>
Dean@312
   770
        private void FormRegionPrivacyStatus_FormRegionShowing(object sender, System.EventArgs e)
Dean@159
   771
        {
Dean@680
   772
            // Do not allow initialization more than once
Dean@680
   773
            if (initialized == false)
Dean@680
   774
            {
Dean@680
   775
                this.SetAssociatedMailItem();
Dean@173
   776
Dean@680
   777
                // Set background color for Office 2013
Dean@159
   778
                try
Dean@159
   779
                {
Dean@680
   780
                    if (Globals.ThisAddIn.Application.Version.Substring(0, 2) == "15")
Dean@159
   781
                    {
Dean@680
   782
                        if (this.IsWithinInspector())
Dean@680
   783
                        {
Dean@680
   784
                            this.BackColor = SystemColors.ButtonFace;
Dean@680
   785
                        }
Dean@680
   786
                        else
Dean@680
   787
                        {
Dean@680
   788
                            this.BackColor = SystemColors.Window;
Dean@680
   789
                        }
Dean@159
   790
                    }
Dean@159
   791
                }
Dean@159
   792
                catch { }
Dean@680
   793
Dean@680
   794
                // Connect cryptable mail item events
Dean@680
   795
                if (this.associatedMailItem != null)
Dean@680
   796
                {
Dean@680
   797
                    try
Dean@680
   798
                    {
Dean@680
   799
                        this.associatedMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@680
   800
                        this.associatedMailItem.DecryptionComplete += MailItem_DecryptionComplete;
Dean@709
   801
                        this.associatedMailItem.GetMirrorComplete += MailItem_GetMirrorComplete;
Dean@682
   802
                        this.associatedMailItem.Send += MailItem_Send;
Dean@680
   803
Dean@680
   804
                        if (this.associatedMailItem.IsInEncryptedStore &&
Dean@680
   805
                            this.associatedMailItem.IsPGPEncrypted)
Dean@680
   806
                        {
Dean@680
   807
                            this.associatedMailItem.Open += MailItem_Open;
Dean@680
   808
                        }
Dean@680
   809
                    }
Dean@680
   810
                    catch { }
Dean@680
   811
                }
Dean@680
   812
Dean@680
   813
                this.CopyStateToUI(new PrivacyState());
Dean@683
   814
                this.TimerRefresh.Tick += TimerRefresh_Tick;
Dean@680
   815
                this.initialized = true;
Dean@179
   816
            }
Dean@159
   817
Dean@683
   818
            // Call the timer tick method manually to refresh data with no delay
Dean@199
   819
            this.TimerRefresh_Tick(null, new EventArgs());
Dean@179
   820
Dean@179
   821
            return;
Dean@159
   822
        }
Dean@159
   823
Dean@159
   824
        /// <summary>
Dean@159
   825
        /// Event handler for when the form region is closed.
Dean@159
   826
        /// </summary>
Dean@312
   827
        private void FormRegionPrivacyStatus_FormRegionClosed(object sender, System.EventArgs e)
Dean@159
   828
        {
Dean@199
   829
            // Disconnect cryptable mail item events
Dean@190
   830
            if (this.associatedMailItem != null)
Dean@179
   831
            {
Dean@179
   832
                try
Dean@179
   833
                {
Dean@445
   834
                    this.associatedMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@680
   835
                    this.associatedMailItem.DecryptionComplete -= MailItem_DecryptionComplete;
Dean@709
   836
                    this.associatedMailItem.GetMirrorComplete -= MailItem_GetMirrorComplete;
markus@201
   837
                    this.associatedMailItem.Open -= MailItem_Open;
Dean@682
   838
                    this.associatedMailItem.Send -= MailItem_Send;
Dean@179
   839
                }
Dean@179
   840
                catch { }
Dean@179
   841
            }
Dean@179
   842
Dean@682
   843
            // Stop and disconnect the refresh timer
Dean@682
   844
            this.TimerRefresh.Stop();
Dean@682
   845
            this.TimerRefresh.Enabled = false;
Dean@682
   846
            this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@682
   847
Dean@179
   848
            return;
Dean@179
   849
        }
Dean@179
   850
Dean@179
   851
        /// <summary>
Dean@179
   852
        /// Event handler called after the refresh timer has elapsed.
Dean@179
   853
        /// </summary>
Dean@179
   854
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
   855
        {
Dean@199
   856
            bool tryAgain = false;
Dean@684
   857
            bool markForDownload = false;
Dean@179
   858
            this.TimerRefresh.Enabled = false; // Only once
Dean@684
   859
            Outlook.OlDownloadState dlState;
markus@201
   860
Dean@709
   861
            /* The Refresh/UI_Update process is a little more complicated here than other forms.
Dean@709
   862
             * There are the following components:
Dean@709
   863
             *   1. TimerRefresh_Tick
Dean@709
   864
             *        This is the main timer tick event handler called any time
Dean@709
   865
             *        a refresh was requested and hasn't been run yet. A refresh
Dean@709
   866
             *        is requested either at initialization or when a property changes
Dean@709
   867
             *        (such as MailItem_PropertyChanged). It is on a timer as many 
Dean@709
   868
             *        property change events could occur rapidy, but only one refresh should
Dean@709
   869
             *        occur for performance reasons.
Dean@709
   870
             * 
Dean@709
   871
             *   2. UpdateUIFromMailItem
Dean@709
   872
             *        This will re-calculate the mail item's color rating and then update the UI.
Dean@709
   873
             *        However, if a mail item is not forcefully unencrypted, it will just call StartDecryption.
Dean@709
   874
             * 
Dean@709
   875
             *   3. MailItem_DecryptionComplete
Dean@709
   876
             *        When decryption of the mail item is complete, this even handler will be called.
Dean@709
   877
             *        This will update the UI with the latest color rating then call StartGetMirror.
Dean@709
   878
             *        The CopyStateToUI method is used which means any open privacy status form will also
Dean@709
   879
             *        be updated.
Dean@709
   880
             * 
Dean@709
   881
             *   4. MailItem_GetMirrorComplete
Dean@709
   882
             *        This is the final step in updating the UI, after a mirror is located, it's contents
Dean@709
   883
             *        will be shown to the unencrypted preview.
Dean@709
   884
             * 
Dean@709
   885
             * The general calling sequence is as shown above 1->4 with each component calling the next.
Dean@709
   886
             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
Dean@709
   887
             */
Dean@709
   888
Dean@179
   889
            // Ensure the tick method is not called more than once
Dean@179
   890
            if (refreshOngoing == false)
Dean@179
   891
            {
Dean@179
   892
                this.refreshOngoing = true;
Dean@179
   893
Dean@179
   894
                if (this.associatedMailItem != null)
Dean@179
   895
                {
Dean@684
   896
                    // Attempt to get the download state
Dean@684
   897
                    try
Dean@684
   898
                    {
Dean@684
   899
                        dlState = this.associatedMailItem.DownloadState;
Dean@684
   900
                    }
Dean@684
   901
                    catch (Exception ex)
Dean@684
   902
                    {
Dean@684
   903
                        Global.AddToLog("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
Dean@684
   904
Dean@684
   905
                        // Assume everything is downloaded, but try to download again as well
Dean@684
   906
                        dlState = Outlook.OlDownloadState.olFullItem;
Dean@684
   907
                        markForDownload = true;
Dean@684
   908
                    }
Dean@684
   909
Dean@684
   910
                    if (dlState == Outlook.OlDownloadState.olFullItem)
Dean@179
   911
                    {
Dean@709
   912
                        // Clear any existing preview and update
Dean@709
   913
                        this.ClearPreview(Properties.Resources.Message_Opening);
Dean@179
   914
                        this.UpdateUIFromMailItem();
Dean@179
   915
                    }
Dean@179
   916
                    else
Dean@179
   917
                    {
Dean@684
   918
                        markForDownload = true;
Dean@684
   919
                    }
Dean@684
   920
Dean@684
   921
                    if (markForDownload)
Dean@684
   922
                    {
Dean@684
   923
                        // Try to mark the message for full download
Dean@684
   924
                        try
Dean@684
   925
                        {
Dean@684
   926
                            this.associatedMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Dean@684
   927
                            tryAgain = true;
Dean@684
   928
                        }
Dean@684
   929
                        catch (Exception ex)
Dean@684
   930
                        {
Dean@684
   931
                            Global.AddToLog("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
Dean@684
   932
                        }
Dean@179
   933
                    }
Dean@179
   934
                }
Dean@179
   935
Dean@199
   936
                // Set the timer to refresh again later automatically
Dean@199
   937
                if (tryAgain)
Dean@199
   938
                {
Dean@199
   939
                    this.TimerRefresh.Interval = 100;
Dean@199
   940
                    this.TimerRefresh.Enabled = true;
Dean@199
   941
                }
Dean@199
   942
Dean@179
   943
                this.refreshOngoing = false;
Dean@179
   944
            }
Dean@175
   945
Dean@159
   946
            return;
Dean@159
   947
        }
Dean@159
   948
Dean@169
   949
        /// <summary>
Dean@680
   950
        /// Event handler for when the decryption process is completed in the associated mail item.
Dean@709
   951
        /// This will then update the form region UI and the privacy status window as needed.
Dean@680
   952
        /// </summary>
Dean@704
   953
        private void MailItem_DecryptionComplete(object sender, CryptableMailItem.DecryptionEventArgs e)
Dean@680
   954
        {
Dean@680
   955
            try
Dean@680
   956
            {
Dean@680
   957
                // Marshal code back to UI thread as necessary
Dean@680
   958
                this.Invoke(new Action(() =>
Dean@680
   959
                    {
Dean@680
   960
                        this.CopyStateToUI(new PrivacyState(e.ColorRating));
Dean@709
   961
Dean@709
   962
                        /* Create the unencrypted preview if the mail item is encrypted and
Dean@709
   963
                         * it is in an encrypted (untrusted) store
Dean@709
   964
                         * 
Dean@709
   965
                         * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Dean@709
   966
                         * it also is initialized after FormRegionPreviewUnencrypted.
Dean@709
   967
                         */
Dean@709
   968
                        if (this.associatedMailItem.IsInEncryptedStore &&
Dean@709
   969
                            this.associatedMailItem.IsPGPEncrypted)
Dean@709
   970
                        {
Dean@709
   971
                            this.associatedMailItem.StartGetMirror();
Dean@709
   972
                        }
Dean@680
   973
                    }));
Dean@680
   974
            }
Dean@680
   975
            catch (Exception ex)
Dean@680
   976
            {
Dean@680
   977
                Global.AddToLog("MailItem_DecryptionComplete: Error setting UI state, " + ex.ToString());
Dean@680
   978
            }
Dean@680
   979
Dean@680
   980
            return;
Dean@680
   981
        }
Dean@680
   982
Dean@680
   983
        /// <summary>
Dean@709
   984
        /// Event handler for when the get mirror locating process is complete for the associated mail item.
Dean@709
   985
        /// This will then update the unencrypted preview in the UI.
Dean@709
   986
        /// </summary>
Dean@709
   987
        private void MailItem_GetMirrorComplete(object sender, CryptableMailItem.GetMirrorEventArgs e)
Dean@709
   988
        {
Dean@709
   989
            try
Dean@709
   990
            {
Dean@709
   991
                // Marshal code back to UI thread as necessary
Dean@709
   992
                this.Invoke(new Action(() =>
Dean@709
   993
                    {
Dean@709
   994
                        WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
Dean@709
   995
Dean@709
   996
                        if ((formRegions != null) &&
Dean@709
   997
                            (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@709
   998
                            (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@709
   999
                        {
Dean@709
  1000
                            formRegions.FormRegionPreviewUnencrypted.SetMessage(e.Mirror);
Dean@709
  1001
                        }
Dean@709
  1002
                    }));
Dean@709
  1003
            }
Dean@709
  1004
            catch (Exception ex)
Dean@709
  1005
            {
Dean@709
  1006
                Global.AddToLog("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
Dean@709
  1007
            }
Dean@709
  1008
Dean@709
  1009
            return;
Dean@709
  1010
        }
Dean@709
  1011
Dean@709
  1012
        /// <summary>
Dean@169
  1013
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
  1014
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
  1015
        /// </summary>
Dean@169
  1016
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
  1017
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
  1018
        /// and the inspector is not displayed.</param>
Dean@169
  1019
        private void MailItem_Open(ref bool cancel)
Dean@159
  1020
        {
Dean@173
  1021
            if (this.associatedMailItem != null && this.associatedMailItem.MirrorDisplay())
Dean@169
  1022
            {
Dean@169
  1023
                cancel = true;
Dean@169
  1024
            }
Dean@169
  1025
Dean@169
  1026
            return;
Dean@159
  1027
        }
Dean@159
  1028
Dean@169
  1029
        /// <summary>
Dean@682
  1030
        /// Event handler for when a mail item is sent.
Dean@682
  1031
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
Dean@682
  1032
        /// </summary>
Dean@682
  1033
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@682
  1034
        /// If the event procedure sets this argument to True, the send operation is not completed 
Dean@682
  1035
        /// and the inspector is left open.</param>
Dean@682
  1036
        private void MailItem_Send(ref bool cancel)
Dean@682
  1037
        {
Dean@682
  1038
            // Stop and disconnect the refresh timer
Dean@682
  1039
            // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
Dean@682
  1040
            this.TimerRefresh.Stop();
Dean@682
  1041
            this.TimerRefresh.Enabled = false;
Dean@682
  1042
            this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@682
  1043
Dean@682
  1044
            return;
Dean@682
  1045
        }
Dean@682
  1046
Dean@682
  1047
        /// <summary>
Dean@169
  1048
        /// Event handler for when a mail item property is changed.
Dean@169
  1049
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
  1050
        /// </summary>
Dean@169
  1051
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@445
  1052
        private void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Dean@159
  1053
        {
Dean@445
  1054
            switch (e.PropertyName.ToUpper())
Dean@159
  1055
            {
Dean@179
  1056
                case "TO":
Dean@179
  1057
                    // Start the refresh timer
Dean@179
  1058
                    this.TimerRefresh.Enabled = true;
Dean@159
  1059
                    break;
Dean@159
  1060
                // Outlook bug: there are always both events, so one is enough
Dean@159
  1061
                //case "CC":
Dean@179
  1062
                //    // Start the refresh timer
Dean@179
  1063
                //    this.TimerRefresh.Enabled = true;
Dean@159
  1064
                //    break;
Dean@159
  1065
            }
Dean@169
  1066
Dean@169
  1067
            return;
Dean@159
  1068
        }
Dean@159
  1069
Dean@179
  1070
        /// <summary>
Dean@312
  1071
        /// Event handler for when the privacy status button is clicked.
Dean@179
  1072
        /// </summary>
Dean@312
  1073
        private void ButtonPrivacyStatus_Click(object sender, EventArgs e)
vb@133
  1074
        {
Dean@310
  1075
            this.BuildAndShowManager();
Dean@179
  1076
            return;
vb@133
  1077
        }
vb@133
  1078
Dean@179
  1079
        /// <summary>
Dean@312
  1080
        /// Event handler for when a mouse button is released over the privacy status button.
Dean@179
  1081
        /// </summary>
Dean@312
  1082
        private void ButtonPrivacyStatus_MouseUp(object sender, MouseEventArgs e)
vb@133
  1083
        {
Dean@179
  1084
            return;
vb@133
  1085
        }
vb@133
  1086
    }
vb@133
  1087
}