Extensions/MailItemExtensions.cs
author Thomas
Tue, 03 Apr 2018 10:17:13 +0200
branchOUT-369
changeset 2100 91f72cbed562
parent 2075 e9022f6bf4fc
child 2092 c42b45e45ebc
permissions -rw-r--r--
Close branch OUT-369
Dean@1403
     1
using MimeKit;
Dean@1403
     2
using pEpCOMServerAdapterLib;
Dean@1303
     3
using System;
Thomas@1954
     4
using System.Collections.Generic;
Dean@1403
     5
using System.IO;
Dean@1303
     6
using System.Text;
Dean@1303
     7
using Outlook = Microsoft.Office.Interop.Outlook;
Dean@1303
     8
Dean@1303
     9
namespace pEp
Dean@1303
    10
{
Dean@1303
    11
    /// <summary>
Dean@1303
    12
    /// Contains extensions for the MailItem as well as utility methods specific for pEp.
Dean@1303
    13
    /// </summary>
Dean@1304
    14
    internal static class MailItemExtensions
Dean@1303
    15
    {
Thomas@1954
    16
        public const string USER_PROPERTY_KEY_ORIG_ENTRY_ID             = "origEntryID";
Thomas@1954
    17
        public const string USER_PROPERTY_KEY_IS_INCOMING               = "isIncoming";
Thomas@1954
    18
        public const string USER_PROPERTY_KEY_IS_MIRROR                 = "isMirror";
Thomas@1955
    19
        public const string UNKNOWN_SENDER                              = "unknown";
Thomas@1954
    20
Thomas@1971
    21
        private static object                     mutexCopiedItemsList  = new object();
Thomas@1971
    22
        private static List<string>               copiedItemsList       = new List<string>();
Thomas@1971
    23
Dean@1303
    24
        /// <summary>
Dean@1303
    25
        /// Enumeration defining the standard, setable pEp properties of an extended MailItem.
Dean@1303
    26
        /// These correspond with the properties in the PEPMessage.
Dean@1303
    27
        /// </summary>
Dean@1303
    28
        public enum PEPProperty
Dean@1303
    29
        {
Dean@1393
    30
            AutoConsume,
Dean@1303
    31
            ForceUnencrypted,
Dean@1303
    32
            KeyList,
Dean@1303
    33
            NeverUnsecure,
Dean@1303
    34
            PEPProtocolVersion,
nikolaj@1791
    35
            Rating,
Thomas@1819
    36
            EnableProtection,
Thomas@1819
    37
            ForceProtection
Dean@1303
    38
        }
Dean@1303
    39
Dean@1303
    40
        /**************************************************************
Dean@1303
    41
         * 
Dean@1303
    42
         * Extensions to Access a PEPProperty
Dean@1303
    43
         * 
Dean@1303
    44
         *************************************************************/
Dean@1303
    45
Dean@1303
    46
        /// <summary>
Dean@1303
    47
        /// Gets whether the given Outlook mail item is marked to never be unsecure.
Dean@1303
    48
        /// </summary>
Thomas@1784
    49
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
    50
        /// <returns>True if the Outlook mail item is marked to never be unsecure, otherwise false.</returns>
Dean@1303
    51
        public static bool GetNeverUnsecure(this Outlook.MailItem omi)
Dean@1303
    52
        {
Dean@1303
    53
            object propValue;
Dean@1303
    54
Dean@1303
    55
            if (omi != null)
Dean@1303
    56
            {
Dean@1303
    57
                // Return status can be ignored here, using the auto default value is good enough
Dean@1303
    58
                omi.GetPEPProperty(PEPProperty.NeverUnsecure, out propValue);
Dean@1303
    59
            }
Dean@1303
    60
            else
Dean@1303
    61
            {
Dean@1303
    62
                propValue = GetPEPPropertyDefault(PEPProperty.NeverUnsecure);
Dean@1303
    63
            }
Dean@1303
    64
Dean@1303
    65
            return ((bool)propValue);
Dean@1303
    66
        }
Dean@1327
    67
Thomas@1795
    68
        /// <summary>
Thomas@1817
    69
        /// Gets whether the given Outlook mail item is marked to enable protection even if pEp is disabled.
Thomas@1795
    70
        /// </summary>
Thomas@1795
    71
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1819
    72
        /// <returns>True if the Outlook mail item is marked to enable protection, otherwise false.</returns>
Thomas@1817
    73
        public static bool GetEnableProtection(this Outlook.MailItem omi)
Thomas@1795
    74
        {
Thomas@1795
    75
            object propValue;
Thomas@1795
    76
Thomas@1795
    77
            if (omi != null)
Thomas@1795
    78
            {
Thomas@1795
    79
                // Return status can be ignored here, using the auto default value is good enough
Thomas@1817
    80
                omi.GetPEPProperty(PEPProperty.EnableProtection, out propValue);
Thomas@1795
    81
            }
Thomas@1795
    82
            else
Thomas@1795
    83
            {
Thomas@1817
    84
                propValue = GetPEPPropertyDefault(PEPProperty.EnableProtection);
Thomas@1795
    85
            }
Thomas@1795
    86
Thomas@1795
    87
            return ((bool)propValue);
Thomas@1795
    88
        }
Thomas@1795
    89
Thomas@1819
    90
        /// <summary>
Thomas@1894
    91
        /// Gets whether the given Outlook mail item is marked with the autoconsume property.
Thomas@1894
    92
        /// </summary>
Thomas@1894
    93
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1894
    94
        /// <returns>True if the Outlook mail item is marked with the autoconsume property, otherwise false.</returns>
Thomas@1894
    95
        public static bool GetIsAutoConsume(this Outlook.MailItem omi)
Thomas@1894
    96
        {
Thomas@1894
    97
            object autoConsume = null;
Thomas@1953
    98
            if (omi?.GetPEPProperty(MailItemExtensions.PEPProperty.AutoConsume, out autoConsume) == true)
Thomas@1894
    99
            {
Thomas@1894
   100
                return (autoConsume != null);
Thomas@1894
   101
            }
Thomas@1894
   102
Thomas@1894
   103
            return false;
Thomas@1894
   104
        }
Thomas@1894
   105
Thomas@1894
   106
        /// <summary>
Thomas@1819
   107
        /// Gets whether the given Outlook mail item is marked to force protection.
Thomas@1819
   108
        /// </summary>
Thomas@1819
   109
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1819
   110
        /// <returns>True if the Outlook mail item is marked to force protection, otherwise false.</returns>
Thomas@2028
   111
        public static bool GetIsForcefullyProtected(this Outlook.MailItem omi)
Thomas@1819
   112
        {
Thomas@1848
   113
            string forceProtectionId = omi.GetForceProtectionId();
Thomas@1819
   114
Thomas@1848
   115
            return (string.IsNullOrEmpty(forceProtectionId) == false);
Thomas@1820
   116
        }
Thomas@1820
   117
Thomas@1820
   118
        /// <summary>
Thomas@1989
   119
        /// Gets whether the given Outlook mail item is marked to send forcefully unencrypted.
Thomas@1989
   120
        /// </summary>
Thomas@1989
   121
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1989
   122
        /// <returns>True if the Outlook mail item is marked to send forcefully unencrypted, otherwise false.</returns>
Thomas@1989
   123
        public static bool GetIsForceUnencrypted(this Outlook.MailItem omi)
Thomas@1989
   124
        {
Thomas@1989
   125
            bool isForceUnencrypted = false;
Thomas@1989
   126
            object value = null;
Thomas@1989
   127
Thomas@1989
   128
            if (omi?.GetPEPProperty(PEPProperty.ForceUnencrypted, out value) == true)
Thomas@1989
   129
            {
Thomas@1989
   130
                isForceUnencrypted = (bool)value;
Thomas@1989
   131
            }
Thomas@1989
   132
Thomas@1989
   133
            return isForceUnencrypted;
Thomas@1989
   134
        }
Thomas@1989
   135
Thomas@1989
   136
        /// <summary>
Thomas@1820
   137
        /// Gets the message GUID that is stored in the force protection MAPI property.
Thomas@1820
   138
        /// </summary>
Thomas@1820
   139
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1820
   140
        /// <returns>The message GUID or null if not set.</returns>
Thomas@1825
   141
        public static string GetForceProtectionId(this Outlook.MailItem omi)
Thomas@1820
   142
        {
Thomas@1820
   143
            object propValue = null;
Thomas@1820
   144
            string guid = null;
Thomas@1820
   145
Thomas@1820
   146
            if (omi?.GetPEPProperty(PEPProperty.ForceProtection, out propValue) ?? false)
Thomas@1820
   147
            {
Thomas@1820
   148
                guid = propValue as string;
Thomas@1820
   149
            }
Thomas@1820
   150
            else
Thomas@1820
   151
            {
Thomas@1820
   152
                Log.Verbose("GetForceProtectionGuid: Could not get GUID. Mail item is null or property is not set.");
Thomas@1820
   153
            }
Thomas@1820
   154
Thomas@1820
   155
            return guid;
Thomas@1819
   156
        }
Thomas@1819
   157
Dean@1303
   158
        /**************************************************************
Dean@1303
   159
         * 
Dean@1303
   160
         * Main Extensions
Dean@1303
   161
         * 
Dean@1303
   162
         *************************************************************/
Dean@1303
   163
Dean@1303
   164
        /// <summary>
Thomas@1988
   165
        /// Adds a disclaimer text to this mail item's body if the
Thomas@1988
   166
        /// respective setting is set for the item's account.
Thomas@1988
   167
        /// </summary>
Thomas@1988
   168
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1988
   169
        public static void AddDisclaimer(this Outlook.MailItem omi)
Thomas@1988
   170
        {
Thomas@1988
   171
            try
Thomas@1988
   172
            {
Thomas@1988
   173
                // Determine the disclaimer setting for the mail item's account
Thomas@1988
   174
                var accountSettings = Globals.ThisAddIn.Settings.GetAccountSettings(omi?.SenderEmailAddress ?? omi?.Sender.Address);
Thomas@1988
   175
Thomas@1988
   176
                /* Add disclaimer if needed:
Thomas@1988
   177
                 *      - if set to add to all messages
Thomas@1988
   178
                 *      - if set to add to encrypted messages and outgoing rating is
Thomas@1988
   179
                 *        at least reliable.
Thomas@1992
   180
                 *        Special cases:
Thomas@1992
   181
                 *          - ForceUnencrypted: checked for in outgoing rating
Thomas@1992
   182
                 *          - ForceProtection: checked for in outgoing rating
Thomas@1992
   183
                 *          - pEp disabled: unencrypted unless EnableProtection is set
Thomas@1988
   184
                 */
Thomas@1988
   185
                if ((accountSettings.AddDisclaimer == PEPSettings.Disclaimer.AllMessages) ||
Thomas@2010
   186
                    ((accountSettings.AddDisclaimer == PEPSettings.Disclaimer.OnlyEncryptedMessages) &&
Thomas@1990
   187
                     (omi.GetOutgoingRating() >= pEpRating.pEpRatingReliable) &&
Thomas@1990
   188
                     (omi.GetIsPEPEnabled())))
Thomas@1988
   189
                {
Thomas@1988
   190
                    // We only add disclaimers to outgoing mails
Thomas@1988
   191
                    if (omi.GetIsIncoming() == false)
Thomas@1988
   192
                    {
Thomas@1988
   193
                        if (string.IsNullOrWhiteSpace(omi.HTMLBody))
Thomas@1988
   194
                        {
Thomas@1988
   195
                            omi.Body += Environment.NewLine +
Thomas@1988
   196
                                        Environment.NewLine +
Thomas@1988
   197
                                        accountSettings.DisclaimerText;
Thomas@1988
   198
                        }
Thomas@1988
   199
                        else
Thomas@1988
   200
                        {
Thomas@1988
   201
                            omi.HTMLBody += "<br><br><p>" +
Thomas@1988
   202
                                            accountSettings.DisclaimerText +
Thomas@1988
   203
                                            "</p>";
Thomas@2010
   204
                        }
Thomas@1988
   205
                    }
Thomas@1988
   206
                    else
Thomas@1988
   207
                    {
Thomas@1988
   208
                        Log.Verbose("AddDisclaimer: Skipped. Mail item is incoming.");
Thomas@1988
   209
                    }
Thomas@1988
   210
                }
Thomas@1988
   211
            }
Thomas@1988
   212
            catch (Exception ex)
Thomas@1988
   213
            {
Thomas@1988
   214
                Log.Error("AddDisclaimer: Error adding disclaimer to mail item. " + ex.ToString());
Thomas@1988
   215
            }
Thomas@1988
   216
        }
Thomas@1988
   217
Thomas@1988
   218
        /// <summary>
Thomas@1954
   219
        /// Creates a new Outlook mail item in the unencrypted folder that is a mirror copy
Thomas@1954
   220
        /// of the original mail item. This method will also update the mirror cache.
Thomas@1956
   221
        /// Note: Normally, it should not be needed to pass a messageId, as we normally use the
Thomas@1956
   222
        /// mail item's entryId. However, in cases where a mail item has no EntryId (e.g. an attached
Thomas@1956
   223
        /// mail), we can store the messageId instead.
Thomas@1954
   224
        /// </summary>
Thomas@1988
   225
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1956
   226
        /// <param name="messageId">Can be used instead of the mail item's entryId.</param>
Thomas@1954
   227
        /// <returns>The newly created mirror Outlook mail item.</returns>
Thomas@1956
   228
        public static Outlook.MailItem CreateMirrorOMI(this Outlook.MailItem omi, string messageId = null)
Thomas@1954
   229
        {
Thomas@1954
   230
            bool created = false;
Thomas@1954
   231
            byte[] bytes;
Thomas@1954
   232
            string str;
Thomas@1954
   233
            Int32 messageFlags;
Thomas@1954
   234
            Outlook.MailItem mirror = null;
Thomas@1954
   235
            Outlook.Folder folder = omi.GetMirrorFolder();
Thomas@1954
   236
Thomas@1954
   237
            try
Thomas@1954
   238
            {
Thomas@1954
   239
                Log.Verbose("CreateMirrorOMI: Creating by new mail item.");
Thomas@1954
   240
Thomas@1954
   241
                mirror = (Outlook.MailItem)folder.Items.Add(Outlook.OlItemType.olMailItem);
Thomas@1954
   242
                mirror.UnRead = false;
Thomas@1954
   243
Thomas@1954
   244
                // Set received and sent time
Thomas@1954
   245
                try
Thomas@1954
   246
                {
Thomas@1954
   247
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageDeliveryTime, omi.ReceivedTime.ToUniversalTime());
Thomas@1954
   248
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagClientSubmitTime, omi.SentOn.ToUniversalTime());
Thomas@1954
   249
                }
Thomas@1954
   250
                catch (Exception ex)
Thomas@1954
   251
                {
Thomas@1954
   252
                    Log.Verbose("CreateMirrorOMI: Failed to set received and sent time. " + ex.ToString());
Thomas@1954
   253
                    throw;
Thomas@1954
   254
                }
Thomas@1954
   255
Thomas@1954
   256
                // Attempt to set sender information
Thomas@1954
   257
                try
Thomas@1954
   258
                {
Thomas@1954
   259
                    mirror.Sender = omi.Sender;
Thomas@1954
   260
                }
Thomas@1954
   261
                catch (Exception ex)
Thomas@1954
   262
                {
Thomas@1954
   263
                    Log.Verbose("CreateMirrorOMI: Failed to set sender directly. " + ex.ToString());
Thomas@1954
   264
                }
Thomas@1954
   265
Thomas@1954
   266
                try
Thomas@1954
   267
                {
Thomas@1954
   268
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderName, omi.SenderName);
Thomas@1954
   269
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEmailAddress, omi.SenderEmailAddress);
Thomas@1954
   270
Thomas@1954
   271
                    // Entry ID is needed to resolve the sender so a reply is possible without having to re-enter address, this is last in case it fails
Thomas@1954
   272
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagSenderEntryId, MapiHelper.GetProperty(omi, MapiProperty.PidTagSenderEntryId));
Thomas@1954
   273
                }
Thomas@1954
   274
                catch (Exception ex)
Thomas@1954
   275
                {
Thomas@1954
   276
                    Log.Verbose("CreateMirrorOMI: Failed to set sender through MAPI properties. " + ex.ToString());
Thomas@1954
   277
                    throw;
Thomas@1954
   278
                }
Thomas@1954
   279
Thomas@1954
   280
                try
Thomas@1954
   281
                {
Thomas@1954
   282
                    mirror.SendUsingAccount = omi.SendUsingAccount;
Thomas@1954
   283
                }
Thomas@1954
   284
                catch (Exception ex)
Thomas@1954
   285
                {
Thomas@1954
   286
                    Log.Verbose("CreateMirrorOMI: Failed to set SendUsingAccount. " + ex.ToString());
Thomas@1954
   287
                }
Thomas@1954
   288
Thomas@1954
   289
                // Set flags
Thomas@1954
   290
                messageFlags = (System.Int32)MapiHelper.GetProperty(mirror, MapiProperty.PidTagMessageFlags);
Thomas@1954
   291
                messageFlags &= ~((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent);  // Clear UNSENT flag -- must be done before save
Thomas@1954
   292
                messageFlags |= ((System.Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfRead);     // Mark as read
Thomas@1954
   293
                try
Thomas@1954
   294
                {
Thomas@1954
   295
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagMessageFlags, messageFlags);
Thomas@1954
   296
                }
Thomas@1954
   297
                catch (Exception ex)
Thomas@1954
   298
                {
Thomas@1954
   299
                    Log.Verbose("CreateMirrorOMI: Failed to set message flags. " + ex.ToString());
Thomas@1954
   300
                }
Thomas@1954
   301
Thomas@1954
   302
                // Conversation information
Thomas@1954
   303
                try
Thomas@1954
   304
                {
Thomas@1954
   305
                    /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
Thomas@1954
   306
                     * This is by design since this property is computed automatically from other properties.
Thomas@1954
   307
                     * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
Thomas@1954
   308
                     */
Thomas@1954
   309
Thomas@1954
   310
                    str = omi.ConversationIndex;
Thomas@1954
   311
                    if (str != null)
Thomas@1954
   312
                    {
Thomas@1954
   313
                        bytes = new byte[str.Length / 2];
Thomas@1954
   314
                        for (int i = 0; i < str.Length; i += 2)
Thomas@1954
   315
                        {
Thomas@1954
   316
                            bytes[i / 2] = Convert.ToByte(str.Substring(i, 2), 16);
Thomas@1954
   317
                        }
Thomas@1954
   318
Thomas@1954
   319
                        MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndex, bytes);
Thomas@1954
   320
                    }
Thomas@1954
   321
Thomas@1954
   322
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationIndexTracking, false);
Thomas@1954
   323
                    MapiHelper.SetProperty(mirror, MapiProperty.PidTagConversationTopic, omi.ConversationTopic);
Thomas@1954
   324
                }
Thomas@1954
   325
                catch (Exception ex)
Thomas@1954
   326
                {
Thomas@1954
   327
                    Log.Verbose("CreateMirrorOMI: Failed to set conversation information. " + ex.ToString());
Thomas@1954
   328
                }
Thomas@1954
   329
Thomas@1954
   330
                mirror.To = omi.To;
Thomas@1954
   331
                mirror.CC = omi.CC;
Thomas@1954
   332
                mirror.BCC = omi.BCC;
Thomas@1954
   333
                mirror.Subject = "p≡p";
Thomas@1954
   334
                mirror.Body = string.Empty;
Thomas@1954
   335
                mirror.Save();
Thomas@1954
   336
Thomas@1954
   337
                /* Set all received-by information
Thomas@1954
   338
                 * 
Thomas@1954
   339
                 * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
Thomas@1954
   340
                 * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
Thomas@1954
   341
                 * 
Thomas@1954
   342
                 * In most situations the received-by information will not be needed.
Thomas@1954
   343
                 * Decryption for example uses the recipients/identities in the original mail item itself.
Thomas@1954
   344
                 * However, the GetMyIdentity(omi) method requires this information in some cases:
Thomas@1954
   345
                 *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
Thomas@1954
   346
                 *    using aliases or when forwarding emails from another account.
Thomas@1954
   347
                 *  • This is primarily needed when displaying mirrors themselves then opening the handshake dialog.
Thomas@1954
   348
                 */
Thomas@1954
   349
                try
Thomas@1954
   350
                {
Thomas@1954
   351
                    /* Get the "received by" email address. In case this returns an internal X500 Exchange address ("/O=DOMAIN/OU=EXCHANGE ADMINISTRATIVE GROUP..."),
Thomas@1954
   352
                     * compare it with the recipients' addresses and take the primary SMTP address.
Thomas@1954
   353
                     */
Thomas@1954
   354
                    string email = MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress) as string;
Thomas@1954
   355
                    if (email.StartsWith("/O"))
Thomas@1954
   356
                    {
Thomas@1954
   357
                        Outlook.Recipients recipients = null;
Thomas@1954
   358
                        Outlook.Recipient recipient = null;
Thomas@1954
   359
                        Outlook.AddressEntry addressEntry = null;
Thomas@1954
   360
                        Outlook.ExchangeUser exchangeUser = null;
Thomas@1954
   361
Thomas@1954
   362
                        try
Thomas@1954
   363
                        {
Thomas@1954
   364
                            recipients = omi.Recipients;
Thomas@1954
   365
Thomas@1954
   366
                            for (int i = 1; i <= recipients.Count; i++)
Thomas@1954
   367
                            {
Thomas@1954
   368
                                recipient = recipients[i];
Thomas@1954
   369
                                addressEntry = recipient?.AddressEntry;
Thomas@1954
   370
                                exchangeUser = addressEntry?.GetExchangeUser();
Thomas@1954
   371
Thomas@1954
   372
                                if (email.ToUpperInvariant().Equals(exchangeUser?.Address?.ToUpperInvariant()))
Thomas@1954
   373
                                {
Thomas@1954
   374
                                    email = exchangeUser?.PrimarySmtpAddress;
Thomas@1954
   375
                                    break;
Thomas@1954
   376
                                }
Thomas@1954
   377
Thomas@1954
   378
                                recipient = null;
Thomas@1954
   379
                                addressEntry = null;
Thomas@1954
   380
                                exchangeUser = null;
Thomas@1954
   381
                            }
Thomas@1954
   382
                        }
Thomas@1954
   383
                        catch (Exception ex)
Thomas@1954
   384
                        {
Thomas@1954
   385
                            Log.Error("CreateMirrorOMI: Error getting ReceivedByEmailAddress. " + ex.ToString());
Thomas@1954
   386
                        }
Thomas@1954
   387
                        finally
Thomas@1954
   388
                        {
Thomas@1954
   389
                            recipients = null;
Thomas@1954
   390
                            recipient = null;
Thomas@1954
   391
                            addressEntry = null;
Thomas@1954
   392
                            exchangeUser = null;
Thomas@1954
   393
                        }
Thomas@1954
   394
                    }
Thomas@1954
   395
                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName, email,
Thomas@1954
   396
                                        Outlook.OlUserPropertyType.olText);
Thomas@1954
   397
                    mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
Thomas@1954
   398
                                        MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
Thomas@1954
   399
                                        Outlook.OlUserPropertyType.olText);
Thomas@1954
   400
                }
Thomas@1954
   401
                catch (Exception ex)
Thomas@1954
   402
                {
Thomas@1954
   403
                    Log.Verbose("CreateMirrorOMI: Failed to set received-by information. " + ex.ToString());
Thomas@1954
   404
                }
Thomas@1954
   405
Thomas@1954
   406
                // Mark the mail item as a mirror
Thomas@1954
   407
                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   408
Thomas@1954
   409
                /* Set the incoming status of the new mail item.
Thomas@1954
   410
                 * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
Thomas@1954
   411
                 * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
Thomas@1954
   412
                 */
Thomas@1954
   413
                if (omi.GetIsIncoming())
Thomas@1954
   414
                {
Thomas@1954
   415
                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   416
                }
Thomas@1954
   417
                else
Thomas@1954
   418
                {
Thomas@1954
   419
                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   420
                }
Thomas@1954
   421
Thomas@1956
   422
                // Add the original EntryID or the messageId if the latter has been passed
Thomas@1956
   423
                mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
Thomas@1954
   424
                mirror.Save();
Thomas@1954
   425
Thomas@1954
   426
                // Move the mirror copy to the correct folder
Thomas@1954
   427
                // This is needed as some account-types/office versions will still create a mail item in the default folder
Thomas@1954
   428
                // even if folder.Items.Add is used to specify a location.
Thomas@1954
   429
                // WARNING: this creates a new mail item that will no longer be referenced here!!
Thomas@1954
   430
                mirror.Move(folder);
Thomas@1954
   431
                created = true;
Thomas@1954
   432
            }
Thomas@1954
   433
            catch (Exception ex)
Thomas@1954
   434
            {
Thomas@1954
   435
                Log.Verbose("CreateMirrorOMI: Creating new mail item failed. " + ex.ToString());
Thomas@1954
   436
                mirror.PermanentlyDelete();
Thomas@1954
   437
                mirror = null;
Thomas@1954
   438
            }
Thomas@1954
   439
Thomas@1954
   440
            if (created == false)
Thomas@1954
   441
            {
Thomas@1954
   442
                try
Thomas@1954
   443
                {
Thomas@1954
   444
                    Log.Verbose("CreateMirrorOMI: Creating by copy.");
Thomas@1954
   445
Thomas@1954
   446
                    // Release any partially created omi from a failed copy
Thomas@1954
   447
                    mirror = null;
Thomas@1954
   448
Thomas@1954
   449
                    /* Attempt to create the mirror by copying
Thomas@1954
   450
                     * Depending on account types, anything after Office 2010 can have the following error:
Thomas@1954
   451
                     *  System.Runtime.InteropServices.COMException (0x80040102): Sorry, Exchange ActiveSync doesn't
Thomas@1954
   452
                     *  support what you're trying to do. 
Thomas@1954
   453
                     *    at Microsoft.Office.Interop.Outlook._MailItem.Copy()
Thomas@1954
   454
                     * When this happens a new mail item must be created.
Thomas@1954
   455
                     */
Thomas@1971
   456
                    lock (mutexCopiedItemsList)
Thomas@1971
   457
                    {
Thomas@1974
   458
                        mirror = (Outlook.MailItem)omi.Copy();
Thomas@1974
   459
                        if (copiedItemsList.Contains(mirror?.EntryID) == false)
Thomas@1971
   460
                        {
Thomas@1974
   461
                            copiedItemsList.Add(mirror?.EntryID);
Thomas@1971
   462
                        }
Thomas@1971
   463
                    }
Thomas@1973
   464
Thomas@1954
   465
                    mirror.UnRead = false;
Thomas@1954
   466
Thomas@1954
   467
                    /* Set all received-by information
Thomas@1954
   468
                     * 
Thomas@1954
   469
                     * This must be stored as a user-property because settings MAPI properties such as "PR_RECEIVED_BY_EMAIL_ADDRESS"
Thomas@1954
   470
                     * is not supported by Outlook. The user-properties are named the same as the MAPI property for simplicity.
Thomas@1954
   471
                     * 
Thomas@1954
   472
                     * In most situations the received-by information will not be needed.
Thomas@1954
   473
                     * Decryption for example uses the recipients/identities in the original mail item itself.
Thomas@1954
   474
                     * However, the GetMyIdentity(omi) method requires this information in some cases:
Thomas@1954
   475
                     *  • The true 'myself' identity of a mail item is not an account registerd in Outlook. This can happen
Thomas@1954
   476
                     *    using aliases or when forwarding emails from another account.
Thomas@1954
   477
                     *  • This is primarily needed when displaying mirrors themselves then opening the privacy status manager.
Thomas@1954
   478
                     */
Thomas@1954
   479
                    try
Thomas@1954
   480
                    {
Thomas@1954
   481
                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByEmailAddress.DaslName,
Thomas@1954
   482
                                            MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByEmailAddress),
Thomas@1954
   483
                                            Outlook.OlUserPropertyType.olText);
Thomas@1954
   484
                        mirror.SetUserProperty(MapiProperty.PidTagReceivedByName.DaslName,
Thomas@1954
   485
                                            MapiHelper.GetProperty(omi, MapiProperty.PidTagReceivedByName),
Thomas@1954
   486
                                            Outlook.OlUserPropertyType.olText);
Thomas@1954
   487
                    }
Thomas@1954
   488
                    catch { }
Thomas@1954
   489
Thomas@1954
   490
                    // Mark the mail item as a mirror
Thomas@1954
   491
                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR, true, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   492
Thomas@1954
   493
                    /* Set the incoming status of the new mail item.
Thomas@1954
   494
                     * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
Thomas@1954
   495
                     * PR_RECEIVED_BY_ENTRYID is only set when copying the original mail item.
Thomas@1954
   496
                     */
Thomas@1954
   497
                    if (omi.GetIsIncoming())
Thomas@1954
   498
                    {
Thomas@1954
   499
                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, true, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   500
                    }
Thomas@1954
   501
                    else
Thomas@1954
   502
                    {
Thomas@1954
   503
                        mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING, false, Outlook.OlUserPropertyType.olYesNo);
Thomas@1954
   504
                    }
Thomas@1954
   505
Thomas@1954
   506
                    // Add the original EntryID to the mirror copy
Thomas@1954
   507
                    // This must be done before the move as the reference is then lost
Thomas@1956
   508
                    mirror.SetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_ORIG_ENTRY_ID, messageId ?? omi.EntryID);
Thomas@1954
   509
                    mirror.Save();
Thomas@1954
   510
Thomas@1954
   511
                    // Move the mirror copy to the correct folder
Thomas@1954
   512
                    // WARNING: this creates a new mail item that will no longer be referenced here!!
Thomas@1954
   513
                    mirror.Move(folder);
Thomas@1954
   514
                }
Thomas@1954
   515
                catch (Exception ex)
Thomas@1954
   516
                {
Thomas@1954
   517
                    Log.Error("CreateMirrorOMI: Creating by copy failed. " + ex.ToString());
Thomas@1954
   518
                }
Thomas@1971
   519
                finally
Thomas@1971
   520
                {
Thomas@1971
   521
                    lock (mutexCopiedItemsList)
Thomas@1971
   522
                    {
Thomas@1971
   523
                        if (copiedItemsList.Contains(omi?.EntryID))
Thomas@1971
   524
                        {
Thomas@1971
   525
                            copiedItemsList.Remove(omi?.EntryID);
Thomas@1971
   526
                        }
Thomas@1971
   527
                    }
Thomas@1971
   528
                }
Thomas@1971
   529
Thomas@1954
   530
            }
Thomas@1954
   531
Thomas@1954
   532
            // Release objects
Thomas@1954
   533
            if (mirror != null)
Thomas@1954
   534
            {
Thomas@1954
   535
                // Marshal.ReleaseComObject(omi);
Thomas@1954
   536
                mirror = null;
Thomas@1954
   537
            }
Thomas@1954
   538
Thomas@1954
   539
            if (folder != null)
Thomas@1954
   540
            {
Thomas@1954
   541
                // Marshal.ReleaseComObject(folder);
Thomas@1954
   542
                folder = null;
Thomas@1954
   543
            }
Thomas@1954
   544
Thomas@1954
   545
            /* Locate and return the mirror that was just created.
Thomas@1954
   546
             * During this find method, the mirror cache will be updated when found.
Thomas@1954
   547
             * It is important to do this here as any .Move methods create a new mail item.
Thomas@1954
   548
             */
Thomas@1960
   549
            return omi.GetMirror(messageId);
Thomas@1954
   550
        }
Thomas@1954
   551
Thomas@1954
   552
        /// <summary>
Thomas@1954
   553
        /// Searches for mirrored outlook mail item associated with the given outlook mail item.
Thomas@1954
   554
        /// To improve performance, this method implements some caching. 
Thomas@1956
   555
        /// Note: Normally, it should not be needed to pass a messageId, as we normally use the
Thomas@1956
   556
        /// mail item's entryId. However, in cases where a mail item has no EntryId (e.g. an attached
Thomas@1956
   557
        /// mail), we can store the messageId instead.
Thomas@1954
   558
        /// </summary>
Thomas@1954
   559
        /// <param name="omi">The outlook mail item to find the mirror for.</param>
Thomas@1956
   560
        /// <param name="messageId">Can be used instead of the mail item's entryId.</param>
Thomas@1960
   561
        /// <returns>The mirror mail item if successful. Otherwise null.</returns>
Thomas@1960
   562
        public static Outlook.MailItem GetMirror(this Outlook.MailItem omi, string messageId = null)
Thomas@1954
   563
        {
Thomas@1954
   564
            Outlook.MailItem mirror = null;
Thomas@1960
   565
            string userName = string.Empty;
Thomas@1954
   566
Thomas@1960
   567
            try
Thomas@1954
   568
            {
Thomas@1960
   569
                if ((omi != null) &&
Thomas@1960
   570
                    (PEPIdentity.GetFromUserName(omi, out userName) == Globals.ReturnStatus.Success))
Thomas@1954
   571
                {
Thomas@1960
   572
                    mirror = PEPMessage.GetMirror(messageId ?? omi.EntryID, userName);
Thomas@1954
   573
                }
Thomas@1960
   574
                else
Thomas@1954
   575
                {
Thomas@1960
   576
                    Log.Error("MsgProcessor.GetMirror: Original is null or From user name could not be retrieved.");
Thomas@1954
   577
                }
Thomas@1954
   578
            }
Thomas@1960
   579
            catch (Exception ex)
Thomas@1954
   580
            {
Thomas@1960
   581
                Log.Error("MsgProcessor.GetMirror: Error getting mirror. " + ex.ToString());
Thomas@1954
   582
            }
Thomas@1954
   583
Thomas@1960
   584
            return mirror;
Thomas@1954
   585
        }
Thomas@1954
   586
Thomas@1954
   587
        /// <summary>
Thomas@1795
   588
        /// Determines whether to enable the form region for this mail item.
Thomas@1795
   589
        /// </summary>
Thomas@1795
   590
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1795
   591
        /// <returns>True if the mail item's form region is to enable, otherwise false.</returns>
Thomas@1795
   592
        public static bool GetEnableFormRegion(this Outlook.MailItem omi)
Thomas@1795
   593
        {
Thomas@1795
   594
            bool enable = true;
Thomas@1795
   595
Thomas@1795
   596
            if (omi != null)
Thomas@1795
   597
            {
Thomas@1795
   598
                try
Thomas@1795
   599
                {
Thomas@1795
   600
                    if (omi.GetIsPEPEnabled() == false)
Thomas@1795
   601
                    {
Thomas@1795
   602
                        if (omi.GetIsIncoming())
Thomas@1795
   603
                        {
Thomas@1795
   604
                            enable = omi.GetIsDecryptAlwaysEnabled();
Thomas@1795
   605
                        }
Thomas@1795
   606
                        else
Thomas@1795
   607
                        {
Thomas@1817
   608
                            enable = omi.GetEnableProtection();
Thomas@1795
   609
                        }
Thomas@1795
   610
                    }
Thomas@1795
   611
                }
Thomas@1795
   612
                catch (Exception ex)
Thomas@1795
   613
                {
Thomas@1795
   614
                    Log.Error("GetEnableFormRegion: Error occured. " + ex.ToString());
Thomas@1795
   615
                }
Thomas@1795
   616
            }
Thomas@1795
   617
Thomas@1795
   618
            return enable;
Thomas@1795
   619
        }
Thomas@1795
   620
Thomas@1795
   621
        /// <summary>
Thomas@1784
   622
        /// Determines if the mail item's store is set to always decrypt.
Thomas@1784
   623
        /// </summary>
Thomas@1784
   624
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
   625
        /// <returns>True if the mail item's store is set to always decrypt, otherwise false.</returns>
Thomas@1784
   626
        public static bool GetIsDecryptAlwaysEnabled(this Outlook.MailItem omi)
Thomas@1784
   627
        {
Thomas@1784
   628
            bool isEnabled = PEPSettings.ACCOUNT_SETTING_IS_DECRYPT_ALWAYS_ENABLED_DEFAULT;
Thomas@1784
   629
            Outlook.Folder folder = null;
Thomas@1784
   630
            Outlook.Store store = null;
Thomas@1784
   631
Thomas@1784
   632
            try
Thomas@1784
   633
            {
Thomas@1784
   634
                folder = omi.Parent as Outlook.Folder;
Thomas@1784
   635
                store = folder?.Store;
Thomas@1784
   636
                isEnabled = store?.GetIsDecryptAlwaysEnabled() ?? PEPSettings.ACCOUNT_SETTING_IS_DECRYPT_ALWAYS_ENABLED_DEFAULT;
Thomas@1784
   637
            }
Thomas@1784
   638
            catch
Thomas@1784
   639
            {
Thomas@1784
   640
                Log.Error("GetDecryptAlwaysEnabled: failure occured, returning default.");
Thomas@1784
   641
            }
Thomas@1784
   642
            finally
Thomas@1784
   643
            {
Thomas@1784
   644
                folder = null;
Thomas@1784
   645
                store = null;
Thomas@1784
   646
            }
Thomas@1784
   647
Thomas@1784
   648
            return isEnabled;
Thomas@1784
   649
        }
Thomas@1784
   650
Thomas@1784
   651
        /// <summary>
Dean@1415
   652
        /// Determines if the mail item is a draft (unsent) from its MAPI message flags.
Dean@1303
   653
        /// This specifically with check the 'mfUnsent' flag.
Dean@1303
   654
        /// </summary>
Thomas@1784
   655
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
   656
        /// <returns>True if the Outlook mail item is a draft (unsent), otherwise false.</returns>
Dean@1303
   657
        public static bool GetIsDraft(this Outlook.MailItem omi)
Dean@1303
   658
        {
Dean@1303
   659
            bool isDraft = false;
Dean@1303
   660
            Int32 messageFlags;
Dean@1303
   661
Dean@1303
   662
            if (omi != null)
Dean@1303
   663
            {
Dean@1411
   664
                // Detect using MAPI message flags
Dean@1350
   665
                messageFlags = (Int32)MapiHelper.GetProperty(omi, MapiProperty.PidTagMessageFlags, (Int32)0);
Dean@1350
   666
                if ((messageFlags & ((Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfUnsent)) > 0)
Dean@1303
   667
                {
Dean@1303
   668
                    isDraft = true;
Dean@1303
   669
                }
Dean@1303
   670
            }
Dean@1303
   671
Dean@1303
   672
            return (isDraft);
Dean@1303
   673
        }
Dean@1303
   674
Dean@1303
   675
        /// <summary>
Dean@1415
   676
        /// Determines if the mail item is submitted (user already pressed send) from its MAPI message flags.
Dean@1411
   677
        /// Submitted items should usually be located within the Outbox.
Dean@1411
   678
        /// This specifically will check the 'mfSubmitted' flag.
Dean@1411
   679
        /// </summary>
Thomas@1784
   680
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
   681
        /// <returns>True if the Outlook mail item is already submitted, otherwise false.</returns>
Dean@1411
   682
        public static bool GetIsSubmitted(this Outlook.MailItem omi)
Dean@1411
   683
        {
Dean@1411
   684
            bool isSubmitted = false;
Dean@1411
   685
            Int32 messageFlags;
Dean@1411
   686
Dean@1411
   687
            if (omi != null)
Dean@1411
   688
            {
Dean@1411
   689
                // Detect using MAPI message flags
Dean@1411
   690
                messageFlags = (Int32)MapiHelper.GetProperty(omi, MapiProperty.PidTagMessageFlags, (Int32)0);
Dean@1411
   691
                if ((messageFlags & ((Int32)MapiPropertyValue.EnumPidTagMessageFlags.mfSubmitted)) > 0)
Dean@1411
   692
                {
Dean@1411
   693
                    isSubmitted = true;
Dean@1411
   694
                }
Dean@1411
   695
            }
Dean@1411
   696
Dean@1411
   697
            return (isSubmitted);
Dean@1411
   698
        }
Dean@1411
   699
Dean@1411
   700
        /// <summary>
Thomas@1796
   701
        /// Gets the originally stored rating of the mail item.
Thomas@1796
   702
        /// </summary>
Thomas@1796
   703
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1796
   704
        /// <returns>The stored rating or null if an error occured.</returns>
Thomas@1796
   705
        public static pEpRating? GetStoredRating(this Outlook.MailItem omi)
Thomas@1796
   706
        {
Thomas@1796
   707
            pEpRating? rating = null;
Thomas@1796
   708
Thomas@1796
   709
            if (omi != null)
Thomas@1796
   710
            {
Thomas@1796
   711
                try
Thomas@1796
   712
                {
Thomas@1796
   713
                    object propValue = null;
Thomas@1796
   714
                    if (omi.GetPEPProperty(PEPProperty.Rating, out propValue))
Thomas@1796
   715
                    {
Thomas@1796
   716
                        rating = (pEpRating)propValue;
Thomas@1796
   717
                    }
Thomas@1796
   718
                }
Thomas@1796
   719
                catch (Exception ex)
Thomas@1796
   720
                {
Thomas@1796
   721
                    Log.Error("GetStoredRating: Error occured. " + ex.ToString());
Thomas@1796
   722
                }
Thomas@1796
   723
            }
Thomas@1796
   724
Thomas@1796
   725
            return rating;
Thomas@1796
   726
        }
Thomas@1796
   727
Thomas@1796
   728
        /// <summary>
Dean@1504
   729
        /// Sets or removes a message flag.
Dean@1504
   730
        /// </summary>
Dean@1504
   731
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1504
   732
        /// <param name="messageFlag">The message flag to set or remove.</param>
Dean@1504
   733
        /// <param name="value">Whether to set or remove the flag.</param>
Dean@1504
   734
        public static void SetMessageFlag(this Outlook.MailItem omi,
Dean@1504
   735
                                          MapiPropertyValue.EnumPidTagMessageFlags messageFlag,
Dean@1504
   736
                                          bool value)
Dean@1504
   737
        {
Dean@1504
   738
            Int32 existingFlags;
Dean@1504
   739
            Int32 newFlags;
Dean@1504
   740
Dean@1504
   741
            if (omi != null)
Dean@1504
   742
            {
Dean@1504
   743
                existingFlags = (Int32)MapiHelper.GetProperty(omi, MapiProperty.PidTagMessageFlags, (Int32)0);
Dean@1504
   744
Dean@1504
   745
                if (value)
Dean@1504
   746
                {
Dean@1504
   747
                    newFlags = existingFlags | (Int32)messageFlag;
Dean@1504
   748
                }
Dean@1504
   749
                else
Dean@1504
   750
                {
Dean@1504
   751
                    newFlags = existingFlags & ~(Int32)messageFlag;
Dean@1504
   752
                }
Dean@1504
   753
Dean@1504
   754
                if (existingFlags != newFlags)
Dean@1504
   755
                {
Dean@1504
   756
                    try
Dean@1504
   757
                    {
Dean@1504
   758
                        MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageFlags, newFlags);
Dean@1504
   759
                    }
Dean@1504
   760
                    catch { }
Dean@1504
   761
                }
Dean@1504
   762
            }
Dean@1504
   763
Dean@1504
   764
            return;
Dean@1504
   765
        }
Dean@1504
   766
Dean@1504
   767
        /// <summary>
Thomas@2075
   768
        /// Sets the user properties that indicate if a mail item has been encrypted
Thomas@2075
   769
        /// and with which rating. 
Thomas@2075
   770
        /// Note: The referenced mail item here is supposed to be a reply or replyAll
Thomas@2075
   771
        /// item and this method is intended to be used when the respective events are
Thomas@2075
   772
        /// being called and the reply item is being opened. This way, after the item
Thomas@2075
   773
        /// is opened, we can access the rating of the original from the reply item.
Thomas@2075
   774
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@2075
   775
        /// <param name="rating">The rating of the original mail item.</param>
Thomas@2075
   776
        /// </summary>
Thomas@2075
   777
        public static void SetOriginallyEncryptedStatus(this Outlook.MailItem omi, pEpRating rating)
Thomas@2075
   778
        {
Thomas@2075
   779
            if (rating >= pEpRating.pEpRatingUnencryptedForSome)
Thomas@2075
   780
            {
Thomas@2075
   781
                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_IS_ORIGINALLY_ENCRYPTED,
Thomas@2075
   782
                                          true,
Thomas@2075
   783
                                          Outlook.OlUserPropertyType.olYesNo);
Thomas@2075
   784
Thomas@2075
   785
                omi?.SetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_ORIGINAL_RATING,
Thomas@2075
   786
                                          rating.ToEngineString(),
Thomas@2075
   787
                                          Outlook.OlUserPropertyType.olText);
Thomas@2075
   788
Thomas@2075
   789
                // If pEp is disabled, set the Enable Protection property
Thomas@2075
   790
                if (omi?.GetIsPEPEnabled() == false)
Thomas@2075
   791
                {
Thomas@2075
   792
                    omi?.SetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, true);
Thomas@2075
   793
                }
Thomas@2075
   794
            }
Thomas@2075
   795
        }
Thomas@2075
   796
Thomas@2075
   797
        /// <summary>
Thomas@1976
   798
        /// Gets whether this mail item is an attached mail (attachment of another mail).
Thomas@1976
   799
        /// This is done by retrieving the mail item's message Id and checking if
Thomas@1976
   800
        /// it is found in the attaached mails cache.
Thomas@1976
   801
        /// </summary>
Thomas@1976
   802
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1976
   803
        /// <param name="messageId">The mail items's messageId</param>
Thomas@1976
   804
        /// <returns>True if it is an attached mail, otherwise false.</returns>
Thomas@1976
   805
        public static bool GetIsAttachedMail(this Outlook.MailItem omi, out string messageId)
Thomas@1976
   806
        {
Thomas@1976
   807
            messageId = null;
Thomas@1976
   808
            HeaderList headers = omi.GetParsedTransportMessageHeaders();
Thomas@1976
   809
Thomas@1976
   810
            try
Thomas@1976
   811
            {
Thomas@1976
   812
                messageId = headers[HeaderId.MessageId];
Thomas@1976
   813
            }
Thomas@1976
   814
            catch (Exception ex)
Thomas@1976
   815
            {
Thomas@1976
   816
                messageId = null;
Thomas@1976
   817
                Log.Verbose("FormRegionPrivacyStatus_FormRegionShowing: Error getting MessageId from item. " + ex.ToString());
Thomas@1976
   818
            }
Thomas@1976
   819
Thomas@1976
   820
            // If MessageId is found in cache, item is an attached mail
Thomas@1976
   821
            return ((string.IsNullOrEmpty(messageId) == false) && (PEPAttachment.AttachedMailsCache.Contains(messageId)));
Thomas@1976
   822
        }
Thomas@1976
   823
Thomas@1976
   824
        /// <summary>
Dean@1303
   825
        /// Gets whether the mail item is marked as incoming (received mail, not sent).
Dean@1303
   826
        /// </summary>
Thomas@1784
   827
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
   828
        /// <returns>True if the Outlook mail item is considered incoming, otherwise false.</returns>
Dean@1303
   829
        public static bool GetIsIncoming(this Outlook.MailItem omi)
Dean@1303
   830
        {
Dean@1331
   831
            object property = null;
Dean@1303
   832
            bool result = true; // Most emails are incoming/received
Dean@1303
   833
Dean@1303
   834
            if (omi != null)
Dean@1303
   835
            {
Dean@1331
   836
                try
Dean@1331
   837
                {
Thomas@1954
   838
                    property = omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_INCOMING);
Dean@1331
   839
                }
Dean@1331
   840
                catch
Dean@1331
   841
                {
Dean@1331
   842
                    property = null;
Dean@1331
   843
                    Log.Warning("GetIsIncoming: Failed to get IsIncoming user property.");
Dean@1331
   844
                }
Dean@1303
   845
Dean@1303
   846
                if (property != null)
Dean@1303
   847
                {
Dean@1303
   848
                    /* Use the stored user property
Dean@1303
   849
                     * This property is set only during creation of a mirror OMI.
Dean@1303
   850
                     * This is necessary because manually setting the PR_RECEIVED_BY_ENTRYID fails if called by user code.
Dean@1303
   851
                     */
Dean@1303
   852
                    result = (bool)property;
Dean@1303
   853
                }
Dean@1303
   854
                else if (omi.GetIsInSentFolder())
Dean@1303
   855
                {
Dean@1303
   856
                    /* Any messages in the sent folder are assumed to be outgoing.
Dean@1303
   857
                     * This is necessary because some account types (ActiveSync) save emails
Dean@1303
   858
                     * in the sent folder with the ReceivedByEntryID set.
Dean@1303
   859
                     * Without detecting the message is in the sent folder first, it would appear
Dean@1303
   860
                     * as incoming.
Dean@1303
   861
                     */
Dean@1303
   862
                    result = false;
Dean@1303
   863
                }
Dean@1303
   864
                else
Dean@1303
   865
                {
Dean@1303
   866
                    // Check ReceivedByEntryID
Dean@1303
   867
                    result = (omi.ReceivedByEntryID != null);
Thomas@1976
   868
Thomas@1976
   869
                    // Doublecheck for attached items
Thomas@1976
   870
                    if ((result == false) &&
Thomas@1976
   871
                        (PEPAttachment.AttachedMailsCache.Count > 0))
Thomas@1976
   872
                    {
Thomas@1976
   873
                        string messageId;
Thomas@1976
   874
                        result = omi.GetIsAttachedMail(out messageId);
Thomas@1976
   875
                    }
Dean@1303
   876
                }
Dean@1303
   877
            }
Dean@1303
   878
            else
Dean@1303
   879
            {
Dean@1303
   880
                Log.Error("GetIsIncoming: Attempted to get for a null MailItem.");
Dean@1303
   881
            }
Dean@1303
   882
Dean@1303
   883
            return (result);
Dean@1303
   884
        }
Dean@1303
   885
Dean@1303
   886
        /// <summary>
Thomas@1661
   887
        /// Determines if the mail item is an ActiveSync type store.
Thomas@1661
   888
        /// </summary>
Thomas@1784
   889
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1661
   890
        /// <returns>True if the mail item is an ActiveSync type store. If this method fails, false is returned.</returns>
Thomas@1661
   891
        public static bool GetIsInActiveSyncStore(this Outlook.MailItem omi)
Thomas@1661
   892
        {
Thomas@1661
   893
            bool isActiveSync = false;
Thomas@1661
   894
            Outlook.Folder folder = null;
Thomas@1661
   895
            Outlook.Store store = null;
Thomas@1661
   896
Thomas@1661
   897
            try
Thomas@1661
   898
            {
Thomas@1661
   899
                folder = (Outlook.Folder)omi.Parent;
Thomas@1661
   900
                store = folder.Store;
Thomas@1661
   901
                isActiveSync = store.GetIsAccountType(Outlook.OlAccountType.olEas);
Thomas@1661
   902
            }
Thomas@1661
   903
            catch
Thomas@1661
   904
            {
Thomas@1829
   905
                isActiveSync = false;
Thomas@1829
   906
                Log.Error("GetIsInActiveSyncStore: failure occured, returning default false.");
Thomas@1661
   907
            }
Thomas@1661
   908
            finally
Thomas@1661
   909
            {
Thomas@1829
   910
                folder = null;
Thomas@1829
   911
                store = null;
Thomas@1661
   912
            }
Thomas@1661
   913
Thomas@1661
   914
            return (isActiveSync);
Thomas@1661
   915
        }
Thomas@1661
   916
Thomas@1661
   917
        /// <summary>
Thomas@1829
   918
        /// Determines if the mail item is an Exchange type store.
Thomas@1829
   919
        /// </summary>
Thomas@1829
   920
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1829
   921
        /// <returns>True if the mail item is an Exchange type store. If this method fails, false is returned.</returns>
Thomas@1829
   922
        public static bool GetIsInExchangeStore(this Outlook.MailItem omi)
Thomas@1829
   923
        {
Thomas@1829
   924
            bool isExchangeStore = false;
Thomas@1829
   925
            Outlook.Folder folder = null;
Thomas@1829
   926
            Outlook.Store store = null;
Thomas@1829
   927
Thomas@1829
   928
            try
Thomas@1829
   929
            {
Thomas@1829
   930
                folder = (Outlook.Folder)omi.Parent;
Thomas@1829
   931
                store = folder.Store;
Thomas@1829
   932
                isExchangeStore = store.GetIsAccountType(Outlook.OlAccountType.olExchange);
Thomas@1829
   933
            }
Thomas@1829
   934
            catch
Thomas@1829
   935
            {
Thomas@1829
   936
                isExchangeStore = false;
Thomas@1829
   937
                Log.Error("GetIsInExchangeStore: failure occured, returning default false.");
Thomas@1829
   938
            }
Thomas@1829
   939
            finally
Thomas@1829
   940
            {
Thomas@1829
   941
                folder = null;
Thomas@1829
   942
                store = null;
Thomas@1829
   943
            }
Thomas@1829
   944
Thomas@1829
   945
            return (isExchangeStore);
Thomas@1829
   946
        }
Thomas@1829
   947
Thomas@1829
   948
        /// <summary>
Dean@1415
   949
        /// Determines if the mail item is an IMAP type store.
Dean@1303
   950
        /// </summary>
Thomas@1784
   951
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1415
   952
        /// <returns>True if the mail item is an IMAP type store. If this method fails, false is returned.</returns>
Dean@1303
   953
        public static bool GetIsInIMAPStore(this Outlook.MailItem omi)
Dean@1303
   954
        {
Dean@1303
   955
            bool isIMAP = false;
Dean@1303
   956
            Outlook.Folder folder = null;
Dean@1303
   957
            Outlook.Store store = null;
Dean@1303
   958
Dean@1303
   959
            try
Dean@1303
   960
            {
Dean@1303
   961
                folder = (Outlook.Folder)omi.Parent;
Dean@1303
   962
                store = folder.Store;
Dean@1454
   963
                isIMAP = store.GetIsAccountType(Outlook.OlAccountType.olImap);
Dean@1303
   964
            }
Dean@1303
   965
            catch
Dean@1303
   966
            {
Dean@1303
   967
                Log.Error("GetIsInIMAPStore: failure occured, returning default false.");
Dean@1303
   968
            }
Dean@1303
   969
            finally
Dean@1303
   970
            {
Dean@1303
   971
                // Release objects
Dean@1303
   972
                if (folder != null)
Dean@1303
   973
                {
vb@1516
   974
                    // Marshal.ReleaseComObject(folder);
Dean@1303
   975
                    folder = null;
Dean@1303
   976
                }
Dean@1303
   977
Dean@1303
   978
                if (store != null)
Dean@1303
   979
                {
vb@1507
   980
                    // Marshal.ReleaseComObject(store);
Dean@1303
   981
                    store = null;
Dean@1303
   982
                }
Dean@1303
   983
            }
Dean@1303
   984
Dean@1303
   985
            return (isIMAP);
Dean@1303
   986
        }
Dean@1303
   987
Dean@1303
   988
        /// <summary>
Dean@1415
   989
        /// Gets whether the mail item is a mirror.
Dean@1415
   990
        /// This is done by checking for the mirror indicating user property.
Dean@1415
   991
        /// </summary>
Thomas@1784
   992
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
   993
        /// <returns>True if the Outlook mail item is a mirror, otherwise false.</returns>
Dean@1415
   994
        public static bool GetIsMirror(this Outlook.MailItem omi)
Dean@1415
   995
        {
Dean@1415
   996
            bool isMirror = false;
Dean@1415
   997
            object propValue;
Dean@1415
   998
Dean@1415
   999
            if (omi != null)
Dean@1415
  1000
            {
Thomas@1954
  1001
                propValue = omi.GetUserProperty(MailItemExtensions.USER_PROPERTY_KEY_IS_MIRROR);
Dean@1415
  1002
Dean@1415
  1003
                if ((propValue != null) &&
Dean@1415
  1004
                    (((bool)propValue) == true))
Dean@1415
  1005
                {
Dean@1415
  1006
                    isMirror = true;
Dean@1415
  1007
                }
Dean@1415
  1008
            }
Dean@1415
  1009
Dean@1415
  1010
            return (isMirror);
Dean@1415
  1011
        }
Dean@1415
  1012
Dean@1415
  1013
        /// <summary>
Dean@1415
  1014
        /// Determines if the mail item has pEp enabled for it.
Dean@1390
  1015
        /// This will handle drafts (using sending account) as well as saved mail items (using store).
Dean@1303
  1016
        /// </summary>
Thomas@1784
  1017
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1415
  1018
        /// <returns>True if the mail item has pEp enabled, otherwise false.</returns>
Dean@1390
  1019
        public static bool GetIsPEPEnabled(this Outlook.MailItem omi)
Dean@1303
  1020
        {
Dean@1303
  1021
            bool isEnabled = PEPSettings.ACCOUNT_SETTING_IS_PEP_ENABLED_DEFAULT;
Dean@1390
  1022
            bool success = false;
Dean@1303
  1023
            Outlook.Folder folder = null;
Dean@1303
  1024
            Outlook.Store store = null;
Dean@1390
  1025
            Outlook.Account acct = null;
Dean@1303
  1026
Dean@1303
  1027
            try
Dean@1303
  1028
            {
Dean@1390
  1029
                // Try using the SendUsingAccount for drafts
Dean@1390
  1030
                try
Dean@1390
  1031
                {
Dean@1390
  1032
                    if (omi.GetIsDraft())
Dean@1390
  1033
                    {
Dean@1390
  1034
                        acct = omi.SendUsingAccount;
Thomas@1736
  1035
                        isEnabled = acct.GetIsPEPEnabled();
Dean@1390
  1036
                        success = true;
Dean@1390
  1037
                    }
Dean@1390
  1038
                }
Dean@1390
  1039
                catch
Dean@1390
  1040
                {
Dean@1390
  1041
                    success = false;
Dean@1390
  1042
                    Log.Warning("GetIsPEPEnabled: failed using SendUsingAccount.");
Dean@1390
  1043
                }
Dean@1390
  1044
Dean@1390
  1045
                // Try using the store
Dean@1390
  1046
                if (success == false)
Dean@1390
  1047
                {
Dean@1390
  1048
                    folder = (Outlook.Folder)omi.Parent;
Dean@1390
  1049
                    store = folder.Store;
Dean@1438
  1050
                    isEnabled = store.GetIsPEPEnabled();
Dean@1390
  1051
                    success = true;
Dean@1390
  1052
                }
Dean@1303
  1053
            }
Dean@1303
  1054
            catch
Dean@1303
  1055
            {
Dean@1390
  1056
                Log.Error("GetIsPEPEnabled: failure occured, returning default.");
Dean@1303
  1057
            }
Dean@1303
  1058
            finally
Dean@1303
  1059
            {
Dean@1303
  1060
                // Release objects
Dean@1390
  1061
                if (acct != null)
Dean@1390
  1062
                {
vb@1507
  1063
                    // Marshal.ReleaseComObject(acct);
Dean@1390
  1064
                    acct = null;
Dean@1390
  1065
                }
Dean@1390
  1066
Dean@1303
  1067
                if (folder != null)
Dean@1303
  1068
                {
vb@1516
  1069
                    // Marshal.ReleaseComObject(folder);
Dean@1303
  1070
                    folder = null;
Dean@1303
  1071
                }
Dean@1303
  1072
Dean@1303
  1073
                if (store != null)
Dean@1303
  1074
                {
vb@1507
  1075
                    // Marshal.ReleaseComObject(store);
Dean@1303
  1076
                    store = null;
Dean@1303
  1077
                }
Dean@1303
  1078
            }
Dean@1303
  1079
Dean@1303
  1080
            return (isEnabled);
Dean@1303
  1081
        }
Dean@1303
  1082
Dean@1303
  1083
        /// <summary>
Dean@1415
  1084
        /// Determines if the mail item is to be stored securely (untrusted account/server).
Dean@1303
  1085
        /// </summary>
Thomas@1784
  1086
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1415
  1087
        /// <returns>True if the mail item is to be stored securely, otherwise false.</returns>
Dean@1303
  1088
        public static bool GetIsInSecureStore(this Outlook.MailItem omi)
Dean@1303
  1089
        {
Dean@1303
  1090
            bool isSecure = PEPSettings.ACCOUNT_SETTING_IS_SECURE_STORAGE_ENABLED_DEFAULT;
Dean@1303
  1091
            Outlook.Folder folder = null;
Dean@1303
  1092
            Outlook.Store store = null;
Dean@1303
  1093
Dean@1303
  1094
            try
Dean@1303
  1095
            {
Dean@1303
  1096
                folder = (Outlook.Folder)omi.Parent;
Dean@1303
  1097
                store = folder.Store;
Dean@1438
  1098
                isSecure = store.GetIsSecureStorageEnabled();
Dean@1303
  1099
            }
Dean@1303
  1100
            catch
Dean@1303
  1101
            {
Dean@1303
  1102
                Log.Error("GetIsInSecureStore: failure occured, returning default.");
Dean@1303
  1103
            }
Dean@1303
  1104
            finally
Dean@1303
  1105
            {
Dean@1303
  1106
                // Release objects
Dean@1303
  1107
                if (folder != null)
Dean@1303
  1108
                {
vb@1516
  1109
                    // Marshal.ReleaseComObject(folder);
Dean@1303
  1110
                    folder = null;
Dean@1303
  1111
                }
Dean@1303
  1112
Dean@1303
  1113
                if (store != null)
Dean@1303
  1114
                {
vb@1507
  1115
                    // Marshal.ReleaseComObject(store);
Dean@1303
  1116
                    store = null;
Dean@1303
  1117
                }
Dean@1303
  1118
            }
Dean@1303
  1119
Dean@1303
  1120
            return (isSecure);
Dean@1303
  1121
        }
Dean@1303
  1122
Dean@1303
  1123
        /// <summary>
Dean@1415
  1124
        /// Determines if the mail item is in its store's default sent folder or a sent folder known
Dean@1303
  1125
        /// by pEp.
Dean@1303
  1126
        /// </summary>
Thomas@1784
  1127
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1415
  1128
        /// <returns>True if the mail item is in the default sent folder, otherwise false.</returns>
Dean@1303
  1129
        public static bool GetIsInSentFolder(this Outlook.MailItem omi)
Dean@1303
  1130
        {
Dean@1303
  1131
            bool result = false;
Dean@1303
  1132
            Outlook.Folder folder = null;
Dean@1303
  1133
            Outlook.Folder rootFolder = null;
Dean@1303
  1134
            Outlook.Folder sentFolder = null;
Dean@1303
  1135
            Outlook.Folders folders = null;
Dean@1303
  1136
            Outlook.Store store = null;
Dean@1303
  1137
Dean@1303
  1138
            try
Dean@1303
  1139
            {
Dean@1303
  1140
                /* The check whether the mailitem is in the Sent folder or a subfolder of it is done in the following way:
Dean@1303
  1141
                 * 1. Get the full path of the containing folder and split it into an array containing all folders of this path
Dean@1303
  1142
                 * 2. Get the mailitem's store and all Level 1 folders of this store
Dean@1303
  1143
                 * 3. Check if the Level 1 folder of the mailitem's folder path (array index 3) matches the Sent folder. If the default method 
Dean@1303
  1144
                 *    doesn't return a Sent folder, check by all known accounts' custom Sent folder Entry IDs.
Dean@1303
  1145
                 */
Dean@1303
  1146
                folder = (Outlook.Folder)omi.Parent;
Dean@1303
  1147
                store = folder.Store;
Dean@1303
  1148
                rootFolder = (Outlook.Folder)store.GetRootFolder();
Dean@1303
  1149
                folders = rootFolder.Folders;
Dean@1303
  1150
                var pathArray = folder.FolderPath.Split('\\');
Dean@1303
  1151
                var folderLevelOneEntryId = folders[pathArray[3]].EntryID;
Dean@1303
  1152
Dean@1303
  1153
                // Trying to get the Sent folder with the default method
Dean@1303
  1154
                try
Dean@1303
  1155
                {
Dean@1303
  1156
                    sentFolder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
Dean@1303
  1157
                }
Dean@1303
  1158
                catch { }
Dean@1303
  1159
Dean@1303
  1160
                // Check for a match between the Sent folder and the Level 1 folder in the mailitem's path
Dean@1303
  1161
                if (sentFolder != null)
Dean@1303
  1162
                {
Dean@1303
  1163
                    if ((folder.EntryID == sentFolder.EntryID) ||
Dean@1303
  1164
                        (folderLevelOneEntryId == sentFolder.EntryID))
Dean@1303
  1165
                    {
Dean@1303
  1166
                        result = true;
Dean@1303
  1167
                    }
Dean@1303
  1168
                }
Dean@1303
  1169
                else
Dean@1303
  1170
                {
Dean@1303
  1171
                    for (int i = 0; i < Globals.ThisAddIn.Settings.AccountSettingsList.Count; i++)
Dean@1303
  1172
                    {
Dean@1348
  1173
                        if ((Globals.ThisAddIn.Settings.AccountSettingsList[i].SentFolderEntryId != null) &&
Dean@1348
  1174
                            (folderLevelOneEntryId == Globals.ThisAddIn.Settings.AccountSettingsList[i].SentFolderEntryId))
Dean@1303
  1175
                        {
Dean@1303
  1176
                            result = true;
Dean@1303
  1177
                            break;
Dean@1303
  1178
                        }
Dean@1303
  1179
                    }
Dean@1303
  1180
                }
Dean@1303
  1181
            }
Dean@1303
  1182
            catch { }
Dean@1303
  1183
            finally
Dean@1303
  1184
            {
Dean@1303
  1185
                // Release objects
Dean@1303
  1186
                if (folder != null)
Dean@1303
  1187
                {
vb@1516
  1188
                    // Marshal.ReleaseComObject(folder);
Dean@1303
  1189
                    folder = null;
Dean@1303
  1190
                }
Dean@1303
  1191
Dean@1303
  1192
                if (rootFolder != null)
Dean@1303
  1193
                {
vb@1507
  1194
                    // Marshal.ReleaseComObject(rootFolder);
Dean@1303
  1195
                    rootFolder = null;
Dean@1303
  1196
                }
Dean@1303
  1197
Dean@1303
  1198
                if (sentFolder != null)
Dean@1303
  1199
                {
vb@1507
  1200
                    // Marshal.ReleaseComObject(sentFolder);
Dean@1303
  1201
                    sentFolder = null;
Dean@1303
  1202
                }
Dean@1303
  1203
Dean@1303
  1204
                if (folders != null)
Dean@1303
  1205
                {
vb@1516
  1206
                    // Marshal.ReleaseComObject(folders);
Dean@1303
  1207
                    folders = null;
Dean@1303
  1208
                }
Dean@1303
  1209
Dean@1303
  1210
                if (store != null)
Dean@1303
  1211
                {
vb@1507
  1212
                    // Marshal.ReleaseComObject(store);
Dean@1303
  1213
                    store = null;
Dean@1303
  1214
                }
Dean@1303
  1215
            }
Dean@1303
  1216
Dean@1303
  1217
            return (result);
Dean@1303
  1218
        }
Dean@1303
  1219
Dean@1303
  1220
        /// <summary>
Dean@1330
  1221
        /// Gets whether the mail item is considered secure.
Dean@1303
  1222
        /// </summary>
Thomas@1784
  1223
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  1224
        /// <returns>True if the mail item is secure, otherwise false.</returns>
Dean@1303
  1225
        public static bool GetIsSecure(this Outlook.MailItem omi)
Dean@1303
  1226
        {
Thomas@2075
  1227
            bool isSecure = false;
Thomas@2075
  1228
Thomas@2075
  1229
            try
Thomas@1736
  1230
            {
Thomas@1736
  1231
                // PGP/MIME format
Thomas@2075
  1232
                if (omi?.GetIsPGPMIMEEncrypted() == true)
Thomas@1736
  1233
                {
Thomas@2075
  1234
                    isSecure = true;
Thomas@1736
  1235
                }
Thomas@2075
  1236
                else if (omi?.EntryID == null)
nikolaj@1834
  1237
                {
Thomas@2075
  1238
                    // OUT-260 To prevent accesing omi.Body by newly composed mails
Thomas@2075
  1239
                    Log.Verbose("GetIsSecure: EntryID is null. Returning false.");
Thomas@2075
  1240
                    isSecure = false;
nikolaj@1834
  1241
                }
Thomas@2075
  1242
                else if (omi?.Body != null && PEPMessage.IsPGPText(omi?.Body))
Thomas@1736
  1243
                {
Thomas@2075
  1244
                    // Partitioned or inline PGP format
Thomas@2075
  1245
                    isSecure = true;
Thomas@1736
  1246
                }
Thomas@1736
  1247
            }
Thomas@2075
  1248
            catch (Exception ex)
Thomas@2075
  1249
            {
Thomas@2075
  1250
                isSecure = false;
Thomas@2075
  1251
                Log.Error("GetIsSecure: Error determining whether item is secure. Returning default (false). " + ex.ToString());
Thomas@2075
  1252
            }
Thomas@1736
  1253
Thomas@2075
  1254
            return isSecure;
Thomas@1736
  1255
        }
Thomas@1736
  1256
Thomas@1736
  1257
        /// <summary>
Thomas@1736
  1258
        /// Determines if the given mail item is encrypted in PGP/MIME format.
Thomas@1736
  1259
        /// </summary>
Thomas@1736
  1260
        /// <param name="omi">The mail item to check encryption for.</param>
Thomas@1736
  1261
        /// <returns>True if the given mail item is PGP/MIME encrypted, otherwise false.</returns>
Thomas@1736
  1262
        public static bool GetIsPGPMIMEEncrypted(this Outlook.MailItem omi)
Thomas@1736
  1263
        {
Thomas@1736
  1264
            bool result = false;
Thomas@1736
  1265
            bool versionInfoFound = false;
Thomas@1736
  1266
            bool contentFound = false;
Thomas@1736
  1267
            PEPAttachment attach;
Thomas@1736
  1268
            Outlook.Attachment attachment = null;
Thomas@1736
  1269
            Outlook.Attachments attachments = null;
Thomas@1736
  1270
Thomas@1736
  1271
            try
Thomas@1736
  1272
            {
Thomas@1736
  1273
                if (omi != null)
Thomas@1736
  1274
                {
Thomas@1736
  1275
                    attachments = omi.Attachments;
Thomas@1736
  1276
Thomas@1736
  1277
                    // Require only two attachments (version identification & encrypted content)
Thomas@1736
  1278
                    // However, allow the attachments to be in any order
Thomas@1736
  1279
                    if (attachments.Count == 2)
Thomas@1736
  1280
                    {
Thomas@1736
  1281
                        // Note: attachment index starts at 1
Thomas@1736
  1282
                        for (int i = 1; i <= attachments.Count; i++)
Thomas@1736
  1283
                        {
Thomas@1736
  1284
                            attachment = attachments[i];
Thomas@1736
  1285
                            attach = new PEPAttachment(attachment);
Thomas@1736
  1286
Thomas@1736
  1287
                            if (attach.IsPGPMIMEVersionInfoFormat)
Thomas@1736
  1288
                            {
Thomas@1736
  1289
                                versionInfoFound = true;
Thomas@1736
  1290
                            }
Thomas@1736
  1291
                            else if (attach.IsPGPMIMEContentFormat)
Thomas@1736
  1292
                            {
Thomas@1736
  1293
                                contentFound = true;
Thomas@1736
  1294
                            }
Thomas@1736
  1295
Thomas@1736
  1296
                            attachment = null;
Thomas@1736
  1297
                        }
Thomas@1736
  1298
Thomas@1736
  1299
                        if (versionInfoFound && contentFound)
Thomas@1736
  1300
                        {
Thomas@1736
  1301
                            result = true;
Thomas@1736
  1302
                        }
Thomas@1736
  1303
                    }
Thomas@1736
  1304
                }
Thomas@1736
  1305
            }
Thomas@1736
  1306
            catch (Exception ex)
Thomas@1736
  1307
            {
Thomas@1736
  1308
                Log.Error("GetIsPGPMIMEEncrypted: Error. " + ex.ToString());
Thomas@1736
  1309
            }
Thomas@1736
  1310
            finally
Thomas@1736
  1311
            {
Thomas@1736
  1312
                attachment = null;
Thomas@1736
  1313
                attachments = null;
Thomas@1736
  1314
            }
Thomas@1736
  1315
Thomas@1736
  1316
            return (result);
Dean@1303
  1317
        }
Dean@1303
  1318
Dean@1303
  1319
        /// <summary>
Dean@1303
  1320
        /// Determines if the given Outlook mail item should be securely stored (use a mirror).
Dean@1303
  1321
        /// This will check: IsInSecureStore, IsSecure, IsMirror &amp; NeverUnsecure.
Dean@1303
  1322
        /// </summary>
Thomas@1784
  1323
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  1324
        /// <returns>True if the Outlook mail item should be stored securely, otherwise false.</returns>
Dean@1303
  1325
        public static bool GetIsSecurelyStored(this Outlook.MailItem omi)
Dean@1303
  1326
        {
Dean@1303
  1327
            if (omi != null)
Dean@1303
  1328
            {
Thomas@1924
  1329
                if ((omi.GetNeverUnsecure() && (omi.GetIsMirror() == false)) ||
Thomas@2028
  1330
                    (omi.GetIsInSecureStore() && (omi.GetIsSecure() || omi.GetIsForcefullyProtected())))
Dean@1303
  1331
                {
Dean@1303
  1332
                    return (true);
Dean@1303
  1333
                }
Dean@1303
  1334
            }
Dean@1303
  1335
Dean@1303
  1336
            return (false);
Dean@1303
  1337
        }
Dean@1303
  1338
Dean@1303
  1339
        /// <summary>
Thomas@1795
  1340
        /// Determines whether this mail item should be processed during sending. This checks
Thomas@1890
  1341
        /// if pEp is enabled and whether the force unencrypted, force protection or enable protection 
Thomas@1890
  1342
        /// properties are being set.
Thomas@1795
  1343
        /// </summary>
Thomas@1795
  1344
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1795
  1345
        /// <returns>True if the mail item should be processed, otherwise false.</returns>
Thomas@1812
  1346
        public static bool GetIsSendProcessingEnabled(this Outlook.MailItem omi)
Thomas@1795
  1347
        {
Thomas@2011
  1348
            bool isEnabled = true;
Thomas@1795
  1349
Thomas@1795
  1350
            if (omi != null)
Thomas@1795
  1351
            {
Thomas@1795
  1352
                try
Thomas@1795
  1353
                {
Thomas@2011
  1354
                    // If pEp is disabled, process in case of ForceProtected or EnableProtection
Thomas@2011
  1355
                    if (omi.GetIsPEPEnabled() == false)
Thomas@1795
  1356
                    {
Thomas@2028
  1357
                        isEnabled = (omi.GetIsForcefullyProtected() || omi.GetEnableProtection());
Thomas@1795
  1358
                    }
Thomas@1795
  1359
                }
Thomas@1795
  1360
                catch (Exception ex)
Thomas@1795
  1361
                {
Thomas@1795
  1362
                    Log.Error("IsProcessingEnabled: Error occured. " + ex.ToString());
Thomas@1795
  1363
                }
Thomas@1795
  1364
            }
Thomas@1795
  1365
Thomas@1795
  1366
            return isEnabled;
Thomas@1795
  1367
        }
Thomas@1795
  1368
Thomas@1795
  1369
        /// <summary>
Thomas@1673
  1370
        /// Determines a mail item's maximum allowable size in kB for sending through the mail item's current store.
Thomas@1673
  1371
        /// </summary>
Thomas@1673
  1372
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1673
  1373
        /// <returns>The maximum allowed size in kB.</returns>
Thomas@1673
  1374
        public static int GetMaxMailSize(this Outlook.MailItem omi)
Thomas@1673
  1375
        {
Thomas@1673
  1376
            int maxFileSize = 0;
Thomas@1673
  1377
            Outlook.Folder folder = null;
Thomas@1673
  1378
            Outlook.Store store = null;
Thomas@1673
  1379
Thomas@1673
  1380
            try
Thomas@1673
  1381
            {
Thomas@1673
  1382
                folder = (Outlook.Folder)omi.Parent;
Thomas@1673
  1383
                store = folder.Store;
Thomas@1673
  1384
                maxFileSize = store.GetMaxSubmitSize();
Thomas@1673
  1385
            }
Thomas@1936
  1386
            catch (Exception ex)
Thomas@1673
  1387
            {
Thomas@1673
  1388
                maxFileSize = 0;
Thomas@1936
  1389
                Log.Error("GetMaxMailSize: failure occured, returning default. " + ex.ToString());
Thomas@1673
  1390
            }
Thomas@1673
  1391
            finally
Thomas@1673
  1392
            {
Thomas@1673
  1393
                folder = null;
Thomas@1673
  1394
                store = null;
Thomas@1673
  1395
            }
Thomas@1673
  1396
Thomas@1673
  1397
            return maxFileSize;
Thomas@1673
  1398
        }
Thomas@1673
  1399
Thomas@1673
  1400
        /// <summary>
Dean@1303
  1401
        /// Gets the pEp store folder used to store the mirror for the given Outlook mail item.
Dean@1348
  1402
        /// This will be determined based on the from user name.
Dean@1348
  1403
        /// The UNKNOWN_SENDER folder is used if a failure occurs in finding the from user name.
Dean@1303
  1404
        /// </summary>
Thomas@1784
  1405
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1784
  1406
        /// <returns>The Outlook folder to store the mirror of the mail item.</returns>
Dean@1303
  1407
        public static Outlook.Folder GetMirrorFolder(this Outlook.MailItem omi)
Dean@1303
  1408
        {
Dean@1348
  1409
            string userName;
Dean@1303
  1410
            string[] specialChars;
Dean@1303
  1411
            Outlook.Folder folder;
Dean@1303
  1412
            Outlook.Folders folders = Globals.ThisAddIn.PEPStoreRootFolder.Folders;
Dean@1303
  1413
            Globals.ReturnStatus sts;
Dean@1303
  1414
            StringBuilder strBuilder = new StringBuilder();
Dean@1303
  1415
Dean@1348
  1416
            sts = PEPIdentity.GetFromUserName(omi, out userName);
Dean@1303
  1417
Dean@1303
  1418
            if (sts == Globals.ReturnStatus.Success)
Dean@1303
  1419
            {
Dean@1303
  1420
                /* Remove special characters from folder name.
Dean@1303
  1421
                 * See: https://msdn.microsoft.com/en-us/library/aa493942(v=exchg.80).aspx
Dean@1303
  1422
                 */
Dean@1303
  1423
                specialChars = new string[] { "[", "]", "/", "\\", "&", "~", "?", "*", "|", "<", ">", "\"", ";", ":", "+" };
Dean@1348
  1424
                if (userName != null)
Dean@1303
  1425
                {
Dean@1348
  1426
                    strBuilder.Append(userName);
Dean@1303
  1427
                    for (int i = 0; i < specialChars.Length; i++)
Dean@1303
  1428
                    {
Dean@1303
  1429
                        strBuilder.Replace(specialChars[i], "");
Dean@1303
  1430
                    }
Dean@1348
  1431
                    userName = strBuilder.ToString();
Dean@1303
  1432
                }
Dean@1303
  1433
Dean@1303
  1434
                // Use unknown if invalid
Dean@1348
  1435
                if (string.IsNullOrWhiteSpace(userName))
Dean@1303
  1436
                {
Thomas@1955
  1437
                    userName = MailItemExtensions.UNKNOWN_SENDER;
Dean@1303
  1438
                }
Dean@1303
  1439
            }
Dean@1303
  1440
            else
Dean@1303
  1441
            {
Thomas@1955
  1442
                userName = MailItemExtensions.UNKNOWN_SENDER;
Dean@1303
  1443
            }
Dean@1303
  1444
Dean@1303
  1445
            try
Dean@1303
  1446
            {
Dean@1348
  1447
                folder = (Outlook.Folder)folders[userName];
Dean@1303
  1448
                Log.Verbose("GetUnencryptedFolder: Using existing folder.");
Dean@1303
  1449
            }
Dean@1303
  1450
            catch
Dean@1303
  1451
            {
Dean@1348
  1452
                folder = (Outlook.Folder)folders.Add(userName);
Dean@1303
  1453
                Log.Verbose("GetUnencryptedFolder: Creating new folder.");
Dean@1303
  1454
            }
Dean@1303
  1455
Dean@1303
  1456
            // Release objects
Dean@1303
  1457
            if (folders != null)
Dean@1303
  1458
            {
vb@1516
  1459
                // Marshal.ReleaseComObject(folders);
Dean@1303
  1460
                folders = null;
Dean@1303
  1461
            }
Dean@1303
  1462
Dean@1303
  1463
            return (folder);
Dean@1303
  1464
        }
Dean@1303
  1465
Dean@1327
  1466
        /// <summary>
Thomas@1971
  1467
        /// Gets whether a given EntryID is in the list of copied items.
Thomas@1971
  1468
        /// </summary>
Thomas@1971
  1469
        /// <param name="entryId">The EntryID to check for.</param>
Thomas@1971
  1470
        /// <returns>True, if in the list. Otherwise false.</returns>
Thomas@1971
  1471
        public static bool IsInCopiedItemsList(string entryId)
Thomas@1971
  1472
        {
Thomas@1971
  1473
            bool isInList = false;
Thomas@1971
  1474
Thomas@1971
  1475
            lock (mutexCopiedItemsList)
Thomas@1971
  1476
            {
Thomas@1971
  1477
                if (copiedItemsList.Contains(entryId))
Thomas@1971
  1478
                {
Thomas@1971
  1479
                    isInList = true;
Thomas@1971
  1480
                }
Thomas@1971
  1481
            }
Thomas@1971
  1482
Thomas@1971
  1483
            return isInList;
Thomas@1971
  1484
        }
Thomas@1971
  1485
Thomas@1971
  1486
        /// <summary>
Dean@1327
  1487
        /// Permanently deletes the mail item from Outlook.
Dean@1327
  1488
        /// This will also remove any mail item data before save.
Dean@1327
  1489
        /// Therefore, it is safe for handling sensitive data.
Dean@1327
  1490
        /// </summary>
Thomas@1784
  1491
        /// <param name="mailItem">The Outlook mail item to process with.</param>
Dean@1327
  1492
        /// <param name="mailStore">The known store containing the mail item being deleted.
Dean@1327
  1493
        /// This is used to locate the deleted folder. Leaving empty or setting to null will
Dean@1327
  1494
        /// automatically try to find the store using the mail item itself.</param>
Dean@1327
  1495
        public static void PermanentlyDelete(this Outlook.MailItem mailItem,
Dean@1327
  1496
                                             Outlook.Store mailStore = null)
Dean@1327
  1497
        {
Dean@1327
  1498
            bool deleted = false;
Dean@1327
  1499
            string deleteValue;
Dean@1327
  1500
            Outlook.Folder folder = null;
Dean@1327
  1501
            Outlook.Folder deletedFolder = null;
Dean@1327
  1502
            Outlook.MailItem deletedMailItem = null;
Dean@1327
  1503
            Outlook.Attachments attachments = null;
Dean@1327
  1504
            Outlook.Recipients recipients = null;
Dean@1327
  1505
            Outlook.Store store = null;
Dean@1327
  1506
            Outlook.Items items = null;
Dean@1327
  1507
Dean@1327
  1508
            try
Dean@1327
  1509
            {
Dean@1327
  1510
                /* Remove all relevant data from the mail item
Dean@1327
  1511
                 * This is done so it is not saved later where it could be unencrypted
Dean@1327
  1512
                 */
Dean@1327
  1513
                recipients = mailItem.Recipients;
Dean@1327
  1514
                while (recipients.Count > 0)
Dean@1327
  1515
                {
Dean@1327
  1516
                    recipients.Remove(1);
Dean@1327
  1517
                }
Dean@1327
  1518
Dean@1327
  1519
                mailItem.Subject = "";
Dean@1327
  1520
                mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
Dean@1327
  1521
                mailItem.Body = "";
Dean@1327
  1522
                mailItem.HTMLBody = "";
Dean@1327
  1523
Dean@1327
  1524
                attachments = mailItem.Attachments;
Dean@1327
  1525
                while (attachments.Count > 0)
Dean@1327
  1526
                {
Dean@1327
  1527
                    attachments.Remove(1);
Dean@1327
  1528
                }
Dean@1327
  1529
Thomas@1839
  1530
                // Add mail
Thomas@1661
  1531
                try
Thomas@1661
  1532
                {
Thomas@1661
  1533
                    mailItem.Save();
Thomas@1661
  1534
                }
Thomas@1936
  1535
                catch (Exception ex)
Thomas@1661
  1536
                {
Thomas@1936
  1537
                    Log.Error("PermanentlyDelete: Error saving mail item. " + ex.ToString());
Thomas@1661
  1538
                }
Dean@1327
  1539
Dean@1327
  1540
                // Locate the store for the mailitem if none was given
Dean@1327
  1541
                if (mailStore == null)
Dean@1327
  1542
                {
Dean@1327
  1543
                    try
Dean@1327
  1544
                    {
Dean@1327
  1545
                        folder = (Outlook.Folder)mailItem.Parent;
Dean@1327
  1546
                        store = folder.Store;
Dean@1327
  1547
                    }
Dean@1327
  1548
                    catch (Exception ex)
Dean@1327
  1549
                    {
Dean@1327
  1550
                        Log.Error("PermanentlyDelete: unable to locate parent store, " + ex.ToString());
Dean@1327
  1551
                    }
Dean@1327
  1552
                    finally
Dean@1327
  1553
                    {
Dean@1327
  1554
                        // Release objects
Dean@1327
  1555
                        if (folder != null)
Dean@1327
  1556
                        {
vb@1516
  1557
                            // Marshal.ReleaseComObject(folder);
Dean@1327
  1558
                            folder = null;
Dean@1327
  1559
                        }
Dean@1327
  1560
                    }
Dean@1327
  1561
                }
Dean@1327
  1562
Dean@1327
  1563
                /* Move the mail item to the deleted folder then delete (otherwise calling .Delete() will only move to deleted items)
Dean@1327
  1564
                 * For ActiveSync accounts, the .Move() call will fail with the error:
Dean@1327
  1565
                 * 'Sorry, Exchange ActiveSync doesn't support what you're trying to do.'
Dean@1327
  1566
                 */
Dean@1327
  1567
                try
Dean@1327
  1568
                {
Dean@1327
  1569
                    if (mailStore != null)
Dean@1327
  1570
                    {
Dean@1327
  1571
                        // Use given store
Dean@1327
  1572
                        deletedFolder = (Outlook.Folder)mailStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
Dean@1327
  1573
                    }
Dean@1327
  1574
                    else
Dean@1327
  1575
                    {
Dean@1327
  1576
                        // Use calculated store
Dean@1327
  1577
                        deletedFolder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
Dean@1327
  1578
                    }
Dean@1327
  1579
                    deletedMailItem = (Outlook.MailItem)mailItem.Move(deletedFolder);
Dean@1327
  1580
Dean@1327
  1581
                    /* Change the subject and Save
Dean@1327
  1582
                     * If the subject (or another property) is not changed the .Save() call will be ignored
Dean@1327
  1583
                     * Calling .Save() is for some reason necessary before .Delete() to work properly
Dean@1327
  1584
                     */
Dean@1327
  1585
                    deletedMailItem.Subject = "pEp";
Thomas@1661
  1586
                    try
Thomas@1661
  1587
                    {
Thomas@1661
  1588
                        deletedMailItem.Save();
Thomas@1661
  1589
                    }
Thomas@1936
  1590
                    catch (Exception ex)
Thomas@1661
  1591
                    {
Thomas@1936
  1592
                        Log.Error("PermanentlyDelete: Error saving deleted mail item. " + ex.ToString());
Thomas@1661
  1593
                    }
Dean@1327
  1594
Dean@1327
  1595
                    // Now that the mail item is in the deleted folder, calling .Delete() will delete permanently
Dean@1327
  1596
                    deletedMailItem.Delete();
Dean@1327
  1597
                    deleted = true;
Dean@1327
  1598
                }
Thomas@1936
  1599
                catch (Exception ex)
Thomas@1661
  1600
                {
Thomas@1936
  1601
                    Log.Error("PermanentlyDelete: Error deleting. " + ex.ToString());
Thomas@1661
  1602
                }
Dean@1327
  1603
                finally
Dean@1327
  1604
                {
Dean@1327
  1605
                    if (deletedFolder != null)
Dean@1327
  1606
                    {
vb@1516
  1607
                        // Marshal.ReleaseComObject(deletedFolder);
Dean@1327
  1608
                        deletedFolder = null;
Dean@1327
  1609
                    }
Dean@1327
  1610
Dean@1327
  1611
                    if (deletedMailItem != null)
Dean@1327
  1612
                    {
vb@1516
  1613
                        // Marshal.ReleaseComObject(deletedMailItem);
Dean@1327
  1614
                        deletedMailItem = null;
Dean@1327
  1615
                    }
Dean@1327
  1616
                }
Dean@1327
  1617
Dean@1327
  1618
                // Try secondary method supporting ActiveSync accounts
Dean@1327
  1619
                if (deleted == false)
Dean@1327
  1620
                {
Dean@1327
  1621
                    if (mailStore != null)
Dean@1327
  1622
                    {
Dean@1327
  1623
                        // Use given store
Dean@1327
  1624
                        deletedFolder = (Outlook.Folder)mailStore.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
Dean@1327
  1625
                    }
Dean@1327
  1626
                    else
Dean@1327
  1627
                    {
Dean@1327
  1628
                        // Use calculated store
Dean@1327
  1629
                        deletedFolder = (Outlook.Folder)store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderDeletedItems);
Dean@1327
  1630
                    }
Dean@1327
  1631
Dean@1327
  1632
                    // Tag the item with a user property so it can be located in the deleted folder
Dean@1327
  1633
                    deleteValue = "DELETE_" + mailItem.EntryID;
Dean@1327
  1634
                    mailItem.SetUserProperty("DELETE", deleteValue, Outlook.OlUserPropertyType.olText);
Thomas@1661
  1635
                    try
Thomas@1661
  1636
                    {
Thomas@1661
  1637
                        mailItem.Save();
Thomas@1661
  1638
                    }
Thomas@1936
  1639
                    catch (Exception ex)
Thomas@1661
  1640
                    {
Thomas@1936
  1641
                        Log.Error("PermanentlyDelete: Error saving mail item. " + ex.ToString());
Thomas@1661
  1642
                    }
Dean@1327
  1643
Dean@1327
  1644
                    // Delete the mail item moving to deleted items folder
Dean@1327
  1645
                    mailItem.Delete();
Dean@1327
  1646
Dean@1327
  1647
                    // Permanently delete item by locating in the delete items folder
Dean@1327
  1648
                    items = deletedFolder.Items;
Dean@1327
  1649
                    for (int i = 1; i <= items.Count; i++)
Dean@1327
  1650
                    {
Dean@1327
  1651
                        deletedMailItem = items[i];
Dean@1327
  1652
Dean@1327
  1653
                        // Check if the property exists
Dean@1327
  1654
                        if ((string)deletedMailItem.GetUserProperty("DELETE", "") == deleteValue)
Dean@1327
  1655
                        {
Dean@1327
  1656
                            deletedMailItem.Delete();
Dean@1327
  1657
                            deleted = true;
Dean@1327
  1658
                            break;
Dean@1327
  1659
                        }
Dean@1327
  1660
vb@1516
  1661
                        // Marshal.ReleaseComObject(deletedMailItem);
Dean@1327
  1662
                        deletedMailItem = null;
Dean@1327
  1663
                    }
Dean@1327
  1664
                }
Dean@1327
  1665
            }
Dean@1327
  1666
            catch (Exception ex)
Dean@1327
  1667
            {
Dean@1327
  1668
                Log.Error("PermanentlyDelete: Failed, " + ex.ToString());
Dean@1327
  1669
            }
Dean@1327
  1670
            finally
Dean@1327
  1671
            {
Dean@1327
  1672
                if (folder != null)
Dean@1327
  1673
                {
vb@1516
  1674
                    // Marshal.ReleaseComObject(folder);
Dean@1327
  1675
                    folder = null;
Dean@1327
  1676
                }
Dean@1327
  1677
Dean@1327
  1678
                if (deletedFolder != null)
Dean@1327
  1679
                {
vb@1516
  1680
                    // Marshal.ReleaseComObject(deletedFolder);
Dean@1327
  1681
                    deletedFolder = null;
Dean@1327
  1682
                }
Dean@1327
  1683
Dean@1327
  1684
                if (deletedMailItem != null)
Dean@1327
  1685
                {
vb@1516
  1686
                    // Marshal.ReleaseComObject(deletedMailItem);
Dean@1327
  1687
                    deletedMailItem = null;
Dean@1327
  1688
                }
Dean@1327
  1689
Dean@1327
  1690
                if (attachments != null)
Dean@1327
  1691
                {
vb@1516
  1692
                    // Marshal.ReleaseComObject(attachments);
Dean@1327
  1693
                    attachments = null;
Dean@1327
  1694
                }
Dean@1327
  1695
Dean@1327
  1696
                if (recipients != null)
Dean@1327
  1697
                {
vb@1516
  1698
                    // Marshal.ReleaseComObject(recipients);
Dean@1327
  1699
                    recipients = null;
Dean@1327
  1700
                }
Dean@1327
  1701
Dean@1327
  1702
                if (store != null)
Dean@1327
  1703
                {
vb@1507
  1704
                    // Marshal.ReleaseComObject(store);
Dean@1327
  1705
                    store = null;
Dean@1327
  1706
                }
Dean@1327
  1707
Dean@1327
  1708
                if (items != null)
Dean@1327
  1709
                {
vb@1516
  1710
                    // Marshal.ReleaseComObject(items);
Dean@1327
  1711
                    items = null;
Dean@1327
  1712
                }
Dean@1327
  1713
            }
Dean@1327
  1714
Dean@1327
  1715
            return;
Dean@1327
  1716
        }
Dean@1327
  1717
Dean@1417
  1718
        /// <summary>
Dean@1455
  1719
        /// Gets the own pEp identity for the SendUsingAccount of the MailItem.
Dean@1455
  1720
        /// Warning: This can return null.
Dean@1455
  1721
        /// </summary>
Thomas@1784
  1722
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1455
  1723
        /// <returns>The own identity for the send using account, otherwise null.</returns>
Dean@1455
  1724
        public static PEPIdentity GetSendUsingAccountIdentity(this Outlook.MailItem omi)
Dean@1455
  1725
        {
Dean@1455
  1726
            PEPIdentity ident = null;
Dean@1455
  1727
            Outlook.Account account = null;
Dean@1455
  1728
            Globals.ReturnStatus sts;
Dean@1455
  1729
Dean@1455
  1730
            try
Dean@1455
  1731
            {
Dean@1455
  1732
                account = omi.SendUsingAccount;
Dean@1455
  1733
Dean@1455
  1734
                // Ignore any failures
Dean@1455
  1735
                sts = PEPIdentity.GetOwnIdentity(account, out ident);
Dean@1455
  1736
            }
Dean@1455
  1737
            catch (Exception ex)
Dean@1455
  1738
            {
Dean@1455
  1739
                Log.Error("GetSendUsingAccountIdentity: Failure occured, " + ex.ToString());
Dean@1455
  1740
            }
Dean@1455
  1741
            finally
Dean@1455
  1742
            {
Dean@1455
  1743
                if (account != null)
Dean@1455
  1744
                {
vb@1507
  1745
                    // Marshal.ReleaseComObject(account);
Dean@1455
  1746
                    account = null;
Dean@1455
  1747
                }
Dean@1455
  1748
            }
Dean@1455
  1749
Dean@1455
  1750
            return (ident);
Dean@1455
  1751
        }
Dean@1455
  1752
Dean@1455
  1753
        /// <summary>
Dean@1417
  1754
        /// Creates a message container for the given Outlook mail item that represents its data
Dean@1417
  1755
        /// and how it is stored/located within Outlook.
Dean@1417
  1756
        /// Warning: This method can take some time (especially if a mirror is being located).
Dean@1417
  1757
        /// </summary>
Thomas@1784
  1758
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1417
  1759
        /// <returns>The new message container, otherwise null.</returns>
Dean@1417
  1760
        public static MsgContainer ToMsgContainer(this Outlook.MailItem omi)
Dean@1417
  1761
        {
Dean@1417
  1762
            PEPMessage newMessage;
Dean@1417
  1763
            MsgContainer msgCont = new MsgContainer();
Dean@1417
  1764
            Globals.ReturnStatus sts;
Dean@1417
  1765
            Outlook.Folder folder = null;
Dean@1417
  1766
            Outlook.MailItem mirrorMailItem = null;
Dean@1417
  1767
            Outlook.Store store = null;
Dean@1417
  1768
Dean@1417
  1769
            Log.Verbose("ToMsgContainer: Started");
Dean@1417
  1770
Dean@1417
  1771
            try
Dean@1417
  1772
            {
Dean@1417
  1773
                // Create Message
Dean@1417
  1774
                sts = PEPMessage.Create(omi, out newMessage);
Dean@1417
  1775
                msgCont.Message = newMessage;
Dean@1417
  1776
                msgCont.MessageCreationStatus = sts;
Dean@1417
  1777
Dean@1417
  1778
                // Create Mirror
Dean@1417
  1779
                if (omi.GetIsSecurelyStored())
Dean@1417
  1780
                {
Thomas@1960
  1781
                    mirrorMailItem = omi.GetMirror();
Dean@1417
  1782
                    if (mirrorMailItem != null)
Dean@1417
  1783
                    {
Dean@1417
  1784
                        sts = PEPMessage.Create(mirrorMailItem, out newMessage);
Dean@1417
  1785
                        msgCont.Mirror = newMessage;
Dean@1417
  1786
                        msgCont.MirrorCreationStatus = sts;
Dean@1417
  1787
                    }
Dean@1417
  1788
                }
Dean@1417
  1789
Dean@1417
  1790
                // Get the store ID
Dean@1417
  1791
                try
Dean@1417
  1792
                {
Dean@1417
  1793
                    folder = (Outlook.Folder)omi.Parent;
Dean@1417
  1794
                    store = folder.Store;
Dean@1417
  1795
                    msgCont.StoreId = store.StoreID;
Dean@1417
  1796
                }
Dean@1417
  1797
                catch
Dean@1417
  1798
                {
Dean@1417
  1799
                    msgCont.StoreId = null;
Dean@1417
  1800
                }
Dean@1417
  1801
Dean@1417
  1802
                // Get other Outlook store/location information
Dean@1417
  1803
                msgCont.EntryId = omi.EntryID;
Dean@1417
  1804
                msgCont.IsDraft = omi.GetIsDraft();
Dean@1417
  1805
                msgCont.IsInSecureStore = omi.GetIsInSecureStore();
Dean@1417
  1806
                msgCont.IsInSentFolder = omi.GetIsInSentFolder();
Dean@1417
  1807
                msgCont.IsMirror = omi.GetIsMirror();
Dean@1417
  1808
            }
Dean@1417
  1809
            catch (Exception ex)
Dean@1417
  1810
            {
Dean@1417
  1811
                Log.Error("ToMsgContainer: Error occured, " + ex.ToString());
Dean@1417
  1812
            }
Dean@1417
  1813
            finally
Dean@1417
  1814
            {
Dean@1417
  1815
                if (folder != null)
Dean@1417
  1816
                {
vb@1516
  1817
                    // Marshal.ReleaseComObject(folder);
Dean@1417
  1818
                    folder = null;
Dean@1417
  1819
                }
Dean@1417
  1820
Dean@1417
  1821
                if (mirrorMailItem != null)
Dean@1417
  1822
                {
vb@1516
  1823
                    // Marshal.ReleaseComObject(mirrorMailItem);
Dean@1417
  1824
                    mirrorMailItem = null;
Dean@1417
  1825
                }
Dean@1417
  1826
Dean@1417
  1827
                if (store != null)
Dean@1417
  1828
                {
vb@1507
  1829
                    // Marshal.ReleaseComObject(store);
Dean@1417
  1830
                    store = null;
Dean@1417
  1831
                }
Dean@1417
  1832
            }
Dean@1417
  1833
Dean@1417
  1834
            Log.Verbose("ToMsgContainer: Completed");
Dean@1417
  1835
Dean@1417
  1836
            return (msgCont);
Dean@1417
  1837
        }
Dean@1417
  1838
Thomas@1841
  1839
        /// <summary>
Thomas@1841
  1840
        /// Saves this Outlook mail item as plain-text (eml) message file.
Thomas@1841
  1841
        /// If no file path is given, the message is stored with a randomized
Thomas@1841
  1842
        /// file name in the Temp directory.
Thomas@1841
  1843
        /// </summary>
Thomas@1841
  1844
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1841
  1845
        /// <param name="fileName">The file path where to store the item.</param>
Thomas@1841
  1846
        /// <returns>The file path where the message was saved or null if an error occured.</returns>
Thomas@1841
  1847
        public static string SaveAsEml(this Outlook.MailItem omi, string fileName = null)
Thomas@1841
  1848
        {
Thomas@1841
  1849
            MimeMessage message;
Thomas@1841
  1850
Thomas@1841
  1851
            // If no file name was given, create one. Else, validate file name.
Thomas@1841
  1852
            if (fileName == null)
Thomas@1841
  1853
            {
Thomas@1841
  1854
                // Create a randomized file name for the attachment
Thomas@1841
  1855
                Random random = new Random();
Thomas@1841
  1856
                string tempPath = Path.GetTempPath();
Thomas@1841
  1857
                fileName = tempPath + "message" + random.Next(10000) + ".eml";
Thomas@1841
  1858
                while (File.Exists(fileName))
Thomas@1841
  1859
                {
Thomas@1841
  1860
                    fileName = tempPath + "message" + random.Next(10000) + ".eml";
Thomas@1841
  1861
                }
Thomas@1841
  1862
            }
Thomas@1841
  1863
            else if (fileName.EndsWith(".eml") == false)
Thomas@1841
  1864
            {
Thomas@1841
  1865
                fileName = null;
Thomas@1841
  1866
                Log.Error("SaveAsEml: File name has to have EML file ending.");
Thomas@1841
  1867
            }
Thomas@1841
  1868
            else
Thomas@1841
  1869
            {
Thomas@1841
  1870
                FileInfo fi = null;
Thomas@1841
  1871
                try
Thomas@1841
  1872
                {
Thomas@1841
  1873
                    fi = new FileInfo(fileName);
Thomas@1841
  1874
                }
Thomas@1841
  1875
                catch (Exception ex)
Thomas@1841
  1876
                {
Thomas@1841
  1877
                    fileName = null;
Thomas@1841
  1878
                    Log.Error("SaveAsEml: Error in file name. " + ex.ToString());
Thomas@1841
  1879
                }
Thomas@1841
  1880
            }
Thomas@1841
  1881
Thomas@1841
  1882
            // If file path is valid, save mail item and return file path
Thomas@1841
  1883
            if (string.IsNullOrEmpty(fileName) == false)
Thomas@1841
  1884
            {
Thomas@1841
  1885
                try
Thomas@1841
  1886
                {
Thomas@1841
  1887
                    message = omi.ToMIMEMessage();
Thomas@1841
  1888
                    message.WriteTo(fileName);
Thomas@1841
  1889
                }
Thomas@1841
  1890
                catch (Exception ex)
Thomas@1841
  1891
                {
Thomas@1841
  1892
                    fileName = null;
Thomas@1841
  1893
                    Log.Error("SaveAsEml: Error saving mail item to EML file. " + ex.ToString());
Thomas@1841
  1894
                }
Thomas@1841
  1895
            }
Thomas@1841
  1896
Thomas@1841
  1897
            return fileName;
Thomas@1841
  1898
        }
Thomas@1841
  1899
Thomas@1841
  1900
        /// <summary>
Thomas@1841
  1901
        /// Converts this Outlook mail item into a MimeMessage.
Thomas@1841
  1902
        /// </summary>
Thomas@1841
  1903
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1841
  1904
        /// <returns>The created MimeMessage or null if an error occured.</returns>
Thomas@1841
  1905
        public static MimeMessage ToMIMEMessage(this Outlook.MailItem omi)
Thomas@1841
  1906
        {
Thomas@1849
  1907
            MimeMessage mimeMessage = null;
Thomas@1841
  1908
            BodyBuilder bodyBuilder = new BodyBuilder();
Thomas@1841
  1909
            PEPMessage pEpMessage = null;
Thomas@1841
  1910
Thomas@1841
  1911
            // Create a PEPMessage
Thomas@1841
  1912
            if (PEPMessage.Create(omi, out pEpMessage) == Globals.ReturnStatus.Success)
Thomas@1841
  1913
            {
Thomas@1849
  1914
                MimeMessage message;
Thomas@1849
  1915
                if (PEPMessage.ToMIMEMessage(pEpMessage, out message) == Globals.ReturnStatus.Success)
Thomas@1849
  1916
                {
Thomas@1849
  1917
                    mimeMessage = message;
Thomas@1849
  1918
                }
Thomas@1849
  1919
                else
Thomas@1849
  1920
                {
Thomas@1849
  1921
                    Log.Error("MailItemExtensions.ToMIMEMessage: Error creating MimeMessage.");
Thomas@1849
  1922
                }
Thomas@1849
  1923
            }
Thomas@1849
  1924
            else
Thomas@1849
  1925
            {
Thomas@1849
  1926
                Log.Error("MailItemExtensions.ToMIMEMessage: Error creating PEPMessage.");
Thomas@1841
  1927
            }
Thomas@1841
  1928
Thomas@1849
  1929
            return mimeMessage;
Thomas@1841
  1930
        }
Thomas@1841
  1931
Dean@1303
  1932
        /**************************************************************
Dean@1303
  1933
         * 
Dean@1303
  1934
         * User/MAPI Property Extensions
Dean@1303
  1935
         * 
Dean@1303
  1936
         *************************************************************/
Dean@1303
  1937
Dean@1303
  1938
        /// <summary>
Dean@1415
  1939
        /// Sets the user property value of the mail item.
Dean@1303
  1940
        /// This will create the user property of the given type if it doesn't already exist.
Dean@1303
  1941
        /// Warning: this will not save the mail item.
Dean@1303
  1942
        /// </summary>
Thomas@1784
  1943
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  1944
        /// <param name="name">The name of the user property.</param>
Dean@1303
  1945
        /// <param name="value">The new value of the user property.</param>
Dean@1303
  1946
        /// <param name="type">The type of the user property.</param>
Dean@1303
  1947
        public static void SetUserProperty(this Outlook.MailItem omi,
Dean@1303
  1948
                                           string name,
Dean@1303
  1949
                                           object value,
Dean@1303
  1950
                                           Outlook.OlUserPropertyType type = Outlook.OlUserPropertyType.olText)
Dean@1303
  1951
        {
Dean@1303
  1952
            Outlook.UserProperties properties;
Dean@1303
  1953
            Outlook.UserProperty up;
Dean@1303
  1954
Dean@1303
  1955
            if ((omi != null) &&
Dean@1303
  1956
                (string.IsNullOrEmpty(name) == false))
Dean@1303
  1957
            {
Dean@1303
  1958
                properties = omi.UserProperties;
Dean@1303
  1959
                up = properties.Find(name);
Dean@1303
  1960
Dean@1303
  1961
                if (up == null)
Dean@1303
  1962
                {
Dean@1303
  1963
                    /* The .Add function has the following parameters:
Dean@1303
  1964
                     * 
Dean@1303
  1965
                     *              Name : The name of the property. 
Dean@1303
  1966
                     *                     The maximum length is 64 characters. 
Dean@1303
  1967
                     *                     The characters, '[', ']', '_' and '#', are not permitted in the name.
Dean@1303
  1968
                     *              Type : The type of the new property.
Dean@1303
  1969
                     * [Optional]
Dean@1303
  1970
                     * AddToFolderFields : True if the property will be added as a custom field to the 
Dean@1303
  1971
                     *                     folder that the item is in. This field can be displayed in 
Dean@1303
  1972
                     *                     the folder's view. False if the property will be added as a 
Dean@1303
  1973
                     *                     custom field to the item but not to the folder. 
Dean@1303
  1974
                     *                     The default value is True.
Dean@1303
  1975
                     * [Optional]
Dean@1303
  1976
                     *     DisplayFormat : Specifies how the property will be displayed in the Outlook user interface. 
Dean@1303
  1977
                     * 
Dean@1303
  1978
                     * It is very important that the AddToFolderFields parameter is FALSE.
Dean@1303
  1979
                     * This is opposite of the default.
Dean@1303
  1980
                     * Setting to false will attach the user property to the mail item itself.
Dean@1303
  1981
                     * See: https://msdn.microsoft.com/en-us/library/office/ff867389.aspx
Dean@1303
  1982
                     */
Dean@1303
  1983
                    up = properties.Add(name, type, false);
Dean@1303
  1984
                }
Dean@1303
  1985
Dean@1303
  1986
                up.Value = value;
Dean@1303
  1987
Dean@1303
  1988
                // Release objects
Dean@1303
  1989
                if (properties != null)
Dean@1303
  1990
                {
vb@1516
  1991
                    // Marshal.ReleaseComObject(properties);
Dean@1303
  1992
                    properties = null;
Dean@1303
  1993
                }
Dean@1303
  1994
Dean@1303
  1995
                if (up != null)
Dean@1303
  1996
                {
vb@1516
  1997
                    // Marshal.ReleaseComObject(up);
Dean@1303
  1998
                    up = null;
Dean@1303
  1999
                }
Dean@1303
  2000
            }
Dean@1303
  2001
Dean@1303
  2002
            return;
Dean@1303
  2003
        }
Dean@1303
  2004
Dean@1303
  2005
        /// <summary>
Dean@1415
  2006
        /// Gets the user property value in the mail item.
Dean@1303
  2007
        /// </summary>
Thomas@1784
  2008
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  2009
        /// <param name="name">The name of the user property.</param>
Dean@1303
  2010
        /// <param name="defaultValue">The default value of the user property to return if not found.</param>
Dean@1303
  2011
        /// <returns>The value of the user property if found, otherwise defaultValue.</returns>
Dean@1303
  2012
        public static object GetUserProperty(this Outlook.MailItem omi,
Dean@1303
  2013
                                             string name,
Dean@1303
  2014
                                             object defaultValue = null)
Dean@1303
  2015
        {
Dean@1303
  2016
            object value = null;
Thomas@1658
  2017
            Outlook.UserProperties properties = null;
Thomas@1658
  2018
            Outlook.UserProperty up = null;
Dean@1303
  2019
Dean@1303
  2020
            if ((omi != null) &&
Dean@1303
  2021
                (string.IsNullOrEmpty(name) == false))
Dean@1303
  2022
            {
Thomas@1658
  2023
                /* This try/catch block is necessary, as the following lines showed to raise an exception of type
Thomas@1658
  2024
                 * "The item has been moved or deleted" (even after the null check). See OUT-256
Thomas@1784
  2025
                 */
Thomas@1658
  2026
                try
Thomas@1658
  2027
                {
Thomas@1658
  2028
                    properties = omi.UserProperties;
Thomas@1658
  2029
                    up = properties.Find(name);
Thomas@1658
  2030
                }
Thomas@1936
  2031
                catch (Exception ex)
Thomas@1658
  2032
                {
Thomas@1936
  2033
                    Log.Verbose("MailItemExtensions.GetUserProperty: Error getting user properties. " + ex.ToString());
Thomas@1658
  2034
                    up = null;
Thomas@1658
  2035
                }
Dean@1303
  2036
Dean@1303
  2037
                if (up == null)
Dean@1303
  2038
                {
Dean@1303
  2039
                    value = defaultValue;
Dean@1303
  2040
                }
Dean@1303
  2041
                else
Dean@1303
  2042
                {
Dean@1303
  2043
                    value = up.Value;
Dean@1303
  2044
                }
Dean@1303
  2045
Dean@1303
  2046
                // Release objects
Dean@1303
  2047
                if (properties != null)
Dean@1303
  2048
                {
vb@1516
  2049
                    // Marshal.ReleaseComObject(properties);
Dean@1303
  2050
                    properties = null;
Dean@1303
  2051
                }
Dean@1303
  2052
Dean@1303
  2053
                if (up != null)
Dean@1303
  2054
                {
vb@1516
  2055
                    // Marshal.ReleaseComObject(up);
Dean@1303
  2056
                    up = null;
Dean@1303
  2057
                }
Dean@1303
  2058
            }
Dean@1303
  2059
Dean@1303
  2060
            return (value);
Dean@1303
  2061
        }
Dean@1303
  2062
Dean@1303
  2063
        /// <summary>
Dean@1415
  2064
        /// Deletes the user property from the mail item (if it exists).
Dean@1303
  2065
        /// Warning: this will not save the mail item.
Dean@1303
  2066
        /// </summary>
Thomas@1784
  2067
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  2068
        /// <param name="name">The name of the user property to delete.</param>
Dean@1303
  2069
        public static void DeleteUserProperty(this Outlook.MailItem omi,
Dean@1303
  2070
                                              string name)
Dean@1303
  2071
        {
Dean@1303
  2072
            Outlook.UserProperties properties;
Dean@1303
  2073
            Outlook.UserProperty up;
Dean@1303
  2074
Dean@1303
  2075
            if ((omi != null) &&
Dean@1303
  2076
                (string.IsNullOrEmpty(name) == false))
Dean@1303
  2077
            {
Dean@1303
  2078
                properties = omi.UserProperties;
Dean@1303
  2079
                up = properties.Find(name);
Dean@1303
  2080
Dean@1303
  2081
                if (up != null)
Dean@1303
  2082
                {
Dean@1303
  2083
                    up.Delete();
Dean@1303
  2084
                }
Dean@1303
  2085
Dean@1303
  2086
                // Release objects
Dean@1303
  2087
                if (properties != null)
Dean@1303
  2088
                {
vb@1516
  2089
                    // Marshal.ReleaseComObject(properties);
Dean@1303
  2090
                    properties = null;
Dean@1303
  2091
                }
Dean@1303
  2092
Dean@1303
  2093
                if (up != null)
Dean@1303
  2094
                {
vb@1516
  2095
                    // Marshal.ReleaseComObject(up);
Dean@1303
  2096
                    up = null;
Dean@1303
  2097
                }
Dean@1303
  2098
            }
Dean@1303
  2099
Dean@1303
  2100
            return;
Dean@1303
  2101
        }
Dean@1303
  2102
Dean@1303
  2103
        /// <summary>
Thomas@1988
  2104
        /// Gets the outgoing rating for this mail item.
Thomas@1988
  2105
        /// </summary>
Thomas@1988
  2106
        /// <param name="omi">The Outlook mail item to process with.</param>
Thomas@1988
  2107
        /// <returns>The outgoing rating for the mail item.</returns>
Thomas@1988
  2108
        public static pEpRating GetOutgoingRating(this Outlook.MailItem omi)
Thomas@1988
  2109
        {
Thomas@1988
  2110
            pEpRating rating = pEpRating.pEpRatingUndefined;
Thomas@1988
  2111
Thomas@2010
  2112
#if READER_RELEASE_MODE
Thomas@2010
  2113
            // If reader mode, always unencrypted
Thomas@2010
  2114
            return (pEpRating.pEpRatingUnencrypted);
Thomas@2010
  2115
#else
Thomas@2010
  2116
            // If mail has no recipients, return undefined
Thomas@2010
  2117
            if (omi?.Recipients?.Count == 0)
Thomas@1988
  2118
            {
Thomas@2010
  2119
                return pEpRating.pEpRatingUndefined;
Thomas@1988
  2120
            }
Thomas@2010
  2121
Thomas@2010
  2122
            // If mail is forcefully protected, return reliable
Thomas@2028
  2123
            if (omi?.GetIsForcefullyProtected() == true)
Thomas@2010
  2124
            {
Thomas@2010
  2125
                return pEpRating.pEpRatingReliable;
Thomas@2010
  2126
            }
Thomas@2010
  2127
Thomas@2011
  2128
            // If mail is forcefully unencrypted, return unencrypted
Thomas@2011
  2129
            if (omi?.GetIsForceUnencrypted() == true)
Thomas@2011
  2130
            {
Thomas@2011
  2131
                return pEpRating.pEpRatingUnencrypted;
Thomas@2011
  2132
            }
Thomas@2011
  2133
Thomas@2010
  2134
            // If mail has BCC recipients, always unencrypted
Thomas@2010
  2135
            if (string.IsNullOrEmpty(omi?.BCC) == false)
Thomas@2010
  2136
            {
Thomas@2010
  2137
                return (pEpRating.pEpRatingUnencrypted);
Thomas@2010
  2138
            }
Thomas@2010
  2139
Thomas@2010
  2140
            // Else calculate it
Thomas@2010
  2141
            PEPMessage message;
Thomas@2010
  2142
            if (PEPMessage.Create(omi, out message, true, false) == Globals.ReturnStatus.Success)
Thomas@2010
  2143
            {
Thomas@2010
  2144
                rating = message?.OutgoingRating ?? pEpRating.pEpRatingUndefined;
Thomas@2010
  2145
            }
Thomas@2010
  2146
            else
Thomas@1988
  2147
            {
Thomas@1988
  2148
                rating = pEpRating.pEpRatingUndefined;
Thomas@2010
  2149
                Log.Error("MailItemExtensions.GetOutgoingRating: Error creating PEPMessage. Returning default rating.");
Thomas@1988
  2150
            }
Thomas@2010
  2151
#endif
Thomas@1988
  2152
            return rating;
Thomas@1988
  2153
        }
Thomas@1988
  2154
Thomas@1988
  2155
        /// <summary>
Dean@1403
  2156
        /// Gets the parsed transport message headers (MIME headers) of the given Outlook mail item.
Dean@1403
  2157
        /// This will internally use the MAPI property PidTagTransportMessageHeaders.
Dean@1403
  2158
        /// Warning: This can return null.
Dean@1403
  2159
        /// </summary>
Thomas@1784
  2160
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1403
  2161
        /// <returns>The parsed transport message headers, otherwise null.</returns>
Thomas@1953
  2162
        public static HeaderList GetParsedTransportMessageHeaders(this Outlook.MailItem omi)
Dean@1403
  2163
        {
Dean@1403
  2164
            string messageHeaders = null;
Dean@1403
  2165
            MemoryStream stream = null;
Dean@1403
  2166
            MimeParser mimeParser;
Dean@1403
  2167
            HeaderList headers = null;
Dean@1403
  2168
Dean@1403
  2169
            if (omi != null)
Dean@1403
  2170
            {
Dean@1403
  2171
                messageHeaders = MapiHelper.GetProperty(omi, MapiProperty.PidTagTransportMessageHeaders, string.Empty) as string;
Dean@1403
  2172
Dean@1403
  2173
                if (string.IsNullOrEmpty(messageHeaders) == false)
Dean@1403
  2174
                {
Dean@1403
  2175
                    // Parse the headers using MimeKit
Dean@1403
  2176
                    try
Dean@1403
  2177
                    {
Dean@1403
  2178
                        stream = new MemoryStream(Encoding.UTF8.GetBytes(messageHeaders));
Dean@1403
  2179
                        mimeParser = new MimeParser(stream);
Dean@1403
  2180
                        headers = mimeParser.ParseHeaders();
Dean@1403
  2181
                    }
Thomas@1936
  2182
                    catch (Exception ex)
Dean@1403
  2183
                    {
Thomas@1936
  2184
                        Log.Error("GetParsedTransportMessageHeaders: Failed to parse MIME headers, " + ex.ToString());
Dean@1403
  2185
                    }
Dean@1403
  2186
                    finally
Dean@1403
  2187
                    {
Dean@1403
  2188
                        if (stream != null)
Dean@1403
  2189
                        {
Dean@1403
  2190
                            stream.Close();
Dean@1403
  2191
                            stream = null;
Dean@1403
  2192
                        }
Dean@1403
  2193
                    }
Dean@1403
  2194
                }
Dean@1403
  2195
            }
Dean@1403
  2196
Dean@1403
  2197
            return (headers);
Dean@1403
  2198
        }
Dean@1403
  2199
Dean@1403
  2200
        /// <summary>
Dean@1303
  2201
        /// Gets the default value for the given UserProperty or MAPI property.
Dean@1303
  2202
        /// Warning: The propertyName for a UserProperty or MAPI property must never be the same.
Dean@1303
  2203
        /// </summary>
Dean@1303
  2204
        /// <param name="property">The pEp defined property to get the default for.</param>
Dean@1303
  2205
        /// <param name="defaultValue">The default value to return if failure.</param>
Dean@1303
  2206
        /// <returns>The default value of the given property.</returns>
Dean@1336
  2207
        public static object GetPEPPropertyDefault(PEPProperty property)
Dean@1303
  2208
        {
Dean@1336
  2209
            object newValue = null;
Dean@1303
  2210
Dean@1303
  2211
            switch (property)
Dean@1303
  2212
            {
Dean@1393
  2213
                case PEPProperty.AutoConsume:
Dean@1393
  2214
                    newValue = null;
Dean@1393
  2215
                    break;
Thomas@1819
  2216
                case PEPProperty.ForceProtection:
Thomas@1819
  2217
                    newValue = null;
Thomas@1819
  2218
                    break;
Dean@1303
  2219
                case PEPProperty.ForceUnencrypted:
Dean@1303
  2220
                    newValue = false;
Dean@1303
  2221
                    break;
Dean@1303
  2222
                case PEPProperty.KeyList:
Dean@1303
  2223
                    newValue = null;
Dean@1303
  2224
                    break;
Dean@1303
  2225
                case PEPProperty.NeverUnsecure:
Dean@1303
  2226
                    newValue = false;
Dean@1303
  2227
                    break;
Dean@1303
  2228
                case PEPProperty.PEPProtocolVersion:
Dean@1303
  2229
                    newValue = null;
Dean@1303
  2230
                    break;
Dean@1303
  2231
                case PEPProperty.Rating:
markus@1337
  2232
                    newValue = pEpRating.pEpRatingUndefined;
Dean@1303
  2233
                    break;
Thomas@1817
  2234
                case PEPProperty.EnableProtection:
Thomas@1795
  2235
                    newValue = false;
Thomas@1795
  2236
                    break;
Dean@1303
  2237
            }
Dean@1303
  2238
Dean@1303
  2239
            return (newValue);
Dean@1303
  2240
        }
Dean@1303
  2241
Dean@1303
  2242
        /// <summary>
Thomas@1784
  2243
        /// Gets the value of either a UserProperty or MAPI property from the given Outlook mail item.
Dean@1303
  2244
        /// The value will be processed (interpreted) for immediate use elsewhere.
Dean@1303
  2245
        /// This method will automatically calculate a default value based on the given propertyName.
Dean@1303
  2246
        /// Warning: The propertyName for a UserProperty or MAPI property must never be the same.
Dean@1303
  2247
        /// </summary>
Thomas@1784
  2248
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  2249
        /// <param name="property">The pEp defined property to get.</param>
Dean@1303
  2250
        /// <param name="value">The output value of the given property (will return calculated default if unsuccessful).</param>
Dean@1303
  2251
        /// <returns>True if successful, otherwise false.</returns>
Dean@1303
  2252
        public static bool GetPEPProperty(this Outlook.MailItem omi,
Dean@1303
  2253
                                          PEPProperty property,
Dean@1303
  2254
                                          out object value)
Dean@1303
  2255
        {
Dean@1303
  2256
            bool success;
Dean@1303
  2257
            object outValue;
Dean@1303
  2258
            object defaultValue;
Dean@1303
  2259
Dean@1303
  2260
            defaultValue = MailItemExtensions.GetPEPPropertyDefault(property);
Thomas@1953
  2261
            success = omi.GetPEPProperty(property, out outValue, defaultValue, null);
Dean@1303
  2262
Dean@1303
  2263
            value = outValue;
Dean@1303
  2264
            return (success);
Dean@1303
  2265
        }
Dean@1303
  2266
Dean@1303
  2267
        /// <summary>
Thomas@1784
  2268
        /// Gets the value of either a UserProperty or MAPI property from the given Outlook mail item.
Dean@1303
  2269
        /// The value will be processed (interpreted) for immediate use elsewhere.
Dean@1303
  2270
        /// Warning: The propertyName for a UserProperty or MAPI property must never be the same.
Dean@1303
  2271
        /// </summary>
Thomas@1784
  2272
        /// <param name="omi">The Outlook mail item to process with.</param>
Dean@1303
  2273
        /// <param name="property">The pEp defined property to get.</param>
Dean@1303
  2274
        /// <param name="value">The output value of the given property (will return defaultValue if unsuccessful).</param>
Dean@1303
  2275
        /// <param name="defaultValue">The default value to return if failure.</param>
Thomas@1953
  2276
        /// <param name="messageHeaders">The message headers of this message.</param>
Dean@1303
  2277
        /// <returns>True if successful, otherwise false.</returns>
Dean@1303
  2278
        public static bool GetPEPProperty(this Outlook.MailItem omi,
Dean@1303
  2279
                                          PEPProperty property,
Dean@1303
  2280
                                          out object value,
Thomas@1953
  2281
                                          object defaultValue,
Thomas@1953
  2282
                                          HeaderList messageHeaders)
Dean@1303
  2283
        {
Dean@1303
  2284
            bool success = false;
Dean@1303
  2285
            object propertyValue;
Dean@1303
  2286
            object outValue = defaultValue;
Dean@1303
  2287
Dean@1303
  2288
            try
Dean@1303
  2289
            {
Dean@1303
  2290
                if (omi != null)
Dean@1303
  2291
                {
Dean@1303
  2292
                    switch (property)
Dean@1303
  2293
                    {
Dean@1393
  2294
                        // Auto consume MAPI property
Dean@1393
  2295
                        case PEPProperty.AutoConsume:
Dean@1393
  2296
                            {
Dean@1393
  2297
                                // Note: this value is passed through completely as a string
Dean@1393
  2298
                                outValue = MailItemExtensions.GetPEPPropertyDefault(property);
Dean@1393
  2299
                                propertyValue = MapiHelper.GetProperty(omi, PEPMessage.PidNamePEPAutoConsume, null);
Dean@1393
  2300
Dean@1393
  2301
                                if (propertyValue != null)
Dean@1393
  2302
                                {
Dean@1393
  2303
                                    outValue = propertyValue;
Dean@1393
  2304
                                }
Dean@1393
  2305
                                else
Dean@1393
  2306
                                {
Thomas@1953
  2307
                                    // As a backup search the original internet message headers   
Thomas@1953
  2308
                                    if (messageHeaders == null)
Thomas@1953
  2309
                                    {
Thomas@1953
  2310
                                        messageHeaders = omi.GetParsedTransportMessageHeaders();
Thomas@1953
  2311
                                    }
Dean@1403
  2312
                                    if (messageHeaders != null)
Dean@1393
  2313
                                    {
Dean@1403
  2314
                                        foreach (Header header in messageHeaders)
Dean@1403
  2315
                                        {
Dean@1403
  2316
                                            if ((header.Field != null) &&
Dean@1403
  2317
                                                (header.Value != null) &&
Dean@1403
  2318
                                                (string.Equals(header.Field.Trim(), PEPMessage.PR_PEP_AUTO_CONSUME_NAME, StringComparison.OrdinalIgnoreCase)))
Dean@1403
  2319
                                            {
Dean@1403
  2320
                                                outValue = header.Value.Trim();
Dean@1403
  2321
                                            }
Dean@1403
  2322
                                        }
Dean@1393
  2323
                                    }
Dean@1393
  2324
                                }
Dean@1393
  2325
Dean@1393
  2326
                                success = true;
Dean@1393
  2327
                                break;
Dean@1393
  2328
                            }
Thomas@1820
  2329
                        // Force protection MAPI property
Thomas@1819
  2330
                        case PEPProperty.ForceProtection:
Thomas@1819
  2331
                            {
Thomas@1820
  2332
                                /* Note that ForceProtection is defined as:
Thomas@1820
  2333
                                 *   ON : ForceProtection property exists with a value of a message GUID
Thomas@1820
  2334
                                 *  OFF : ForceProtection property does not exist or has a value of null
Thomas@1820
  2335
                                 */
Thomas@1819
  2336
                                outValue = MailItemExtensions.GetPEPPropertyDefault(property);
Thomas@1819
  2337
                                propertyValue = MapiHelper.GetProperty(omi, PEPMessage.PidNamePEPForceProtection, null);
Thomas@1819
  2338
Thomas@1819
  2339
                                if (propertyValue != null)
Thomas@1819
  2340
                                {
Thomas@1820
  2341
                                    outValue = propertyValue as string;
Thomas@1819
  2342
                                }
Thomas@1819
  2343
                                else
Thomas@1819
  2344
                                {
Thomas@1819
  2345
                                    // As a backup search the original internet message headers
Thomas@1953
  2346
                                    if (messageHeaders == null)
Thomas@1953
  2347
                                    {
Thomas@1953
  2348
                                        messageHeaders = omi.GetParsedTransportMessageHeaders();
Thomas@1953
  2349
                                    }
Thomas@1819
  2350
                                    if (messageHeaders != null)
Thomas@1819
  2351
                                    {
Thomas@1819
  2352
                                        foreach (Header header in messageHeaders)
Thomas@1819
  2353
                                        {
Thomas@1819
  2354
                                            if ((header.Field != null) &&
Thomas@1819
  2355
                                                (header.Value != null) &&
Thomas@1819
  2356
                                                (string.Equals(header.Field.Trim(), PEPMessage.PR_PEP_FORCE_PROTECTION_NAME, StringComparison.OrdinalIgnoreCase)))
Thomas@1819
  2357
                                            {
Thomas@1823
  2358
                                                outValue = header.Value.ToString();
Thomas@1819
  2359
                                            }
Thomas@1819
  2360
                                        }
Thomas@1819
  2361
                                    }
Thomas@1819
  2362
                                }
Thomas@1819
  2363
Thomas@1819
  2364
                                success = true;
Thomas@1819
  2365
                                break;
Thomas@1819
  2366
                            }
Dean@1303
  2367
                        // Force unencrypted user property
Dean@1303
  2368
                        case PEPProperty.ForceUnencrypted:
Dean@1303
  2369
                            {
Dean@1303
  2370
                                /* Note that ForceUnencrypted is defined as:
Dean@1303
  2371
                                 *   ON : ForceUnencrypted property exists with a value of 'True'
Dean@1303
  2372
                                 *  OFF : ForceUnencrypted property does not exist or has a value of 'False' or null
Dean@1303
  2373
                                 */
Dean@1303
  2374
Dean@1303
  2375
                                outValue = MailItemExtensions.GetPEPPropertyDefault(property);
Dean@1303
  2376
                                propertyValue = omi.GetUserProperty(CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED);
Dean@1303
  2377
Dean@1303
  2378
                                if ((propertyValue != null) &&
Dean@1303
  2379
                                    (propertyValue is bool) &&
Dean@1303
  2380
                                    ((bool)propertyValue == true))
Dean@1303
  2381
                                {
Dean@1303
  2382
                                    outValue = true;
Dean@1303
  2383
                                }
Dean@1303
  2384
Dean@1303
  2385
                                success = true;
Dean@1303
  2386
                                break;
Dean@1303
  2387
                            }
Dean@1303
  2388
                        // Key list MAPI property
Dean@1303
  2389
                        case PEPProperty.KeyList:
Dean@1303
  2390
                            {
Dean@1303
  2391
                                // Note: this value is passed through completely as a string
Dean@1393
  2392
                                outValue = MapiHelper.GetProperty(omi, PEPMessage.PidNameKeyList, MailItemExtensions.GetPEPPropertyDefault(property));
Dean@1303
  2393
                                success = true;
Dean@1303
  2394
                                break;
Dean@1303
  2395
                            }
Dean@1303
  2396
                        // Never unsecure MAPI property
Dean@1303
  2397
                        case PEPProperty.NeverUnsecure:
Dean@1303
  2398
                            {
Dean@1303
  2399
                                /* Note that NeverUnsecure is defined as:
Dean@1303
  2400
                                 *   ON : NeverUnsecure property exists with ANY value ('1' is the default)