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