UI/FormRegionPrivacyStatus.cs
author Thomas
Tue, 17 Jan 2017 17:17:51 +0100
changeset 1547 78720b1a2290
parent 1529 a0670373f5b4
child 1551 de7d9dd0b223
permissions -rw-r--r--
OUT-155: Limit max repetitions for recalculating
Dean@1069
     1
´╗┐using pEp.UI;
Dean@1069
     2
using pEpCOMServerAdapterLib;
Dean@159
     3
using System;
vb@133
     4
using System.Collections.Generic;
Dean@445
     5
using System.ComponentModel;
Dean@859
     6
using System.Diagnostics;
Thomas@1524
     7
using System.Linq;
Dean@159
     8
using System.Runtime.InteropServices;
Dean@1074
     9
using System.Windows;
vb@133
    10
using System.Windows.Forms;
Dean@1069
    11
using System.Windows.Media.Imaging;
vb@133
    12
using Outlook = Microsoft.Office.Interop.Outlook;
vb@133
    13
vb@133
    14
namespace pEp
vb@133
    15
{
Dean@159
    16
    /// <summary>
Dean@312
    17
    /// Partial class for the privacy status form region that is displayed below every outlook message.
Dean@159
    18
    /// </summary>
Dean@910
    19
    internal partial class FormRegionPrivacyStatus
vb@133
    20
    {
vb@133
    21
        #region Form Region Factory
vb@133
    22
vb@133
    23
        [Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
Dean@312
    24
        [Microsoft.Office.Tools.Outlook.FormRegionName("pEp.FormRegionPrivacyStatus")]
Dean@312
    25
        public partial class FormRegionPrivacyStatusFactory
vb@133
    26
        {
vb@133
    27
            // Occurs before the form region is initialized.
vb@133
    28
            // To prevent the form region from appearing, set e.Cancel to true.
vb@133
    29
            // Use e.OutlookItem to get a reference to the current Outlook item.
Dean@312
    30
            private void FormRegionPrivacyStatus_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
vb@133
    31
            {
Dean@1138
    32
                Outlook.MailItem omi;
Dean@1138
    33
Dean@1138
    34
                try
Dean@1138
    35
                {
Dean@1138
    36
                    omi = (Outlook.MailItem)e.OutlookItem;
Dean@1138
    37
                }
Dean@1138
    38
                catch
Dean@1138
    39
                {
Dean@1138
    40
                    // Never load if it's not a MailItem
Dean@1138
    41
                    e.Cancel = true;
Dean@1138
    42
                    return;
Dean@1138
    43
                }
Dean@1138
    44
Dean@985
    45
                //WindowFormRegionCollection formRegions;
Dean@327
    46
Dean@327
    47
                /* There is a Microsoft bug at least in Outlook 2013 and Windows 8.1
Dean@327
    48
                 * This bug causes multiple PrivacyStatus form regions to appear stacked on top of each other.
Dean@327
    49
                 * To trigger this bug, on an unencrypted server, click reply to compose an in-line response.
Dean@327
    50
                 * Then click to another tab such as People or Tasks. Then click back on the mail tab to view 
Dean@327
    51
                 * the original email again. Two form regions will be visible: 
Dean@327
    52
                 * (1) for the status during the in-line reply and 
Dean@327
    53
                 * (2) for the status of only the received message.
Dean@327
    54
                 * 
Dean@327
    55
                 * To fix this bug, any existing form regions are found and closed when initializing a new privacy status
Dean@327
    56
                 * form region.
Dean@327
    57
                 */
Dean@985
    58
                /*
Dean@327
    59
                try
Dean@327
    60
                {
Dean@987
    61
                    formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@327
    62
                    if (formRegions.FormRegionPrivacyStatus != null)
Dean@327
    63
                    {
Dean@985
    64
                        // Note: there seems to be no way to actually close the form region.
Dean@985
    65
                        // Therefore, this is as close as possible to actually closing it.
Dean@985
    66
                        // The actual form regions will be cleaned up as soon as another email is selected.
Dean@327
    67
                        formRegions.FormRegionPrivacyStatus.OutlookFormRegion.Visible = false;
Dean@327
    68
                    }
Dean@327
    69
                }
Dean@327
    70
                catch { }
Dean@985
    71
                */
Dean@1169
    72
Dean@327
    73
                return;
vb@133
    74
            }
vb@133
    75
        }
vb@133
    76
vb@133
    77
        #endregion
vb@133
    78
Dean@159
    79
        /* Notes:
Dean@179
    80
         * 
Dean@159
    81
         * Use this.OutlookItem to get a reference to the current Outlook item.
Dean@159
    82
         * Use this.OutlookFormRegion to get a reference to the form region.
Dean@179
    83
         * 
Dean@179
    84
         * UI State Managment:
Dean@179
    85
         * 
Dean@179
    86
         * The UI state is almost entirely set from the associated mail item data.
Dean@179
    87
         * However, a separate state class is maintained to represent the UI as some separation is needed.
Dean@179
    88
         * This logical separation MUST be maintained throughout the code.
Dean@179
    89
         * Specific cases are noted where possible.
Dean@179
    90
         * 
Dean@356
    91
         * The separate privacy status manager form state is also managed here.
Dean@159
    92
         */
Dean@159
    93
Dean@1384
    94
        /// <summary>
Dean@1384
    95
        /// Event for when the form region is expanded or collapsed.
Dean@1384
    96
        /// </summary>
Dean@1384
    97
        public event EventHandler Expanded;
Dean@1384
    98
Dean@1390
    99
        private CryptableMailItem       cryptableMailItem      = null;
Dean@1390
   100
        private bool                    displayMirrorRequested = false;
Dean@1390
   101
        private bool                    isEnabled              = true;
Dean@1384
   102
        private bool?                   isExpandedPrevious     = null;
Dean@1390
   103
        private bool                    isManagerFormEnabled   = true;
Dean@1390
   104
        private bool                    isStarted              = false;
Dean@758
   105
        private FormManagePrivacyStatus managerForm            = null;
Thomas@1505
   106
        private bool                    processingOngoing      = false;
Dean@1402
   107
        private bool                    refreshOngoing         = false;
Thomas@1419
   108
        private bool                    repeatProcessing       = false;
Thomas@1547
   109
        private int                     repeatCounter          = 0;
Thomas@1547
   110
        private const int               maxRepeatCount         = 5;
Dean@259
   111
Dean@159
   112
        /**************************************************************
Dean@159
   113
         * 
Dean@1375
   114
         * Property Accessors
Dean@1375
   115
         * 
Dean@1375
   116
         *************************************************************/
Dean@1375
   117
Dean@1375
   118
        /// <summary>
Dean@1377
   119
        /// Gets or sets the displayed state.
Dean@1375
   120
        /// </summary>
Dean@1377
   121
        public FormControlPrivacyStatus.State DisplayState
Dean@1375
   122
        {
Dean@1377
   123
            get { return (this.FormControlPrivacyStatusChild.DisplayState); }
Dean@1377
   124
            set { this.FormControlPrivacyStatusChild.DisplayState = value; }
Dean@1375
   125
        }
Dean@1375
   126
Dean@1375
   127
        /**************************************************************
Dean@1375
   128
         * 
Dean@159
   129
         * Methods
Dean@159
   130
         * 
Dean@159
   131
         *************************************************************/
Dean@159
   132
Dean@171
   133
        /// <summary>
Dean@438
   134
        /// Determines if this form region is running in an inspector window.
Dean@438
   135
        /// If not true, it is assumed to be within an explorer window.
Dean@438
   136
        /// </summary>
Dean@438
   137
        /// <returns>True if an inspector window, false if within an explorer.</returns>
Dean@438
   138
        private bool IsWithinInspector()
Dean@438
   139
        {
Dean@438
   140
            bool isWithinInspector = false;
Dean@895
   141
            Outlook.Inspector insp = null;
Dean@438
   142
Dean@438
   143
            try
Dean@438
   144
            {
Dean@895
   145
                /* There are two potential methods to determine if the item is within an inspector.
Dean@895
   146
                 * (1) Use this.OutlookFormRegion.Parent which will contain either the Explorer or an Inspector
Dean@895
   147
                 *     A cast could be tried to an Explorer of this parent and if it fails, it's assumed to be an inspector
Dean@895
   148
                 * (2) Use this.OutlookFormRegion.Inspector which will contain the Inspector if it exists.
Dean@895
   149
                 *     This will fail or return null if this form region is not running within it's own Inspector window.
Dean@895
   150
                 */
Dean@895
   151
                insp = this.OutlookFormRegion.Inspector;
Dean@895
   152
Dean@895
   153
                if (insp != null)
Dean@895
   154
                {
Dean@895
   155
                    isWithinInspector = true;
Dean@895
   156
                }
Dean@438
   157
            }
Dean@438
   158
            catch
Dean@438
   159
            {
Dean@895
   160
                isWithinInspector = false;
Dean@438
   161
            }
Dean@438
   162
            finally
Dean@438
   163
            {
Dean@895
   164
                if (insp != null)
Dean@438
   165
                {
vb@1516
   166
                    // Marshal.ReleaseComObject(insp);
Dean@895
   167
                    insp = null;
Dean@438
   168
                }
Dean@438
   169
            }
Dean@438
   170
Dean@438
   171
            return (isWithinInspector);
Dean@438
   172
        }
Dean@438
   173
Dean@438
   174
        /// <summary>
Dean@672
   175
        /// Completes the handshake process when the identity of a partner was previously marked as mistrusted.
Dean@281
   176
        /// </summary>
Dean@646
   177
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   178
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@672
   179
        private void DoHandshakeForMistrustedKey(PEPIdentity myself,
Dean@672
   180
                                                 PEPIdentity partner)
Dean@281
   181
        {
Dean@281
   182
            DialogResult result;
Dean@281
   183
Dean@1074
   184
            result = System.Windows.Forms.MessageBox.Show(this.ParentForm,
Dean@1074
   185
                                                          pEp.Properties.Resources.Message_WarningMistrustedKey,
Dean@1074
   186
                                                          pEp.Properties.Resources.Message_TitleConfirmOperation,
Thomas@1184
   187
                                                          MessageBoxButtons.YesNo,
Thomas@1184
   188
                                                          MessageBoxIcon.Warning);
Dean@281
   189
Dean@423
   190
            if (result == DialogResult.Yes)
Dean@281
   191
            {
Dean@646
   192
                this.DoHandshake(myself, partner);
Dean@281
   193
            }
Dean@281
   194
Dean@281
   195
            return;
Dean@281
   196
        }
Dean@281
   197
Dean@281
   198
        /// <summary>
Dean@281
   199
        /// Completes the handshake process where the identity of a partner is confirmed.
Dean@179
   200
        /// </summary>
Dean@646
   201
        /// <param name="myself">The personal identity to complete the handshake with.</param>
Dean@646
   202
        /// <param name="partner">The identity of the partner to complete the handshake with.</param>
Dean@646
   203
        private void DoHandshake(PEPIdentity myself,
Dean@646
   204
                                 PEPIdentity partner)
vb@133
   205
        {
Dean@179
   206
            DialogResult result;
Dean@155
   207
            FormHandshake handshakeDialog;
markus@201
   208
Dean@1249
   209
            Log.Verbose("DoHandshake: Handshake started.");
vb@139
   210
Dean@155
   211
            // Create and show handshake dialog
Dean@1075
   212
            handshakeDialog = new FormHandshake();
Dean@1082
   213
            handshakeDialog.StartPosition = FormStartPosition.CenterParent;
Dean@1377
   214
            handshakeDialog.DisplayState = new FormControlHandshake.State(myself, partner,
Dean@1377
   215
                                                                          Globals.ThisAddIn.Settings.TrustwordsCulture);
Dean@1086
   216
Dean@179
   217
            result = handshakeDialog.ShowDialog(this);
Dean@646
   218
            this.ProcessDoHandshakeResult(result, partner);
Dean@356
   219
Dean@356
   220
            return;
Dean@356
   221
        }
Dean@356
   222
Dean@356
   223
        /// <summary>
Dean@356
   224
        /// Processes the result of the do handshake dialog after a user makes a selection.
Dean@356
   225
        /// </summary>
Dean@356
   226
        /// <param name="result">The result of the handshake dialog selection.</param>
Dean@356
   227
        /// <param name="partner">The identity of the partner to handshake with.</param>
Dean@356
   228
        private void ProcessDoHandshakeResult(DialogResult result,
Dean@384
   229
                                              PEPIdentity partner)
Dean@356
   230
        {
markus@1337
   231
            pEpRating partnerIdentityRating;
markus@1337
   232
            pEpColor partnerIdentityColor;
markus@1337
   233
            pEpIdentity identityPartner = ThisAddIn.PEPEngine.UpdateIdentity(partner.ToCOMType());
vb@133
   234
vb@133
   235
            switch (result)
vb@133
   236
            {
vb@133
   237
                case DialogResult.Yes:
Dean@279
   238
                    {
Dean@1310
   239
                        // Get the rating/color to determine if key was previously mistrusted -- warning to user must be displayed earlier
Dean@1295
   240
                        try
Dean@281
   241
                        {
markus@1337
   242
                            partnerIdentityRating = ThisAddIn.PEPEngine.IdentityRating(identityPartner);
Dean@1310
   243
                        }
Dean@1310
   244
                        catch (COMException ex)
Dean@1310
   245
                        {
markus@1337
   246
                            partnerIdentityRating = pEpRating.pEpRatingUndefined;
Dean@1310
   247
                            Log.Warning("ProcessDoHandshakeResult: Failed to get identity rating, " + ex.ToString());
Dean@1310
   248
                        }
Dean@1341
   249
                        partnerIdentityColor = partnerIdentityRating.ToColor();
Dean@1310
   250
Dean@1310
   251
                        // Process result
Dean@1310
   252
                        try
Dean@1310
   253
                        {
markus@1337
   254
                            if (partnerIdentityColor == pEpColor.pEpColorRed)
Dean@1295
   255
                            {
markus@1337
   256
                                ThisAddIn.PEPEngine.KeyResetTrust(ref identityPartner);
Dean@1295
   257
                            }
Dean@1295
   258
markus@1337
   259
                            identityPartner = ThisAddIn.PEPEngine.TrustPersonalKey(ref identityPartner);
Dean@281
   260
                        }
Dean@1295
   261
                        catch (Exception ex)
Dean@1295
   262
                        {
Dean@1295
   263
                            Log.Error("ProcessDoHandshakeResult: Error occured while trying to set trust: " + ex.ToString());
Dean@1295
   264
                        }
Dean@279
   265
Dean@1130
   266
                        this.ImmediateRatingAndUIUpdate();
Dean@1117
   267
                        this.UpdateManagePrivacyStatusForm();
Dean@279
   268
Dean@279
   269
                        break;
Dean@279
   270
                    }
vb@133
   271
                case DialogResult.No:
Dean@279
   272
                    {
Dean@1295
   273
                        try
Dean@1295
   274
                        {
markus@1337
   275
                            ThisAddIn.PEPEngine.KeyMistrusted(ref identityPartner);
Dean@1295
   276
                        }
Dean@1295
   277
                        catch (Exception ex)
Dean@1295
   278
                        {
Dean@1295
   279
                            Log.Error("ProcessDoHandshakeResult: Error occured while trying to mistrust key: " + ex.ToString());
Dean@1295
   280
                        }
Dean@279
   281
Dean@1130
   282
                        this.ImmediateRatingAndUIUpdate();
Dean@1117
   283
                        this.UpdateManagePrivacyStatusForm();
Dean@279
   284
Dean@279
   285
                        break;
Dean@279
   286
                    }
vb@133
   287
            }
Dean@279
   288
Dean@1249
   289
            Log.Verbose("ProcessDoHandshakeResult: Handshake complete.");
Dean@740
   290
Dean@279
   291
            return;
vb@133
   292
        }
vb@133
   293
Dean@179
   294
        /// <summary>
Dean@179
   295
        /// Reverses any past handshake confirmation by unconfirming the given identity partner.
Dean@179
   296
        /// </summary>
Dean@384
   297
        /// <param name="partner">The identity of the partner to unconfirm.</param>
Dean@384
   298
        private void UndoHandshake(PEPIdentity partner)
vb@133
   299
        {
markus@1337
   300
            pEpIdentity identityPartner = ThisAddIn.PEPEngine.UpdateIdentity(partner.ToCOMType());
markus@1337
   301
            ThisAddIn.PEPEngine.KeyResetTrust(ref identityPartner);
Dean@279
   302
Dean@1130
   303
            this.ImmediateRatingAndUIUpdate();
Dean@1117
   304
            this.UpdateManagePrivacyStatusForm();
Dean@279
   305
Dean@279
   306
            return;
vb@133
   307
        }
vb@133
   308
Dean@161
   309
        /// <summary>
Dean@279
   310
        /// Builds a new manager form state using this encryption state/mail item current state.
Dean@279
   311
        /// </summary>
Dean@279
   312
        /// <returns>A new manager form state.</returns>
Dean@1069
   313
        private FormControlManagePrivacyStatus.State GetManagerState()
Dean@279
   314
        {
Dean@737
   315
            int currIndex = 0;
Dean@527
   316
            bool isMyself;
Dean@364
   317
            string trustwordsShort;
Dean@1069
   318
            BitmapImage imageForceUnencOn;
Dean@1069
   319
            BitmapImage imageGreen;
Dean@1069
   320
            BitmapImage imageNoColor;
Dean@1069
   321
            BitmapImage imageRed;
Dean@1069
   322
            BitmapImage imageYellow;
Dean@384
   323
            List<PEPIdentity> identities;
Dean@1106
   324
            PEPIdentity identity;
Dean@384
   325
            PEPIdentity myIdentity;
Dean@259
   326
            SelectionItem item;
Dean@1069
   327
            FormControlManagePrivacyStatus.State managerState = new FormControlManagePrivacyStatus.State();
Dean@1069
   328
Dean@1390
   329
            if (this.cryptableMailItem != null)
Dean@769
   330
            {
Dean@1298
   331
                // Load all images from resources
Dean@1298
   332
                imageForceUnencOn = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImageForceUnencOn.png", UriKind.RelativeOrAbsolute));
Dean@1298
   333
                imageGreen = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusGreen.png", UriKind.RelativeOrAbsolute));
Dean@1298
   334
                imageNoColor = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusNoColor.png", UriKind.RelativeOrAbsolute));
Dean@1298
   335
                imageRed = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusRed.png", UriKind.RelativeOrAbsolute));
Dean@1298
   336
                imageYellow = new BitmapImage(new Uri("pack://application:,,,/pEp;component/Resources/ImagePrivacyStatusYellow.png", UriKind.RelativeOrAbsolute));
Dean@1298
   337
Dean@1390
   338
                // Resolve all recipients -- this ensures the identities list is correctly populated
Dean@1390
   339
                this.ResolveAllRecipients();
Dean@332
   340
Dean@1298
   341
                managerState.Rating = this.FormControlPrivacyStatusChild.DisplayState.Rating;
Dean@1390
   342
                managerState.IsIncoming = this.cryptableMailItem.IsIncoming;
Dean@259
   343
Dean@1298
   344
                // Get identities
Dean@1390
   345
                identities = this.cryptableMailItem.Recipients;
Dean@1390
   346
                myIdentity = this.cryptableMailItem.Myself;
Dean@1106
   347
Dean@1402
   348
                try
Dean@1402
   349
                {
Dean@1402
   350
                    myIdentity.Rating = ThisAddIn.PEPEngine.IdentityRating(myIdentity.ToCOMType());
Dean@1402
   351
                }
Dean@1402
   352
                catch (COMException ex)
Dean@1402
   353
                {
Dean@1402
   354
                    myIdentity.Rating = pEpRating.pEpRatingUndefined;
Dean@1402
   355
                    Log.Warning("GetManagerState: Failed to get myself identity rating, " + ex.ToString());
Dean@1402
   356
                }
Dean@1402
   357
Dean@1298
   358
                // Include the from identity for incoming messages at the beginning
Dean@1390
   359
                identity = this.cryptableMailItem.From;
Dean@1390
   360
                if ((this.cryptableMailItem.IsIncoming) &&
Dean@1298
   361
                    (identity != null))
Dean@1298
   362
                {
Dean@1298
   363
                    identities.Insert(0, identity);
Dean@1298
   364
                }
Dean@259
   365
Dean@1298
   366
                // Remove own identity in the MailItem from the list
Dean@1298
   367
                if (myIdentity != null)
Dean@638
   368
                {
Dean@1298
   369
                    for (int i = (identities.Count - 1); i >= 0; i--)
Dean@1106
   370
                    {
Dean@1298
   371
                        if ((identities[i] != null) &&
Dean@1298
   372
                            (identities[i].EqualsByAddress(myIdentity)))
Dean@1298
   373
                        {
Dean@1298
   374
                            identities.RemoveAt(i);
Dean@1298
   375
                        }
Dean@1106
   376
                    }
Dean@638
   377
                }
Dean@366
   378
Thomas@1524
   379
                // Remove duplicates (by address) and add identities
Dean@1298
   380
                identities = PEPIdentity.ToFlatList(identities);
Thomas@1524
   381
                identities = identities.GroupBy(x => x.Address).Select(x => x.First()).ToList();
Dean@1298
   382
                managerState.Identities.Clear();
Dean@1298
   383
                foreach (PEPIdentity ident in identities)
Dean@1298
   384
                {
Dean@1298
   385
                    // Needed so index can be used within anonymous methods without getting into the 'outer variable trap' of currIndex
Dean@1298
   386
                    int index = currIndex;
Dean@737
   387
Dean@1298
   388
                    if (ident.IsAddressValid)
Dean@1298
   389
                    {
Dean@1298
   390
                        // Update the partner identity to get a fingerprint, preserve IsForceUnencrypted
markus@1337
   391
                        pEpIdentity partnerIdentity_s = ThisAddIn.PEPEngine.UpdateIdentity(ident.ToCOMType());
Dean@1298
   392
                        PEPIdentity partnerIdentity = new PEPIdentity(partnerIdentity_s);
Dean@1298
   393
                        partnerIdentity.IsForceUnencrypted = ident.IsForceUnencrypted;
Dean@774
   394
Dean@1298
   395
                        try
Dean@1298
   396
                        {
Dean@1362
   397
                            partnerIdentity.Rating = ThisAddIn.PEPEngine.IdentityRating(partnerIdentity_s);
Dean@1298
   398
                        }
Dean@1298
   399
                        catch (COMException ex)
Dean@1298
   400
                        {
Dean@1362
   401
                            partnerIdentity.Rating = pEpRating.pEpRatingUndefined;
Dean@1402
   402
                            Log.Warning("GetManagerState: Failed to get partner identity rating, " + ex.ToString());
Dean@1298
   403
                        }
Dean@1018
   404
Dean@1298
   405
                        isMyself = PEPIdentity.GetIsOwnIdentity(partnerIdentity.Address);
Dean@724
   406
Dean@1298
   407
                        // Calculate trustwords
Dean@1430
   408
                        trustwordsShort = AdapterExtensions.GetTrustwords(myIdentity,
Dean@1430
   409
                                                                          partnerIdentity,
Dean@1430
   410
                                                                          Globals.ThisAddIn.Settings.TrustwordsCulture?.TwoLetterISOLanguageName,
Dean@1430
   411
                                                                          false);
Dean@880
   412
Dean@1298
   413
                        item = new SelectionItem();
Dean@1348
   414
                        item.TextLine1 = partnerIdentity.UserName;
Dean@1298
   415
                        item.TextLine2 = partnerIdentity.Address;
Dean@1430
   416
                        item.Tag = trustwordsShort;
Dean@259
   417
Dean@1298
   418
                        // Don't show both the user name and address if they are the same
Dean@1298
   419
                        if ((item.TextLine1 != null) &&
Dean@1298
   420
                            (item.TextLine2 != null) &&
Dean@1298
   421
                            (item.TextLine1 == item.TextLine2))
Dean@1298
   422
                        {
Dean@1298
   423
                            item.IsTwoTextLinesVisible = false;
Dean@1298
   424
                        }
Dean@332
   425
Dean@1298
   426
                        // Set image
Dean@1298
   427
                        if ((partnerIdentity.IsForceUnencryptedBool) &&
Dean@1298
   428
                            (managerState.IsIncoming == false))
Dean@641
   429
                        {
Dean@1298
   430
                            item.ItemImage = imageForceUnencOn;
Dean@641
   431
                        }
Dean@1298
   432
                        else
Dean@1298
   433
                        {
Dean@1362
   434
                            switch (partnerIdentity.Rating.ToColor())
Dean@1298
   435
                            {
markus@1337
   436
                                case pEpColor.pEpColorGreen:
Dean@1298
   437
                                    item.ItemImage = imageGreen;
Dean@1298
   438
                                    break;
markus@1337
   439
                                case pEpColor.pEpColorYellow:
Dean@1298
   440
                                    item.ItemImage = imageYellow;
Dean@1298
   441
                                    break;
markus@1337
   442
                                case pEpColor.pEpColorRed:
Dean@1298
   443
                                    item.ItemImage = imageRed;
Dean@1298
   444
                                    break;
markus@1337
   445
                                case pEpColor.pEpColorNoColor:
Dean@1298
   446
                                    item.ItemImage = imageNoColor;
Dean@1298
   447
                                    break;
Dean@1298
   448
                                default:
Dean@1298
   449
                                    item.ItemImage = null;
Dean@1298
   450
                                    break;
Dean@1298
   451
                            }
Dean@1298
   452
                        }
Dean@259
   453
Dean@1298
   454
                        // Set button
Dean@1298
   455
                        if ((isMyself) ||
Dean@1298
   456
                            ((partnerIdentity.IsForceUnencryptedBool) &&
Dean@1298
   457
                             (managerState.IsIncoming == false)))
Dean@485
   458
                        {
Dean@1298
   459
                            item.IsButtonVisible = false;
Dean@641
   460
                            item.IsExpandable = false;
Dean@485
   461
                        }
Dean@485
   462
                        else
Dean@485
   463
                        {
Dean@1362
   464
                            switch (partnerIdentity.Rating.ToColor())
Dean@1298
   465
                            {
Dean@1362
   466
                                case pEpColor.pEpColorGreen:
Dean@1362
   467
                                    {
Dean@1362
   468
                                        // Undo handshake
Dean@1362
   469
                                        item.TextButton = pEp.Properties.Resources.PrivacyStatus_StopTrusting;
Dean@1362
   470
                                        item.IsButtonVisible = true;
Dean@1362
   471
                                        item.ButtonOnClick = (x, y) => { this.UndoHandshake(partnerIdentity.Copy()); };
Dean@1298
   472
Dean@1362
   473
                                        item.IsExpandable = false;
Dean@1298
   474
Dean@1362
   475
                                        break;
Dean@1362
   476
                                    }
Dean@1362
   477
                                case pEpColor.pEpColorYellow:
Dean@1362
   478
                                    {
Dean@1362
   479
                                        // Do handshake
Dean@1362
   480
                                        item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@1362
   481
                                        item.IsButtonVisible = true;
Dean@1362
   482
                                        item.ButtonOnClick = (x, y) => { this.DoHandshake(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@1298
   483
Dean@1362
   484
                                        item.IsExpandable = true;
Dean@1362
   485
                                        item.ExpandedText = pEp.Properties.Resources.Handshake_ConfirmTrustwordsText + "\n\n" +
Dean@1362
   486
                                                            trustwordsShort;
Dean@1298
   487
Dean@1362
   488
                                        item.ExpandedButton1Text = pEp.Properties.Resources.Handshake_ConfirmText;
Dean@1362
   489
                                        item.ExpandedButton1OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.Yes, partnerIdentity.Copy()); };
Dean@1362
   490
                                        item.ExpandedButton1Style = (Style)Globals.ResourceDict["StyleConfirmButton"];
Dean@1362
   491
Dean@1362
   492
                                        item.ExpandedButton2Text = pEp.Properties.Resources.Handshake_CancelText;
Dean@1362
   493
                                        item.ExpandedButton2OnClick = (x, y) =>
Dean@1362
   494
                                        {
Dean@1362
   495
                                            SelectionItem selItem;
Dean@1362
   496
                                            FormControlManagePrivacyStatus.State activeState;
Dean@1362
   497
Dean@1362
   498
                                            if (this.managerForm != null)
Dean@1362
   499
                                            {
Dean@1377
   500
                                                activeState = this.managerForm.DisplayState;
Dean@1362
   501
Dean@1362
   502
                                                if ((index >= 0) &&
Dean@1362
   503
                                                    (index < activeState.Identities.Count))
Dean@1362
   504
                                                {
Dean@1362
   505
                                                    selItem = activeState.Identities[index];
Dean@1362
   506
                                                    selItem.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@1362
   507
                                                    selItem.IsExpanded = false;
Dean@1362
   508
                                                    selItem.IsExpandable = false;
Dean@1362
   509
                                                }
Dean@1362
   510
                                            }
Dean@1362
   511
                                        };
Dean@1362
   512
                                        item.ExpandedButton2Style = (Style)Globals.ResourceDict["StyleCancelButton"];
Dean@1362
   513
Dean@1362
   514
                                        item.ExpandedButton3Text = pEp.Properties.Resources.Handshake_WrongText;
Dean@1362
   515
                                        item.ExpandedButton3OnClick = (x, y) => { this.ProcessDoHandshakeResult(DialogResult.No, partnerIdentity.Copy()); };
Dean@1362
   516
                                        item.ExpandedButton3Style = (Style)Globals.ResourceDict["StyleWrongButton"];
Dean@1362
   517
Dean@1362
   518
                                        break;
Dean@1362
   519
                                    }
Dean@1362
   520
                                case pEpColor.pEpColorRed:
Dean@1298
   521
                                    {
Dean@1362
   522
                                        // Redo handshake with confirmation
Dean@1362
   523
                                        item.TextButton = pEp.Properties.Resources.PrivacyStatus_Handshake;
Dean@1362
   524
                                        item.IsButtonVisible = true;
Dean@1362
   525
                                        item.ButtonOnClick = (x, y) => { this.DoHandshakeForMistrustedKey(myIdentity.Copy(), partnerIdentity.Copy()); };
Dean@1298
   526
Dean@1362
   527
                                        item.IsExpandable = false;
Dean@1298
   528
Dean@1362
   529
                                        break;
Dean@1362
   530
                                    }
Dean@1362
   531
                                default:
Dean@1362
   532
                                    {
Dean@1362
   533
                                        item.IsButtonVisible = false;
Dean@1362
   534
                                        item.IsExpandable = false;
Dean@1362
   535
                                        break;
Dean@1362
   536
                                    }
Dean@1298
   537
                            }
Dean@485
   538
                        }
Dean@366
   539
                    }
Dean@1298
   540
                    else // Invalid identity
Dean@1298
   541
                    {
Dean@1298
   542
                        item = new SelectionItem();
Dean@1348
   543
                        item.TextLine1 = ident.UserName;
Dean@1298
   544
                        item.TextLine2 = ident.Address;
Dean@1298
   545
                        item.ItemImage = null;
Dean@1298
   546
                        item.IsTwoTextLinesVisible = true;
Dean@1298
   547
                        item.IsButtonVisible = false;
Dean@1298
   548
                    }
Dean@1298
   549
Dean@1298
   550
                    managerState.Identities.Add(item);
Dean@1298
   551
                    currIndex++;
Dean@259
   552
                }
Dean@259
   553
Dean@1298
   554
                // Attempt to select and expand the first identity requiring a handshake
Dean@1298
   555
                for (int i = 0; i < managerState.Identities.Count; i++)
Dean@375
   556
                {
Dean@1298
   557
                    // Determine if it's a handshake identity by checking if it's expandable
Dean@1298
   558
                    if (managerState.Identities[i].IsExpandable)
Dean@1298
   559
                    {
Dean@1298
   560
                        managerState.Identities[i].TextButton = Properties.Resources.PrivacyStatus_HandshakeAdvanced;
Dean@1298
   561
                        managerState.Identities[i].IsExpanded = true;
Dean@1298
   562
                        managerState.SelectedIdentityIndex = i;
Dean@1298
   563
                        break;
Dean@1298
   564
                    }
Dean@375
   565
                }
Dean@375
   566
            }
Dean@375
   567
Dean@279
   568
            return (managerState);
Dean@279
   569
        }
Dean@279
   570
Dean@279
   571
        /// <summary>
Dean@279
   572
        /// Builds the latest state of the encryption status manager then shows the UI.
Dean@279
   573
        /// </summary>
Dean@279
   574
        private void BuildAndShowManager()
Dean@279
   575
        {
Dean@279
   576
            DialogResult result;
Dean@313
   577
            FormManagePrivacyStatus form;
Dean@279
   578
Dean@483
   579
            try
Dean@483
   580
            {
Dean@483
   581
                // Show the form
Dean@483
   582
                form = new FormManagePrivacyStatus();
Dean@1082
   583
                form.StartPosition = FormStartPosition.CenterParent;
Dean@1021
   584
                form.FormClosed += ManagerForm_FormClosed;
Dean@1377
   585
                form.DisplayState = this.GetManagerState();
Dean@259
   586
Dean@483
   587
                this.managerForm = form;
Dean@1073
   588
                result = form.ShowDialog(this.ParentForm);
Dean@483
   589
            }
Dean@483
   590
            catch (Exception ex)
Dean@483
   591
            {
Dean@860
   592
                Globals.StopAndSendCrashReport(ex);
Dean@483
   593
            }
Dean@259
   594
Dean@259
   595
            return;
Dean@259
   596
        }
Dean@259
   597
Dean@259
   598
        /// <summary>
Dean@1130
   599
        /// Schedules for the pEp rating and UI (including displayed mirror) to be updated.
Dean@1001
   600
        /// This can be called many times with no issue as the update is only run every n milliseconds.
Dean@179
   601
        /// </summary>
Dean@1130
   602
        public void RequestRatingAndUIUpdate()
Dean@1001
   603
        {
Dean@1390
   604
            if (this.isEnabled)
Dean@1390
   605
            {
Dean@1390
   606
                this.TimerRefresh.Enabled = true;
Dean@1390
   607
            }
Dean@1001
   608
            return;
Dean@1001
   609
        }
Dean@1001
   610
Dean@1001
   611
        /// <summary>
Dean@1130
   612
        /// Immediately starts the update of UI rating based on the associated mail item.
Dean@1001
   613
        /// This will start decryption as necessary and also will update the displayed mirror.
Dean@1001
   614
        /// This method by-passes the refresh timer completely.
Dean@1001
   615
        /// WARNING: This method assumes the message is fully downloaded already.
Dean@1001
   616
        /// </summary>
Dean@1130
   617
        private void ImmediateRatingAndUIUpdate()
Dean@159
   618
        {
Dean@1390
   619
            if ((this.isEnabled) &&
Dean@1390
   620
                (this.cryptableMailItem != null))
Dean@159
   621
            {
Dean@1301
   622
                Log.Verbose("ImmediateRatingAndUIUpdate: Starting processing.");
Dean@740
   623
Dean@1301
   624
                // Start the rating calculation/decryption process
Dean@1390
   625
                this.cryptableMailItem.StartProcessing();
Thomas@1505
   626
                this.processingOngoing = true;
Dean@159
   627
            }
Dean@159
   628
Dean@179
   629
            return;
Dean@159
   630
        }
Dean@159
   631
Dean@709
   632
        /// <summary>
Thomas@1458
   633
        /// Workaround method to update the current inspector window. This is done by moving the mail item
Thomas@1458
   634
        /// to a temporary folder first and then back to the current folder. Both folders CANNOT be the same.
Thomas@1458
   635
        /// As a fallback, the mail item stays in the temporary folder if moving back to the current folder
Thomas@1458
   636
        /// fails.
Thomas@1458
   637
        /// </summary>
Thomas@1547
   638
        private void UpdateInspector()
Thomas@1458
   639
        {
Thomas@1458
   640
            Outlook.Application application = null;
Thomas@1547
   641
            Outlook.Folder currentFolder = null;
Thomas@1547
   642
            Outlook.Folder tempFolder = null;
Thomas@1458
   643
            Outlook.Inspector currentInspector = null;
Thomas@1458
   644
            Outlook.Inspector newInspector = null;
Thomas@1458
   645
            Outlook.MailItem omi = null;
Thomas@1458
   646
            Outlook.MailItem tempMailItem = null;
Thomas@1547
   647
            Outlook.Store store = null;
Thomas@1458
   648
Thomas@1458
   649
            omi = this.OutlookItem as Outlook.MailItem;
Thomas@1458
   650
Thomas@1458
   651
            if (omi != null)
Thomas@1458
   652
            {
Thomas@1458
   653
                try
Thomas@1458
   654
                {
Thomas@1458
   655
                    application = omi.Application;
Thomas@1458
   656
                    currentInspector = omi.GetInspector;
Thomas@1547
   657
                    currentFolder = omi.Parent as Outlook.Folder;
Thomas@1458
   658
Thomas@1458
   659
                    if ((currentInspector != null) &&
Thomas@1547
   660
                        (application != null) &&
Thomas@1547
   661
                        (currentFolder != null))
Thomas@1458
   662
                    {
Thomas@1458
   663
                        var left = currentInspector.Left;
Thomas@1458
   664
                        var top = currentInspector.Top;
Thomas@1458
   665
                        var width = currentInspector.Width;
Thomas@1458
   666
                        var height = currentInspector.Height;
Thomas@1458
   667
                        var windowState = currentInspector.WindowState;
Thomas@1458
   668
Thomas@1547
   669
                        /* Check, if in trusted store. In that case, use the default drafts folder
Thomas@1547
   670
                         * as temporary folder. If the store is untrusted, use the pEp drafts folder.
Thomas@1547
   671
                         */
Thomas@1547
   672
                        store = currentFolder.Store;
Thomas@1547
   673
                        if (store?.GetIsSecureStorageEnabled() ?? false)
Thomas@1547
   674
                        {
Thomas@1547
   675
                            tempFolder = Globals.ThisAddIn.GetPEPStoreDraftsFolder();
Thomas@1547
   676
                        }
Thomas@1547
   677
                        else
Thomas@1547
   678
                        {
Thomas@1547
   679
                            tempFolder = store.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderDrafts) as Outlook.Folder;
Thomas@1547
   680
                        }
Thomas@1458
   681
Thomas@1547
   682
                        if (tempFolder != null)
Thomas@1458
   683
                        {
Thomas@1547
   684
                            tempMailItem = omi.Move(tempFolder) as Outlook.MailItem;
Thomas@1547
   685
Thomas@1547
   686
                            if (tempMailItem != null)
Thomas@1458
   687
                            {
Thomas@1547
   688
                                try
Thomas@1547
   689
                                {
Thomas@1547
   690
                                    omi = tempMailItem.Move(currentFolder) as Outlook.MailItem;
Thomas@1547
   691
                                }
Thomas@1547
   692
                                catch
Thomas@1547
   693
                                {
Thomas@1547
   694
                                    omi = tempMailItem.Copy();
Thomas@1547
   695
                                }
Thomas@1547
   696
Thomas@1547
   697
                                newInspector = application.Inspectors.Add(omi);
Thomas@1547
   698
Thomas@1547
   699
                                if (windowState == Outlook.OlWindowState.olNormalWindow)
Thomas@1547
   700
                                {
Thomas@1547
   701
                                    newInspector.Left = left;
Thomas@1547
   702
                                    newInspector.Top = top;
Thomas@1547
   703
                                    newInspector.Width = width;
Thomas@1547
   704
                                    newInspector.Height = height;
Thomas@1547
   705
                                }
Thomas@1547
   706
Thomas@1547
   707
                                newInspector.Display();
Thomas@1547
   708
                                newInspector.WindowState = windowState;
Thomas@1547
   709
Thomas@1547
   710
                                repeatProcessing = false;
Thomas@1458
   711
                            }
Thomas@1547
   712
                        }
Thomas@1547
   713
                        else
Thomas@1547
   714
                        {
Thomas@1547
   715
                            Log.Error("UpdateInspector: Cannot get temporary folder.");
Thomas@1458
   716
                        }
Thomas@1458
   717
                    }
Thomas@1458
   718
                    else
Thomas@1458
   719
                    {
Thomas@1458
   720
                        Log.Verbose("UpdateInspector: Error retrieving inspector window or application.");
Thomas@1458
   721
                    }
Thomas@1458
   722
                }
Thomas@1458
   723
                catch (Exception e)
Thomas@1458
   724
                {
Thomas@1458
   725
                    Log.Verbose("UpdateInspector: Error updating inspector window. " + e.Message);
Thomas@1458
   726
                }
Thomas@1458
   727
                finally
Thomas@1458
   728
                {
Thomas@1458
   729
                    if (application != null)
Thomas@1458
   730
                    {
vb@1507
   731
                        //Marshal.ReleaseComObject(application);
Thomas@1458
   732
                        application = null;
Thomas@1458
   733
                    }
Thomas@1458
   734
Thomas@1458
   735
                    if (currentInspector != null)
Thomas@1458
   736
                    {
vb@1516
   737
                        // Marshal.ReleaseComObject(currentInspector);
Thomas@1458
   738
                        currentInspector = null;
Thomas@1458
   739
                    }
Thomas@1458
   740
Thomas@1458
   741
                    if (newInspector != null)
Thomas@1458
   742
                    {
vb@1516
   743
                        // Marshal.ReleaseComObject(newInspector);
Thomas@1458
   744
                        newInspector = null;
Thomas@1458
   745
                    }
Thomas@1458
   746
Thomas@1458
   747
                    if (tempMailItem != null)
Thomas@1458
   748
                    {
vb@1516
   749
                        // Marshal.ReleaseComObject(tempMailItem);
Thomas@1458
   750
                        tempMailItem = null;
Thomas@1458
   751
                    }
Thomas@1458
   752
Thomas@1458
   753
                    if (omi != null)
Thomas@1458
   754
                    {
vb@1516
   755
                        // Marshal.ReleaseComObject(omi);
Thomas@1458
   756
                        omi = null;
Thomas@1458
   757
                    }
Thomas@1458
   758
                }
Thomas@1458
   759
            }
Thomas@1458
   760
Thomas@1458
   761
            return;
Thomas@1458
   762
        }
Thomas@1458
   763
Thomas@1458
   764
        /// <summary>
Dean@1117
   765
        /// Immediately update the manage privacy status form display state.
Dean@1117
   766
        /// This by default will completely rebuild the display state.
Dean@1117
   767
        /// </summary>
Dean@1130
   768
        /// <param name="onlyRating">True to update only the rating, false to rebuild the entire display state.</param>
Dean@1130
   769
        private void UpdateManagePrivacyStatusForm(bool onlyRating = false)
Dean@1117
   770
        {
Dean@1117
   771
            if (this.managerForm != null)
Dean@1117
   772
            {
Dean@1130
   773
                if (onlyRating)
Dean@1117
   774
                {
Dean@1130
   775
                    // Only update the message rating
Dean@1377
   776
                    this.managerForm.DisplayState.Rating = this.FormControlPrivacyStatusChild.DisplayState.Rating;
Dean@1117
   777
                }
Dean@1117
   778
                else
Dean@1117
   779
                {
Dean@1117
   780
                    // Rebuild the entire display state which will update any identity changes
Dean@1377
   781
                    this.managerForm.DisplayState = this.GetManagerState();
Dean@1117
   782
                }
Dean@1117
   783
            }
Dean@1117
   784
Dean@1117
   785
            return;
Dean@1117
   786
        }
Dean@1117
   787
Dean@1117
   788
        /// <summary>
Dean@709
   789
        /// Clears the associated unencrypted preview and displays the given note (if any).
Dean@709
   790
        /// </summary>
Dean@709
   791
        /// <param name="note">The note to diplsay.</param>
Dean@1483
   792
        private void SetNote(string note = null)
Dean@709
   793
        {
Dean@987
   794
            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
   795
Dean@1476
   796
            if (formRegions != null)
Dean@709
   797
            {
Dean@1476
   798
                // IPM.Note.Secure.pEp
Dean@1476
   799
                if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@1476
   800
                    (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@1476
   801
                {
Dean@1483
   802
                    formRegions.FormRegionPreviewUnencrypted.DisplayState.SetNote(note);
Dean@1476
   803
                }
Dean@1476
   804
Dean@1476
   805
                // IPM.Note
Dean@1476
   806
                if ((formRegions.FormRegionPreviewUnencrypted2 != null) &&
Dean@1476
   807
                    (formRegions.FormRegionPreviewUnencrypted2.Visible))
Dean@1476
   808
                {
Dean@1483
   809
                    formRegions.FormRegionPreviewUnencrypted2.DisplayState.SetNote(note);
Dean@1476
   810
                }
Dean@709
   811
            }
Dean@709
   812
Dean@709
   813
            return;
Dean@709
   814
        }
Dean@709
   815
Dean@1390
   816
        /// <summary>
Dean@1390
   817
        /// Sets whether processing of the mail item is enabled.
Dean@1390
   818
        /// This should commonly be set from the .GetIsPEPEnabled() value.
Dean@1390
   819
        /// </summary>
Dean@1390
   820
        private void SetIsEnabled(bool enabled)
Dean@1390
   821
        {
Dean@1390
   822
            bool setByCache = false;
Dean@1390
   823
            PEPIdentity currIdent;
Dean@1390
   824
            Globals.ReturnStatus sts;
Dean@1390
   825
            Outlook.MailItem omi = null;
Dean@1390
   826
            Outlook.Recipient currUser = null;
Dean@1390
   827
            Outlook.Account currAccount = null;
Dean@1390
   828
            Outlook.Account sendingAccount = null;
Dean@1390
   829
            Outlook.NameSpace ns = null;
Dean@1390
   830
Dean@1390
   831
            this.OutlookFormRegion.Visible = enabled;
Dean@1390
   832
            this.isEnabled = enabled;
Dean@1390
   833
Dean@1390
   834
            if (enabled)
Dean@1390
   835
            {
Dean@1390
   836
                // Do not allow initialization more than once
Dean@1390
   837
                if (this.isStarted == false)
Dean@1390
   838
                {
Dean@1390
   839
                    /* It's possible for new draft MailItems to be created outside the context of an account.
Dean@1390
   840
                     * In this situation the SendUsingAccount will always be null which of course breaks several pEp operations.
Dean@1390
   841
                     * The operations themselves cannot make the assumption about what account information to use.
Dean@1390
   842
                     * Therefore, the situation is detected here and for draft mail items a null SendUsingAccount will be 
Dean@1390
   843
                     * set with the session's default account.
Dean@1390
   844
                     */
Dean@1390
   845
                    try
Dean@1390
   846
                    {
Dean@1390
   847
                        ns = Globals.ThisAddIn.Application.Session;
Dean@1390
   848
Dean@1390
   849
                        if ((this.OutlookItem is Outlook.MailItem) &&
Dean@1390
   850
                            ((Outlook.MailItem)this.OutlookItem).GetIsDraft())
Dean@1390
   851
                        {
Dean@1390
   852
                            omi = this.OutlookItem as Outlook.MailItem;
Dean@1390
   853
                            sendingAccount = omi.SendUsingAccount;
Dean@1390
   854
                            currUser = ns.CurrentUser;
Dean@1390
   855
Dean@1390
   856
                            if (sendingAccount == null)
Dean@1390
   857
                            {
Dean@1390
   858
                                sts = PEPIdentity.Create(currUser, out currIdent);
Dean@1390
   859
Dean@1390
   860
                                if (sts == Globals.ReturnStatus.Success)
Dean@1390
   861
                                {
Dean@1390
   862
                                    currAccount = PEPIdentity.GetOwnAccount(currIdent.Address);
Dean@1390
   863
                                    omi.SendUsingAccount = currAccount;
Dean@1390
   864
                                }
Dean@1390
   865
                            }
Dean@1390
   866
                        }
Dean@1390
   867
                    }
Dean@1390
   868
                    catch { }
Dean@1390
   869
                    finally
Dean@1390
   870
                    {
Dean@1390
   871
                        if (omi != null)
Dean@1390
   872
                        {
vb@1516
   873
                            // Marshal.ReleaseComObject(omi);
Dean@1390
   874
                            omi = null;
Dean@1390
   875
                        }
Dean@1390
   876
Dean@1390
   877
                        if (currUser != null)
Dean@1390
   878
                        {
vb@1507
   879
                            //Marshal.ReleaseComObject(currUser);
Dean@1390
   880
                            currUser = null;
Dean@1390
   881
                        }
Dean@1390
   882
Dean@1390
   883
                        if (currAccount != null)
Dean@1390
   884
                        {
vb@1507
   885
                            //Marshal.ReleaseComObject(currAccount);
Dean@1390
   886
                            currAccount = null;
Dean@1390
   887
                        }
Dean@1390
   888
Dean@1390
   889
                        if (sendingAccount != null)
Dean@1390
   890
                        {
vb@1507
   891
                            //Marshal.ReleaseComObject(sendingAccount);
Dean@1390
   892
                            sendingAccount = null;
Dean@1390
   893
                        }
Dean@1390
   894
Dean@1390
   895
                        if (ns != null)
Dean@1390
   896
                        {
vb@1507
   897
                            //Marshal.ReleaseComObject(ns);
Dean@1390
   898
                            ns = null;
Dean@1390
   899
                        }
Dean@1390
   900
                    }
Dean@1390
   901
Dean@1390
   902
                    // Set reader upgrade link visibility
Dean@1390
   903
                    if ((Globals.RELEASE_MODE == Globals.ReleaseMode.Reader) &&
Dean@1390
   904
                        (this.cryptableMailItem != null) &&
Dean@1390
   905
                        (this.cryptableMailItem.IsDraft))
Dean@1390
   906
                    {
Dean@1390
   907
                        this.FormControlPrivacyStatusChild.DisplayState.UpgradeLinkIsVisible = true;
Dean@1390
   908
                    }
Dean@1390
   909
                    else
Dean@1390
   910
                    {
Dean@1390
   911
                        this.FormControlPrivacyStatusChild.DisplayState.UpgradeLinkIsVisible = false;
Dean@1390
   912
                    }
Dean@1390
   913
Dean@1390
   914
                    /* For a MailItem being forwarded or replied to it's import to check against the encrypted conversation cache.
Dean@1390
   915
                     * This is normally done within CryptableMailItem_EncryptedConversationCacheUpdated; however,
Dean@1390
   916
                     * for trusted servers that use an in-line reponse, the EncryptedConversationCacheUpdated event occurs
Dean@1390
   917
                     * BEFORE the new mail item is created. This means it never sees the event.
Dean@1390
   918
                     * To get around this issue, when the form region is first shown, also check if the mail item
Dean@1390
   919
                     * exists in the encrypted conversation cache and should be marked as formerly encrypted.
Dean@1390
   920
                     * If this check passes, never event connect the CryptableMailItem_EncryptedConversationCacheUpdated event.
Dean@1390
   921
                     */
Dean@1390
   922
                    if (this.cryptableMailItem != null)
Dean@1390
   923
                    {
Dean@1390
   924
                        setByCache = this.cryptableMailItem.SetIsOriginallyEncryptedByCache();
Dean@1390
   925
                    }
Dean@1390
   926
Dean@1390
   927
                    // Connect events
Dean@1390
   928
                    if (setByCache == false) { CryptableMailItem.EncryptedConversationCacheUpdated += CryptableMailItem_EncryptedConversationCacheUpdated; }
Dean@1390
   929
                    this.FormControlPrivacyStatusChild.PrivacyViewClick += FormControlPrivacyStatusChild_PrivacyViewClick;
Dean@1390
   930
                    this.Expanded += FormRegionPrivacyStatus_Expanded;
Dean@1390
   931
Dean@1390
   932
                    this.TimerRefresh.Tick += TimerRefresh_Tick;
Dean@1390
   933
                    this.isStarted = true;
Dean@1390
   934
                }
Dean@1390
   935
            }
Dean@1390
   936
            else
Dean@1390
   937
            {
Dean@1390
   938
                // Disconnect events
Dean@1390
   939
                CryptableMailItem.EncryptedConversationCacheUpdated -= CryptableMailItem_EncryptedConversationCacheUpdated;
Dean@1390
   940
                this.FormControlPrivacyStatusChild.PrivacyViewClick -= FormControlPrivacyStatusChild_PrivacyViewClick;
Dean@1390
   941
                this.Expanded -= FormRegionPrivacyStatus_Expanded;
Dean@1390
   942
Dean@1390
   943
                // Stop and disconnect the refresh timer
Dean@1390
   944
                this.TimerRefresh.Stop();
Dean@1390
   945
                this.TimerRefresh.Enabled = false;
Dean@1390
   946
                this.TimerRefresh.Tick -= TimerRefresh_Tick;
Dean@1390
   947
Dean@1390
   948
                this.isStarted = false;
Dean@1390
   949
            }
Dean@1390
   950
Dean@1390
   951
            return;
Dean@1390
   952
        }
Dean@1390
   953
Dean@1390
   954
        /// <summary>
Dean@1390
   955
        /// Resolves all recipients of the Outlook mail item.
Dean@1390
   956
        /// </summary>
Dean@1390
   957
        private void ResolveAllRecipients()
Dean@1390
   958
        {
Dean@1390
   959
            if ((this.isEnabled) &&
Dean@1390
   960
                (this.cryptableMailItem != null))
Dean@1390
   961
            {
Dean@1390
   962
                /*
Dean@1390
   963
                 * Note: The PropertyChanged changed event must be disconnected before trying to resolve.
Dean@1390
   964
                 * This is because the resolve process can modify the contents of the mail item which triggers an event.
Dean@1390
   965
                 * The PropertyChanged event would then trigger a UI refresh cycle. However, because the GetManagerState itself 
Dean@1390
   966
                 * is called within the UI refresh, an infinite loop could occur trying to resolve a recipient that
Dean@1390
   967
                 * cannot be resolved(no address).
Dean@1390
   968
                 */
Dean@1390
   969
                this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@1390
   970
                this.cryptableMailItem.ResolveAllRecipients();
Dean@1390
   971
                this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@1390
   972
            }
Dean@1390
   973
Dean@1390
   974
            return;
Dean@1390
   975
        }
Dean@1390
   976
Dean@159
   977
        /**************************************************************
Dean@159
   978
         * 
Dean@159
   979
         * Event Handling
Dean@159
   980
         * 
Dean@159
   981
         *************************************************************/
Dean@159
   982
Dean@159
   983
        /// <summary>
Dean@680
   984
        /// Event handler that is called when the form region is displayed.
Dean@1211
   985
        /// This is called each time the form region looses then regains visibility 
Dean@680
   986
        /// (for example an other email is selected then back to this one).
Dean@159
   987
        /// </summary>
Dean@1461
   988
        private void FormRegionPrivacyStatus_FormRegionShowing(object sender, EventArgs e)
Dean@159
   989
        {
Dean@1390
   990
            // Set mail item
Dean@1390
   991
            if (this.OutlookItem is Outlook.MailItem)
Dean@1390
   992
            {
Dean@1390
   993
                this.cryptableMailItem = new CryptableMailItem((Outlook.MailItem)this.OutlookItem);
Dean@1390
   994
            }
Dean@1390
   995
            else
Dean@1390
   996
            {
Dean@1390
   997
                this.cryptableMailItem = null;
Dean@1390
   998
            }
Dean@1169
   999
Dean@1390
  1000
            // Connect cryptable mail item events
Dean@1390
  1001
            if (this.cryptableMailItem != null)
Dean@680
  1002
            {
Dean@1197
  1003
                try
Dean@1197
  1004
                {
Dean@1390
  1005
                    this.cryptableMailItem.PropertyChanged += MailItem_PropertyChanged;
Dean@1390
  1006
                    this.cryptableMailItem.ProcessingCompleted += MailItem_ProcessingCompleted;
Dean@1390
  1007
                    this.cryptableMailItem.GetMirrorCompleted += MailItem_GetMirrorCompleted;
Dean@1390
  1008
                    this.cryptableMailItem.Send += MailItem_Send;
Dean@1390
  1009
Dean@1390
  1010
                    if (this.cryptableMailItem.IsSecurelyStored)
Dean@1197
  1011
                    {
Dean@1390
  1012
                        this.cryptableMailItem.Open += MailItem_Open;
Dean@1197
  1013
                    }
Dean@1197
  1014
                }
Dean@1197
  1015
                catch { }
Dean@179
  1016
            }
Dean@159
  1017
Dean@1390
  1018
            // Update pEp enabled status
Dean@1390
  1019
            this.SetIsEnabled(((Outlook.MailItem)this.OutlookItem).GetIsPEPEnabled());
Dean@1390
  1020
            if (this.isEnabled)
Dean@1390
  1021
            {
Dean@1390
  1022
                // Call the timer tick method manually to refresh data with no delay
Dean@1390
  1023
                this.TimerRefresh_Tick(null, new EventArgs());
Dean@1390
  1024
            }
Dean@179
  1025
Dean@179
  1026
            return;
Dean@159
  1027
        }
Dean@159
  1028
Dean@159
  1029
        /// <summary>
Dean@159
  1030
        /// Event handler for when the form region is closed.
Dean@159
  1031
        /// </summary>
Dean@312
  1032
        private void FormRegionPrivacyStatus_FormRegionClosed(object sender, System.EventArgs e)
Dean@159
  1033
        {
Dean@1390
  1034
            // Disconnect cryptable mail item
Dean@1390
  1035
            if (this.cryptableMailItem != null)
Dean@179
  1036
            {
Dean@179
  1037
                try
Dean@179
  1038
                {
Dean@1390
  1039
                    this.cryptableMailItem.PropertyChanged -= MailItem_PropertyChanged;
Dean@1390
  1040
                    this.cryptableMailItem.ProcessingCompleted -= MailItem_ProcessingCompleted;
Dean@1390
  1041
                    this.cryptableMailItem.GetMirrorCompleted -= MailItem_GetMirrorCompleted;
Dean@1390
  1042
                    this.cryptableMailItem.Open -= MailItem_Open;
Dean@1390
  1043
                    this.cryptableMailItem.Send -= MailItem_Send;
Dean@179
  1044
                }
Dean@179
  1045
                catch { }
Dean@1390
  1046
Dean@1390
  1047
                this.cryptableMailItem.Dispose();
Dean@1390
  1048
                this.cryptableMailItem = null;
Dean@179
  1049
            }
Dean@179
  1050
Dean@1390
  1051
            // Disconnect other
Dean@1390
  1052
            this.SetIsEnabled(false);
Dean@682
  1053
Dean@179
  1054
            return;
Dean@179
  1055
        }
Dean@179
  1056
Dean@179
  1057
        /// <summary>
Dean@1384
  1058
        /// Event handler for when the form region is expanded or collapsed.
Dean@1384
  1059
        /// </summary>
Dean@1384
  1060
        private void FormRegionPrivacyStatus_Expanded(object sender, EventArgs e)
Dean@1384
  1061
        {
Dean@1385
  1062
            /* This Outlook form region has a bug where clicking the '+' button to expand will also
Dean@1385
  1063
             * raise a click event on the privacy status button. Basically, Outlook would fire the click event 
Dean@1385
  1064
             * (FormControlPrivacyStatusChild_PrivacyViewClick) immediately after the region is expanded even though at 
Dean@1385
  1065
             * the time it was clicked it was collapsed and the click already captured by the expander '+' button.
Dean@1385
  1066
             * This code here works around that issue by disabling the manager form when the form region is collapsed.
Dean@1385
  1067
             * Since the click event occurs BEFORE the expanded event, this will disable opening the manage privacy status
Dean@1385
  1068
             * form in this situation.
Dean@1385
  1069
             */
Dean@1390
  1070
            this.isManagerFormEnabled = this.OutlookFormRegion.IsExpanded;
Dean@1384
  1071
Dean@1384
  1072
            return;
Dean@1384
  1073
        }
Dean@1384
  1074
Dean@1384
  1075
        /// <summary>
Dean@1384
  1076
        /// Event handler called after the monitor timer has elapsed.
Dean@1384
  1077
        /// This should be used only for quick polling of changes in Outlook or the UI state.
Dean@1384
  1078
        /// </summary>
Dean@1384
  1079
        private void TimerMonitor_Tick(object sender, EventArgs e)
Dean@1384
  1080
        {
Dean@1384
  1081
            bool isExpandedCurrent;
Dean@1384
  1082
Dean@1384
  1083
            // Check for IsExpanded changes
Dean@1384
  1084
            isExpandedCurrent = this.OutlookFormRegion.IsExpanded;
Dean@1384
  1085
            if ((this.isExpandedPrevious == null) ||
Dean@1384
  1086
                ((bool)this.isExpandedPrevious != isExpandedCurrent))
Dean@1384
  1087
            {
Dean@1384
  1088
                this.Expanded?.Invoke(this, new EventArgs());
Dean@1384
  1089
            }
Dean@1384
  1090
            this.isExpandedPrevious = isExpandedCurrent;
Dean@1384
  1091
Dean@1384
  1092
            return;
Dean@1384
  1093
        }
Dean@1384
  1094
Dean@1384
  1095
        /// <summary>
Dean@179
  1096
        /// Event handler called after the refresh timer has elapsed.
Dean@179
  1097
        /// </summary>
Dean@179
  1098
        private void TimerRefresh_Tick(object sender, EventArgs e)
Dean@179
  1099
        {
Dean@1402
  1100
            bool tryAgain = false;
Thomas@1547
  1101
#pragma warning disable 219
Dean@1402
  1102
            bool markForDownload = false;
Thomas@1547
  1103
#pragma warning restore 219
Dean@179
  1104
            this.TimerRefresh.Enabled = false; // Only once
Dean@1402
  1105
            Outlook.OlDownloadState dlState;
markus@201
  1106
Dean@709
  1107
            /* The Refresh/UI_Update process is a little more complicated here than other forms.
Dean@709
  1108
             * There are the following components:
Dean@709
  1109
             *   1. TimerRefresh_Tick
Dean@709
  1110
             *        This is the main timer tick event handler called any time
Dean@1130
  1111
             *        a refresh was requested (RequestRatingAndUIUpdate) and hasn't been run yet. 
Dean@1001
  1112
             *        A refresh is requested either at initialization or when a property changes
Dean@709
  1113
             *        (such as MailItem_PropertyChanged). It is on a timer as many 
Dean@709
  1114
             *        property change events could occur rapidy, but only one refresh should
Dean@709
  1115
             *        occur for performance reasons.
Dean@709
  1116
             * 
Dean@1130
  1117
             *   2. ImmediateRatingAndUIUpdate
Dean@1307
  1118
             *        This will re-calculate the mail item's rating.
Dean@1307
  1119
             *        This internally just calls CryptableMailItem.StartProcessing.
Dean@709
  1120
             * 
Dean@1130
  1121
             *   3. MailItem_ProcessingCompleted
Dean@1307
  1122
             *        When processing of the mail item is complete, this even handler will be called.
Dean@1130
  1123
             *        This will update the UI with the latest rating then call StartGetMirror.
Dean@709
  1124
             *        The CopyStateToUI method is used which means any open privacy status form will also
Dean@709
  1125
             *        be updated.
Dean@709
  1126
             * 
Dean@709
  1127
             *   4. MailItem_GetMirrorComplete
Dean@1402
  1128
             *        This is the final step in updating the UI, after a mirror is located, it's contents
Dean@1307
  1129
             *        will be shown in the unencrypted preview.
Dean@709
  1130
             * 
Dean@709
  1131
             * The general calling sequence is as shown above 1->4 with each component calling the next.
Dean@709
  1132
             * However, for methods that update the mail item directly, commonly only 2->4 is needed.
Dean@709
  1133
             */
Dean@709
  1134
Dean@179
  1135
            // Ensure the tick method is not called more than once
Dean@1390
  1136
            if ((this.isEnabled) &&
Dean@1402
  1137
                (refreshOngoing == false))
Dean@179
  1138
            {
Dean@1402
  1139
                this.refreshOngoing = true;
Dean@1402
  1140
Thomas@1419
  1141
                if ((this.cryptableMailItem != null) &&
Thomas@1419
  1142
                    (this.cryptableMailItem.IsBeingProcessed == false))
Dean@1402
  1143
                {
Dean@1402
  1144
                    // Attempt to get the download state
Dean@1402
  1145
                    try
Dean@1402
  1146
                    {
Dean@1402
  1147
                        dlState = this.cryptableMailItem.DownloadState;
Dean@1402
  1148
                    }
Dean@1402
  1149
                    catch (Exception ex)
Dean@1402
  1150
                    {
Dean@1402
  1151
                        Log.Warning("TimerRefresh_Tick: Get DownloadState failed, " + ex.ToString());
Dean@1402
  1152
Dean@1402
  1153
                        // Assume everything is downloaded, but try to download again as well
Dean@1402
  1154
                        dlState = Outlook.OlDownloadState.olFullItem;
Dean@1402
  1155
                        markForDownload = true;
Dean@1402
  1156
                    }
Dean@1402
  1157
Dean@1402
  1158
                    if (dlState == Outlook.OlDownloadState.olFullItem)
Dean@1402
  1159
                    {
Dean@1402
  1160
                        this.ImmediateRatingAndUIUpdate();
Dean@1402
  1161
                    }
Dean@1402
  1162
                    else
Dean@1402
  1163
                    {
Dean@1402
  1164
                        markForDownload = true;
Dean@1402
  1165
                    }
Dean@1402
  1166
Thomas@1529
  1167
                    /* 12/16/2016: It could be verified via testing that setting the MarkForDownload property
Thomas@1529
  1168
                     * can be a way to crash Outlook under certain circumstances (e.g. with IMAP on Outlook 2010 or on Windows 7). 
Thomas@1529
  1169
                     * This then is not caught by a try/catch block and therefore has to be considered an Outlook bug.
Thomas@1529
  1170
                     * It seems that in newer versions of Outlook/Windows, they fixed it, causing exceptions, if at all.
Thomas@1529
  1171
                     * For now, the following is commented out to prevent a crash. If at any point we see that header-only
Thomas@1529
  1172
                     * messages cause bigger issues, this decision has to be reevaluated.
Thomas@1529
  1173
                     */
Thomas@1529
  1174
                    //if (markForDownload)
Thomas@1529
  1175
                    //{
Thomas@1529
  1176
                    //    // Try to mark the message for full download
Thomas@1529
  1177
                    //    try
Thomas@1529
  1178
                    //    {
Thomas@1529
  1179
                    //        this.cryptableMailItem.MarkForDownload = Outlook.OlRemoteStatus.olMarkedForDownload;
Thomas@1529
  1180
                    //        tryAgain = true;
Thomas@1529
  1181
                    //    }
Thomas@1529
  1182
                    //    catch (Exception ex)
Thomas@1529
  1183
                    //    {
Thomas@1529
  1184
                    //        Log.Warning("TimerRefresh_Tick: MarkForDownload failed, " + ex.ToString());
Thomas@1529
  1185
                    //    }
Thomas@1529
  1186
                    //}
Dean@1402
  1187
                }
Thomas@1419
  1188
                else
Thomas@1419
  1189
                {
Thomas@1419
  1190
                    repeatProcessing = true;
Thomas@1419
  1191
                }
Dean@1402
  1192
Dean@1402
  1193
                // Set the timer to refresh again later automatically
Dean@1402
  1194
                if (tryAgain)
Dean@1402
  1195
                {
Dean@1402
  1196
                    this.TimerRefresh.Interval = 100;
Dean@1402
  1197
                    this.TimerRefresh.Enabled = true;
Dean@1402
  1198
                }
Dean@1402
  1199
Dean@1402
  1200
                this.refreshOngoing = false;
Dean@179
  1201
            }
Dean@175
  1202
Dean@159
  1203
            return;
Dean@159
  1204
        }
Dean@159
  1205
Dean@169
  1206
        /// <summary>
Dean@1096
  1207
        /// Event handler for when the processing is completed in the associated mail item.
Dean@709
  1208
        /// This will then update the form region UI and the privacy status window as needed.
Dean@680
  1209
        /// </summary>
Dean@1461
  1210
        private void MailItem_ProcessingCompleted(object sender, MsgProcessor.ProcessingCompletedEventArgs e)
Dean@680
  1211
        {
Dean@1249
  1212
            Log.Verbose("MailItem_ProcessingComplete: Decryption completed.");
Dean@740
  1213
Dean@680
  1214
            try
Dean@680
  1215
            {
Dean@680
  1216
                // Marshal code back to UI thread as necessary
Dean@680
  1217
                this.Invoke(new Action(() =>
Dean@680
  1218
                    {
Dean@1390
  1219
                        if (this.isEnabled)
Dean@1390
  1220
                        {
Thomas@1505
  1221
                            try
Thomas@1505
  1222
                            {
Thomas@1505
  1223
                                this.FormControlPrivacyStatusChild.DisplayState.Rating = e.ProcessedRating;
Thomas@1505
  1224
                                RibbonCustomizations.Invalidate();
Thomas@1505
  1225
                                this.UpdateManagePrivacyStatusForm(true); // Only update the rating
Thomas@1505
  1226
                            }
Thomas@1505
  1227
                            catch (Exception ex)
Thomas@1505
  1228
                            {
Thomas@1505
  1229
                                Log.Verbose("MailItem_ProcessingComplete: Error. " + ex.ToString());
Thomas@1505
  1230
                            }
Dean@709
  1231
Thomas@1547
  1232
                            if (repeatProcessing &&
Thomas@1547
  1233
                                (repeatCounter++ < maxRepeatCount))
Dean@747
  1234
                            {
Thomas@1419
  1235
                                repeatProcessing = false;
Thomas@1419
  1236
                                this.RequestRatingAndUIUpdate();
Thomas@1419
  1237
                            }
Thomas@1419
  1238
                            else
Thomas@1419
  1239
                            {
Thomas@1470
  1240
                                /* Check if the mail item is in Outbox and update the inspector window if possible.
Thomas@1470
  1241
                                 * This is the case when a submitted, but not yet sent email is opened again when working 
Thomas@1470
  1242
                                 * offline or without internet connection. Without this update, Outlook removes the message class 
Thomas@1470
  1243
                                 * "IPM.Note.SMIME.MultipartSigned" at the next send event and the message gets invalid and can't be
Thomas@1470
  1244
                                 * opened again (i.e. is lost).
Thomas@1458
  1245
                                 */
Thomas@1458
  1246
                                try
Thomas@1458
  1247
                                {
Thomas@1458
  1248
                                    Outlook.MailItem omi = this.OutlookItem as Outlook.MailItem;
Thomas@1458
  1249
Thomas@1458
  1250
                                    if ((omi != null) &&
Thomas@1458
  1251
                                        (omi.GetIsSubmitted()) &&
Thomas@1458
  1252
                                        (omi.GetIsDraft()))
Thomas@1458
  1253
                                    {
Thomas@1458
  1254
                                        var insp = this.OutlookFormRegion.Inspector;
Thomas@1458
  1255
Thomas@1458
  1256
                                        if (insp != null)
Thomas@1458
  1257
                                        {
Thomas@1547
  1258
                                            UpdateInspector();
Thomas@1458
  1259
                                        }
Thomas@1458
  1260
                                    }
Thomas@1458
  1261
                                }
Thomas@1458
  1262
                                catch (Exception ex)
Thomas@1458
  1263
                                {
Thomas@1505
  1264
                                    Log.Verbose("MailItem_ProcessingComplete: Error while checking if mail item is in outbox or updating inspector. " + ex.Message);
Thomas@1458
  1265
                                }
Thomas@1458
  1266
Thomas@1419
  1267
                                /* Create the unencrypted preview if the mail item is encrypted and
Thomas@1419
  1268
                                 * it is in an encrypted (untrusted) store
Thomas@1419
  1269
                                 * 
Thomas@1419
  1270
                                 * This is done here because FormRegionPrivacyStatus has the cryptable mail item and
Thomas@1419
  1271
                                 * it also is initialized after FormRegionPreviewUnencrypted.
Thomas@1419
  1272
                                 */
Thomas@1419
  1273
                                try
Dean@1390
  1274
                                {
Thomas@1419
  1275
                                    if (this.cryptableMailItem.IsSecurelyStored)
Thomas@1419
  1276
                                    {
Thomas@1419
  1277
                                        Log.Verbose("MailItem_ProcessingComplete: Starting mirror location.");
Thomas@1419
  1278
                                        this.cryptableMailItem.StartGetMirror();
Thomas@1419
  1279
                                    }
Thomas@1419
  1280
                                    else
Thomas@1419
  1281
                                    {
Dean@1483
  1282
                                        this.SetNote();
Thomas@1419
  1283
                                    }
Dean@1390
  1284
                                }
Thomas@1419
  1285
                                catch (Exception ex)
Dean@1390
  1286
                                {
Thomas@1419
  1287
                                    // Error is possible in some situations where the mail item was deleted or moved while decryption was ongoing.
Thomas@1419
  1288
                                    // While rare, just log the issue and stop the process
Thomas@1419
  1289
                                    Log.Warning("MailItem_ProcessingComplete: Failed to start mirror location, " + ex.ToString());
Dean@1390
  1290
                                }
Dean@747
  1291
                            }
Dean@709
  1292
                        }
Dean@680
  1293
                    }));
Dean@680
  1294
            }
Dean@680
  1295
            catch (Exception ex)
Dean@680
  1296
            {
Dean@1249
  1297
                Log.Error("MailItem_ProcessingComplete: Error setting UI state, " + ex.ToString());
Dean@680
  1298
            }
Dean@680
  1299
Thomas@1505
  1300
            this.processingOngoing = false;
Thomas@1505
  1301
Dean@680
  1302
            return;
Dean@680
  1303
        }
Dean@680
  1304
Dean@680
  1305
        /// <summary>
Dean@709
  1306
        /// Event handler for when the get mirror locating process is complete for the associated mail item.
Dean@709
  1307
        /// This will then update the unencrypted preview in the UI.
Dean@709
  1308
        /// </summary>
Dean@1096
  1309
        private void MailItem_GetMirrorCompleted(object sender, CryptableMailItem.GetMirrorCompletedEventArgs e)
Dean@709
  1310
        {
Dean@709
  1311
            try
Dean@709
  1312
            {
Dean@709
  1313
                // Marshal code back to UI thread as necessary
Dean@709
  1314
                this.Invoke(new Action(() =>
Dean@709
  1315
                    {
Dean@1390
  1316
                        if (this.isEnabled)
Dean@1390
  1317
                        {
Dean@1390
  1318
                            WindowFormRegionCollection formRegions = Globals.FormRegions[Globals.ThisAddIn.Application.ActiveWindow()];
Dean@709
  1319
Dean@1390
  1320
                            if ((e.Mirror == null) &&
Dean@1390
  1321
                                (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.Failure))
Dean@910
  1322
                            {
Dean@1483
  1323
                                this.SetNote(Properties.Resources.Message_OpenError);
Dean@1390
  1324
                                Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, failure during decryption.");
Dean@910
  1325
                            }
Dean@1390
  1326
                            else if ((e.Mirror == null) &&
Dean@1390
  1327
                                     (this.cryptableMailItem.LastProcessedStatus == Globals.ReturnStatus.FailureNoConnection))
Dean@1390
  1328
                            {
Dean@1483
  1329
                                this.SetNote(Properties.Resources.Message_DecryptionNoConnection);
Dean@1390
  1330
                                Log.Verbose("MailItem_GetMirrorComplete: Cannot display mirror, connection failure during decryption.");
Dean@1390
  1331
                            }
Dean@1390
  1332
                            else
Dean@1390
  1333
                            {
Dean@1476
  1334
                                if (formRegions != null)
Dean@1390
  1335
                                {
Dean@1476
  1336
                                    // IPM.Note.Secure.pEp
Dean@1476
  1337
                                    if ((formRegions.FormRegionPreviewUnencrypted != null) &&
Dean@1476
  1338
                                        (formRegions.FormRegionPreviewUnencrypted.Visible))
Dean@1476
  1339
                                    {
Dean@1483
  1340
                                        formRegions.FormRegionPreviewUnencrypted.DisplayState.SetMessage(e.Mirror);
Dean@1476
  1341
                                    }
Dean@1476
  1342
Dean@1476
  1343
                                    // IPM.Note
Dean@1476
  1344
                                    if ((formRegions.FormRegionPreviewUnencrypted2 != null) &&
Dean@1476
  1345
                                        (formRegions.FormRegionPreviewUnencrypted2.Visible))
Dean@1476
  1346
                                    {
Dean@1476
  1347
                                        formRegions.FormRegionPreviewUnencrypted2.DisplayState.SetMessage(e.Mirror);
Dean@1476
  1348
                                    }
Dean@1476
  1349
Dean@1390
  1350
                                    Log.Verbose("MailItem_GetMirrorComplete: Mirror found and displayed.");
Dean@1390
  1351
                                }
Dean@1390
  1352
                            }
Dean@758
  1353
Dean@1390
  1354
                            // Display the mirror if necessary
Dean@1390
  1355
                            if ((this.cryptableMailItem != null) &&
Dean@1390
  1356
                                (this.displayMirrorRequested))
Dean@1390
  1357
                            {
Dean@1390
  1358
                                this.cryptableMailItem.DisplayMirror();
Dean@1390
  1359
                                this.displayMirrorRequested = false;
Dean@1390
  1360
                            }
Dean@758
  1361
                        }
Dean@709
  1362
                    }));
Dean@709
  1363
            }
Dean@709
  1364
            catch (Exception ex)
Dean@709
  1365
            {
Dean@1249
  1366
                Log.Error("MailItem_GetMirrorComplete: Error displaying preview, " + ex.ToString());
Dean@709
  1367
            }
Dean@709
  1368
Dean@709
  1369
            return;
Dean@709
  1370
        }
Dean@709
  1371
Dean@709
  1372
        /// <summary>
Dean@807
  1373
        /// Event handler for the static mail item encrypted conversation cache updated.
Dean@807
  1374
        /// This event is fired after the conversation cache has been updated with parent information following a
Dean@807
  1375
        /// forward or reply mail item event (on a different, likely parent, mail item).
Dean@807
  1376
        /// </summary>
Dean@807
  1377
        private void CryptableMailItem_EncryptedConversationCacheUpdated(object sender, EventArgs e)
Dean@807
  1378
        {
Dean@1390
  1379
            if (this.isEnabled)
Dean@1390
  1380
            {
Dean@1390
  1381
                // Process the mail item now that the cache is updated
Dean@1390
  1382
                this.cryptableMailItem.SetIsOriginallyEncryptedByCache();
Dean@807
  1383
Dean@1390
  1384
                // Remove the event handler -- this can only be processed once because it's timing dependent
Dean@1390
  1385
                CryptableMailItem.EncryptedConversationCacheUpdated -= CryptableMailItem_EncryptedConversationCacheUpdated;
Dean@1390
  1386
            }
Dean@807
  1387
Dean@807
  1388
            return;
Dean@807
  1389
        }
Dean@807
  1390
Dean@807
  1391
        /// <summary>
Dean@169
  1392
        /// Event handler for when a mail item is being opened in an inspector.
Dean@180
  1393
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865989.aspx
Dean@169
  1394
        /// </summary>
Dean@169
  1395
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@169
  1396
        /// If the event procedure sets this argument to True, the open operation is not completed 
Dean@169
  1397
        /// and the inspector is not displayed.</param>
Dean@169
  1398
        private void MailItem_Open(ref bool cancel)
Dean@159
  1399
        {
Dean@758
  1400
            bool result;
Dean@758
  1401
Dean@1390
  1402
            if ((this.isEnabled) &&
Dean@1390
  1403
                (this.cryptableMailItem != null) &&
Dean@1390
  1404
                (this.cryptableMailItem.IsSecurelyStored))
Dean@169
  1405
            {
Dean@758
  1406
                // Try to open the mirror
Dean@1390
  1407
                result = this.cryptableMailItem.DisplayMirror();
Dean@758
  1408
Dean@758
  1409
                if (result == false)
Dean@758
  1410
                {
Dean@758
  1411
                    // Set flag to open after decryption/mirror location
Dean@758
  1412
                    this.displayMirrorRequested = true;
Dean@758
  1413
                }
Dean@758
  1414
Dean@758
  1415
                // Always cancel opening the original
Dean@169
  1416
                cancel = true;
Dean@169
  1417
            }
Dean@169
  1418
Dean@169
  1419
            return;
Dean@159
  1420
        }
Dean@159
  1421
Dean@169
  1422
        /// <summary>
Dean@682
  1423
        /// Event handler for when a mail item is sent.
Dean@682
  1424
        /// See: https://msdn.microsoft.com/en-us/library/office/ff865379.aspx
Dean@682
  1425
        /// </summary>
Dean@682
  1426
        /// <param name="cancel">Whether to cancel the event: Value is False when the event occurs. 
Dean@682
  1427
        /// If the event procedure sets this argument to True, the send operation is not completed 
Dean@682
  1428
        /// and the inspector is left open.</param>
Dean@682
  1429
        private void MailItem_Send(ref bool cancel)
Dean@682
  1430
        {
Dean@807
  1431
            DialogResult result;
Dean@807
  1432
Dean@1390
  1433
            if (this.isEnabled)
Dean@807
  1434
            {
Thomas@1505
  1435
                if ((this.cryptableMailItem.IsBeingProcessed) ||
Thomas@1505
  1436
                    (this.processingOngoing))
Thomas@1505
  1437
                {
Thomas@1505
  1438
                    Log.Verbose("MailItem_Send cancelled. Mail item still being processed.");
Thomas@1505
  1439
                    cancel = true;
Thomas@1505
  1440
                    return;
Thomas@1505
  1441
                }
Thomas@1505
  1442
Dean@1390
  1443
                if ((Globals.ThisAddIn.Settings.IsSecurityLossWarningEnabled) &&
Dean@1390
  1444
                    (this.cryptableMailItem.IsOriginallyEncrypted) &&
Dean@1390
  1445
                    (this.FormControlPrivacyStatusChild.DisplayState.Rating < pEpRating.pEpRatingUnreliable))
Dean@1390
  1446
                {
Thomas@1318
  1447
Thomas@1318
  1448
#if READER_RELEASE_MODE
Dean@1390
  1449
                    FormReaderSplash warningMessage = new FormReaderSplash(true);
Dean@1390
  1450
                    result = warningMessage.ShowDialog();
Thomas@1318
  1451
Dean@1390
  1452
                    if (result != DialogResult.OK)
Dean@1390
  1453
                    {
Dean@1390
  1454
                        // Cancel sending
Dean@1390
  1455
                        cancel = true;
Dean@1390
  1456
                    }
Dean@1390
  1457
#else
Dean@1390
  1458
                    result = System.Windows.Forms.MessageBox.Show(this.ParentForm,
Dean@1390
  1459
                                                                  pEp.Properties.Resources.Message_WarningSecurityLoss,
Dean@1390
  1460
                                                                  pEp.Properties.Resources.Message_TitleConfirmOperation,
Dean@1390
  1461
                                                                  MessageBoxButtons.YesNo,
Dean@1390
  1462
                                                                  MessageBoxIcon.Warning);
Dean@1390
  1463
Dean@1390
  1464
                    if (result == DialogResult.No)
Dean@1390
  1465
                    {
Dean@1390
  1466
                        // Cancel sending
Dean@1390
  1467
                        cancel = true;
Dean@1390
  1468
                    }
Dean@1390
  1469
#endif
Dean@1390
  1470
                }
Dean@1390
  1471
Dean@1390
  1472
                // Stop and disconnect the refresh timer
Dean@1390
  1473
                // This is necessary so an ongoing refresh doesn't try to access a mail item as it's being moved
Dean@1390
  1474
                if (cancel == false)
Thomas@1318
  1475
                {
Dean@1390
  1476
                    this.TimerRefresh.Stop();
Dean@1390
  1477
                    this.TimerRefresh.Enabled = false;
Dean@1390
  1478
                    this.TimerRefresh.Tick -= TimerRefresh_Tick;
Thomas@1318
  1479
                }
Dean@807
  1480
            }
Dean@682
  1481
Dean@682
  1482
            return;
Dean@682
  1483
        }
Dean@682
  1484
Dean@682
  1485
        /// <summary>
Dean@169
  1486
        /// Event handler for when a mail item property is changed.
Dean@169
  1487
        /// See: https://msdn.microsoft.com/en-us/library/office/ff866739.aspx
Dean@169
  1488
        /// </summary>
Dean@169
  1489
        /// <param name="propertyName">The name of the property that was changed.</param>
Dean@445
  1490
        private void MailItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
Dean@159
  1491
        {
Dean@1349
  1492
            switch (e.PropertyName.ToUpperInvariant())
Dean@159
  1493
            {
Dean@1390
  1494
                case "BCC":
Dean@1390
  1495
                    {
Dean@1390
  1496
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Dean@1390
  1497
                        break;
Dean@1390
  1498
                    }
Dean@1390
  1499
                case "CC":
Dean@1390
  1500
                    {
Dean@1390
  1501
                        // Outlook always fires Bcc, Cc and To together so only "TO" is used
Dean@1390
  1502
                        break;
Dean@1390
  1503
                    }
Dean@1390
  1504
                case "SENTONBEHALFOFNAME":
Dean@1390
  1505
                    {
Dean@1390
  1506
                        // Always fired with "SENDUSINGACCOUNT" so is ignored
Dean@1390
  1507
                        break;
Dean@1390
  1508
                    }
Dean@1390
  1509
                case "SENDUSINGACCOUNT":
Dean@1390
  1510
                    {
Dean@1390
  1511
                        // Update pEp enabled status
Dean@1390
  1512
                        this.SetIsEnabled(((Outlook.MailItem)this.OutlookItem).GetIsPEPEnabled());
Dean@1390
  1513
Dean@1390
  1514
                        // Refresh the UI
Dean@1390
  1515
                        this.ResolveAllRecipients();
Dean@1390
  1516
                        this.RequestRatingAndUIUpdate();
Dean@1390
  1517
                        RibbonCustomizations.Invalidate();
Dean@1390
  1518
Dean@1390
  1519
                        break;
Dean@1390
  1520
                    }
Dean@179
  1521
                case "TO":
Dean@1390
  1522
                    {
Dean@1390
  1523
                        if (this.isEnabled)
Dean@1390
  1524
                        {
Dean@1390
  1525
                            this.RequestRatingAndUIUpdate();
Dean@1390
  1526
                        }
Dean@1390
  1527
                        break;
Dean@1390
  1528
                    }
Dean@159
  1529
            }
Dean@169
  1530
Dean@169
  1531
            return;
Dean@159
  1532
        }
Dean@159
  1533
Dean@179
  1534
        /// <summary>
Dean@1021
  1535
        /// Event handler for when the manager form is closed.
Dean@1021
  1536
        /// </summary>
Dean@1021
  1537
        private void ManagerForm_FormClosed(object sender, FormClosedEventArgs e)
Dean@1021
  1538
        {
Dean@1021
  1539
            // Remove the reference held in the FormRegionPrivacyStatus so it stops getting updated
Dean@1021
  1540
            if (this.managerForm != null)
Dean@1021
  1541
            {
Dean@1021
  1542
                this.managerForm.FormClosed -= ManagerForm_FormClosed;
Dean@1021
  1543
                this.managerForm = null;
Dean@1021
  1544
            }
Dean@1021
  1545
Dean@1021
  1546
            return;
Dean@1021
  1547
        }
Dean@1021
  1548
Dean@1021
  1549
        /// <summary>
Dean@859
  1550
        /// Event handler for when the pEp website hyperlink is clicked.
Dean@859
  1551
        /// </summary>
Dean@859
  1552
        private void LinkLabelUpgrade_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
Dean@859
  1553
        {
Dean@966
  1554
            try
Dean@966
  1555
            {
Dean@1007
  1556
                Process.Start(Globals.PEP_WEBSITE_UPGRADE_LINK);
Dean@966
  1557
            }
Dean@966
  1558
            catch (Exception ex)
Dean@966
  1559
            {
Dean@1249
  1560
                Log.Error("LinkLabelUpgrade_LinkClicked: Unable to open website link, " + ex.ToString());
Dean@966
  1561
            }
Dean@966
  1562
Dean@859
  1563
            return;
Dean@859
  1564
        }
Dean@1047
  1565
Dean@1047
  1566
        /// <summary>
Dean@1086
  1567
        /// Event handler for when the privacy view button is clicked within the form control.
Dean@1047
  1568
        /// </summary>
Dean@1086
  1569
        private void FormControlPrivacyStatusChild_PrivacyViewClick(object sender, System.Windows.RoutedEventArgs e)
Dean@1047
  1570
        {
Dean@1390
  1571
            if (this.isManagerFormEnabled)
Dean@1384
  1572
            {
Dean@1384
  1573
                this.RequestRatingAndUIUpdate();
Dean@1384
  1574
                this.BuildAndShowManager();
Dean@1384
  1575
            }
Dean@1384
  1576
Dean@1047
  1577
            return;
Dean@1047
  1578
        }
vb@133
  1579
    }
vb@133
  1580
}