FormRegionEncryptionStatus.cs
author Dean Looyengoed
Fri, 01 Jan 2016 00:25:22 +0100
changeset 199 94f5017acda0
parent 198 ca1b6e20f1a6
child 201 9e0548fa3942
permissions -rw-r--r--
Detect when making the unencrypted preview fails and continuously attempt to refresh.
This may need a timeout if there is too much of a performance hit in testing.
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@159
    14
    /// Partial class for the encryption status panel that is displayed below every outlook message.
Dean@159
    15
    /// </summary>
Dean@196
    16
    partial class FormRegionEncryptionStatus
vb@133
    17
    {
Dean@164
    18
        private static readonly Color COLOR_RED        = Color.Red;
Dean@164
    19
        private static readonly Color COLOR_YELLOW     = Color.Gold;
Dean@164
    20
        private static readonly Color COLOR_GREEN      = Color.Green;
Dean@164
    21
        private static readonly Color COLOR_GREY       = Color.Gainsboro;
Dean@164
    22
        private static readonly Color TEXT_COLOR_BLACK = Color.Black;
Dean@164
    23
        private static readonly Color TEXT_COLOR_WHITE = Color.White;
Dean@162
    24
vb@133
    25
        #region Form Region Factory
vb@133
    26
vb@133
    27
        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
Dean@196
    28
        [Microsoft.Office.Tools.Outlook.FormRegionName("pEp.FormRegionEncryptionStatus")]
Dean@196
    29
        public partial class FormRegionEncryptionStatusFactory
vb@133
    30
        {
vb@133
    31
            // Occurs before the form region is initialized.
vb@133
    32
            // To prevent the form region from appearing, set e.Cancel to true.
vb@133
    33
            // Use e.OutlookItem to get a reference to the current Outlook item.
Dean@196
    34
            private void FormRegionEncryptionStatus_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
vb@133
    35
            {
vb@133
    36
            }
vb@133
    37
        }
vb@133
    38
vb@133
    39
        #endregion
vb@133
    40
Dean@159
    41
        /* Notes:
Dean@179
    42
         * 
Dean@159
    43
         * Use this.OutlookItem to get a reference to the current Outlook item.
Dean@159
    44
         * Use this.OutlookFormRegion to get a reference to the form region.
Dean@179
    45
         * 
Dean@179
    46
         * UI State Managment:
Dean@179
    47
         * 
Dean@179
    48
         * The UI state is almost entirely set from the associated mail item data.
Dean@179
    49
         * However, a separate state class is maintained to represent the UI as some separation is needed.
Dean@179
    50
         * This logical separation MUST be maintained throughout the code.
Dean@179
    51
         * Specific cases are noted where possible.
Dean@179
    52
         * 
Dean@159
    53
         */
Dean@159
    54
Dean@170
    55
        private CryptableMailItem associatedMailItem = null;
Dean@179
    56
        private bool              refreshOngoing     = false;
Dean@179
    57
        private bool              eventsAreConnected = false;
Dean@170
    58
Dean@170
    59
        // UI data or controls not stored in the UI
Dean@179
    60
        private _pEp_color stateUIColorRating; // WARNING: Do NOT use this directly
vb@133
    61
Dean@159
    62
        /**************************************************************
Dean@159
    63
         * 
Dean@159
    64
         * Methods
Dean@159
    65
         * 
Dean@159
    66
         *************************************************************/
Dean@159
    67
Dean@171
    68
        /// <summary>
Dean@171
    69
        /// Method used to show/report an error based on build mode.
Dean@171
    70
        /// </summary>
Dean@171
    71
        /// <param name="reason">The reason/explanation to stop.</param>
Dean@159
    72
        static void StopHere(string reason)
vb@133
    73
        {
Dean@159
    74
#if DEBUG
Dean@159
    75
            MessageBox.Show(reason);
Dean@159
    76
#else
Dean@159
    77
            try
vb@133
    78
            {
Dean@159
    79
                ThisAddIn.pEp.log("internal error", "pEp for Outlook", reason, "in EncryptionStatusPanel.cs");
vb@133
    80
            }
Dean@159
    81
            catch (COMException) { }
Dean@159
    82
            catch (Exception) { }
Dean@159
    83
#endif
vb@133
    84
        }
vb@133
    85
Dean@170
    86
        /// <summary>
Dean@170
    87
        /// Sets the cryptable mail item associated with this encryption status panel.
Dean@170
    88
        /// The associated mail item can then be accessed through its local variable.
Dean@170
    89
        /// </summary>
Dean@170
    90
        private void SetAssociatedMailItem()
Dean@170
    91
        {
Dean@170
    92
            bool errorOccurred = false;
Dean@170
    93
            Outlook.MailItem omi = null;
Dean@170
    94
            Outlook.MAPIFolder omiFolder;
Dean@170
    95
            Outlook.MAPIFolder deletedFolder;
Dean@170
    96
Dean@170
    97
            // Null check
Dean@170
    98
            if (!errorOccurred)
Dean@170
    99
            {
Dean@170
   100
                try
Dean@170
   101
                {
Dean@170
   102
                    if (this.OutlookItem == null)
Dean@170
   103
                    {
Dean@170
   104
                        errorOccurred = true;
Dean@170
   105
                    }
Dean@170
   106
                }
Dean@170
   107
                catch (COMException)
Dean@170
   108
                {
Dean@170
   109
                    errorOccurred = true;
Dean@170
   110
                }
Dean@170
   111
            }
Dean@170
   112
Dean@170
   113
            // Attempt to get and cast the outlook mail item
Dean@170
   114
            if (!errorOccurred)
Dean@170
   115
            {
Dean@170
   116
                try
Dean@170
   117
                {
Dean@170
   118
                    omi = (Outlook.MailItem)this.OutlookItem;
Dean@170
   119
                }
Dean@170
   120
                catch
Dean@170
   121
                {
Dean@170
   122
                    errorOccurred = true;
Dean@170
   123
                }
Dean@170
   124
            }
Dean@170
   125
Dean@170
   126
            // Ensure the mail item is not in the deleted folder
Dean@170
   127
            if (!errorOccurred)
Dean@170
   128
            {
Dean@170
   129
                try
Dean@170
   130
                {
Dean@170
   131
                    omiFolder = omi.Parent;
Dean@170
   132
Dean@170
   133
                    if (omiFolder != null)
Dean@170
   134
                    {
Dean@170
   135
                        deletedFolder = omiFolder.Store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
Dean@170
   136
Dean@170
   137
                        if ((deletedFolder != null) && 
Dean@170
   138
                            (omiFolder.EntryID == deletedFolder.EntryID))
Dean@170
   139
                        {
Dean@170
   140
                            errorOccurred = true;
Dean@170
   141
                        }
Dean@170
   142
                    }
Dean@170
   143
                    else
Dean@170
   144
                    {
Dean@170
   145
                        errorOccurred = true;
Dean@170
   146
                    }
Dean@170
   147
                }
Dean@170
   148
                catch
Dean@170
   149
                {
Dean@170
   150
                    errorOccurred = true;
Dean@170
   151
                }
Dean@170
   152
            }
Dean@170
   153
Dean@170
   154
            // Finally set the associated mail item
Dean@170
   155
            if ((errorOccurred) ||
Dean@170
   156
                (omi == null))
Dean@170
   157
            {
Dean@170
   158
                this.associatedMailItem = null;
Dean@170
   159
            }
Dean@170
   160
            else
Dean@170
   161
            {
Dean@170
   162
                // Check if the associated mail item has already been set
Dean@170
   163
                if (this.associatedMailItem != null)
Dean@170
   164
                {
Dean@170
   165
                    // Only re-set the mail item if the EntryID has changed
Dean@170
   166
                    if (this.associatedMailItem.EntryID != omi.EntryID)
Dean@170
   167
                    {
Dean@170
   168
                        this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   169
                    }
Dean@170
   170
                }
Dean@170
   171
                else
Dean@170
   172
                {
Dean@170
   173
                    this.associatedMailItem = new CryptableMailItem(omi);
Dean@170
   174
                }
Dean@170
   175
            }
Dean@170
   176
Dean@170
   177
            return;
Dean@170
   178
        }
Dean@170
   179
Dean@179
   180
        /// <summary>
Dean@179
   181
        /// Starts the handshake process where the identity of a partner can be confirmed.
Dean@179
   182
        /// </summary>
Dean@179
   183
        /// <param name="identityPartner">The identity of the partner to complete the handshake with.</param>
Dean@179
   184
        private void DoHandshake(pEp_identity_s identityPartner)
vb@133
   185
        {
Dean@155
   186
            string ownShort;
Dean@155
   187
            string ownLong;
Dean@155
   188
            string ownFpr;
Dean@155
   189
            string partnerShort;
Dean@155
   190
            string partnerLong;
Dean@155
   191
            string partnerFpr;
Dean@155
   192
            string[] lines;
Dean@179
   193
            DialogResult result;
Dean@155
   194
            pEp_identity_s me;
Dean@155
   195
            FormHandshake handshakeDialog;
Dean@155
   196
            FormHandshake.State state = new FormHandshake.State();
Dean@176
   197
            
Dean@190
   198
            Globals.ThisAddIn.LogVerbose("doHandshake");
Dean@190
   199
            Globals.ThisAddIn.LogVerbose(identityPartner.address);
vb@139
   200
vb@132
   201
            if (identityPartner.username == "")
vb@133
   202
                identityPartner.username = identityPartner.address;
Dean@190
   203
            Globals.ThisAddIn.LogVerbose(identityPartner.username);
vb@133
   204
dean@144
   205
            identityPartner.user_id = CryptableMailItem.GetUserIDFromAddress(identityPartner.address, identityPartner.username);
Dean@190
   206
            Globals.ThisAddIn.LogVerbose(identityPartner.user_id);
vb@133
   207
Dean@173
   208
            if (this.associatedMailItem.IsIncoming)
vb@133
   209
            {
Dean@173
   210
                string entryID = this.associatedMailItem.ReceivedByEntryID;
vb@133
   211
                string address = "";
vb@133
   212
Dean@190
   213
                foreach (Outlook.Account a in Globals.ThisAddIn.Application.Session.Accounts){
vb@133
   214
                    if (a.CurrentUser.EntryID == entryID) {
vb@133
   215
                        address = a.SmtpAddress;
vb@133
   216
                        break;
vb@133
   217
                    }
vb@133
   218
                }
vb@133
   219
vb@133
   220
                if (address == "")
Dean@190
   221
                    address = Globals.ThisAddIn.Application.Session.Accounts[1].SmtpAddress;
vb@133
   222
Dean@190
   223
                me = Globals.ThisAddIn.mySelf(address);
vb@133
   224
            }
vb@133
   225
            else // outgoing
vb@133
   226
            {
Dean@190
   227
                Globals.ThisAddIn.LogVerbose("mailItem.from_address: " + this.associatedMailItem.FromAddress);
Dean@190
   228
                me = Globals.ThisAddIn.mySelf(this.associatedMailItem.FromAddress);
vb@133
   229
            }
vb@133
   230
Dean@190
   231
            Globals.ThisAddIn.LogVerbose(me.fpr);
vb@139
   232
Dean@155
   233
            ownShort = ThisAddIn.pEp.trustwords(me.fpr, max_words: 5).ToLower();
Dean@155
   234
            ownLong  = ThisAddIn.pEp.trustwords(me.fpr).ToLower();
Dean@161
   235
            ownFpr   = this.ToQuadruple(me.fpr);
vb@133
   236
Dean@190
   237
            Globals.ThisAddIn.LogVerbose(identityPartner.fpr);
vb@139
   238
Dean@155
   239
            partnerShort = ThisAddIn.pEp.trustwords(identityPartner.fpr, max_words: 5).ToLower();
Dean@155
   240
            partnerLong  = ThisAddIn.pEp.trustwords(identityPartner.fpr).ToLower();
Dean@161
   241
            partnerFpr   = this.ToQuadruple(identityPartner.fpr);
vb@133
   242
Dean@155
   243
            if (ownFpr.CompareTo(partnerFpr) > 0)
vb@133
   244
            {
Dean@155
   245
                state.TrustwordsShort = partnerShort + ownShort;
Dean@155
   246
                state.TrustwordsFull  = partnerLong  + ownLong;
Dean@155
   247
Dean@155
   248
                lines = new string[3];
Dean@155
   249
                lines[0] = pEp.Properties.Resources.TrustwordsPartnershortPartner + partnerFpr;
Dean@155
   250
                lines[2] = pEp.Properties.Resources.TrustwordsPartnershortMyself + ownFpr;
Dean@155
   251
                state.Fingerprint = lines;
vb@133
   252
            }
vb@133
   253
            else
vb@133
   254
            {
Dean@155
   255
                state.TrustwordsShort = ownShort + " " + partnerShort;
Dean@155
   256
                state.TrustwordsFull  = ownLong  + " " + partnerLong;
Dean@155
   257
Dean@155
   258
                lines = new string[3];
Dean@155
   259
                lines[0] = pEp.Properties.Resources.TrustwordsOwnshortMyself + ownFpr;
Dean@155
   260
                lines[2] = pEp.Properties.Resources.TrustwordsOwnshortPartner + partnerFpr;
Dean@155
   261
                state.Fingerprint = lines;
vb@133
   262
            }
vb@133
   263
Dean@190
   264
            Globals.ThisAddIn.LogVerbose("try to show dialog");
vb@139
   265
Dean@155
   266
            // Create and show handshake dialog
Dean@155
   267
            handshakeDialog = new FormHandshake(state);
Dean@179
   268
            handshakeDialog.StartPosition = FormStartPosition.CenterScreen;
Dean@179
   269
            result = handshakeDialog.ShowDialog(this);
Dean@155
   270
Dean@190
   271
            Globals.ThisAddIn.LogVerbose("handshakeDialog.ShowDialog(this) => " + result.ToString());
vb@133
   272
vb@133
   273
            switch (result)
vb@133
   274
            {
vb@133
   275
                case DialogResult.Yes:
Dean@173
   276
                    this.associatedMailItem.ColorRating = _pEp_color.pEp_rating_trusted;
vb@132
   277
                    identityPartner = ThisAddIn.pEp.trust_personal_key(identityPartner);
Dean@179
   278
                    this.UpdateUIFromMailItem();
vb@133
   279
                    break;
vb@133
   280
                case DialogResult.No:
vb@133
   281
                    ThisAddIn.pEp.key_compromized(identityPartner);
vb@133
   282
                    identityPartner.comm_type = _pEp_comm_type.pEp_ct_compromized;
Dean@173
   283
                    this.associatedMailItem.ColorRating = _pEp_color.pEp_rating_red;
Dean@179
   284
                    this.UpdateUIFromMailItem();
vb@133
   285
                    break;
vb@133
   286
            }
vb@133
   287
        }
vb@133
   288
Dean@179
   289
        /// <summary>
Dean@179
   290
        /// Reverses any past handshake confirmation by unconfirming the given identity partner.
Dean@179
   291
        /// </summary>
Dean@179
   292
        /// <param name="identityPartner">The identity of the partner to unconfirm.</param>
Dean@179
   293
        private void UndoHandshake(pEp_identity_s identityPartner)
vb@133
   294
        {
vb@133
   295
            ThisAddIn.pEp.update_identity(identityPartner);
vb@133
   296
            identityPartner.comm_type ^= _pEp_comm_type.pEp_ct_confirmed;
vb@133
   297
            ThisAddIn.pEp.update_identity(identityPartner);
Dean@194
   298
            
Dean@179
   299
            this.UpdateUIFromMailItem();
vb@133
   300
        }
vb@133
   301
Dean@161
   302
        /// <summary>
Dean@161
   303
        /// Formats the given text string as separated 4-character groups.
Dean@161
   304
        /// Example: 49422235FC99585B891C --> 4942 2235 FC99 585B 891C
Dean@161
   305
        /// </summary>
Dean@161
   306
        /// <param name="text">The text to format in 4-character groups.</param>
Dean@161
   307
        /// <returns>The re-formatted string.</returns>
Dean@161
   308
        private string ToQuadruple(string text)
Dean@159
   309
        {
Dean@159
   310
            List<string> result = new List<string>();
Dean@159
   311
Dean@161
   312
            if (text != null)
Dean@159
   313
            {
Dean@161
   314
                for (int i = 0; i < text.Length; i += 4)
Dean@159
   315
                {
Dean@161
   316
                    try
Dean@161
   317
                    {
Dean@161
   318
                        result.Add(text.Substring(i, 4));
Dean@161
   319
                    }
Dean@161
   320
                    catch (ArgumentOutOfRangeException)
Dean@161
   321
                    {
Dean@161
   322
                        result.Add(text.Substring(i));
Dean@161
   323
                        break;
Dean@161
   324
                    }
Dean@159
   325
                }
Dean@159
   326
            }
Dean@159
   327
Dean@159
   328
            return String.Join(" ", result);
Dean@159
   329
        }
Dean@196
   330
        
Dean@196
   331
        /// <summary>
Dean@196
   332
        /// Makes the unencrypted preview form.
Dean@196
   333
        /// This gets the active form region then fills it's content.
Dean@196
   334
        /// </summary>
Dean@198
   335
        /// <returns>True if successful, otherwise false.</returns>
Dean@198
   336
        private bool MakePreview()
Dean@159
   337
        {
Dean@198
   338
            bool success = true;
Dean@198
   339
            bool isSuccessful;
Dean@198
   340
            byte[] rtfBody;
Dean@198
   341
            string subject;
Dean@159
   342
            WindowFormRegionCollection formRegions;
Dean@198
   343
            
Dean@198
   344
            formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveExplorer()];
Dean@159
   345
Dean@198
   346
            if ((formRegions != null) &&
Dean@198
   347
                (formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@198
   348
                (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@198
   349
            {
Dean@198
   350
                // Attempt to the the RTF body
Dean@198
   351
                isSuccessful = this.associatedMailItem.MirrorTryGetRTFBody(out rtfBody);
Dean@198
   352
                if (isSuccessful == false)
Dean@198
   353
                {
Dean@198
   354
                    return (false);
Dean@198
   355
                }
Dean@159
   356
Dean@198
   357
                // Attempt to get the subject
Dean@198
   358
                isSuccessful = this.associatedMailItem.MirrorTryGetSubject(out subject);
Dean@198
   359
                if (isSuccessful == false)
Dean@159
   360
                {
Dean@198
   361
                    return (false);
Dean@159
   362
                }
Dean@196
   363
Dean@198
   364
                // Add data to the form
Dean@198
   365
                formRegions.FormRegionPreviewUnencrypted.RichTextBoxPreview.Rtf  = System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length);
Dean@198
   366
                formRegions.FormRegionPreviewUnencrypted.TextBoxSubject.Text     = subject;
Dean@198
   367
                formRegions.FormRegionPreviewUnencrypted.TextBoxFrom.Text        = this.associatedMailItem.FromUsername + " <" + this.associatedMailItem.FromAddress + ">";
Dean@198
   368
            }
Dean@198
   369
            else
Dean@198
   370
            {
Dean@198
   371
                success = false;
Dean@198
   372
            }
Dean@198
   373
Dean@198
   374
            return (success);
Dean@159
   375
        }
Dean@196
   376
        
Dean@179
   377
        /// <summary>
Dean@179
   378
        /// Updates the status of the UI state based on the associated mail item.
Dean@179
   379
        /// Any previous state changes in the UI are preserved.
Dean@179
   380
        /// </summary>
Dean@179
   381
        private void UpdateUIFromMailItem()
Dean@159
   382
        {
Dean@179
   383
            State state;
Dean@159
   384
Dean@173
   385
            if (this.associatedMailItem != null)
Dean@159
   386
            {
Dean@179
   387
                state = this.CopyUIToState();
Dean@179
   388
Dean@179
   389
                // Set encryption status
Dean@179
   390
                if (this.associatedMailItem.SendUnencrypted == CheckState.Checked)
Dean@159
   391
                {
Dean@179
   392
                    // Always set to unencrypted
Dean@179
   393
                    state.EncryptionStatus = _pEp_color.pEp_rating_unencrypted;
Dean@159
   394
                }
Dean@159
   395
                else
Dean@159
   396
                {
Dean@179
   397
                    state.EncryptionStatus = this.associatedMailItem.ColorRating;
Dean@159
   398
                }
Dean@179
   399
Dean@179
   400
                // Set send unencrypted state
Dean@179
   401
                state.SendUnencryptedCheckState = this.associatedMailItem.SendUnencrypted;
Dean@179
   402
Dean@179
   403
                this.CopyStateToUI(state);
Dean@159
   404
            }
Dean@159
   405
Dean@179
   406
            return;
Dean@159
   407
        }
Dean@159
   408
Dean@172
   409
        #region StateMethods
Dean@172
   410
Dean@172
   411
        /// <summary>
Dean@172
   412
        /// Connects or disconnects all control events from the UI.
Dean@172
   413
        /// </summary>
Dean@172
   414
        /// <param name="connect">True to connect events, false to disconnect.</param>
Dean@172
   415
        private void ConnectEvents(bool connect)
Dean@172
   416
        {
Dean@172
   417
            // Connect events only if not already connected
Dean@172
   418
            if ((connect == true) && 
Dean@172
   419
                (this.eventsAreConnected == false))
Dean@172
   420
            {
Dean@179
   421
                this.ButtonEncryptionStatus.Click     += this.ButtonEncryptionStatus_Click;
Dean@179
   422
                this.ButtonEncryptionStatus.MouseUp   += this.ButtonEncryptionStatus_MouseUp;
Dean@179
   423
                this.LinkLabelExplanation.LinkClicked += this.LinkLabelExplanation_LinkClicked;
Dean@179
   424
Dean@179
   425
                this.PictureBoxOptions.Click      += this.PictureBoxOptions_Click;
Dean@179
   426
                this.PictureBoxOptions.MouseHover += this.PictureBoxOptions_MouseHover;
Dean@179
   427
Dean@179
   428
                this.ToolStripMenuItemSendUnencrypted.Click += this.ToolStripMenuItemSendUnencrypted_Click;
Dean@172
   429
Dean@172
   430
                this.eventsAreConnected = true;
Dean@172
   431
            }
Dean@172
   432
            // Always attempt to disconnect
Dean@172
   433
            else if (connect == false)
Dean@172
   434
            {
Dean@179
   435
                this.ButtonEncryptionStatus.Click     -= this.ButtonEncryptionStatus_Click;
Dean@179
   436
                this.ButtonEncryptionStatus.MouseUp   -= this.ButtonEncryptionStatus_MouseUp;
Dean@179
   437
                this.LinkLabelExplanation.LinkClicked -= this.LinkLabelExplanation_LinkClicked;
Dean@179
   438
Dean@179
   439
                this.PictureBoxOptions.Click      -= this.PictureBoxOptions_Click;
Dean@179
   440
                this.PictureBoxOptions.MouseHover -= this.PictureBoxOptions_MouseHover;
Dean@179
   441
Dean@179
   442
                this.ToolStripMenuItemSendUnencrypted.Click -= this.ToolStripMenuItemSendUnencrypted_Click;
Dean@172
   443
Dean@172
   444
                this.eventsAreConnected = false;
Dean@172
   445
            }
Dean@172
   446
Dean@172
   447
            return;
Dean@172
   448
        }
Dean@172
   449
Dean@172
   450
        /// <summary>
Dean@172
   451
        /// Refreshes the UI by reloading the state.
Dean@172
   452
        /// </summary>
Dean@172
   453
        private void RefreshUI()
Dean@172
   454
        {
Dean@172
   455
            this.CopyStateToUI(this.CopyUIToState());
Dean@172
   456
            return;
Dean@172
   457
        }
Dean@172
   458
Dean@172
   459
        /// <summary>
Dean@172
   460
        /// Copies the given state to the UI.
Dean@172
   461
        /// Events are turned off until the process is complete.
Dean@172
   462
        /// </summary>
Dean@172
   463
        /// <param name="state">The state to set to the UI.</param>
Dean@172
   464
        private void CopyStateToUI(State state)
Dean@172
   465
        {
Dean@172
   466
            this.ConnectEvents(false);
Dean@172
   467
            
Dean@172
   468
            ///////////////////////////////////////////////////////////
Dean@172
   469
            // Set UI data
Dean@172
   470
            ///////////////////////////////////////////////////////////
Dean@172
   471
Dean@179
   472
            // Save UI state maintained outside of controls
Dean@179
   473
            this.stateUIColorRating = state.EncryptionStatus;
Dean@179
   474
Dean@172
   475
            this.LinkLabelExplanation.Text        = state.Title;
Dean@172
   476
            this.ButtonEncryptionStatus.BackColor = state.ButtonBackground;
Dean@172
   477
            this.ButtonEncryptionStatus.ForeColor = state.ButtonForeground;
Dean@172
   478
            this.ButtonEncryptionStatus.Text      = state.ButtonText;
Dean@172
   479
Dean@172
   480
            ///////////////////////////////////////////////////////////
Dean@172
   481
            // Set UI selections
Dean@172
   482
            ///////////////////////////////////////////////////////////
Dean@172
   483
Dean@179
   484
            /* Note: When displaying the send unencrypted checked state,
Dean@179
   485
             * convert any indeterminate state to unchecked.
Dean@179
   486
             * This is necessary for the end user.
Dean@179
   487
             * As a result of this change during display, the UI state will 
Dean@179
   488
             * carry this change as soon as a refresh occurs.
Dean@179
   489
             * This is not a problem because the mail item itself is not updated
Dean@179
   490
             * until the user clicks the send unencrypted checkbox themselves.
Dean@179
   491
             * This is a case where the UI state and mail item are different.
Dean@179
   492
             */
Dean@179
   493
            if (state.SendUnencryptedCheckState == CheckState.Checked)
Dean@179
   494
            {
Dean@179
   495
                this.ToolStripMenuItemSendUnencrypted.CheckState = CheckState.Checked;
Dean@179
   496
            }
Dean@179
   497
            else
Dean@179
   498
            {
Dean@179
   499
                // Both indeterminate and unchecked shown as unchecked
Dean@179
   500
                this.ToolStripMenuItemSendUnencrypted.CheckState = CheckState.Unchecked;
Dean@179
   501
            }
Dean@172
   502
Dean@172
   503
            ///////////////////////////////////////////////////////////
Dean@172
   504
            // Set UI control visibility
Dean@172
   505
            ///////////////////////////////////////////////////////////
Dean@172
   506
Dean@172
   507
            this.ConnectEvents(true);
Dean@172
   508
Dean@172
   509
            return;
Dean@172
   510
        }
Dean@172
   511
Dean@172
   512
        /// <summary>
Dean@172
   513
        /// Copies the UI to a new state.
Dean@172
   514
        /// </summary>
Dean@172
   515
        /// <returns>The state of the UI.</returns>
Dean@172
   516
        private State CopyUIToState()
Dean@172
   517
        {
Dean@172
   518
            State state = new State();
Dean@172
   519
Dean@179
   520
            state.EncryptionStatus          = this.stateUIColorRating;
Dean@179
   521
            state.SendUnencryptedCheckState = this.ToolStripMenuItemSendUnencrypted.CheckState;
Dean@172
   522
Dean@172
   523
            return (state);
Dean@172
   524
        }
Dean@172
   525
Dean@172
   526
        #endregion
Dean@172
   527
Dean@159
   528
        /**************************************************************
Dean@159
   529
         * 
Dean@159
   530
         * Event Handling
Dean@159
   531
         * 
Dean@159
   532
         *************************************************************/
Dean@159
   533
Dean@159
   534
        /// <summary>
Dean@159
   535
        /// Event handler that is called before the form region is displayed.
Dean@159
   536
        /// </summary>
Dean@196
   537
        private void FormRegionEncryptionStatus_FormRegionShowing(object sender, System.EventArgs e)
Dean@159
   538
        {
Dean@179
   539
            State state;
Dean@179
   540
Dean@173
   541
            this.SetAssociatedMailItem();
Dean@173
   542
Dean@199
   543
            // Connect cryptable mail item events
Dean@189
   544
            if (this.associatedMailItem != null)
Dean@159
   545
            {
Dean@159
   546
                try
Dean@159
   547
                {
Dean@189
   548
                    this.associatedMailItem.PropertyChange += MailItem_PropertyChange;
Dean@179
   549
Dean@189
   550
                    if (this.associatedMailItem.IsInEncryptedStore &&
Dean@198
   551
                        this.associatedMailItem.IsPGPEncrypted)
Dean@159
   552
                    {
Dean@189
   553
                        this.associatedMailItem.Open += MailItem_Open;
Dean@159
   554
                    }
Dean@159
   555
                }
Dean@159
   556
                catch { }
Dean@179
   557
            }
Dean@159
   558
Dean@179
   559
            // Set the default UI state
Dean@179
   560
            state = new State();
Dean@179
   561
            state.EncryptionStatus = _pEp_color.pEp_rating_undefined;
Dean@179
   562
            this.CopyStateToUI(state);
Dean@179
   563
Dean@199
   564
            // Call the timer tick method manually to refresh data
Dean@199
   565
            this.TimerRefresh_Tick(null, new EventArgs());
Dean@179
   566
Dean@179
   567
            return;
Dean@159
   568
        }
Dean@159
   569
Dean@159
   570
        /// <summary>
Dean@159
   571
        /// Event handler for when the form region is closed.
Dean@159
   572
        /// </summary>
Dean@196
   573
        private void FormRegionEncryptionStatus_FormRegionClosed(object sender, System.EventArgs e)
Dean@159
   574
        {
Dean@199
   575
            // Disconnect cryptable mail item events
Dean@190
   576
            if (this.associatedMailItem != null)
Dean@179
   577
            {
Dean@179
   578
                try
Dean@179
   579
                {
Dean@190
   580
                    this.associatedMailItem.PropertyChange -= MailItem_PropertyChange;
Dean@190
   581
                    this.associatedMailItem.Open           -= MailItem_Open;
Dean@179
   582
                }
Dean@179
   583
                catch { }
Dean@179
   584
            }
Dean@179
   585
Dean@179
   586
            return;
Dean@179
   587
        }
Dean@179
   588
Dean@179
   589
        /// <summary>
Dean@179
   590
        /// Event handler called after the refresh timer has elapsed.
Dean@179
   591
        /// </summary>
Dean@179
   592
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
   593
        {
Dean@199
   594
            bool tryAgain = false;
Dean@199
   595
            bool isSuccessful;
Dean@179
   596
            this.TimerRefresh.Enabled = false; // Only once
Dean@179
   597
            
Dean@179
   598
            // Ensure the tick method is not called more than once
Dean@179
   599
            if (refreshOngoing == false)
Dean@179
   600
            {
Dean@179
   601
                this.refreshOngoing = true;
Dean@179
   602
Dean@179
   603
                if (this.associatedMailItem != null)
Dean@179
   604
                {
Dean@179
   605
                    if (this.associatedMailItem.DownloadState == Outlook.OlDownloadState.olFullItem)
Dean@179
   606
                    {
Dean@179
   607
                        this.UpdateUIFromMailItem();
Dean@199
   608
Dean@199
   609
                        /* Create the unencrypted preview if the mail item is encrypted and
Dean@199
   610
                         * it is in an encrypted (untrusted) store
Dean@199
   611
                         * 
Dean@199
   612
                         * This is done here because FormRegionEncryptionStatus has the cryptable mail item and
Dean@199
   613
                         * it also is initialized after FormRegionPreviewUnencrypted.
Dean@199
   614
                         */
Dean@199
   615
                        if (this.associatedMailItem.IsInEncryptedStore &&
Dean@199
   616
                            this.associatedMailItem.IsPGPEncrypted)
Dean@199
   617
                        {
Dean@199
   618
                            isSuccessful = this.MakePreview();
Dean@199
   619
Dean@199
   620
                            if (isSuccessful == false)
Dean@199
   621
                            {
Dean@199
   622
                                tryAgain = true;
Dean@199
   623
                            }
Dean@199
   624
                        }
Dean@179
   625
                    }
Dean@179
   626
                    else
Dean@179
   627
                    {
Dean@179
   628
                        this.associatedMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Dean@199
   629
                        tryAgain = true;
Dean@179
   630
                    }
Dean@179
   631
                }
Dean@179
   632
Dean@199
   633
                // Set the timer to refresh again later automatically
Dean@199
   634
                if (tryAgain)
Dean@199
   635
                {
Dean@199
   636
                    this.TimerRefresh.Interval = 100;
Dean@199
   637
                    this.TimerRefresh.Enabled = true;
Dean@199
   638
                }
Dean@199
   639
Dean@179
   640
                this.refreshOngoing = false;
Dean@179
   641
            }
Dean@175
   642
Dean@159
   643
            return;
Dean@159
   644
        }
Dean@159
   645
Dean@169
   646
        /// <summary>
Dean@169
   647
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
   648
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
   649
        /// </summary>
Dean@169
   650
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
   651
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
   652
        /// and the inspector is not displayed.</param>
Dean@169
   653
        private void MailItem_Open(ref bool cancel)
Dean@159
   654
        {
Dean@173
   655
            if (this.associatedMailItem != null && this.associatedMailItem.MirrorDisplay())
Dean@169
   656
            {
Dean@169
   657
                cancel = true;
Dean@169
   658
            }
Dean@169
   659
Dean@169
   660
            return;
Dean@159
   661
        }
Dean@159
   662
Dean@169
   663
        /// <summary>
Dean@169
   664
        /// Event handler for when a mail item property is changed.
Dean@169
   665
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
   666
        /// </summary>
Dean@169
   667
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@169
   668
        private void MailItem_PropertyChange(string propertyName)
Dean@159
   669
        {
Dean@179
   670
            switch (propertyName.ToUpper())
Dean@159
   671
            {
Dean@179
   672
                case "TO":
Dean@179
   673
                    // Start the refresh timer
Dean@179
   674
                    this.TimerRefresh.Enabled = true;
Dean@159
   675
                    break;
Dean@159
   676
                // Outlook bug: there are always both events, so one is enough
Dean@159
   677
                //case "CC":
Dean@179
   678
                //    // Start the refresh timer
Dean@179
   679
                //    this.TimerRefresh.Enabled = true;
Dean@159
   680
                //    break;
Dean@159
   681
            }
Dean@169
   682
Dean@169
   683
            return;
Dean@159
   684
        }
Dean@159
   685
Dean@179
   686
        /// <summary>
Dean@179
   687
        /// Event handler for when the encryption status button is clicked.
Dean@179
   688
        /// </summary>
Dean@178
   689
        private void ButtonEncryptionStatus_Click(object sender, EventArgs e)
vb@133
   690
        {
Dean@179
   691
            string text;
Dean@179
   692
            string reason;
Dean@179
   693
            string[] keys;
Dean@179
   694
            State state = this.CopyUIToState();
Dean@179
   695
            
Dean@179
   696
            switch (state.EncryptionStatus)
vb@133
   697
            {
vb@133
   698
                case _pEp_color.pEp_rating_green:
vb@133
   699
                    try
vb@133
   700
                    {
Dean@179
   701
                        keys = this.associatedMailItem.Keylist;
Dean@179
   702
Dean@179
   703
                        if (keys.Length > 0)
vb@133
   704
                        {
Dean@179
   705
                            if (keys.Length > 1)
Dean@179
   706
                            {
Dean@179
   707
                                text = String.Format(pEp.Properties.Resources.EncryptionStatusClickMessageMultiple + " {0}.",
Dean@179
   708
                                                     String.Join(", ", keys));
Dean@179
   709
                            }
vb@133
   710
                            else
Dean@179
   711
                            {
Dean@179
   712
                                text = String.Format(pEp.Properties.Resources.EncryptionStatusClickMessageSingle + " {0}.", 
Dean@179
   713
                                                     keys[0]);
Dean@179
   714
                            }
Dean@179
   715
Dean@179
   716
                            // Display all keys the message is encrypted with
Dean@179
   717
                            MessageBox.Show(text, 
Dean@179
   718
                                            pEp.Properties.Resources.EncryptionStatusClickMessageBox, 
Dean@179
   719
                                            MessageBoxButtons.OK, 
Dean@179
   720
                                            MessageBoxIcon.Information);
vb@133
   721
                        }
vb@133
   722
                    }
vb@133
   723
                    catch (Exception ex)
vb@133
   724
                    {
vb@133
   725
                        StopHere(ex.ToString());
vb@133
   726
                    }
vb@133
   727
                    break;
vb@133
   728
vb@133
   729
                case _pEp_color.pEp_rating_yellow:
vb@133
   730
                    try
vb@133
   731
                    {
Dean@173
   732
                        if (this.associatedMailItem.IsIncoming)
vb@133
   733
                        {
vb@133
   734
                            pEp_identity_s identityPartner = new pEp_identity_s();
Dean@173
   735
                            identityPartner.address = this.associatedMailItem.FromAddress;
Dean@173
   736
                            identityPartner.username = this.associatedMailItem.FromUsername;
dean@144
   737
                            identityPartner.user_id = CryptableMailItem.GetUserIDFromAddress(identityPartner.address, identityPartner.username);
vb@139
   738
vb@133
   739
                            try
vb@133
   740
                            {
vb@133
   741
                                identityPartner = ThisAddIn.pEp.update_identity(identityPartner);
vb@133
   742
                            }
vb@133
   743
                            catch
vb@133
   744
                            {
Dean@179
   745
                                state.EncryptionStatus = _pEp_color.pEp_rating_undefined;
Dean@179
   746
                                this.CopyStateToUI(state);
vb@133
   747
                                return;
vb@133
   748
                            }
Dean@179
   749
                            this.DoHandshake(identityPartner);
vb@133
   750
                        }
vb@133
   751
                        else // outgoing
vb@133
   752
                        {
Dean@190
   753
                            Globals.ThisAddIn.LogVerbose("yellow, handshake initiated");
vb@139
   754
vb@133
   755
                            List<pEp_identity_s> partnersToCheck = new List<pEp_identity_s>();
vb@133
   756
Dean@173
   757
                            foreach (pEp_identity_s identity in this.associatedMailItem.Addresses)
vb@133
   758
                            {
Dean@190
   759
                                Globals.ThisAddIn.LogVerbose("adding " + identity.username + " <" + identity.address + ">");
vb@139
   760
vb@133
   761
                                try
vb@133
   762
                                {
vb@133
   763
                                    pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(identity);
vb@133
   764
                                    if (identityPartner.comm_type >= _pEp_comm_type.pEp_ct_unconfirmed_encryption
vb@133
   765
                                        && identityPartner.comm_type < _pEp_comm_type.pEp_ct_confirmed_encryption)
vb@133
   766
                                    {
vb@133
   767
                                        partnersToCheck.Add(identityPartner);
vb@133
   768
                                    }
vb@133
   769
                                }
vb@133
   770
                                catch
vb@133
   771
                                {
vb@133
   772
                                }
vb@133
   773
                            }
vb@133
   774
vb@133
   775
                            if (partnersToCheck.Count == 0)
vb@133
   776
                            {
Dean@179
   777
                                state.EncryptionStatus = _pEp_color.pEp_rating_undefined;
Dean@179
   778
                                this.CopyStateToUI(state);
vb@133
   779
                                return;
vb@133
   780
                            }
vb@133
   781
Dean@173
   782
                            pEp_identity_s[] addresses = this.associatedMailItem.Addresses;
vb@133
   783
vb@133
   784
                            if (addresses.Length == 1)
vb@133
   785
                            {
Dean@179
   786
                                this.DoHandshake(partnersToCheck[0]);
vb@133
   787
                            }
vb@133
   788
                            else if (addresses.Length > 1)
vb@133
   789
                            {
Dean@178
   790
                                ContextMenuHandshake.Items.Clear();
Dean@179
   791
                                foreach (pEp_identity_s identity in partnersToCheck) 
Dean@179
   792
                                {
Dean@179
   793
                                    text = identity.username + " <" + identity.address + ">";
Dean@179
   794
                                    ContextMenuHandshake.Items.Add(text, 
Dean@179
   795
                                                                   null, 
Dean@179
   796
                                                                   (x, y) => { this.DoHandshake(identity); });
vb@133
   797
                                }
Dean@178
   798
                                ContextMenuHandshake.Show(ButtonEncryptionStatus, 10, 10);
vb@133
   799
                            }
vb@133
   800
                        }
vb@133
   801
                    }
vb@133
   802
                    catch (COMException ex)
vb@133
   803
                    {
vb@133
   804
                        StopHere(ex.ToString());
vb@133
   805
                    }
vb@133
   806
                    catch (Exception ex)
vb@133
   807
                    {
vb@133
   808
                        StopHere(ex.ToString());
vb@133
   809
                    }
vb@133
   810
                    break;
vb@133
   811
vb@133
   812
                case _pEp_color.pEp_rating_unencrypted:
Dean@173
   813
                    if (this.associatedMailItem.IsIncoming)
vb@133
   814
                    {
vb@133
   815
                        MessageBox.Show(pEp.Properties.Resources.RatingUnencryptedMessageboxReasonBody, pEp.Properties.Resources.RatingUnencryptedMessageboxReasonTitle);
vb@133
   816
                    }
vb@133
   817
                    else
vb@133
   818
                    {
vb@133
   819
                        try
vb@133
   820
                        {
Dean@179
   821
                            reason = "";
Dean@173
   822
                            foreach (pEp_identity_s identity in this.associatedMailItem.Addresses)
vb@133
   823
                            {
vb@133
   824
                                if (identity.comm_type < _pEp_comm_type.pEp_ct_security_by_obscurity)
vb@133
   825
                                {
vb@133
   826
                                    if (reason != "")
vb@133
   827
                                        reason += "\n";
vb@133
   828
                                    // BUG: reason string in English language only and trivial
vb@133
   829
                                    string ct = identity.comm_type.ToString();
vb@133
   830
                                    ct = new string(ct.Skip(7).ToArray());
vb@133
   831
                                    ct = ct.Replace("_", " ");
vb@133
   832
                                    reason += identity.username + " <" + identity.address + ">: " + ct;
vb@133
   833
                                }
vb@133
   834
                            }
vb@133
   835
                            if (reason != "")
vb@133
   836
                                MessageBox.Show(reason, pEp.Properties.Resources.RatingUnencryptedMessageboxReasonTitle);
vb@133
   837
                        }
vb@133
   838
                        catch (COMException ex)
vb@133
   839
                        {
vb@133
   840
                            StopHere(ex.ToString());
vb@133
   841
                        }
vb@133
   842
                    }
vb@133
   843
                    break;
vb@133
   844
vb@133
   845
                case _pEp_color.pEp_rating_cannot_decrypt:
vb@133
   846
                case _pEp_color.pEp_rating_have_no_key:
vb@133
   847
                    try
vb@133
   848
                    {
Dean@179
   849
                        keys = this.associatedMailItem.Keylist;
vb@133
   850
vb@133
   851
                        if (keys.Length > 1)
vb@133
   852
                        {
vb@133
   853
                            if (keys.Length == 2)
Dean@179
   854
                            {
vb@133
   855
                                reason = pEp.Properties.Resources.RatingHavenokeyMessageboxReasonBodyNokey;
Dean@179
   856
                            }
vb@133
   857
                            else
Dean@179
   858
                            {
Dean@179
   859
                                reason = string.Format(pEp.Properties.Resources.RatingHavenokeyMessageboxReasonBodySomekey, 
Dean@179
   860
                                                       keys.Length - 1);
Dean@179
   861
                            }
vb@133
   862
vb@133
   863
                            string keyinfo = "";
vb@133
   864
vb@133
   865
                            foreach (string key in keys)
vb@133
   866
                            {
vb@133
   867
                                if (key.Length >= 8)
vb@133
   868
                                    keyinfo += "\n" + key;
vb@133
   869
                            }
vb@133
   870
vb@133
   871
                            reason += keyinfo;
vb@133
   872
Dean@179
   873
                            MessageBox.Show(reason, 
Dean@179
   874
                                            pEp.Properties.Resources.RatingHavenokeyTitle);
vb@133
   875
                        }
vb@133
   876
                        else if (keys.Length == 1)
vb@133
   877
                        {
Dean@179
   878
                            MessageBox.Show(pEp.Properties.Resources.RatingHavenokeyMessageboxReasonError + keys[0], 
Dean@179
   879
                                            pEp.Properties.Resources.RatingHavenokeyTitle);
vb@133
   880
                        }
vb@133
   881
                        else
vb@133
   882
                        {
Dean@179
   883
                            MessageBox.Show(pEp.Properties.Resources.RatingHavenokeyMessageboxReasonUnknownformat, 
Dean@179
   884
                                            pEp.Properties.Resources.RatingHavenokeyTitle);
vb@133
   885
                        }
vb@133
   886
                    }
vb@133
   887
                    catch (COMException ex)
vb@133
   888
                    {
vb@133
   889
                        StopHere(ex.ToString());
vb@133
   890
                    }
vb@133
   891
                    break;
vb@133
   892
                    
vb@133
   893
                case _pEp_color.pEp_rating_undefined:
vb@133
   894
                    break;
vb@133
   895
            }
Dean@179
   896
Dean@179
   897
            return;
vb@133
   898
        }
vb@133
   899
Dean@179
   900
        /// <summary>
Dean@179
   901
        /// Event handler for when a mouse button is released over the encryption status button.
Dean@179
   902
        /// This will show the context menu.
Dean@179
   903
        /// </summary>
Dean@179
   904
        private void ButtonEncryptionStatus_MouseUp(object sender, MouseEventArgs e)
vb@133
   905
        {
Dean@179
   906
            bool showContextMenu = false;
Dean@179
   907
            string text;
Dean@179
   908
            Button button;
vb@133
   909
Dean@179
   910
            if ((sender != null) &&
Dean@179
   911
                (e.Button == System.Windows.Forms.MouseButtons.Right))
Dean@179
   912
            { 
Dean@179
   913
                button = (Button)sender;
Dean@179
   914
                
Dean@179
   915
                // Remove all tool strip menu items except the first, which should be send unencrypted
Dean@179
   916
                while (this.ContextMenuEncryptionStatus.Items.Count > 1)
Dean@179
   917
                {
Dean@179
   918
                    this.ContextMenuEncryptionStatus.Items.RemoveAt(1);
Dean@179
   919
                }
vb@133
   920
Dean@179
   921
                // Enable the send unencrypted menu item
Dean@173
   922
                if (this.associatedMailItem != null && 
Dean@173
   923
                    !this.associatedMailItem.IsIncoming && 
Dean@173
   924
                    !this.associatedMailItem.IsInSentFolder && 
Dean@173
   925
                    this.associatedMailItem.OutgoingColor > _pEp_color.pEp_rating_unencrypted)
vb@133
   926
                {
Dean@179
   927
                    this.ToolStripMenuItemSendUnencrypted.Visible = true;
Dean@179
   928
                    showContextMenu = true;
Dean@179
   929
                }
Dean@179
   930
                else
Dean@179
   931
                {
Dean@179
   932
                    this.ToolStripMenuItemSendUnencrypted.Visible = false;
Dean@179
   933
                }
Dean@179
   934
Dean@179
   935
                // Build and enable any options to untrust identities
Dean@179
   936
                if (this.associatedMailItem != null)
Dean@179
   937
                {
Dean@179
   938
                    if (this.associatedMailItem.IsIncoming)
vb@133
   939
                    {
Dean@179
   940
                        // Create and update identity of the sender
Dean@179
   941
                        pEp_identity_s ident;
Dean@179
   942
                        ident          = new pEp_identity_s();
Dean@179
   943
                        ident.address  = this.associatedMailItem.FromAddress;
Dean@179
   944
                        ident.username = this.associatedMailItem.FromUsername;
Dean@179
   945
                        ident.user_id  = CryptableMailItem.GetUserIDFromAddress(ident.address, ident.username);
Dean@179
   946
                        ident = ThisAddIn.pEp.update_identity(ident);
Dean@179
   947
Dean@179
   948
                        text = pEp.Properties.Resources.IdentityTrustText + 
Dean@179
   949
                               ident.username + " <" + ident.address + ">";
Dean@179
   950
Dean@179
   951
                        this.ContextMenuEncryptionStatus.Items.Add(text, 
Dean@179
   952
                                                                   null, 
Dean@179
   953
                                                                   (x, y) => { this.UndoHandshake(ident); });
vb@133
   954
                    }
Dean@179
   955
                    else
Dean@173
   956
                    {
Dean@179
   957
                        foreach (pEp_identity_s ident in this.associatedMailItem.Addresses)
Dean@179
   958
                        {
Dean@179
   959
                            pEp_identity_s identityPartner = ThisAddIn.pEp.update_identity(ident);
Dean@179
   960
Dean@179
   961
                            if (identityPartner.comm_type >= _pEp_comm_type.pEp_ct_confirmed_encryption)
Dean@179
   962
                            {
Dean@179
   963
                                text = pEp.Properties.Resources.IdentityTrustText + 
Dean@179
   964
                                       ident.username + " <" + ident.address + ">";
Dean@179
   965
Dean@179
   966
                                this.ContextMenuEncryptionStatus.Items.Add(text, 
Dean@179
   967
                                                                           null, 
Dean@179
   968
                                                                           (x, y) => { this.UndoHandshake(ident); });
Dean@179
   969
                            }
Dean@179
   970
                        }
vb@133
   971
                    }
vb@133
   972
Dean@179
   973
                    showContextMenu = true;
Dean@179
   974
                }
Dean@179
   975
Dean@179
   976
                // Show the context menu
Dean@179
   977
                if (showContextMenu)
Dean@179
   978
                {
Dean@179
   979
                    this.ContextMenuEncryptionStatus.Show(button.PointToScreen(e.Location));
vb@133
   980
                }
vb@133
   981
            }
Dean@179
   982
Dean@179
   983
            return;
vb@133
   984
        }
vb@133
   985
Dean@179
   986
        /// <summary>
Dean@179
   987
        /// Event handler for when the send unencrypted tool strip menu is clicked.
Dean@179
   988
        /// This will update whether the email is sent unencrypted or not.
Dean@179
   989
        /// </summary>
Dean@179
   990
        private void ToolStripMenuItemSendUnencrypted_Click(object sender, EventArgs e)
vb@133
   991
        {
Dean@180
   992
            /* Note: This portion of the code follows convention for easier maintainabilty.
Dean@180
   993
             * It is not the most simple approach -- however, please don't simplify without consideration.
Dean@180
   994
             */
Dean@180
   995
Dean@179
   996
            // Toggle the checked state
Dean@179
   997
            this.ToolStripMenuItemSendUnencrypted.Checked = !this.ToolStripMenuItemSendUnencrypted.Checked;
Dean@179
   998
Dean@179
   999
            // Change the mail item based on UI state, also refresh
Dean@179
  1000
            State state = this.CopyUIToState();
Dean@179
  1001
            this.associatedMailItem.SendUnencrypted = state.SendUnencryptedCheckState;
Dean@179
  1002
            this.CopyStateToUI(state);
Dean@179
  1003
Dean@179
  1004
            this.UpdateUIFromMailItem();
Dean@179
  1005
Dean@179
  1006
            return;
Dean@179
  1007
        }
Dean@179
  1008
Dean@179
  1009
        /// <summary>
Dean@179
  1010
        /// Event handler for when the explanation link label is clicked.
Dean@179
  1011
        /// This will show detailed information for the current encryption state.
Dean@179
  1012
        /// </summary>
Dean@179
  1013
        private void LinkLabelExplanation_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
Dean@179
  1014
        {
Dean@179
  1015
            State state = this.CopyUIToState();
Dean@179
  1016
Dean@179
  1017
            var result = MessageBox.Show(
Dean@179
  1018
                            state.Explanation + "\n\n" + state.Suggestion,
Dean@179
  1019
                            state.Title,
Dean@179
  1020
                            MessageBoxButtons.OK,
Dean@179
  1021
                            state.EncryptionStatus == _pEp_color.pEp_rating_under_attack
Dean@179
  1022
                                ? MessageBoxIcon.Stop
Dean@179
  1023
                                : MessageBoxIcon.Information
Dean@179
  1024
                        );
Dean@179
  1025
Dean@179
  1026
            return;
vb@133
  1027
        }
Dean@151
  1028
Dean@151
  1029
        /// <summary>
Dean@151
  1030
        /// Event handler for when the options picture box is clicked.
Dean@151
  1031
        /// This will open the options form for user editing.
Dean@151
  1032
        /// </summary>
Dean@151
  1033
        private void PictureBoxOptions_Click(object sender, EventArgs e)
Dean@151
  1034
        {
Dean@159
  1035
            DialogResult result;
Dean@152
  1036
            FormOptions frm = new FormOptions();
Dean@154
  1037
            frm.StartPosition = FormStartPosition.CenterScreen;
Dean@159
  1038
            result = frm.ShowDialog(this.ParentForm); // Must show as dialog to block code
Dean@151
  1039
Dean@151
  1040
            return;
Dean@151
  1041
        }
Dean@151
  1042
Dean@151
  1043
        /// <summary>
Dean@151
  1044
        /// Event handler for when the mouse hovers over the options picture box.
Dean@151
  1045
        /// This is a work-around to show a tool tip.
Dean@151
  1046
        /// </summary>
Dean@151
  1047
        private void PictureBoxOptions_MouseHover(object sender, EventArgs e)
Dean@151
  1048
        {
Dean@151
  1049
            ToolTip toolTip = new ToolTip();
Dean@174
  1050
            toolTip.SetToolTip(this.PictureBoxOptions, "Click to open options"); // TODO: translate me
Dean@151
  1051
            return;
Dean@151
  1052
        }
Dean@166
  1053
Dean@166
  1054
        /**************************************************************
Dean@166
  1055
         * 
Dean@166
  1056
         * Sub-classes
Dean@166
  1057
         * 
Dean@166
  1058
         *************************************************************/
Dean@166
  1059
Dean@166
  1060
        /// <summary>
Dean@166
  1061
        /// Class used to store the state of the encryption status panel.
Dean@166
  1062
        /// </summary>
Dean@166
  1063
        public class State
Dean@166
  1064
        {
Dean@166
  1065
            private _pEp_color _EncryptionStatus;
Dean@179
  1066
            private CheckState _SendUnencryptedCheckState;
Dean@166
  1067
Dean@166
  1068
            private string _Title;
Dean@166
  1069
            private string _Explanation;
Dean@166
  1070
            private string _Suggestion;
Dean@166
  1071
            private Color  _ButtonBackground;
Dean@166
  1072
            private Color  _ButtonForeground;
Dean@166
  1073
            private string _ButtonText;
Dean@166
  1074
Dean@166
  1075
            /**************************************************************
Dean@166
  1076
             * 
Dean@166
  1077
             * Constructors
Dean@166
  1078
             * 
Dean@166
  1079
             *************************************************************/
Dean@166
  1080
Dean@166
  1081
            /// <summary>
Dean@166
  1082
            /// Default constructor.
Dean@166
  1083
            /// </summary>
Dean@166
  1084
            public State()
Dean@166
  1085
            {
Dean@166
  1086
                this.Reset();
Dean@166
  1087
            }
Dean@166
  1088
Dean@166
  1089
            /**************************************************************
Dean@166
  1090
             * 
Dean@166
  1091
             * Property Accessors
Dean@166
  1092
             * 
Dean@166
  1093
             *************************************************************/
Dean@166
  1094
Dean@166
  1095
            /// <summary>
Dean@166
  1096
            /// Gets or sets the encryption status as a pEp color rating.
Dean@166
  1097
            /// </summary>
Dean@166
  1098
            public _pEp_color EncryptionStatus
Dean@166
  1099
            {
Dean@166
  1100
                get { return (this._EncryptionStatus); }
Dean@166
  1101
                set 
Dean@166
  1102
                { 
Dean@166
  1103
                    this._EncryptionStatus = value;
Dean@179
  1104
                    this.UpdateDependentProperties();
Dean@166
  1105
                }
Dean@166
  1106
            }
Dean@166
  1107
Dean@166
  1108
            /// <summary>
Dean@179
  1109
            /// Gets or sets whether the send unencrypted checkbox is checked by the user.
Dean@179
  1110
            /// </summary>
Dean@179
  1111
            public CheckState SendUnencryptedCheckState
Dean@179
  1112
            {
Dean@179
  1113
                get { return (this._SendUnencryptedCheckState); }
Dean@179
  1114
                set { this._SendUnencryptedCheckState = value; }
Dean@179
  1115
            }
Dean@179
  1116
Dean@179
  1117
            /// <summary>
Dean@166
  1118
            /// Gets the title of the encryption status.
Dean@166
  1119
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1120
            /// </summary>
Dean@166
  1121
            public string Title
Dean@166
  1122
            {
Dean@166
  1123
                get { return (this._Title); }
Dean@166
  1124
            }
Dean@166
  1125
Dean@166
  1126
            /// <summary>
Dean@166
  1127
            /// Gets the explanation for the encryption status.
Dean@166
  1128
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1129
            /// </summary>
Dean@166
  1130
            public string Explanation
Dean@166
  1131
            {
Dean@166
  1132
                get { return (this._Explanation); }
Dean@166
  1133
            }
Dean@166
  1134
Dean@166
  1135
            /// <summary>
Dean@166
  1136
            /// Gets the suggestion to improve the encryption status.
Dean@166
  1137
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1138
            /// </summary>
Dean@166
  1139
            public string Suggestion
Dean@166
  1140
            {
Dean@166
  1141
                get { return (this._Suggestion); }
Dean@166
  1142
            }
Dean@166
  1143
Dean@166
  1144
            /// <summary>
Dean@166
  1145
            /// Gets the background color of the encryption button.
Dean@166
  1146
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1147
            /// </summary>
Dean@166
  1148
            public Color ButtonBackground
Dean@166
  1149
            {
Dean@166
  1150
                get { return (this._ButtonBackground); }
Dean@166
  1151
            }
Dean@166
  1152
Dean@166
  1153
            /// <summary>
Dean@166
  1154
            /// Gets the foreground color of the encryption button.
Dean@166
  1155
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1156
            /// </summary>
Dean@166
  1157
            public Color ButtonForeground
Dean@166
  1158
            {
Dean@166
  1159
                get { return (this._ButtonForeground); }
Dean@166
  1160
            }
Dean@166
  1161
Dean@166
  1162
            /// <summary>
Dean@166
  1163
            /// Gets the text of the encryption button.
Dean@166
  1164
            /// This is dependent on EncryptionStatus and therefore automatically set.
Dean@166
  1165
            /// </summary>
Dean@166
  1166
            public string ButtonText
Dean@166
  1167
            {
Dean@166
  1168
                get { return (this._ButtonText); }
Dean@166
  1169
            }
Dean@166
  1170
Dean@166
  1171
            /**************************************************************
Dean@166
  1172
             * 
Dean@166
  1173
             * Methods
Dean@166
  1174
             * 
Dean@166
  1175
             *************************************************************/
Dean@166
  1176
Dean@166
  1177
            /// <summary>
Dean@166
  1178
            /// Resets the object to it's default values.
Dean@166
  1179
            /// </summary>
Dean@166
  1180
            public void Reset()
Dean@166
  1181
            {
Dean@179
  1182
                this._EncryptionStatus          = _pEp_color.pEp_rating_undefined;
Dean@179
  1183
                this._SendUnencryptedCheckState = CheckState.Indeterminate;
Dean@179
  1184
                this.UpdateDependentProperties();
Dean@166
  1185
Dean@166
  1186
                return;
Dean@166
  1187
            }
Dean@166
  1188
Dean@166
  1189
            /// <summary>
Dean@166
  1190
            /// Updates any properties dependent on the encryption status.
Dean@166
  1191
            /// </summary>
Dean@179
  1192
            private void UpdateDependentProperties()
Dean@166
  1193
            {
Dean@166
  1194
                switch (this._EncryptionStatus)
Dean@166
  1195
                {
Dean@166
  1196
                    case _pEp_color.pEp_rating_trusted:
Dean@166
  1197
                    case _pEp_color.pEp_rating_trusted_and_anonymized:
Dean@166
  1198
                        this._Title       = pEp.Properties.Resources.RatingTrustedTitle;
Dean@166
  1199
                        this._Explanation = pEp.Properties.Resources.RatingTrustedExplanation;
Dean@166
  1200
                        this._Suggestion  = pEp.Properties.Resources.RatingTrustedSuggestion;
Dean@166
  1201
                        
Dean@166
  1202
                        this._ButtonBackground = COLOR_GREEN;
Dean@166
  1203
                        this._ButtonForeground = TEXT_COLOR_WHITE;
Dean@166
  1204
                        this._ButtonText       = pEp.Properties.Resources.RatingTrustedButtontext;
Dean@166
  1205
                        break;
Dean@166
  1206
Dean@166
  1207
                    case _pEp_color.pEp_rating_reliable:
Dean@166
  1208
                        this._Title       = pEp.Properties.Resources.RatingReliableTitle;
Dean@182
  1209
                        this._Explanation = pEp.Properties.Resources.RatingReliableExplanation;
Dean@166
  1210
                        this._Suggestion  = pEp.Properties.Resources.RatingReliableSuggestion;
Dean@166
  1211
                        
Dean@166
  1212
                        this._ButtonBackground = COLOR_YELLOW;
Dean@166
  1213
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1214
                        this._ButtonText       = pEp.Properties.Resources.RatingReliableButtontext;
Dean@166
  1215
                        break;
Dean@166
  1216
Dean@166
  1217
                    case _pEp_color.pEp_rating_unreliable:
Dean@166
  1218
                        this._Title       = pEp.Properties.Resources.RatingUnreliableTitle;
Dean@166
  1219
                        this._Explanation = pEp.Properties.Resources.RatingUnreliableExplanation;
Dean@166
  1220
                        this._Suggestion  = pEp.Properties.Resources.RatingUnreliableSuggestion;
Dean@166
  1221
                        
Dean@166
  1222
                        this._ButtonBackground = COLOR_GREY;
Dean@166
  1223
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1224
                        this._ButtonText       = pEp.Properties.Resources.RatingUnreliableButtontext;
Dean@166
  1225
                        break;
Dean@166
  1226
Dean@166
  1227
                    case _pEp_color.pEp_rating_unencrypted:
Dean@166
  1228
                        this._Title       = pEp.Properties.Resources.RatingUnencryptedTitle;
Dean@166
  1229
                        this._Explanation = pEp.Properties.Resources.RatingUnencryptedExplanation;
Dean@166
  1230
                        this._Suggestion  = pEp.Properties.Resources.RatingUnencryptedSuggestion;
Dean@166
  1231
                        
Dean@166
  1232
                        this._ButtonBackground = COLOR_GREY;
Dean@166
  1233
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1234
                        this._ButtonText       = pEp.Properties.Resources.RatingUnencryptedButtontext;
Dean@166
  1235
                        break;
Dean@166
  1236
Dean@166
  1237
                    case _pEp_color.pEp_rating_under_attack:
Dean@166
  1238
                        this._Title       = pEp.Properties.Resources.RatingUnderattackTitle;
Dean@166
  1239
                        this._Explanation = pEp.Properties.Resources.RatingUnderattackExplanation;
Dean@166
  1240
                        this._Suggestion  = pEp.Properties.Resources.RatingUnderattackSuggestion;
Dean@166
  1241
                        
Dean@166
  1242
                        this._ButtonBackground = COLOR_RED;
Dean@166
  1243
                        this._ButtonForeground = TEXT_COLOR_WHITE;
Dean@166
  1244
                        this._ButtonText       = pEp.Properties.Resources.RatingUnderattackButtontext;
Dean@166
  1245
                        break;
Dean@166
  1246
Dean@166
  1247
                    case _pEp_color.pEp_rating_undefined:
Dean@166
  1248
                        this._Title       = pEp.Properties.Resources.RatingUndefinedTitle;
Dean@166
  1249
                        this._Explanation = pEp.Properties.Resources.RatingUndefinedExplanation;
Dean@166
  1250
                        this._Suggestion  = pEp.Properties.Resources.RatingUndefinedSuggestion;
Dean@166
  1251
                        
Dean@166
  1252
                        this._ButtonBackground = COLOR_GREY;
Dean@166
  1253
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1254
                        this._ButtonText       = pEp.Properties.Resources.RatingUndefinedButtontext;
Dean@166
  1255
                        break;
Dean@166
  1256
Dean@166
  1257
                    case _pEp_color.pEp_rating_cannot_decrypt:
Dean@166
  1258
                    case _pEp_color.pEp_rating_have_no_key:
Dean@166
  1259
                        this._Title       = pEp.Properties.Resources.RatingHavenokeyTitle;
Dean@166
  1260
                        this._Explanation = pEp.Properties.Resources.RatingHavenokeyExplanation;
Dean@166
  1261
                        this._Suggestion  = pEp.Properties.Resources.RatingHavenokeySuggestion;
Dean@166
  1262
                        
Dean@166
  1263
                        this._ButtonBackground = COLOR_GREY;
Dean@166
  1264
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1265
                        this._ButtonText       = pEp.Properties.Resources.RatingHavenokeyButtontext;
Dean@166
  1266
                        break;
Dean@166
  1267
Dean@166
  1268
                    default:
Dean@166
  1269
                        this._Title       = "";
Dean@166
  1270
                        this._Explanation = "";
Dean@166
  1271
                        this._Suggestion  = "";
Dean@166
  1272
                        
Dean@166
  1273
                        this._ButtonBackground = COLOR_GREY;
Dean@166
  1274
                        this._ButtonForeground = TEXT_COLOR_BLACK;
Dean@166
  1275
                        this._ButtonText       = "";
Dean@166
  1276
                        break;
Dean@166
  1277
                }
Dean@166
  1278
Dean@166
  1279
                return;
Dean@166
  1280
            }
Dean@166
  1281
Dean@166
  1282
        }
vb@133
  1283
    }
vb@133
  1284
}