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