PEPMessage.cs
author Thomas
Thu, 01 Mar 2018 10:07:49 +0100
changeset 2025 16d165ee211e
parent 2017 2b8ec8253118
child 2027 bd9dd65f8c6b
child 2030 feaa39471f5f
permissions -rw-r--r--
Use new string instance in copy method
Dean@384
     1
using Microsoft.Win32;
Thomas@1841
     2
using MimeKit;
Dean@384
     3
using pEpCOMServerAdapterLib;
Dean@384
     4
using System;
Dean@384
     5
using System.Collections.Generic;
Dean@1094
     6
using System.ComponentModel;
Thomas@1820
     7
using System.IO;
Dean@1238
     8
using System.Text;
Dean@384
     9
using Outlook = Microsoft.Office.Interop.Outlook;
Dean@384
    10
Dean@384
    11
namespace pEp
Dean@384
    12
{
Dean@384
    13
    /// <summary>
markus@1337
    14
    /// Class for a completely in-memory message based on the pEp engine TextMessage.
Dean@384
    15
    /// </summary>
Dean@1094
    16
    internal class PEPMessage : INotifyPropertyChanged,
Dean@1238
    17
                                IEquatable<PEPMessage>,
Dean@1094
    18
                                Interfaces.ICopy<PEPMessage>,
Dean@1094
    19
                                Interfaces.IReset
Dean@384
    20
    {
Dean@1094
    21
        /// <summary>
Dean@1094
    22
        /// Event raised when a property is changed on a component.
Dean@1094
    23
        /// </summary>
Dean@1094
    24
        public event PropertyChangedEventHandler PropertyChanged;
Dean@1094
    25
Dean@1223
    26
        // pEp named MAPI properties
Dean@1393
    27
        public const string PR_ENC_STATUS_NAME           = "X-EncStatus";
Dean@1393
    28
        public const string PR_KEY_LIST_NAME             = "X-KeyList";
Dean@1393
    29
        public const string PR_PEP_AUTO_CONSUME_NAME     = "pEp-auto-consume";
Thomas@1819
    30
        public const string PR_PEP_FORCE_PROTECTION_NAME = "pEp-force-protection";
Dean@1393
    31
        public const string PR_PEP_NEVER_UNSECURE_NAME   = "X-pEp-Never-Unsecure";
Dean@1393
    32
        public const string PR_PEP_PROTOCOL_VERSION_NAME = "X-pEp-Version";
Dean@780
    33
Thomas@1822
    34
        public const string PR_PEP_NEVER_UNSECURE_VALUE  = "yes";
Dean@1435
    35
Dean@1393
    36
        public static readonly MapiProperty.MapiProp PidNameEncStatus          = new MapiProperty.MapiProp(PR_ENC_STATUS_NAME,           MapiProperty.PS_INTERNET_HEADERS);
Dean@1393
    37
        public static readonly MapiProperty.MapiProp PidNameKeyList            = new MapiProperty.MapiProp(PR_KEY_LIST_NAME,             MapiProperty.PS_INTERNET_HEADERS);
Dean@1393
    38
        public static readonly MapiProperty.MapiProp PidNamePEPAutoConsume     = new MapiProperty.MapiProp(PR_PEP_AUTO_CONSUME_NAME,     MapiProperty.PS_INTERNET_HEADERS);
Thomas@1819
    39
        public static readonly MapiProperty.MapiProp PidNamePEPForceProtection = new MapiProperty.MapiProp(PR_PEP_FORCE_PROTECTION_NAME, MapiProperty.PS_INTERNET_HEADERS);
Dean@1393
    40
        public static readonly MapiProperty.MapiProp PidNamePEPNeverUnsecure   = new MapiProperty.MapiProp(PR_PEP_NEVER_UNSECURE_NAME,   MapiProperty.PS_INTERNET_HEADERS);
Dean@1393
    41
        public static readonly MapiProperty.MapiProp PidNamePEPProtocolVersion = new MapiProperty.MapiProp(PR_PEP_PROTOCOL_VERSION_NAME, MapiProperty.PS_INTERNET_HEADERS);
Thomas@1467
    42
Thomas@1960
    43
        private static object                     mutexMirror           = new object();
Thomas@1960
    44
        private static Dictionary<string, string> mirrorCache           = new Dictionary<string, string>();
Thomas@1960
    45
Dean@384
    46
        private List<PEPAttachment> _Attachments;
Dean@1393
    47
        private string              _AutoConsume;
Dean@1348
    48
        private List<PEPIdentity>   _Bcc;
Dean@1348
    49
        private List<PEPIdentity>   _Cc;
Dean@1348
    50
        private string              _ConversationId;
Dean@1113
    51
        private string              _ConversationIndex;
Dean@1113
    52
        private string              _ConversationTopic;
Dean@1340
    53
        private pEpMsgDirection     _Direction;
Thomas@1817
    54
        private bool                _EnableProtection;
Thomas@1848
    55
        private string              _ForceProtectionId;
Dean@1094
    56
        private bool                _ForceUnencrypted;
Dean@384
    57
        private PEPIdentity         _From;
Dean@1348
    58
        private string              _Id;
Dean@1094
    59
        private string              _KeyList;
Dean@384
    60
        private List<string>        _Keywords;
Dean@384
    61
        private string              _LongMsg;
Dean@1354
    62
        private string              _LongMsgFormattedHtml;
Dean@1354
    63
        private string              _LongMsgFormattedRtf;
Dean@1104
    64
        private bool                _NeverUnsecure;
Dean@1212
    65
        private string              _PEPProtocolVersion;
Dean@1340
    66
        private pEpRating           _Rating;
Dean@721
    67
        private DateTime?           _ReceivedOn;
Dean@721
    68
        private DateTime?           _SentOn;
Dean@384
    69
        private string              _ShortMsg;
Dean@384
    70
        private List<PEPIdentity>   _To;
Dean@384
    71
Dean@384
    72
        /**************************************************************
Dean@384
    73
         * 
Dean@384
    74
         * Constructors
Dean@384
    75
         * 
Dean@384
    76
         *************************************************************/
Dean@384
    77
Dean@384
    78
        /// <summary>
Dean@384
    79
        /// Default constructor.
Dean@384
    80
        /// </summary>
Dean@384
    81
        public PEPMessage()
Dean@384
    82
        {
Dean@1094
    83
            this.Reset();
Dean@384
    84
        }
Dean@384
    85
Dean@384
    86
        /**************************************************************
Dean@384
    87
         * 
Dean@384
    88
         * Property Accessors
Dean@384
    89
         * 
Dean@384
    90
         *************************************************************/
Dean@384
    91
Dean@910
    92
        #region Property Accessors
Dean@910
    93
Dean@384
    94
        /// <summary>
Dean@384
    95
        /// Gets the list of attachements for this message.
Dean@1094
    96
        ///          MailItem : Corresponds to property 'Attachments' which contains 'Attachment'
Dean@1094
    97
        /// CryptableMailItem : not exposed
Dean@1348
    98
        ///       TextMessage : Corresponds to property 'Attachments' which contains 'Blob'
Dean@384
    99
        /// </summary>
Dean@384
   100
        public List<PEPAttachment> Attachments
Dean@384
   101
        {
Dean@384
   102
            get { return (this._Attachments); }
Dean@384
   103
        }
Dean@384
   104
Dean@1421
   105
        /// <summary>
Dean@1393
   106
        /// Gets or sets whether this message should be automatically consumed by the pEp engine.
Dean@1393
   107
        /// Note: While this is stored as a header field, it is OK to apply to any MailItem and outgoing messages.
Dean@1393
   108
        /// It's intended function is only to add to outgoing messages generated by the engine.
Dean@1393
   109
        ///          MailItem : Corresponds to MAPI Property PidNamePEPAutoConsume (Header field)
Dean@1393
   110
        /// CryptableMailItem : not supported
Dean@1421
   111
        ///       TextMessage : Corresponds with the key PR_PEP_AUTO_CONSUME_NAME within 'opt_fields' array.
Dean@1421
   112
        /// </summary>
Dean@1393
   113
        public string AutoConsume
Dean@1393
   114
        {
Dean@1393
   115
            get { return (this._AutoConsume); }
Dean@1393
   116
            set
Dean@1393
   117
            {
Dean@1393
   118
                this._AutoConsume = value;
Dean@1393
   119
                this.RaisePropertyChangedEvent(nameof(this.AutoConsume));
Dean@1393
   120
            }
Dean@1393
   121
        }
Dean@1393
   122
Dean@384
   123
        /// <summary>
Dean@387
   124
        /// Gets the list of identities to be blind carbon copied on the message.
Dean@1094
   125
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   126
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1348
   127
        ///       TextMessage : Corresponds to property 'Bcc'
Dean@384
   128
        /// </summary>
Dean@1348
   129
        public List<PEPIdentity> Bcc
Dean@384
   130
        {
Dean@1348
   131
            get { return (this._Bcc); }
Dean@384
   132
        }
Dean@384
   133
Dean@384
   134
        /// <summary>
Dean@384
   135
        /// Gets the list of identities to be carbon copied on the message.
Dean@1094
   136
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   137
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1348
   138
        ///       TextMessage : Corresponds to property 'Cc'
Dean@384
   139
        /// </summary>
Dean@1348
   140
        public List<PEPIdentity> Cc
Dean@384
   141
        {
Dean@1348
   142
            get { return (this._Cc); }
Dean@384
   143
        }
Dean@384
   144
Dean@384
   145
        /// <summary>
Dean@1113
   146
        /// Gets or sets the conversation ID of the message.
Dean@1113
   147
        /// Outlook should normally manage this itself.
Dean@1113
   148
        ///          MailItem : Corresponds to property 'ConversationID' (Underlying MAPI property PidTagConversationId)
Dean@1113
   149
        /// CryptableMailItem : Corresponds to property 'ConversationID'
Dean@1340
   150
        ///       TextMessage : not supported
Dean@1113
   151
        /// </summary>
Dean@1348
   152
        public string ConversationId
Dean@1113
   153
        {
Dean@1348
   154
            get { return (this._ConversationId); }
Dean@1113
   155
            set
Dean@1113
   156
            {
Dean@1348
   157
                this._ConversationId = value;
Dean@1348
   158
                this.RaisePropertyChangedEvent(nameof(this.ConversationId));
Dean@1113
   159
            }
Dean@1113
   160
        }
Dean@1113
   161
Dean@1113
   162
        /// <summary>
Dean@1113
   163
        /// Gets or sets the conversation index of the message.
Dean@1113
   164
        /// Outlook should normally manage this itself.
Dean@1113
   165
        ///          MailItem : Corresponds to property 'ConversationIndex' (Underlying MAPI property PidTagConversationIndex)
Dean@1113
   166
        /// CryptableMailItem : Corresponds to property 'ConversationIndex'
Dean@1340
   167
        ///       TextMessage : not supported
Dean@1113
   168
        /// </summary>
Dean@1113
   169
        public string ConversationIndex
Dean@1113
   170
        {
Dean@1113
   171
            get { return (this._ConversationIndex); }
Dean@1113
   172
            set
Dean@1113
   173
            {
Dean@1113
   174
                this._ConversationIndex = value;
Dean@1242
   175
                this.RaisePropertyChangedEvent(nameof(this.ConversationIndex));
Dean@1113
   176
            }
Dean@1113
   177
        }
Dean@1113
   178
Dean@1113
   179
        /// <summary>
Dean@1113
   180
        /// Gets or sets the conversation index of the message.
Dean@1113
   181
        /// Outlook should normally manage this itself.
Dean@1113
   182
        ///          MailItem : Corresponds to property 'ConversationTopic' (Underlying MAPI property PidTagConversationTopic)
Dean@1113
   183
        /// CryptableMailItem : Corresponds to property 'ConversationTopic'
Dean@1340
   184
        ///       TextMessage : not supported
Dean@1113
   185
        /// </summary>
Dean@1113
   186
        public string ConversationTopic
Dean@1113
   187
        {
Dean@1113
   188
            get { return (this._ConversationTopic); }
Dean@1113
   189
            set
Dean@1113
   190
            {
Dean@1113
   191
                this._ConversationTopic = value;
Dean@1242
   192
                this.RaisePropertyChangedEvent(nameof(this.ConversationTopic));
Dean@1113
   193
            }
Dean@1113
   194
        }
Dean@1113
   195
Dean@1113
   196
        /// <summary>
Dean@721
   197
        /// Gets the date and time when the message was either sent or received.
Dean@1094
   198
        /// This corresponds with the SentOn and ReceivedOn properties defined separately.
Dean@691
   199
        /// </summary>
Dean@691
   200
        public DateTime? DateTimeSentOrReceived
Dean@691
   201
        {
Dean@721
   202
            get
Dean@721
   203
            {
markus@1337
   204
                if (this._Direction == pEpMsgDirection.pEpDirIncoming)
Dean@721
   205
                {
Dean@721
   206
                    return (this._ReceivedOn);
Dean@721
   207
                }
Dean@721
   208
                else
Dean@721
   209
                {
Dean@721
   210
                    return (this._SentOn);
Dean@721
   211
                }
Dean@721
   212
            }
Dean@691
   213
        }
Dean@691
   214
Dean@691
   215
        /// <summary>
Dean@384
   216
        /// Gets or sets the direction (incoming or outgoing) of the message.
Dean@1094
   217
        ///          MailItem : not supported (calculated from various properties)
Dean@1094
   218
        /// CryptableMailItem : Corresponds 1-to-1 with property 'IsIncoming'
Dean@1348
   219
        ///       TextMessage : Corresponds to property 'Dir'
Dean@384
   220
        /// </summary>
markus@1337
   221
        public pEpMsgDirection Direction
Dean@384
   222
        {
Dean@384
   223
            get { return (this._Direction); }
Dean@1094
   224
            set
Dean@1094
   225
            {
Dean@1094
   226
                this._Direction = value;
Dean@1242
   227
                this.RaisePropertyChangedEvent(nameof(this.Direction));
Dean@1094
   228
            }
Dean@1094
   229
        }
Dean@1094
   230
Dean@1094
   231
        /// <summary>
Thomas@1817
   232
        /// Gets or sets the enable protection status.
Thomas@1817
   233
        ///          MailItem : Corresponds to UserProperty USER_PROPERTY_KEY_ENABLE_PROTECTION
Thomas@1817
   234
        /// CryptableMailItem : Corresponds to property 'EnableProtection'
Thomas@1795
   235
        ///       TextMessage : not supported
Thomas@1795
   236
        /// </summary>
Thomas@1817
   237
        public bool EnableProtection
Thomas@1795
   238
        {
Thomas@1817
   239
            get { return (this._EnableProtection); }
Thomas@1795
   240
            set
Thomas@1795
   241
            {
Thomas@1817
   242
                this._EnableProtection = value;
Thomas@1817
   243
                this.RaisePropertyChangedEvent(nameof(this.EnableProtection));
Thomas@1795
   244
            }
Thomas@1795
   245
        }
Thomas@1795
   246
Thomas@1795
   247
        /// <summary>
Thomas@1848
   248
        /// Gets or sets the message's force protection id (if any).
Thomas@1819
   249
        ///          MailItem : Corresponds to MAPI Property PidNamePEPForceProtection (Header field)
Thomas@1819
   250
        /// CryptableMailItem : not supported
Thomas@1819
   251
        ///       TextMessage : Corresponds with the key PR_PEP_FORCE_PROTECTION_NAME within 'opt_fields' array.
Thomas@1819
   252
        /// </summary>
Thomas@1848
   253
        public string ForceProtectionId
Thomas@1819
   254
        {
Thomas@1848
   255
            get { return (this._ForceProtectionId); }
Thomas@1819
   256
            set
Thomas@1819
   257
            {
Thomas@1848
   258
                this._ForceProtectionId = value;
Thomas@1848
   259
                this.RaisePropertyChangedEvent(nameof(this.ForceProtectionId));
Thomas@1819
   260
            }
Thomas@1819
   261
        }
Thomas@1819
   262
Thomas@1819
   263
        /// <summary>
Dean@1094
   264
        /// Gets or sets the force unencrypted status.
Dean@1094
   265
        ///          MailItem : Corresponds to UserProperty USER_PROPERTY_KEY_FORCE_UNENCRYPTED
Dean@1094
   266
        /// CryptableMailItem : Corresponds to property 'ForceUnencryptedBool'
Dean@1340
   267
        ///       TextMessage : not supported
Dean@1094
   268
        /// </summary>
Dean@1094
   269
        public bool ForceUnencrypted
Dean@1094
   270
        {
Dean@1094
   271
            get { return (this._ForceUnencrypted); }
Dean@1094
   272
            set
Dean@1094
   273
            {
Dean@1094
   274
                this._ForceUnencrypted = value;
Dean@1242
   275
                this.RaisePropertyChangedEvent(nameof(this.ForceUnencrypted));
Dean@1094
   276
            }
Dean@384
   277
        }
Dean@384
   278
Dean@384
   279
        /// <summary>
Dean@384
   280
        /// Gets or sets the from identity of the message.
Dean@384
   281
        /// Warning: this value can be null.
Dean@1094
   282
        ///          MailItem : not supported (calculated from various properties)
Dean@1094
   283
        /// CryptableMailItem : Corresponds to property 'From'
Dean@1348
   284
        ///       TextMessage : Corresponds to property 'From'
Dean@384
   285
        /// </summary>
Dean@384
   286
        public PEPIdentity From
Dean@384
   287
        {
Dean@384
   288
            get { return (this._From); }
Dean@1094
   289
            set
Dean@1094
   290
            {
Dean@1094
   291
                this._From = value;
Dean@1242
   292
                this.RaisePropertyChangedEvent(nameof(this.From));
Dean@1094
   293
            }
Dean@384
   294
        }
Dean@384
   295
Dean@384
   296
        /// <summary>
Dean@384
   297
        /// Gets or sets the ID of the message.
Dean@384
   298
        /// Warning: this value can be null.
Dean@1095
   299
        ///          MailItem : Corresponds to MAPI property PidTagInternetMessageId
Dean@1095
   300
        /// CryptableMailItem : not supported
Dean@1348
   301
        ///       TextMessage : Corresponds to property 'Id'
Dean@384
   302
        /// </summary>
Dean@1348
   303
        public string Id
Dean@384
   304
        {
Dean@1348
   305
            get { return (this._Id); }
Dean@1094
   306
            set
Dean@1094
   307
            {
Dean@1348
   308
                this._Id = value;
Dean@1348
   309
                this.RaisePropertyChangedEvent(nameof(this.Id));
Dean@1094
   310
            }
Dean@384
   311
        }
Dean@384
   312
Dean@384
   313
        /// <summary>
Dean@1330
   314
        /// Gets whether this message is considered secure.
Dean@927
   315
        /// This will forward the call to the static method of the same purpose.
Dean@927
   316
        /// </summary>
Dean@1330
   317
        public bool IsSecure
Dean@927
   318
        {
Dean@1330
   319
            get { return (PEPMessage.GetIsSecure(this)); }
Dean@927
   320
        }
Dean@927
   321
Dean@927
   322
        /// <summary>
Dean@1224
   323
        /// Gets whether this message is secured using PGP/MIME format.
Dean@1224
   324
        /// This will forward the call to the static method of the same purpose.
Dean@1224
   325
        /// </summary>
Dean@1224
   326
        public bool IsPGPMIMEEncrypted
Dean@1224
   327
        {
Dean@1224
   328
            get { return (PEPMessage.GetIsPGPMIMEEncrypted(this)); }
Dean@1224
   329
        }
Dean@1224
   330
Dean@1224
   331
        /// <summary>
Dean@1094
   332
        /// Gets or sets the list of keys associated with this message.
Dean@1094
   333
        /// Commonly this contains the list of decryption keys.
Dean@1094
   334
        /// Warning: Since this is stored as a header field, care must be taken not to apply this to a MailItem on an 
Dean@1094
   335
        /// untrusted server or on an outgoing message.
Dean@1393
   336
        ///          MailItem : Corresponds to MAPI Property PidNameKeyList (Header field)
Dean@1118
   337
        /// CryptableMailItem : not supported
Dean@1393
   338
        ///       TextMessage : Corresponds with the key PR_KEY_LIST_NAME within 'opt_fields' array. 
Dean@1094
   339
        ///                     This is also an out parameter of the decrypt function.
Dean@1094
   340
        /// </summary>
Dean@1094
   341
        public string KeyList
Dean@1094
   342
        {
Dean@1094
   343
            get { return (this._KeyList); }
Dean@1094
   344
            set
Dean@1094
   345
            {
Dean@1094
   346
                this._KeyList = value;
Dean@1242
   347
                this.RaisePropertyChangedEvent(nameof(this.KeyList));
Dean@1094
   348
            }
Dean@1094
   349
        }
Dean@1094
   350
Dean@1094
   351
        /// <summary>
Dean@384
   352
        /// Gets the list of keywords associated with the message.
Dean@1094
   353
        ///          MailItem : Corresponds to property 'Categories'
Dean@1094
   354
        /// CryptableMailItem : not supported
Dean@1348
   355
        ///       TextMessage : Corresponds to property 'Keywords'
Dean@384
   356
        /// </summary>
Dean@384
   357
        public List<string> Keywords
Dean@384
   358
        {
Dean@384
   359
            get { return (this._Keywords); }
Dean@384
   360
        }
Dean@384
   361
Dean@384
   362
        /// <summary>
Dean@1094
   363
        /// Gets or sets the plain text long-form (body) of the message.
Dean@384
   364
        /// Warning: this value can be null.
Dean@1094
   365
        ///          MailItem : Corresponds to property 'Body' (also BodyFormat)
Dean@1094
   366
        /// CryptableMailItem : not exposed (processed internally)
Dean@1348
   367
        ///       TextMessage : Corresponds to property 'LongMsg'
Dean@384
   368
        /// </summary>
Dean@384
   369
        public string LongMsg
Dean@384
   370
        {
Dean@384
   371
            get { return (this._LongMsg); }
Dean@1094
   372
            set
Dean@1094
   373
            {
Dean@1094
   374
                this._LongMsg = value;
Dean@1242
   375
                this.RaisePropertyChangedEvent(nameof(this.LongMsg));
Dean@1094
   376
            }
Dean@384
   377
        }
Dean@384
   378
Dean@384
   379
        /// <summary>
Dean@697
   380
        /// Gets or sets the HTML formatted long-form (body) of the message.
Dean@384
   381
        /// Warning: this value can be null.
Dean@1094
   382
        ///          MailItem : Corresponds to property 'HTMLBody' (also BodyFormat)
Dean@1094
   383
        /// CryptableMailItem : not exposed (processed internally)
Dean@1348
   384
        ///       TextMessage : Corresponds to property 'LongMsgFormatted'
Dean@384
   385
        /// </summary>
Dean@1354
   386
        public string LongMsgFormattedHtml
Dean@384
   387
        {
Dean@1354
   388
            get { return (this._LongMsgFormattedHtml); }
Dean@1094
   389
            set
Dean@1094
   390
            {
Dean@1354
   391
                this._LongMsgFormattedHtml = value;
Dean@1354
   392
                this.RaisePropertyChangedEvent(nameof(this.LongMsgFormattedHtml));
Dean@1094
   393
            }
Dean@697
   394
        }
Dean@697
   395
Dean@697
   396
        /// <summary>
Dean@697
   397
        /// Gets or sets the RTF formatted long-form (body) of the message.
Dean@1094
   398
        /// Warning: this value can be null, it is only supported when creating from a MailItem. It is
Dean@1094
   399
        /// not applied to a MailItem during .ApplyTo as it's unsupported by the engine.
Dean@1094
   400
        ///          MailItem : Corresponds to property 'RTFBody' (also BodyFormat)
Dean@1094
   401
        /// CryptableMailItem : not exposed (processed internally)
Dean@1340
   402
        ///       TextMessage : not supported
Dean@697
   403
        /// </summary>
Dean@1354
   404
        public string LongMsgFormattedRtf
Dean@697
   405
        {
Dean@1354
   406
            get { return (this._LongMsgFormattedRtf); }
Dean@1094
   407
            set
Dean@1094
   408
            {
Dean@1354
   409
                this._LongMsgFormattedRtf = value;
Dean@1354
   410
                this.RaisePropertyChangedEvent(nameof(this.LongMsgFormattedRtf));
Dean@1094
   411
            }
Dean@384
   412
        }
Dean@384
   413
Dean@384
   414
        /// <summary>
Dean@1104
   415
        /// Gets or sets whether this message is marked to never be unsecure.
Dean@1104
   416
        /// Note: While this is stored as a header field, it is OK to apply to any MailItem and outgoing messages.
Dean@1104
   417
        /// It's intended function is to flag a message to keep it encrypted.
Dean@1393
   418
        ///          MailItem : Corresponds to MAPI Property PidNamePEPNeverUnsecure (Header field)
Dean@1104
   419
        /// CryptableMailItem : Corresponds to property 'NeverUnsecure'
Dean@1340
   420
        ///       TextMessage : not supported
Dean@1104
   421
        /// </summary>
Dean@1104
   422
        public bool NeverUnsecure
Dean@1104
   423
        {
Dean@1104
   424
            get { return (this._NeverUnsecure); }
Dean@1104
   425
            set
Dean@1104
   426
            {
Dean@1104
   427
                this._NeverUnsecure = value;
Dean@1242
   428
                this.RaisePropertyChangedEvent(nameof(this.NeverUnsecure));
Dean@1104
   429
            }
Dean@1104
   430
        }
Dean@1104
   431
Thomas@2012
   432
        /// <summary>
Thomas@2012
   433
        /// Gets the outgoing rating of this message.
Thomas@2012
   434
        /// </summary>
Thomas@2010
   435
        public pEpRating OutgoingRating
Thomas@2010
   436
        {
Thomas@2010
   437
            get
Thomas@2010
   438
            {
Thomas@2010
   439
                pEpRating rating = pEpRating.pEpRatingUndefined;
Thomas@2010
   440
Thomas@2010
   441
#if READER_RELEASE_MODE
Thomas@2010
   442
                // If reader mode, always unencrypted
Thomas@2010
   443
                rating = pEpRating.pEpRatingUnencrypted;
Thomas@2010
   444
#else
Thomas@2010
   445
                if (this.ForceUnencrypted)
Thomas@2010
   446
                {
Thomas@2010
   447
                    rating = pEpRating.pEpRatingUnencrypted;
Thomas@2010
   448
                }
Thomas@2010
   449
                else if (string.IsNullOrEmpty(this.ForceProtectionId) == false)
Thomas@2010
   450
                {
Thomas@2010
   451
                    rating = pEpRating.pEpRatingReliable;
Thomas@2010
   452
                }
Thomas@2010
   453
                else
Thomas@2010
   454
                {
Thomas@2010
   455
                    PEPMessage workingMessage = this.Copy();
Thomas@2010
   456
                    workingMessage.FlattenAllRecipientIdentities();
Thomas@2010
   457
                    workingMessage.Direction = pEpMsgDirection.pEpDirOutgoing;
Thomas@2010
   458
Thomas@2010
   459
                    try
Thomas@2010
   460
                    {
Thomas@2010
   461
                        rating = ThisAddIn.PEPEngine.OutgoingMessageRating(workingMessage.ToCOMType());
Thomas@2010
   462
                    }
Thomas@2010
   463
                    catch (Exception ex)
Thomas@2010
   464
                    {
Thomas@2010
   465
                        rating = pEpRating.pEpRatingUndefined;
Thomas@2010
   466
                        Log.Error("OutgoingRating: Error getting outgoing rating from engine. " + ex.ToString());
Thomas@2010
   467
                    }
Thomas@2010
   468
                }
Thomas@2010
   469
#endif
Thomas@2010
   470
                return rating;
Thomas@2010
   471
            }
Thomas@2010
   472
        }
Thomas@2010
   473
Dean@1104
   474
        /// <summary>
Dean@1212
   475
        /// Gets or sets the pEp protocol (or 'format') version of this message.
Dean@1212
   476
        /// This is not to be confused with pEp engine version which can be different.
Dean@1094
   477
        /// This is commonly set after decryption.
Dean@1094
   478
        /// Note: While this is stored as a header field, it is OK to apply to any MailItem and outgoing messages.
Dean@1094
   479
        /// It's intended function is just to show the version of pEp last used to process the message.
Dean@1393
   480
        ///          MailItem : Corresponds to MAPI Property PidNamePEPProtocolVersion (Header field)
Dean@1094
   481
        /// CryptableMailItem : not supported
Dean@1393
   482
        ///       TextMessage : Corresponds with the key PR_PEP_PROTOCOL_VERSION_NAME within 'opt_fields' array. 
Dean@384
   483
        /// </summary>
Dean@1212
   484
        public string PEPProtocolVersion
Dean@384
   485
        {
Dean@1212
   486
            get { return (this._PEPProtocolVersion); }
Dean@1094
   487
            set
Dean@1094
   488
            {
Dean@1212
   489
                this._PEPProtocolVersion = value;
Dean@1242
   490
                this.RaisePropertyChangedEvent(nameof(this.PEPProtocolVersion));
Dean@1094
   491
            }
Dean@384
   492
        }
Dean@384
   493
Dean@384
   494
        /// <summary>
Dean@1303
   495
        /// Gets or sets the pEp rating of the message.
Dean@1303
   496
        /// This should corresponds primarily with the decryption rating.
Dean@1303
   497
        /// Warning: Since this is stored as a header field, care must be taken not to apply this to a MailItem on an 
Dean@1303
   498
        /// untrusted server or on an outgoing message.
Dean@1393
   499
        ///          MailItem : Corresponds to MAPI Property PidNameEncStatus (Header field)
Dean@1303
   500
        /// CryptableMailItem : not exposed (processed internally)
Dean@1393
   501
        ///       TextMessage : Corresponds with the key PR_ENC_STATUS_NAME within 'opt_fields' array
Dean@1303
   502
        /// </summary>
markus@1337
   503
        public pEpRating Rating
Dean@1303
   504
        {
Dean@1303
   505
            get { return (this._Rating); }
Dean@1303
   506
            set
Dean@1303
   507
            {
Dean@1303
   508
                this._Rating = value;
Dean@1303
   509
                this.RaisePropertyChangedEvent(nameof(this.Rating));
Dean@1303
   510
            }
Dean@1303
   511
        }
Dean@1303
   512
Dean@1303
   513
        /// <summary>
Dean@721
   514
        /// Gets or sets the date and time when the message was received.
Dean@1094
   515
        ///          MailItem : Corresponds to property 'ReceivedTime'
Dean@1094
   516
        /// CryptableMailItem : not supported
Dean@1340
   517
        ///       TextMessage : Corresponds to property 'recv'
Dean@721
   518
        /// </summary>
Dean@721
   519
        public DateTime? ReceivedOn
Dean@721
   520
        {
Dean@721
   521
            get { return (this._ReceivedOn); }
Dean@1094
   522
            set
Dean@1094
   523
            {
Dean@1094
   524
                this._ReceivedOn = value;
Dean@1242
   525
                this.RaisePropertyChangedEvent(nameof(this.ReceivedOn));
Dean@1094
   526
            }
Dean@721
   527
        }
Dean@721
   528
Dean@721
   529
        /// <summary>
Dean@721
   530
        /// Gets or sets the date and time when the message was sent.
Dean@1094
   531
        ///          MailItem : Corresponds to property 'SentOn'
Dean@1094
   532
        /// CryptableMailItem : not supported
Dean@1340
   533
        ///       TextMessage : Corresponds to property 'sent'
Dean@721
   534
        /// </summary>
Dean@721
   535
        public DateTime? SentOn
Dean@721
   536
        {
Dean@721
   537
            get { return (this._SentOn); }
Dean@1094
   538
            set
Dean@1094
   539
            {
Dean@1094
   540
                this._SentOn = value;
Dean@1242
   541
                this.RaisePropertyChangedEvent(nameof(this.SentOn));
Dean@1094
   542
            }
Dean@721
   543
        }
Dean@721
   544
Dean@721
   545
        /// <summary>
Dean@384
   546
        /// Gets or sets the short-form (subject) of the message.
Dean@384
   547
        /// Warning: this value can be null.
Dean@1094
   548
        ///          MailItem : Corresponds to property 'Subject'
Dean@1094
   549
        /// CryptableMailItem : not supported
Dean@1348
   550
        ///       TextMessage : Corresponds to property 'Shortmsg'
Dean@384
   551
        /// </summary>
Dean@384
   552
        public string ShortMsg
Dean@384
   553
        {
Dean@384
   554
            get { return (this._ShortMsg); }
Dean@1094
   555
            set
Dean@1094
   556
            {
Dean@1094
   557
                this._ShortMsg = value;
Dean@1242
   558
                this.RaisePropertyChangedEvent(nameof(this.ShortMsg));
Dean@1094
   559
            }
Dean@384
   560
        }
Dean@384
   561
Dean@384
   562
        /// <summary>
Dean@384
   563
        /// Gets the list of identities to receive the message.
Dean@1094
   564
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   565
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1348
   566
        ///       TextMessage : Corresponds to property 'To'
Dean@384
   567
        /// </summary>
Dean@384
   568
        public List<PEPIdentity> To
Dean@384
   569
        {
Dean@384
   570
            get { return (this._To); }
Dean@384
   571
        }
Dean@384
   572
Dean@625
   573
        /// <summary>
Dean@1348
   574
        /// Gets the total number of all recipients in the message (Bcc, Cc &amp; To).
Dean@625
   575
        /// </summary>
Dean@625
   576
        public int RecipientCount
Dean@625
   577
        {
Dean@1348
   578
            get { return (this._Bcc.Count + this._Cc.Count + this._To.Count); }
Dean@625
   579
        }
Dean@625
   580
Dean@625
   581
        /// <summary>
Dean@1348
   582
        /// Gets a list of all recipients in the message (Bcc, Cc &amp; To).
Dean@625
   583
        /// Each recipient in the returned list is a copy.
Dean@625
   584
        /// </summary>
Dean@625
   585
        public PEPIdentity[] Recipients
Dean@625
   586
        {
Dean@625
   587
            get
Dean@625
   588
            {
Dean@625
   589
                List<PEPIdentity> recipients = new List<PEPIdentity>();
Dean@625
   590
Dean@1348
   591
                // Bcc
Dean@1348
   592
                for (int i = 0; i < this._Bcc.Count; i++)
Dean@625
   593
                {
Dean@1348
   594
                    recipients.Add(this._Bcc[i].Copy());
Dean@625
   595
                }
Dean@625
   596
Dean@1348
   597
                // Cc
Dean@1348
   598
                for (int i = 0; i < this._Cc.Count; i++)
Dean@625
   599
                {
Dean@1348
   600
                    recipients.Add(this._Cc[i].Copy());
Dean@625
   601
                }
Dean@625
   602
Dean@625
   603
                // To
Dean@625
   604
                for (int i = 0; i < this._To.Count; i++)
Dean@625
   605
                {
Dean@625
   606
                    recipients.Add(this._To[i].Copy());
Dean@625
   607
                }
Dean@625
   608
Dean@625
   609
                return (recipients.ToArray());
Dean@625
   610
            }
Dean@625
   611
        }
Dean@625
   612
Thomas@2010
   613
#endregion
Dean@910
   614
Dean@384
   615
        /**************************************************************
Dean@384
   616
         * 
Dean@384
   617
         * Methods
Dean@384
   618
         * 
Dean@384
   619
         *************************************************************/
Dean@384
   620
Dean@384
   621
        /// <summary>
Dean@1094
   622
        /// Raises the property changed event, if possible, with the given arguments.
Dean@1094
   623
        /// </summary>
Dean@1094
   624
        /// <param name="propertyName">The name of the property that changed.</param>
Dean@1094
   625
        private void RaisePropertyChangedEvent(string propertyName)
Dean@1094
   626
        {
Dean@1244
   627
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Dean@1094
   628
            return;
Dean@1094
   629
        }
Thomas@2017
   630
        
Dean@1094
   631
        /// <summary>
markus@1337
   632
        /// Returns this pEp message as a new pEp engine TextMessage struct.
Dean@910
   633
        /// Warning: Any identity members (groups) are lost, call FlattenAllRecipientIdentities() before this method.
Dean@384
   634
        /// </summary>
Dean@1094
   635
        /// <param name="alwaysAddOptFields">Whether to always add optional fields (default is false). When false, 
Dean@1094
   636
        /// optional fields will not be added if they are undefined/null/empty in the PEPMessage. This is to prevent 
Dean@1094
   637
        /// against adding optional fields when they have never been set.
Dean@1094
   638
        /// </param>
Dean@384
   639
        /// <returns>A pEp engine identity.</returns>
markus@1337
   640
        public TextMessage ToCOMType(bool alwaysAddOptFields = false)
Dean@384
   641
        {
Dean@1095
   642
            long recvSec;
Dean@1095
   643
            long sentSec;
Dean@1095
   644
            TimeSpan span;
markus@1337
   645
            List<Blob> attachments = new List<Blob>();
markus@1337
   646
            List<pEpIdentity> bcc = new List<pEpIdentity>();
markus@1337
   647
            List<pEpIdentity> cc = new List<pEpIdentity>();
markus@1337
   648
            List<pEpIdentity> to = new List<pEpIdentity>();
markus@1337
   649
            List<StringPair> optionalFields = new List<StringPair>();
markus@1337
   650
            StringPair field;
markus@1337
   651
            TextMessage result = new TextMessage();
Dean@384
   652
Dean@388
   653
            // Convert attachments
Dean@384
   654
            for (int i = 0; i < this._Attachments.Count; i++)
Dean@384
   655
            {
Dean@384
   656
                attachments.Add(this._Attachments[i].ToCOMType());
Dean@384
   657
            }
Dean@398
   658
Dean@1348
   659
            // Convert Bcc
Dean@1348
   660
            for (int i = 0; i < this._Bcc.Count; i++)
Dean@384
   661
            {
Dean@1348
   662
                bcc.Add(this._Bcc[i].ToCOMType());
Dean@384
   663
            }
Dean@398
   664
Dean@1348
   665
            // Convert Cc
Dean@1348
   666
            for (int i = 0; i < this._Cc.Count; i++)
Dean@384
   667
            {
Dean@1348
   668
                cc.Add(this._Cc[i].ToCOMType());
Dean@384
   669
            }
Dean@398
   670
Dean@388
   671
            // Convert To
Dean@388
   672
            for (int i = 0; i < this._To.Count; i++)
Dean@388
   673
            {
Dean@388
   674
                to.Add(this._To[i].ToCOMType());
Dean@388
   675
            }
Dean@388
   676
Dean@1094
   677
            // Create optional fields
Dean@1094
   678
            if ((alwaysAddOptFields) ||
Dean@1393
   679
                (string.IsNullOrEmpty(this._AutoConsume) == false))
Dean@1094
   680
            {
markus@1337
   681
                field = new StringPair();
Dean@1393
   682
                field.Name = PEPMessage.PR_PEP_AUTO_CONSUME_NAME;
Dean@1393
   683
                field.Value = this._AutoConsume;
Dean@1094
   684
                optionalFields.Add(field);
Dean@1094
   685
            }
Dean@1094
   686
Dean@1094
   687
            if ((alwaysAddOptFields) ||
Thomas@1848
   688
                (string.IsNullOrEmpty(this._ForceProtectionId) == false))
Thomas@1819
   689
            {
Thomas@1819
   690
                field = new StringPair();
Thomas@1819
   691
                field.Name = PEPMessage.PR_PEP_FORCE_PROTECTION_NAME;
Thomas@1848
   692
                field.Value = this._ForceProtectionId;
Thomas@1819
   693
                optionalFields.Add(field);
Thomas@1819
   694
            }
Thomas@1819
   695
Thomas@1819
   696
            if ((alwaysAddOptFields) ||
Dean@1094
   697
                (string.IsNullOrEmpty(this._KeyList) == false))
Dean@1094
   698
            {
markus@1337
   699
                field = new StringPair();
Dean@1393
   700
                field.Name = PEPMessage.PR_KEY_LIST_NAME;
markus@1347
   701
                field.Value = this._KeyList;
Dean@1094
   702
                optionalFields.Add(field);
Dean@1094
   703
            }
Dean@1094
   704
Dean@1094
   705
            if ((alwaysAddOptFields) ||
Dean@1104
   706
                (this._NeverUnsecure == true))
Dean@1095
   707
            {
markus@1337
   708
                field = new StringPair();
Dean@1393
   709
                field.Name = PEPMessage.PR_PEP_NEVER_UNSECURE_NAME;
Dean@1435
   710
                field.Value = PEPMessage.PR_PEP_NEVER_UNSECURE_VALUE;
Dean@1095
   711
                optionalFields.Add(field);
Dean@1095
   712
            }
Dean@1095
   713
Dean@1095
   714
            if ((alwaysAddOptFields) ||
Dean@1212
   715
                (string.IsNullOrEmpty(this._PEPProtocolVersion) == false))
Dean@1094
   716
            {
markus@1337
   717
                field = new StringPair();
Dean@1393
   718
                field.Name = PEPMessage.PR_PEP_PROTOCOL_VERSION_NAME;
markus@1347
   719
                field.Value = this._PEPProtocolVersion;
Dean@1094
   720
                optionalFields.Add(field);
Dean@1094
   721
            }
Dean@1409
   722
Dean@1393
   723
            if ((alwaysAddOptFields) ||
Dean@1393
   724
                (this._Rating != pEpRating.pEpRatingUndefined))
Dean@1393
   725
            {
Dean@1393
   726
                field = new StringPair();
Dean@1393
   727
                field.Name = PEPMessage.PR_ENC_STATUS_NAME;
Dean@1393
   728
                field.Value = this._Rating.ToEngineString();
Dean@1393
   729
                optionalFields.Add(field);
Dean@1393
   730
            }
Dean@1409
   731
Dean@1095
   732
            // ReceivedOn
Dean@1095
   733
            recvSec = -1;
Dean@1095
   734
            if (this._ReceivedOn != null)
Dean@1095
   735
            {
Thomas@1649
   736
                DateTime receivedOnUtc;
Thomas@1649
   737
                try
Thomas@1649
   738
                {
Thomas@1649
   739
                    receivedOnUtc = TimeZoneInfo.ConvertTimeToUtc((DateTime)this._ReceivedOn);
Thomas@1649
   740
                }
Thomas@1936
   741
                catch (Exception ex)
Thomas@1649
   742
                {
Thomas@1936
   743
                    Log.Verbose("PEPMessage.ToCOMType: Error converting received time to UTC. " + ex.ToString());
Thomas@1649
   744
                    receivedOnUtc = (DateTime)this._ReceivedOn;
Thomas@1649
   745
                }
Thomas@1649
   746
                span = receivedOnUtc - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
Dean@1095
   747
                recvSec = (long)span.TotalSeconds;
Dean@1095
   748
            }
Dean@1095
   749
Dean@1095
   750
            // SentOn
Dean@1095
   751
            sentSec = -1;
Dean@1095
   752
            if (this._SentOn != null)
Dean@1095
   753
            {
Thomas@1649
   754
                DateTime sentOnUtc;
Thomas@1649
   755
                try
Thomas@1649
   756
                {
Thomas@1649
   757
                    sentOnUtc = TimeZoneInfo.ConvertTimeToUtc((DateTime)this._SentOn);
Thomas@1649
   758
                }
Thomas@1936
   759
                catch (Exception ex)
Thomas@1649
   760
                {
Thomas@1936
   761
                    Log.Verbose("PEPMessage.ToCOMType: Error converting sent time to UTC. " + ex.ToString());
Thomas@1649
   762
                    sentOnUtc = (DateTime)this._SentOn;
Thomas@1649
   763
                }
Thomas@1649
   764
                span = sentOnUtc - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
Dean@1095
   765
                sentSec = (long)span.TotalSeconds;
Dean@1095
   766
            }
Dean@1095
   767
markus@1337
   768
            /* Note: Skip the following properties which are not supported in TextMessage
Dean@1354
   769
             *   • ConversationId
Dean@1113
   770
             *   • ConversationIndex
Dean@1113
   771
             *   • ConversationTopic
Thomas@1817
   772
             *   • EnableProtection
Dean@1094
   773
             *   • ForceUnencrypted
Dean@1354
   774
             *   • LongMsgFormattedRtf
Dean@1095
   775
             * 
Dean@1095
   776
             * Also not the following are handled as optional fields
Dean@1130
   777
             *   • Rating
Thomas@1819
   778
             *   • ForceProtection
Dean@1104
   779
             *   • NeverUnsecure
Dean@1095
   780
             *   • KeyList
Dean@1212
   781
             *   • PEPProtocolVersion
Dean@1095
   782
             * 
markus@1337
   783
             * This also skips a number of TextMessage properties currently unsupported in PEPMessage.
Dean@697
   784
             */
markus@1347
   785
            result.Attachments = attachments.ToArray();
markus@1347
   786
            result.Bcc = bcc.ToArray();
markus@1347
   787
            result.Cc = cc.ToArray();
markus@1347
   788
            result.Dir = this._Direction;
markus@1347
   789
            result.From = (this._From != null ? this._From.ToCOMType() : result.From);
Dean@1348
   790
            result.Id = this._Id;
markus@1347
   791
            result.Keywords = this._Keywords.ToArray();
markus@1356
   792
            result.LongMsg = this._LongMsg;
markus@1356
   793
            result.LongMsgFormatted = this._LongMsgFormattedHtml;
markus@1347
   794
            result.OptFields = optionalFields.ToArray();
markus@1347
   795
            result.Recv = ((recvSec >= 0) ? recvSec : result.Recv);
markus@1347
   796
            result.Sent = ((sentSec >= 0) ? sentSec : result.Sent);
markus@1356
   797
            result.ShortMsg = this._ShortMsg;
markus@1347
   798
            result.To = to.ToArray();
Dean@384
   799
Dean@384
   800
            return (result);
Dean@384
   801
        }
Dean@384
   802
Dean@384
   803
        /// <summary>
Thomas@1849
   804
        /// Converts a PEPMessage into a MimeKit.MimeMessage.
Thomas@1841
   805
        /// </summary>
Thomas@1849
   806
        /// <param name="pEpMessage">The PEPMessage to convert.</param>
Thomas@1849
   807
        /// <param name="mimeMessage">The created MimeMessage.</param>
Thomas@1849
   808
        /// <returns>The status of this method.</returns>
Thomas@1849
   809
        public static Globals.ReturnStatus ToMIMEMessage(PEPMessage pEpMessage, out MimeMessage mimeMessage)
Thomas@1841
   810
        {
Thomas@1849
   811
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Thomas@1841
   812
            MimeMessage message = new MimeMessage();
Thomas@1841
   813
            BodyBuilder bodyBuilder = new BodyBuilder();
Thomas@1841
   814
Thomas@1841
   815
            // Convert TextMessage to MimeMessage
Thomas@1841
   816
            // Add attachments to body builder
Thomas@1849
   817
            for (int i = 0; i < pEpMessage.Attachments?.Count; i++)
Thomas@1841
   818
            {
Thomas@1849
   819
                try
Thomas@1849
   820
                {
Thomas@1849
   821
                    PEPAttachment currentAttachment = pEpMessage.Attachments[i];
Thomas@1850
   822
                    MimePart messageAttachment = bodyBuilder.Attachments.Add(currentAttachment.FileName, currentAttachment.Data) as MimePart;
Thomas@1841
   823
Thomas@1850
   824
                    // In case of inline attachments, add content id
Thomas@1849
   825
                    if (string.IsNullOrEmpty(currentAttachment.ContentId) == false)
Thomas@1849
   826
                    {
Thomas@1849
   827
                        messageAttachment.ContentId = currentAttachment.ContentId;
Thomas@1850
   828
                        messageAttachment.ContentDisposition = new ContentDisposition(ContentDisposition.Inline);
Thomas@1849
   829
                    }
Thomas@1841
   830
                }
Thomas@1849
   831
                catch (Exception ex)
Thomas@1849
   832
                {
Thomas@1849
   833
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   834
                    Log.Error("ToMIMEMessage: Error parsing attachment. " + ex.ToString());
Thomas@1849
   835
                }
Thomas@1841
   836
            }
Thomas@1841
   837
Thomas@1841
   838
            // Add body to body builder
Thomas@1849
   839
            bodyBuilder.TextBody = pEpMessage.LongMsg;
Thomas@1849
   840
            bodyBuilder.HtmlBody = pEpMessage.LongMsgFormattedHtml;
Thomas@1841
   841
Thomas@1841
   842
            // Add attachments and body to message
Thomas@1841
   843
            message.Body = bodyBuilder.ToMessageBody();
Thomas@1841
   844
Thomas@1841
   845
            // Process recipients
Thomas@1841
   846
            // BCC
Thomas@1849
   847
            for (int i = 0; i < pEpMessage.Bcc?.Count; i++)
Thomas@1841
   848
            {
Thomas@1841
   849
                InternetAddress address;
Thomas@1849
   850
                try
Thomas@1841
   851
                {
Thomas@1849
   852
                    if (InternetAddress.TryParse(pEpMessage.Bcc[i].Address, out address))
Thomas@1849
   853
                    {
Thomas@1849
   854
                        address.Name = pEpMessage.Bcc[i].UserName;
Thomas@1849
   855
                        message.Bcc.Add(address);
Thomas@1849
   856
                    }
Thomas@1849
   857
                }
Thomas@1849
   858
                catch (Exception ex)
Thomas@1849
   859
                {
Thomas@1849
   860
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   861
                    Log.Error("ToMIMEMessage: Error parsing BCC identity. " + ex.ToString());
Thomas@1841
   862
                }
Thomas@1841
   863
            }
Thomas@1841
   864
Thomas@1841
   865
            // CC
Thomas@1849
   866
            for (int i = 0; i < pEpMessage.Cc?.Count; i++)
Thomas@1841
   867
            {
Thomas@1841
   868
                InternetAddress address;
Thomas@1849
   869
                try
Thomas@1841
   870
                {
Thomas@1849
   871
                    if (InternetAddress.TryParse(pEpMessage.Cc[i].Address, out address))
Thomas@1849
   872
                    {
Thomas@1849
   873
                        address.Name = pEpMessage.Cc[i].UserName;
Thomas@1849
   874
                        message.Cc.Add(address);
Thomas@1849
   875
                    }
Thomas@1849
   876
                }
Thomas@1849
   877
                catch (Exception ex)
Thomas@1849
   878
                {
Thomas@1849
   879
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   880
                    Log.Error("ToMIMEMessage: Error parsing CC identity. " + ex.ToString());
Thomas@1841
   881
                }
Thomas@1841
   882
            }
Thomas@1841
   883
Thomas@1841
   884
            // To
Thomas@1849
   885
            for (int i = 0; i < pEpMessage.To?.Count; i++)
Thomas@1841
   886
            {
Thomas@1841
   887
                InternetAddress address;
Thomas@1849
   888
                try
Thomas@1841
   889
                {
Thomas@1849
   890
                    if (InternetAddress.TryParse(pEpMessage.To[i].Address, out address))
Thomas@1849
   891
                    {
Thomas@1849
   892
                        address.Name = pEpMessage.To[i].UserName;
Thomas@1849
   893
                        message.To.Add(address);
Thomas@1849
   894
                    }
Thomas@1849
   895
                }
Thomas@1849
   896
                catch (Exception ex)
Thomas@1849
   897
                {
Thomas@1849
   898
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   899
                    Log.Error("ToMIMEMessage: Error parsing To identity. " + ex.ToString());
Thomas@1841
   900
                }
Thomas@1841
   901
            }
Thomas@1841
   902
Thomas@1841
   903
            // From
Thomas@1841
   904
            InternetAddress from;
Thomas@1849
   905
            try
Thomas@1841
   906
            {
Thomas@1849
   907
                if (InternetAddress.TryParse(pEpMessage.From.Address, out from))
Thomas@1849
   908
                {
Thomas@1849
   909
                    from.Name = pEpMessage.From.UserName;
Thomas@1849
   910
                    message.From.Add(from);
Thomas@1849
   911
                }
Thomas@1849
   912
            }
Thomas@1849
   913
            catch (Exception ex)
Thomas@1849
   914
            {
Thomas@1849
   915
                status = Globals.ReturnStatus.Failure;
Thomas@1849
   916
                Log.Error("ToMIMEMessage: Error parsing From identity. " + ex.ToString());
Thomas@1841
   917
            }
Thomas@1841
   918
Thomas@1841
   919
            // Message ID
Thomas@1849
   920
            if (string.IsNullOrEmpty(pEpMessage.Id) == false)
Thomas@1841
   921
            {
Thomas@1849
   922
                message.MessageId = pEpMessage.Id;
Thomas@1841
   923
            }
Thomas@1841
   924
Thomas@1841
   925
            // Subject
Thomas@1849
   926
            if (string.IsNullOrEmpty(pEpMessage.ShortMsg) == false)
Thomas@1841
   927
            {
Thomas@1849
   928
                message.Subject = pEpMessage.ShortMsg;
Thomas@1841
   929
            }
Thomas@1841
   930
Thomas@1849
   931
            // Add pEp header fields
Thomas@1849
   932
            if (string.IsNullOrEmpty(pEpMessage.AutoConsume) == false)
Thomas@1841
   933
            {
Thomas@1849
   934
                try
Thomas@1849
   935
                {
Thomas@1849
   936
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_PEP_AUTO_CONSUME_NAME, pEpMessage.AutoConsume);
Thomas@1849
   937
                    message.Headers.Add(header);
Thomas@1849
   938
                }
Thomas@1849
   939
                catch (Exception ex)
Thomas@1849
   940
                {
Thomas@1849
   941
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   942
                    Log.Error("ToMIMEMessage: Error adding AutoConsume header. " + ex.ToString());
Thomas@1849
   943
                }
Thomas@1849
   944
            }
Thomas@1849
   945
Thomas@1849
   946
            if (string.IsNullOrEmpty(pEpMessage.ForceProtectionId) == false)
Thomas@1849
   947
            {
Thomas@1849
   948
                try
Thomas@1849
   949
                {
Thomas@1849
   950
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_PEP_FORCE_PROTECTION_NAME, pEpMessage.ForceProtectionId);
Thomas@1849
   951
                    message.Headers.Add(header);
Thomas@1849
   952
                }
Thomas@1849
   953
                catch (Exception ex)
Thomas@1849
   954
                {
Thomas@1849
   955
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   956
                    Log.Error("ToMIMEMessage: Error adding ForceProtection header. " + ex.ToString());
Thomas@1849
   957
                }
Thomas@1849
   958
            }
Thomas@1849
   959
Thomas@1849
   960
            if (string.IsNullOrEmpty(pEpMessage.KeyList) == false)
Thomas@1849
   961
            {
Thomas@1849
   962
                try
Thomas@1849
   963
                {
Thomas@1849
   964
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_KEY_LIST_NAME, pEpMessage.KeyList);
Thomas@1849
   965
                    message.Headers.Add(header);
Thomas@1849
   966
                }
Thomas@1849
   967
                catch (Exception ex)
Thomas@1849
   968
                {
Thomas@1849
   969
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   970
                    Log.Error("ToMIMEMessage: Error adding KeyList header. " + ex.ToString());
Thomas@1849
   971
                }
Thomas@1849
   972
            }
Thomas@1849
   973
Thomas@1849
   974
            if (pEpMessage.NeverUnsecure)
Thomas@1849
   975
            {
Thomas@1849
   976
                try
Thomas@1849
   977
                {
Thomas@1849
   978
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_PEP_NEVER_UNSECURE_NAME, PEPMessage.PR_PEP_NEVER_UNSECURE_VALUE);
Thomas@1849
   979
                    message.Headers.Add(header);
Thomas@1849
   980
                }
Thomas@1849
   981
                catch (Exception ex)
Thomas@1849
   982
                {
Thomas@1849
   983
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   984
                    Log.Error("ToMIMEMessage: Error adding NeverUnsecure header. " + ex.ToString());
Thomas@1849
   985
                }
Thomas@1849
   986
            }
Thomas@1849
   987
Thomas@1849
   988
            if (string.IsNullOrEmpty(pEpMessage.PEPProtocolVersion) == false)
Thomas@1849
   989
            {
Thomas@1849
   990
                try
Thomas@1849
   991
                {
Thomas@1849
   992
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_PEP_PROTOCOL_VERSION_NAME, pEpMessage.PEPProtocolVersion);
Thomas@1849
   993
                    message.Headers.Add(header);
Thomas@1849
   994
                }
Thomas@1849
   995
                catch (Exception ex)
Thomas@1849
   996
                {
Thomas@1849
   997
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
   998
                    Log.Error("ToMIMEMessage: Error adding AutConsume header. " + ex.ToString());
Thomas@1849
   999
                }
Thomas@1849
  1000
            }
Thomas@1849
  1001
Thomas@1849
  1002
            if (pEpMessage.Rating != pEpRating.pEpRatingUndefined)
Thomas@1849
  1003
            {
Thomas@1849
  1004
                try
Thomas@1849
  1005
                {
Thomas@1849
  1006
                    Header header = new Header(Encoding.Unicode, PEPMessage.PR_ENC_STATUS_NAME, pEpMessage.Rating.ToEngineString());
Thomas@1849
  1007
                    message.Headers.Add(header);
Thomas@1849
  1008
                }
Thomas@1849
  1009
                catch (Exception ex)
Thomas@1849
  1010
                {
Thomas@1849
  1011
                    status = Globals.ReturnStatus.Failure;
Thomas@1849
  1012
                    Log.Error("ToMIMEMessage: Error adding AutConsume header. " + ex.ToString());
Thomas@1849
  1013
                }
Thomas@1841
  1014
            }
Thomas@1841
  1015
Thomas@1841
  1016
            // Message date
Thomas@1849
  1017
            try
Thomas@1841
  1018
            {
Thomas@1849
  1019
                if (pEpMessage.ReceivedOn != null)
Thomas@1849
  1020
                {
Thomas@1849
  1021
                    message.Date = new DateTimeOffset((DateTime)pEpMessage.ReceivedOn, TimeSpan.Zero);
Thomas@1849
  1022
                }
Thomas@1849
  1023
                else if (pEpMessage.SentOn != null)
Thomas@1849
  1024
                {
Thomas@1849
  1025
                    message.Date = new DateTimeOffset((DateTime)pEpMessage.SentOn, TimeSpan.Zero);
Thomas@1849
  1026
                }
Thomas@1841
  1027
            }
Thomas@1849
  1028
            catch (Exception ex)
Thomas@1841
  1029
            {
Thomas@1849
  1030
                status = Globals.ReturnStatus.Failure;
Thomas@1849
  1031
                Log.Error("ToMIMEMessage: Error setting message date. " + ex.ToString());
Thomas@1841
  1032
            }
Thomas@1841
  1033
Thomas@1849
  1034
            // Return MimeMessage
Thomas@1849
  1035
            mimeMessage = message;
Thomas@1841
  1036
Thomas@1849
  1037
            return status;
Thomas@1841
  1038
        }
Thomas@1841
  1039
Thomas@1841
  1040
        /// <summary>
Dean@1238
  1041
        /// Serves as a hash function for a particular type.
Dean@1238
  1042
        /// </summary>
Dean@1238
  1043
        /// <returns>A hash code for the current object.</returns>
Dean@1238
  1044
        public override int GetHashCode()
Dean@1238
  1045
        {
Dean@1238
  1046
            return base.GetHashCode();
Dean@1238
  1047
        }
Dean@1238
  1048
Dean@1238
  1049
        /// <summary>
Dean@1238
  1050
        /// Indicates whether the current object is equal to another object of the same type.
Dean@1238
  1051
        /// </summary>
Dean@1238
  1052
        /// <param name="obj">The object to check equality with.</param>
Dean@1238
  1053
        /// <returns>True if both objects are considered equal, otherwise false.</returns>
Dean@1238
  1054
        public override bool Equals(object obj)
Dean@1238
  1055
        {
Dean@1238
  1056
            if ((obj == null) ||
Dean@1238
  1057
                !(obj is PEPMessage))
Dean@1238
  1058
            {
Dean@1238
  1059
                return (false);
Dean@1238
  1060
            }
Dean@1238
  1061
Dean@1238
  1062
            return (this.Equals((PEPMessage)obj));
Dean@1238
  1063
        }
Dean@1238
  1064
Dean@1238
  1065
        /// <summary>
Dean@1238
  1066
        /// Indicates whether the current object is equal to another object of the same type.
Dean@1238
  1067
        /// </summary>
Dean@1238
  1068
        /// <param name="obj">The object to check equality with.</param>
Dean@1238
  1069
        /// <returns>True if both objects are considered equal, otherwise false.</returns>
Dean@1238
  1070
        public bool Equals(PEPMessage obj)
Dean@1238
  1071
        {
Dean@1238
  1072
            if (obj == null)
Dean@1238
  1073
            {
Dean@1238
  1074
                return (false);
Dean@1238
  1075
            }
Dean@1238
  1076
Dean@1238
  1077
            if (Comparisons.Equals(this.Attachments, obj.Attachments) &&
Dean@1348
  1078
                Comparisons.Equals(this.Bcc, obj.Bcc) &&
Dean@1348
  1079
                Comparisons.Equals(this.Cc, obj.Cc) &&
Dean@1348
  1080
                Comparisons.Equals(this.ConversationId, obj.ConversationId) &&
Dean@1238
  1081
                Comparisons.Equals(this.ConversationIndex, obj.ConversationIndex) &&
Dean@1238
  1082
                Comparisons.Equals(this.ConversationTopic, obj.ConversationTopic) &&
Dean@1238
  1083
                Comparisons.Equals(this.Direction, obj.Direction) &&
Thomas@1817
  1084
                Comparisons.Equals(this.EnableProtection, obj.EnableProtection) &&
Thomas@1848
  1085
                Comparisons.Equals(this.ForceProtectionId, obj.ForceProtectionId) &&
Dean@1238
  1086
                Comparisons.Equals(this.ForceUnencrypted, obj.ForceUnencrypted) &&
Dean@1238
  1087
                Comparisons.Equals(this.From, obj.From) &&
Dean@1348
  1088
                Comparisons.Equals(this.Id, obj.Id) &&
Dean@1238
  1089
                Comparisons.Equals(this.KeyList, obj.KeyList) &&
Dean@1238
  1090
                Comparisons.Equals(this.Keywords, obj.Keywords) &&
Dean@1238
  1091
                Comparisons.Equals(this.LongMsg, obj.LongMsg) &&
Dean@1354
  1092
                Comparisons.Equals(this.LongMsgFormattedHtml, obj.LongMsgFormattedHtml) &&
Dean@1354
  1093
                Comparisons.Equals(this.LongMsgFormattedRtf, obj.LongMsgFormattedRtf) &&
Dean@1238
  1094
                Comparisons.Equals(this.NeverUnsecure, obj.NeverUnsecure) &&
Dean@1238
  1095
                Comparisons.Equals(this.PEPProtocolVersion, obj.PEPProtocolVersion) &&
Dean@1303
  1096
                Comparisons.Equals(this.Rating, obj.Rating) &&
Dean@1238
  1097
                Comparisons.Equals(this.ReceivedOn, obj.ReceivedOn) &&
Dean@1238
  1098
                Comparisons.Equals(this.SentOn, obj.SentOn) &&
Dean@1238
  1099
                Comparisons.Equals(this.ShortMsg, obj.ShortMsg) &&
Dean@1238
  1100
                Comparisons.Equals(this.To, obj.To))
Dean@1238
  1101
            {
Dean@1238
  1102
                return (true);
Dean@1238
  1103
            }
Dean@1238
  1104
Dean@1238
  1105
            return (false);
Dean@1238
  1106
        }
Dean@1238
  1107
Dean@1238
  1108
        /// <summary>
Thomas@1326
  1109
        /// Indicates whether the content of the current PEPMessage is equal to another one's.
Thomas@1326
  1110
        /// </summary>
Thomas@1326
  1111
        /// <param name="obj">The object to check equality with.</param>
Thomas@1326
  1112
        /// <returns>True if both objects' content is considered equal, otherwise false.</returns>
Thomas@1326
  1113
        public bool EqualsByContent(PEPMessage obj)
Thomas@1326
  1114
        {
Thomas@1326
  1115
            if (obj == null)
Thomas@1326
  1116
            {
Thomas@1326
  1117
                return false;
Thomas@1326
  1118
            }
Thomas@1326
  1119
Thomas@1326
  1120
            if (Comparisons.Equals(this.ConversationTopic, obj.ConversationTopic) &&
Thomas@1326
  1121
                Comparisons.Equals(this.Keywords, obj.Keywords) &&
Thomas@1326
  1122
                Comparisons.Equals(this.LongMsg, obj.LongMsg) &&
Dean@1354
  1123
                Comparisons.Equals(this.LongMsgFormattedHtml, obj.LongMsgFormattedHtml) &&
Dean@1354
  1124
                Comparisons.Equals(this.LongMsgFormattedRtf, obj.LongMsgFormattedRtf) &&
Thomas@1326
  1125
                Comparisons.Equals(this.ShortMsg, obj.ShortMsg))
Thomas@1326
  1126
            {
Thomas@1326
  1127
                return true;
Thomas@1326
  1128
            }
Thomas@1326
  1129
            else
Thomas@1326
  1130
            {
Thomas@1326
  1131
                return false;
Thomas@1326
  1132
            }
Thomas@1326
  1133
        }
Thomas@1326
  1134
Thomas@1326
  1135
        /// <summary>
Thomas@1294
  1136
        /// Gets a deep copy of the object and all its data.
Dean@389
  1137
        /// </summary>
Dean@389
  1138
        /// <returns>The deep copy of the object.</returns>
Dean@389
  1139
        public PEPMessage Copy()
Dean@389
  1140
        {
Dean@390
  1141
            return (this.Copy(false));
Dean@390
  1142
        }
Dean@390
  1143
Dean@390
  1144
        /// <summary>
Dean@390
  1145
        /// Gets a copy of the PEPMessage with or without data.
Dean@390
  1146
        /// </summary>
Dean@586
  1147
        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
Dean@586
  1148
        /// and optional properties.</param>
Dean@390
  1149
        /// <returns>The copy of the PEPMessage.</returns>
Dean@390
  1150
        public PEPMessage Copy(bool createWithoutContent = false)
Dean@390
  1151
        {
Dean@389
  1152
            PEPMessage copy = new PEPMessage();
Dean@389
  1153
Dean@389
  1154
            // Attachments
Dean@389
  1155
            copy.Attachments.Clear();
Dean@390
  1156
            if (createWithoutContent == false)
Dean@389
  1157
            {
Dean@390
  1158
                for (int i = 0; i < this._Attachments.Count; i++)
Dean@390
  1159
                {
Dean@390
  1160
                    copy.Attachments.Add(this._Attachments[i].Copy());
Dean@390
  1161
                }
Dean@389
  1162
            }
Dean@389
  1163
Dean@1393
  1164
            copy.AutoConsume = (this._AutoConsume == null ? null : string.Copy(this._AutoConsume));
Dean@1393
  1165
Dean@1348
  1166
            // Bcc
Dean@1348
  1167
            copy.Bcc.Clear();
Dean@1348
  1168
            for (int i = 0; i < this._Bcc.Count; i++)
Dean@389
  1169
            {
Dean@1348
  1170
                copy.Bcc.Add(this._Bcc[i].Copy());
Dean@389
  1171
            }
Dean@389
  1172
Dean@1348
  1173
            // Cc
Dean@1348
  1174
            copy.Cc.Clear();
Dean@1348
  1175
            for (int i = 0; i < this._Cc.Count; i++)
Dean@389
  1176
            {
Dean@1348
  1177
                copy.Cc.Add(this._Cc[i].Copy());
Dean@389
  1178
            }
Dean@389
  1179
Dean@1348
  1180
            copy.ConversationId = (this._ConversationId == null ? null : string.Copy(this._ConversationId));
Dean@1291
  1181
            copy.ConversationIndex = (this._ConversationIndex == null ? null : string.Copy(this._ConversationIndex));
Dean@1291
  1182
            copy.ConversationTopic = (this._ConversationTopic == null ? null : string.Copy(this._ConversationTopic));
Dean@389
  1183
            copy.Direction = this._Direction;
Thomas@1817
  1184
            copy.EnableProtection = this._EnableProtection;
Thomas@2025
  1185
            copy.ForceProtectionId = (this._ForceProtectionId == null ? null : string.Copy(this._ForceProtectionId));
Dean@1094
  1186
            copy.ForceUnencrypted = this._ForceUnencrypted;
Dean@389
  1187
            copy.From = (this._From == null ? null : this._From.Copy());
Dean@1348
  1188
            copy.Id = (this._Id == null ? null : string.Copy(this._Id));
Dean@1291
  1189
            copy.KeyList = (this._KeyList == null ? null : string.Copy(this._KeyList));
Dean@389
  1190
Dean@389
  1191
            // Keywords
Dean@389
  1192
            copy.Keywords.Clear();
Dean@389
  1193
            for (int i = 0; i < this._Keywords.Count; i++)
Dean@389
  1194
            {
Dean@389
  1195
                copy.Keywords.Add(this._Keywords[i]);
Dean@389
  1196
            }
Dean@398
  1197
Dean@390
  1198
            // Body
Dean@390
  1199
            if (createWithoutContent == false)
Dean@390
  1200
            {
Thomas@1294
  1201
                copy.LongMsg = (this._LongMsg == null ? null : string.Copy(this._LongMsg));
Dean@1354
  1202
                copy.LongMsgFormattedHtml = (this._LongMsgFormattedHtml == null ? null : string.Copy(this._LongMsgFormattedHtml));
Dean@1354
  1203
                copy.LongMsgFormattedRtf = (this._LongMsgFormattedRtf == null ? null : string.Copy(this._LongMsgFormattedRtf));
Dean@390
  1204
            }
Dean@390
  1205
            else
Dean@390
  1206
            {
Dean@390
  1207
                copy.LongMsg = null;
Dean@1354
  1208
                copy.LongMsgFormattedHtml = null;
Dean@1354
  1209
                copy.LongMsgFormattedRtf = null;
Dean@390
  1210
            }
Dean@389
  1211
Dean@1104
  1212
            copy.NeverUnsecure = this._NeverUnsecure;
Dean@1291
  1213
            copy.PEPProtocolVersion = (this._PEPProtocolVersion == null ? null : string.Copy(this._PEPProtocolVersion));
Dean@1303
  1214
            copy.Rating = this._Rating;
Dean@604
  1215
Dean@721
  1216
            // ReceivedOn
Dean@721
  1217
            if (this._ReceivedOn != null)
Dean@721
  1218
            {
Dean@721
  1219
                copy.ReceivedOn = new DateTime(((DateTime)this._ReceivedOn).Ticks);
Dean@721
  1220
            }
Dean@721
  1221
            else
Dean@721
  1222
            {
Dean@721
  1223
                copy.ReceivedOn = null;
Dean@721
  1224
            }
Dean@721
  1225
Dean@721
  1226
            // SentOn
Dean@721
  1227
            if (this._SentOn != null)
Dean@721
  1228
            {
Dean@721
  1229
                copy.SentOn = new DateTime(((DateTime)this._SentOn).Ticks);
Dean@721
  1230
            }
Dean@721
  1231
            else
Dean@721
  1232
            {
Dean@721
  1233
                copy.SentOn = null;
Dean@721
  1234
            }
Dean@721
  1235
Dean@1291
  1236
            copy.ShortMsg = (this._ShortMsg == null ? null : string.Copy(this._ShortMsg));
Dean@389
  1237
Dean@389
  1238
            // To
Dean@389
  1239
            copy.To.Clear();
Dean@389
  1240
            for (int i = 0; i < this._To.Count; i++)
Dean@389
  1241
            {
Dean@389
  1242
                copy.To.Add(this._To[i].Copy());
Dean@389
  1243
            }
Dean@389
  1244
Dean@389
  1245
            return (copy);
Dean@389
  1246
        }
Dean@389
  1247
Dean@389
  1248
        /// <summary>
Thomas@1294
  1249
        /// Resets the object to its default state/values.
Dean@1094
  1250
        /// </summary>
Dean@1094
  1251
        public void Reset()
Dean@1094
  1252
        {
Dean@1094
  1253
            this._Attachments = new List<PEPAttachment>();
Dean@1393
  1254
            this._AutoConsume = null;
Dean@1348
  1255
            this._Bcc = new List<PEPIdentity>();
Dean@1348
  1256
            this._Cc = new List<PEPIdentity>();
Dean@1348
  1257
            this._ConversationId = null;
Dean@1113
  1258
            this._ConversationIndex = null;
Dean@1113
  1259
            this._ConversationTopic = null;
markus@1337
  1260
            this._Direction = pEpMsgDirection.pEpDirIncoming;
Thomas@1817
  1261
            this._EnableProtection = false;
Thomas@1848
  1262
            this._ForceProtectionId = null;
Dean@1094
  1263
            this._ForceUnencrypted = false;
Dean@1094
  1264
            this._From = null;
Dean@1348
  1265
            this._Id = null;
Dean@1094
  1266
            this._KeyList = null;
Dean@1094
  1267
            this._Keywords = new List<string>();
Dean@1094
  1268
            this._LongMsg = null;
Dean@1354
  1269
            this._LongMsgFormattedHtml = null;
Dean@1354
  1270
            this._LongMsgFormattedRtf = null;
Dean@1104
  1271
            this._NeverUnsecure = false;
Dean@1212
  1272
            this._PEPProtocolVersion = null;
markus@1337
  1273
            this._Rating = pEpRating.pEpRatingUndefined;
Dean@1094
  1274
            this._ReceivedOn = null;
Dean@1094
  1275
            this._SentOn = null;
Dean@1094
  1276
            this._ShortMsg = null;
Dean@1094
  1277
            this._To = new List<PEPIdentity>();
Dean@1094
  1278
Dean@1242
  1279
            this.RaisePropertyChangedEvent(nameof(this.Attachments));
Dean@1393
  1280
            this.RaisePropertyChangedEvent(nameof(this.AutoConsume));
Dean@1348
  1281
            this.RaisePropertyChangedEvent(nameof(this.Bcc));
Dean@1348
  1282
            this.RaisePropertyChangedEvent(nameof(this.Cc));
Dean@1348
  1283
            this.RaisePropertyChangedEvent(nameof(this.ConversationId));
Dean@1242
  1284
            this.RaisePropertyChangedEvent(nameof(this.ConversationIndex));
Dean@1242
  1285
            this.RaisePropertyChangedEvent(nameof(this.ConversationTopic));
Dean@1242
  1286
            this.RaisePropertyChangedEvent(nameof(this.Direction));
Thomas@1817
  1287
            this.RaisePropertyChangedEvent(nameof(this.EnableProtection));
Thomas@1848
  1288
            this.RaisePropertyChangedEvent(nameof(this.ForceProtectionId));
Dean@1242
  1289
            this.RaisePropertyChangedEvent(nameof(this.ForceUnencrypted));
Dean@1242
  1290
            this.RaisePropertyChangedEvent(nameof(this.From));
Dean@1348
  1291
            this.RaisePropertyChangedEvent(nameof(this.Id));
Dean@1242
  1292
            this.RaisePropertyChangedEvent(nameof(this.KeyList));
Dean@1242
  1293
            this.RaisePropertyChangedEvent(nameof(this.Keywords));
Dean@1242
  1294
            this.RaisePropertyChangedEvent(nameof(this.LongMsg));
Dean@1354
  1295
            this.RaisePropertyChangedEvent(nameof(this.LongMsgFormattedHtml));
Dean@1354
  1296
            this.RaisePropertyChangedEvent(nameof(this.LongMsgFormattedRtf));
Dean@1242
  1297
            this.RaisePropertyChangedEvent(nameof(this.NeverUnsecure));
Dean@1242
  1298
            this.RaisePropertyChangedEvent(nameof(this.PEPProtocolVersion));
Dean@1303
  1299
            this.RaisePropertyChangedEvent(nameof(this.Rating));
Dean@1242
  1300
            this.RaisePropertyChangedEvent(nameof(this.ReceivedOn));
Dean@1242
  1301
            this.RaisePropertyChangedEvent(nameof(this.SentOn));
Dean@1242
  1302
            this.RaisePropertyChangedEvent(nameof(this.ShortMsg));
Dean@1242
  1303
            this.RaisePropertyChangedEvent(nameof(this.To));
Dean@1094
  1304
Dean@1094
  1305
            return;
Dean@1094
  1306
        }
Dean@1094
  1307
Dean@1094
  1308
        /// <summary>
Dean@1095
  1309
        /// Copies main properties that are unsupported by the engine from the given message into this message.
Dean@1113
  1310
        /// This is commonly used to restore information that would otherwise be lost in conversions to/from 
markus@1337
  1311
        /// TextMessage during engine processing.
Dean@1354
  1312
        /// Key properties that should be set separately for encryption concerns (such as LongMsgFormattedRtf) are ignored.
Dean@1095
  1313
        /// </summary>
Dean@1095
  1314
        /// <param name="msg">The message to copy over properties from.</param>
Dean@1095
  1315
        public void SetNonEnginePropertiesFrom(PEPMessage msg)
Dean@1095
  1316
        {
Dean@1095
  1317
            /* Include the following properties:
Thomas@1531
  1318
             *   • AutoConsume
Dean@1354
  1319
             *   • ConversationId
Dean@1113
  1320
             *   • ConversationIndex
Dean@1113
  1321
             *   • ConversationTopic
Thomas@1817
  1322
             *   • EnableProtection
Thomas@1819
  1323
             *   • ForceProtection
Dean@1095
  1324
             *   • ForceUnencrypted
Dean@1104
  1325
             *   • NeverUnsecure
Dean@1095
  1326
             * 
Dean@1095
  1327
             * Also note:
Dean@1130
  1328
             *              Rating: This is handled by the decrypt function of the engine only. It should not be
Dean@1095
  1329
             *                      added back separately so is skipped.
Dean@1095
  1330
             *             KeyList: This is handled by the decrypt function of the engine only. It should not be
Dean@1095
  1331
             *                      added back separately so is skipped.
Dean@1354
  1332
             * LongMsgFormattedRtf: This is completely unsupported by the engine but otherwise should be encrypted.
Dean@1095
  1333
             *                      Due to this, it's completely skipped.
Dean@1212
  1334
             *  PEPProtocolVersion: This is handled in both the decrypt and encrypt functions of the engine.
markus@1337
  1335
             *                      It should almost always be set within the TextMessage there isn't needed to add back.
Dean@1095
  1336
             */
Dean@1095
  1337
Dean@1095
  1338
            if (msg != null)
Dean@1095
  1339
            {
Thomas@1531
  1340
                this._AutoConsume = msg.AutoConsume;
Dean@1348
  1341
                this._ConversationId = msg.ConversationId;
Dean@1113
  1342
                this._ConversationIndex = msg.ConversationIndex;
Dean@1113
  1343
                this._ConversationTopic = msg.ConversationTopic;
Thomas@1817
  1344
                this._EnableProtection = msg.EnableProtection;
Thomas@1848
  1345
                this._ForceProtectionId = msg.ForceProtectionId;
Dean@1095
  1346
                this._ForceUnencrypted = msg.ForceUnencrypted;
Dean@1104
  1347
                this._NeverUnsecure = msg.NeverUnsecure;
Dean@1095
  1348
Thomas@1531
  1349
                this.RaisePropertyChangedEvent(nameof(this.AutoConsume));
Dean@1348
  1350
                this.RaisePropertyChangedEvent(nameof(this.ConversationId));
Dean@1242
  1351
                this.RaisePropertyChangedEvent(nameof(this.ConversationIndex));
Dean@1242
  1352
                this.RaisePropertyChangedEvent(nameof(this.ConversationTopic));
Thomas@1848
  1353
                this.RaisePropertyChangedEvent(nameof(this.ForceProtectionId));
Thomas@1817
  1354
                this.RaisePropertyChangedEvent(nameof(this.EnableProtection));
Dean@1242
  1355
                this.RaisePropertyChangedEvent(nameof(this.ForceUnencrypted));
Dean@1242
  1356
                this.RaisePropertyChangedEvent(nameof(this.NeverUnsecure));
Dean@1095
  1357
            }
Dean@1095
  1358
Dean@1095
  1359
            return;
Dean@1095
  1360
        }
Dean@1095
  1361
Dean@1095
  1362
        /// <summary>
Thomas@1953
  1363
        /// Sets all pEp properties at once. This method improves performance as the MimeKit 
Thomas@1953
  1364
        /// message headers are only retrieved once and used for all properties.
Thomas@1953
  1365
        /// </summary>
Thomas@1953
  1366
        /// <param name="omi">The Outlook mail item to read the pEp properties from.</param>
Thomas@1953
  1367
        /// <param name="direction">Whether it is an incoming or outgoing message.</param>
Thomas@1953
  1368
        /// <param name="secureMessage">Whether the message is secure (encrypted) or not.</param>
Thomas@1953
  1369
        /// <param name="messageHeaders">The message headers of this message.</param>
Thomas@2015
  1370
        public void SetPEPProperties(Outlook.MailItem omi, HeaderList messageHeaders)
Thomas@1953
  1371
        {
Thomas@1953
  1372
            object propValue = null;
Thomas@1953
  1373
Thomas@2015
  1374
            // AutoConsume
Thomas@2015
  1375
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.AutoConsume, out propValue, MailItemExtensions.GetPEPPropertyDefault(MailItemExtensions.PEPProperty.AutoConsume), messageHeaders);
Thomas@2015
  1376
            this.AutoConsume = propValue as string;
Thomas@1953
  1377
Thomas@2015
  1378
            // PEPProtocolVersion
Thomas@2015
  1379
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.PEPProtocolVersion, out propValue, MailItemExtensions.GetPEPPropertyDefault(MailItemExtensions.PEPProperty.PEPProtocolVersion), messageHeaders);
Thomas@2015
  1380
            this.PEPProtocolVersion = propValue as string;
Thomas@1953
  1381
Thomas@2015
  1382
            // Rating
Thomas@2015
  1383
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.Rating, out propValue);
Thomas@2015
  1384
            this.Rating = (pEpRating)propValue;
Thomas@1953
  1385
Thomas@2015
  1386
            // KeyList
Thomas@2015
  1387
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.KeyList, out propValue);
Thomas@2015
  1388
            this.KeyList = propValue as string;
Thomas@1953
  1389
Thomas@2015
  1390
            // EnableProtection
Thomas@2015
  1391
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.EnableProtection, out propValue);
Thomas@2015
  1392
            this.EnableProtection = (bool)propValue;
Thomas@2015
  1393
Thomas@2015
  1394
            // ForceUnencrypted
Thomas@2015
  1395
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.ForceUnencrypted, out propValue);
Thomas@2015
  1396
            this.ForceUnencrypted = propValue as bool? ?? false;
Thomas@1953
  1397
Thomas@1953
  1398
            // ForceProtection
Thomas@1953
  1399
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.ForceProtection, out propValue, MailItemExtensions.GetPEPPropertyDefault(MailItemExtensions.PEPProperty.ForceProtection), messageHeaders);
Thomas@1953
  1400
            this.ForceProtectionId = propValue as string;
Thomas@1953
  1401
Thomas@1953
  1402
            // NeverUnsecure
Thomas@1953
  1403
            omi.GetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, out propValue, MailItemExtensions.GetPEPPropertyDefault(MailItemExtensions.PEPProperty.NeverUnsecure), messageHeaders);
Thomas@1953
  1404
            this.NeverUnsecure = (bool)propValue;
Thomas@1953
  1405
Thomas@1953
  1406
            Log.Verbose("SetPEPProperties: Values retrieved");
Thomas@1953
  1407
        }
Thomas@1953
  1408
Thomas@2010
  1409
Thomas@2010
  1410
        /// <summary>
Thomas@2010
  1411
        /// Gets the outgoing pEp rating of the given message based on the recipients force unencrypted status.
Thomas@2010
  1412
        /// The IsForceUnencrypted property of each recipient must have already been set in the message.
Thomas@2010
  1413
        /// This property is copied from any associated Outlook contact's force unencrypted user property.
Thomas@2010
  1414
        /// </summary>
Thomas@2010
  1415
        /// <param name="message">The message to get the rating for.</param>
Thomas@2010
  1416
        /// <returns>The rating: undefined, reliable, unencrypted or unencrypted_for_some.
Thomas@2010
  1417
        /// Will return undefined by default or if no recipients exist.</returns>
Thomas@2010
  1418
        public pEpRating GetOutgoingRatingByRecipients()
Thomas@2010
  1419
        {
Thomas@2010
  1420
            // TODO: Check whether this method should be part of the engine?
Thomas@2010
  1421
            int unencryptedCount = 0;
Thomas@2010
  1422
            pEpRating rating = pEpRating.pEpRatingUndefined;
Thomas@2010
  1423
            List<PEPIdentity> forceUnencryptedList = new List<PEPIdentity>();
Thomas@2010
  1424
            PEPIdentity[] recipients;
Thomas@2010
  1425
            PEPMessage workingMessage;
Thomas@2010
  1426
Thomas@2010
  1427
            workingMessage = this.Copy(true);
Thomas@2010
  1428
            workingMessage.FlattenAllRecipientIdentities();
Thomas@2010
  1429
Thomas@2010
  1430
            recipients = workingMessage.Recipients;
Thomas@2010
  1431
Thomas@2010
  1432
            if (recipients.Length > 0)
Thomas@2010
  1433
            {
Thomas@2010
  1434
                // Calculate for all recipients
Thomas@2010
  1435
                for (int i = 0; i < recipients.Length; i++)
Thomas@2010
  1436
                {
Thomas@2010
  1437
                    if (recipients[i].IsForceUnencryptedBool)
Thomas@2010
  1438
                    {
Thomas@2010
  1439
                        unencryptedCount++;
Thomas@2010
  1440
                    }
Thomas@2010
  1441
                }
Thomas@2010
  1442
Thomas@2010
  1443
                // Final rating determination
Thomas@2010
  1444
                if (unencryptedCount == recipients.Length)
Thomas@2010
  1445
                {
Thomas@2010
  1446
                    rating = pEpRating.pEpRatingUnencrypted;
Thomas@2010
  1447
                }
Thomas@2010
  1448
                else if (unencryptedCount == 0)
Thomas@2010
  1449
                {
Thomas@2010
  1450
                    // Assume encrypted (will use engine rating in the end)
Thomas@2010
  1451
                    rating = pEpRating.pEpRatingReliable;
Thomas@2010
  1452
                }
Thomas@2010
  1453
                else if (unencryptedCount < recipients.Length)
Thomas@2010
  1454
                {
Thomas@2010
  1455
                    rating = pEpRating.pEpRatingUnencryptedForSome;
Thomas@2010
  1456
                }
Thomas@2010
  1457
                else
Thomas@2010
  1458
                {
Thomas@2010
  1459
                    // Should never get here
Thomas@2010
  1460
                    rating = pEpRating.pEpRatingUndefined;
Thomas@2010
  1461
                }
Thomas@2010
  1462
            }
Thomas@2010
  1463
Thomas@2010
  1464
            return (rating);
Thomas@2010
  1465
        }
Thomas@2010
  1466
Thomas@1953
  1467
        /// <summary>
Dean@384
  1468
        /// Applies this pEp message's data to the given Outlook item.
Dean@384
  1469
        /// </summary>
Dean@384
  1470
        /// <param name="omi">The Outlook mail item to apply this pEp message's data to.</param>
Thomas@1299
  1471
        /// <param name="setInternalHeaderFields">Whether to set internal header fields (Stored as MAPI properites) such as 
Dean@1130
  1472
        /// Rating and KeyList. Warning: Never apply these to outgoing messages -- used only for mirrors or internal MailItems.
Dean@1212
  1473
        /// Note that some header fields will be applied regardless such as NeverUnsecure or PEPProtocolVersion. 
Dean@1094
  1474
        /// That is because these are not considered internal only and don't contain sensitive information.</param>
Thomas@1299
  1475
        /// /// <param name="setSender">Whether to set the sender manually. This is only needed when creating a sent message. 
Thomas@1299
  1476
        /// Important: Setting this to true for outgoing messages can cause problems with Exchange accounts.</param>
Thomas@1823
  1477
        /// <param name="setRecipients">Whether to set the message recipients manually. This should normally be set to true
Thomas@1823
  1478
        /// for all common messages and makes only sense to be omitted in special cases like a FPP reply message.</param>
Dean@910
  1479
        /// <returns>The status of the method.</returns>
Dean@910
  1480
        public Globals.ReturnStatus ApplyTo(Outlook.MailItem omi,
Thomas@1467
  1481
                                            bool setInternalHeaderFields,
Thomas@1823
  1482
                                            bool setSender,
Thomas@1823
  1483
                                            bool setRecipients = true)
Dean@384
  1484
        {
Thomas@1467
  1485
            bool fromRecipientRemoved = false;
Thomas@1467
  1486
            bool isPGPMIMEMsg = this.IsPGPMIMEEncrypted;
Dean@1113
  1487
            byte[] bytes;
Dean@543
  1488
            Outlook.Attachments attachments = null;
Dean@543
  1489
            Outlook.Recipient newRecipient = null;
Dean@543
  1490
            Outlook.Recipients recipients = null;
Dean@543
  1491
            Outlook.Account currAccount = null;
Dean@543
  1492
            Outlook.Account sendUsingAccount = null;
Dean@543
  1493
            Outlook.Accounts accounts = null;
Thomas@1119
  1494
            Outlook.Recipient fromRecipient = null;
Thomas@1467
  1495
            Outlook.NameSpace ns = null;
Thomas@1467
  1496
            PEPIdentity ident;
Dean@910
  1497
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@408
  1498
Dean@543
  1499
            try
Dean@408
  1500
            {
Thomas@1467
  1501
                ns = Globals.ThisAddIn.Application.Session;
Thomas@1467
  1502
Thomas@1823
  1503
                if (setRecipients)
Dean@543
  1504
                {
Thomas@1823
  1505
                    // Remove all existing recipients
Thomas@1823
  1506
                    recipients = omi.Recipients;
Thomas@1823
  1507
                    while (recipients.Count > 0)
Thomas@1823
  1508
                    {
Thomas@1823
  1509
                        recipients.Remove(1);
Thomas@1823
  1510
                    }
Dean@543
  1511
Thomas@1823
  1512
                    // Set recipients
Thomas@1823
  1513
                    for (int i = 0; i < this._Bcc.Count; i++)
Dean@543
  1514
                    {
Thomas@1823
  1515
                        if (string.IsNullOrWhiteSpace(this._Bcc[i].Address) == false)
Thomas@1823
  1516
                        {
Thomas@1823
  1517
                            // Add by address
Thomas@1823
  1518
                            newRecipient = recipients.Add(this._Bcc[i].Address);
Thomas@1823
  1519
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Dean@543
  1520
Thomas@1823
  1521
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1522
                            newRecipient = null;
Thomas@1823
  1523
                        }
Thomas@1823
  1524
                        else if (string.IsNullOrWhiteSpace(this._Bcc[i].UserName) == false)
Thomas@1823
  1525
                        {
Thomas@1823
  1526
                            // Add by user name (required for distribution lists)
Thomas@1823
  1527
                            newRecipient = recipients.Add(this._Bcc[i].UserName);
Thomas@1823
  1528
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Thomas@1823
  1529
Thomas@1823
  1530
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1531
                            newRecipient = null;
Thomas@1823
  1532
                        }
Dean@543
  1533
                    }
Thomas@1823
  1534
Thomas@1823
  1535
                    for (int i = 0; i < this._Cc.Count; i++)
Dean@795
  1536
                    {
Thomas@1823
  1537
                        if (string.IsNullOrWhiteSpace(this._Cc[i].Address) == false)
Thomas@1823
  1538
                        {
Thomas@1823
  1539
                            // Add by address
Thomas@1823
  1540
                            newRecipient = recipients.Add(this._Cc[i].Address);
Thomas@1823
  1541
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Dean@795
  1542
Thomas@1823
  1543
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1544
                            newRecipient = null;
Thomas@1823
  1545
                        }
Thomas@1823
  1546
                        else if (string.IsNullOrWhiteSpace(this._Cc[i].UserName) == false)
Thomas@1823
  1547
                        {
Thomas@1823
  1548
                            // Add by user name (required for distribution lists)
Thomas@1823
  1549
                            newRecipient = recipients.Add(this._Cc[i].UserName);
Thomas@1823
  1550
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Thomas@1823
  1551
Thomas@1823
  1552
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1553
                            newRecipient = null;
Thomas@1823
  1554
                        }
Dean@795
  1555
                    }
Dean@543
  1556
Thomas@1823
  1557
                    for (int i = 0; i < this._To.Count; i++)
Dean@543
  1558
                    {
Thomas@1823
  1559
                        if (string.IsNullOrWhiteSpace(this._To[i].Address) == false)
Thomas@1823
  1560
                        {
Thomas@1823
  1561
                            // Add by address
Thomas@1823
  1562
                            newRecipient = recipients.Add(this._To[i].Address);
Thomas@1823
  1563
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@543
  1564
Thomas@1823
  1565
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1566
                            newRecipient = null;
Thomas@1823
  1567
                        }
Thomas@1823
  1568
                        else if (string.IsNullOrWhiteSpace(this._To[i].UserName) == false)
Thomas@1823
  1569
                        {
Thomas@1823
  1570
                            // Add by user name (required for distribution lists)
Thomas@1823
  1571
                            newRecipient = recipients.Add(this._To[i].UserName);
Thomas@1823
  1572
                            newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@795
  1573
Thomas@1823
  1574
                            // Marshal.ReleaseComObject(newRecipient);
Thomas@1823
  1575
                            newRecipient = null;
Thomas@1823
  1576
                        }
Dean@795
  1577
                    }
Dean@543
  1578
                }
Dean@543
  1579
Thomas@1119
  1580
                /* Add the pEp From identity as its own recipient. This will be removed later.
Dean@1135
  1581
                 * However, here it simplifies getting the Sender/From AddressEntry, which will be set later.
Dean@1135
  1582
                 * 
Dean@1135
  1583
                 * Note: Outlook will not allow the Sender to be set for received mail items.
Dean@1135
  1584
                 * If you try to set the sender in this situation, it will always throw an error.
Dean@1135
  1585
                 * To mitigate this, the Sender should only be set to the MailItem if one is not already existing that already
Dean@1135
  1586
                 * matches the Sender we would otherwise try to set. This is considered good enough as determining
Dean@1135
  1587
                 * if a mail item is received is not completely reliable.
Thomas@1119
  1588
                 */
Thomas@1299
  1589
                if (setSender)
Thomas@1119
  1590
                {
Thomas@1299
  1591
                    if ((this._From != null) &&
Thomas@1299
  1592
                        ((omi.Sender == null) ||
Thomas@1299
  1593
                         ((omi.Sender != null) &&
Thomas@1299
  1594
                          (this._From != null) &&
Thomas@1299
  1595
                          (this._From.EqualsByAddress(omi.Sender.Address) == false))))
Thomas@1131
  1596
                    {
Thomas@1299
  1597
                        if (string.IsNullOrWhiteSpace(this._From.Address) == false)
Thomas@1299
  1598
                        {
Thomas@1299
  1599
                            // Add by address
Thomas@1299
  1600
                            fromRecipient = recipients.Add(this._From.Address);
Thomas@1299
  1601
                            fromRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Thomas@1299
  1602
                        }
Dean@1348
  1603
                        else if (string.IsNullOrWhiteSpace(this._From.UserName) == false)
Thomas@1299
  1604
                        {
Dean@1348
  1605
                            // Add by user name (required for distribution lists)
Dean@1348
  1606
                            fromRecipient = recipients.Add(this._From.UserName);
Thomas@1299
  1607
                            fromRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Thomas@1299
  1608
                        }
Thomas@1131
  1609
                    }
Thomas@1299
  1610
Thomas@1299
  1611
                    try
Thomas@1131
  1612
                    {
Thomas@1299
  1613
                        recipients.ResolveAll();
Thomas@1131
  1614
                    }
Thomas@1299
  1615
                    catch { }
Thomas@1119
  1616
Thomas@1299
  1617
                    /* Set sender account
Thomas@1467
  1618
                     * Note that if this fails and the account is null, it will eventually use the default account.
Thomas@1467
  1619
                     * If the send using account is already populated, this usually cannot be re-set. (Exception for unsaved drafts)
Thomas@1299
  1620
                     */
Thomas@1299
  1621
                    sendUsingAccount = omi.SendUsingAccount;
Dean@543
  1622
Thomas@1299
  1623
                    if ((this._From != null) &&
Thomas@1467
  1624
                        (this._From.Address != null))
Thomas@1299
  1625
                    {
Thomas@1467
  1626
                        accounts = ns.Accounts;
Dean@543
  1627
Thomas@1299
  1628
                        // Note: Index starts at 1
Thomas@1299
  1629
                        for (int i = 1; i <= accounts.Count; i++)
Thomas@1299
  1630
                        {
Thomas@1299
  1631
                            currAccount = accounts[i];
Thomas@1467
  1632
                            var sts = PEPIdentity.GetOwnIdentity(currAccount, out ident);
Dean@543
  1633
Thomas@1467
  1634
                            if ((ident != null) &&
Thomas@1467
  1635
                                (ident.EqualsByAddress(this._From)))
Thomas@1299
  1636
                            {
Thomas@1299
  1637
                                /* Try to set the SendUsingAccount
Thomas@1299
  1638
                                 * This will fail if the mail item is already marked as sent or the SendUsingAccount is not null, etc...
Thomas@1299
  1639
                                 * If it fails, Outlook will in the end just use the default account.
Thomas@1299
  1640
                                 * This property should ideally be set before a mail item is saved.
Thomas@1299
  1641
                                 */
Thomas@1299
  1642
                                try
Thomas@1299
  1643
                                {
Thomas@1299
  1644
                                    omi.SendUsingAccount = currAccount;
Thomas@1299
  1645
                                }
Thomas@1299
  1646
                                catch { }
Dean@543
  1647
vb@1516
  1648
                                // Marshal.ReleaseComObject(currAccount);
Thomas@1299
  1649
                                currAccount = null;
Thomas@1299
  1650
Thomas@1299
  1651
                                break;
Dean@543
  1652
                            }
Dean@543
  1653
vb@1516
  1654
                            // Marshal.ReleaseComObject(currAccount);
Dean@543
  1655
                            currAccount = null;
Thomas@1299
  1656
                        }
Thomas@1299
  1657
                    }
Dean@543
  1658
Thomas@1299
  1659
                    /* Set Sender
Thomas@1299
  1660
                     * Outlook takes the Sender property to display the respective name in the Sent folder.
Thomas@1299
  1661
                     * This Sender property is based on the name, the email address and the EntryID MAPI properties. As the EntryID can't be accessed
Thomas@1299
  1662
                     * directly with MAPI methods, we have to set these properties indirectly through the Sender.
Thomas@1299
  1663
                     */
Thomas@1299
  1664
                    if (fromRecipient != null)
Thomas@1299
  1665
                    {
Thomas@1299
  1666
                        try
Thomas@1299
  1667
                        {
Thomas@1299
  1668
                            omi.Sender = fromRecipient.AddressEntry;
Thomas@1299
  1669
                        }
Thomas@1299
  1670
                        catch
Thomas@1299
  1671
                        {
Thomas@1299
  1672
                            Log.Warning("PEPMessage.ApplyTo: Failed to set the Sender.");
Dean@543
  1673
                        }
Dean@543
  1674
Thomas@1299
  1675
                        // Remove the From recipient from the Recipients collection by searching for a match by EntryID
Thomas@1299
  1676
                        for (int i = 1; i <= recipients.Count; i++)
Thomas@1299
  1677
                        {
Thomas@1299
  1678
                            newRecipient = recipients[i];
Thomas@1299
  1679
                            if (newRecipient != null)
Thomas@1299
  1680
                            {
Thomas@1299
  1681
                                if ((string.IsNullOrEmpty(newRecipient.EntryID) == false) &&
Thomas@1299
  1682
                                    (string.IsNullOrEmpty(fromRecipient.EntryID) == false) &&
Thomas@1299
  1683
                                    (newRecipient.EntryID == fromRecipient.EntryID))
Thomas@1299
  1684
                                {
Thomas@1299
  1685
                                    try
Thomas@1299
  1686
                                    {
Thomas@1299
  1687
                                        recipients.Remove(i);
Thomas@1299
  1688
                                        fromRecipientRemoved = true;
Thomas@1299
  1689
                                    }
Thomas@1299
  1690
                                    catch
Thomas@1299
  1691
                                    {
Thomas@1299
  1692
                                        Log.Warning("PEPMessage.ApplyTo: Error removing 'From' recipient from Recipients collection.");
Thomas@1299
  1693
                                    }
Thomas@1299
  1694
                                    break;
Thomas@1299
  1695
                                }
Thomas@1299
  1696
vb@1516
  1697
                                // Marshal.ReleaseComObject(newRecipient);
Thomas@1299
  1698
                                newRecipient = null;
Thomas@1299
  1699
                            }
Thomas@1299
  1700
                        }
Thomas@1299
  1701
Thomas@1299
  1702
                        // Fallback solution in case there is no EntryID match
Thomas@1299
  1703
                        if (fromRecipientRemoved == false)
Thomas@1299
  1704
                        {
Thomas@1299
  1705
                            try
Thomas@1299
  1706
                            {
Thomas@1299
  1707
                                recipients.Remove(recipients.Count);
Thomas@1299
  1708
                                Log.Warning("PEPMessage.ApplyTo: No EntryID match for 'From' recipient in Recipients collection. Removed using fallback solution.");
Thomas@1299
  1709
                            }
Thomas@1299
  1710
                            catch
Thomas@1299
  1711
                            {
Thomas@1299
  1712
                                Log.Error("PEPMessage.ApplyTo: No EntryID match for 'From' recipient in Recipients collection. Fallback solution also failed.");
Thomas@1299
  1713
                            }
Thomas@1299
  1714
                        }
Thomas@1299
  1715
Thomas@1299
  1716
                        // Set Sender's name and email properties via MAPIProperty (won't be created automatically when assigníng Sender)
Thomas@1299
  1717
                        try
Thomas@1299
  1718
                        {
Dean@1350
  1719
                            MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderName, this._From.UserName);
Dean@1350
  1720
                            MapiHelper.SetProperty(omi, MapiProperty.PidTagSenderEmailAddress, this._From.Address);
Thomas@1299
  1721
                        }
Thomas@1299
  1722
                        catch (Exception ex)
Thomas@1299
  1723
                        {
Thomas@1299
  1724
                            Log.Warning("PEPMessage.ApplyTo: Unable to set sender's name or email address via MAPIProperty. " + ex.Message);
Thomas@1299
  1725
                        }
Thomas@1299
  1726
vb@1516
  1727
                        // Marshal.ReleaseComObject(fromRecipient);
Thomas@1299
  1728
                        fromRecipient = null;
Dean@543
  1729
                    }
Dean@543
  1730
                }
Thomas@1299
  1731
                else
Thomas@1119
  1732
                {
Thomas@1119
  1733
                    try
Thomas@1119
  1734
                    {
Thomas@1299
  1735
                        recipients.ResolveAll();
Thomas@1119
  1736
                    }
Thomas@1299
  1737
                    catch { }
Thomas@1119
  1738
                }
Thomas@1119
  1739
Dean@1056
  1740
                /* Set the encoding to UTF-8
Dean@1056
  1741
                 * See: https://msdn.microsoft.com/en-us/library/office/ff860730.aspx
Dean@1058
  1742
                 * All PEPMessages should be UTF especially those coming from the engine.
Dean@1058
  1743
                 * 
Dean@1058
  1744
                 * It is important that the encoding is set BEFORE the body and other text of the 
Dean@1058
  1745
                 * mail item. This is necessary to avoid character encoding issues where
Dean@1058
  1746
                 * Outlook will not respect the UTF encoding of strings set to the body/subject/etc.
Dean@1058
  1747
                 * It will instead try to use the strings with the encoding of the codepage.
Dean@1056
  1748
                 */
Dean@1056
  1749
                try
Dean@1056
  1750
                {
Dean@1350
  1751
                    MapiHelper.SetProperty(omi, MapiProperty.PidTagInternetCodepage, 65001);
Dean@1350
  1752
                    MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageCodepage, 65001);
Dean@1056
  1753
                }
Dean@1056
  1754
                catch
Dean@1056
  1755
                {
Dean@1249
  1756
                    Log.Warning("PEPMessage.ApplyTo: Failed to set UTF-8 encoding.");
Dean@1056
  1757
                }
Dean@1056
  1758
Dean@543
  1759
                // Set the subject
Dean@543
  1760
                omi.Subject = this._ShortMsg;
Dean@543
  1761
Dean@1224
  1762
                /* Set the body
Dean@1224
  1763
                 * PGP/MIME format must be handled specially.
Dean@1224
  1764
                 * In addition, RTF format is ignored. Only HTML is used the same as the pEp engine.
Dean@1224
  1765
                 */
Dean@1231
  1766
                if (isPGPMIMEMsg)
Dean@1224
  1767
                {
Dean@1236
  1768
                    /* Clear any old body content, these cannot exist for PGP/MIME encrypted messages.
Dean@1236
  1769
                     * Note that setting the RTFBody to null or an empty byte array throws an exception.
Dean@1236
  1770
                     * Therefore, it is sent to a single zero byte to be constant.
Dean@1236
  1771
                     * The RTFBody is ignored when sending the actual message.
Dean@1236
  1772
                     */
markus@1228
  1773
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
Dean@1236
  1774
                    omi.Body = null;
markus@1228
  1775
                    omi.HTMLBody = null;
Dean@1236
  1776
                    omi.RTFBody = new byte[] { 0x00 };
markus@1228
  1777
Dean@1236
  1778
                    // Now, set the mail mime type to S/MIME multipart/signed, this is used later to add a special attachment
Dean@1275
  1779
                    try
Dean@1275
  1780
                    {
Dean@1350
  1781
                        MapiHelper.SetProperty(omi, MapiProperty.PidTagMessageClass, MapiPropertyValue.PidTagMessageClassSMIMEMultipartSigned);
Dean@1275
  1782
                    }
Dean@1275
  1783
                    catch
Dean@1275
  1784
                    {
Dean@1275
  1785
                        status = Globals.ReturnStatus.Failure;
Dean@1275
  1786
                        throw new Exception("Failure to set message class for PGP/MIME message.");
Dean@1275
  1787
                    }
Dean@1224
  1788
                }
Dean@1354
  1789
                else if (string.IsNullOrWhiteSpace(this._LongMsgFormattedHtml))
Dean@543
  1790
                {
Thomas@1671
  1791
                    omi.Body = this._LongMsg;
Dean@543
  1792
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
Dean@543
  1793
                }
Dean@543
  1794
                else
Dean@543
  1795
                {
Thomas@1671
  1796
                    omi.HTMLBody = this._LongMsgFormattedHtml;
Dean@543
  1797
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
Dean@543
  1798
                }
Dean@543
  1799
Dean@543
  1800
                // Remove any previous attachments
Dean@543
  1801
                attachments = omi.Attachments;
Thomas@1770
  1802
                while (attachments.Count > 0)
Dean@543
  1803
                {
Thomas@1770
  1804
                    /* OUT-193: We cannot use attachments.Remove() here, as it
Thomas@1770
  1805
                     * seems to be buggy in Outlook 2013. Let's hope that
Thomas@1770
  1806
                     * using Attachment.Delete() has no bad side effects on
Thomas@1770
  1807
                     * other Outlook versions.
Thomas@1770
  1808
                     * OUT-292: The Delete() method can fail under rare circumstances.
Thomas@1770
  1809
                     * In this case, just log the error and break. 
Thomas@1770
  1810
                     * NOTE: We can NOT use a for loop here, as this leads to unforeseeable 
Thomas@1770
  1811
                     * issues with actual attachments (supposedly due to race conditions on 
Thomas@1770
  1812
                     * multithreaded decryption operations).
Thomas@1823
  1813
                     */
Thomas@1768
  1814
                    try
Thomas@1768
  1815
                    {
Thomas@1770
  1816
                        attachments[attachments.Count].Delete();
Thomas@1768
  1817
                    }
Thomas@1768
  1818
                    catch (Exception ex)
Thomas@1768
  1819
                    {
Thomas@1770
  1820
                        Log.Error("Applyto: Error deleting attachment. " + ex.ToString());
Thomas@1770
  1821
                        break;
Thomas@1768
  1822
                    }
Dean@543
  1823
                }
Dean@543
  1824
Dean@1231
  1825
                if (isPGPMIMEMsg)
Dean@543
  1826
                {
Dean@1236
  1827
                    PEPAttachment pgpMIME = this.ConvertToPGPMIMEAttachment();
Dean@1236
  1828
Dean@1236
  1829
                    if (pgpMIME != null)
Dean@1236
  1830
                    {
Thomas@1673
  1831
                        try
Thomas@1673
  1832
                        {
Thomas@1673
  1833
                            pgpMIME.AddTo(attachments);
Thomas@1673
  1834
                        }
Thomas@1936
  1835
                        catch (Exception ex)
Thomas@1673
  1836
                        {
Thomas@1936
  1837
                            Log.Verbose("Failed to add PGP/MIME attachment. " + ex.ToString());
Thomas@1673
  1838
Thomas@1673
  1839
                            /* If adding the attachment fails, check if it is because of file size limitations
Thomas@1673
  1840
                             * and throw dedicated exception in that case (needed for user feedback).
Thomas@1823
  1841
                             */
Thomas@1673
  1842
                            var pgpgMIMESizeInKB = pgpMIME.Data.Length / 1000; // Get size in kB
Thomas@1673
  1843
                            if (pgpgMIMESizeInKB > omi.GetMaxMailSize())
Thomas@1673
  1844
                            {
Thomas@1673
  1845
                                throw new AttachmentSizeException(string.Format("Failed to add PGP/MIME attachment due to size restrictions. Allowed size: {0} kB. Actual size: {1} kB.", omi.GetMaxMailSize(), pgpgMIMESizeInKB));
Thomas@1673
  1846
                            }
Thomas@1673
  1847
                            else
Thomas@1673
  1848
                            {
Thomas@1673
  1849
                                throw;
Thomas@1673
  1850
                            }
Thomas@1673
  1851
                        }
Dean@1236
  1852
                    }
Dean@1236
  1853
                    else
Dean@1236
  1854
                    {
Dean@1236
  1855
                        throw new Exception("Failed to create and add PGP/MIME attachment.");
Dean@1236
  1856
                    }
Dean@1224
  1857
                }
Dean@1224
  1858
                else
Dean@1224
  1859
                {
Dean@1224
  1860
                    for (int i = 0; i < this._Attachments.Count; i++)
Dean@1224
  1861
                    {
Thomas@1788
  1862
                        try
Thomas@1788
  1863
                        {
Thomas@1788
  1864
                            this._Attachments[i].AddTo(attachments, ("attachment" + i.ToString()));
Thomas@1788
  1865
                        }
Thomas@1788
  1866
                        catch (Exception ex)
Thomas@1788
  1867
                        {
Thomas@1788
  1868
                            Log.Error("ApplyTo: Error adding attachment. " + ex.ToString());
Thomas@1788
  1869
                        }
Dean@1224
  1870
                    }
Dean@543
  1871
                }
Dean@543
  1872
Dean@1095
  1873
                // ID
Dean@1224
  1874
                try
Dean@1224
  1875
                {
Dean@1350
  1876
                    MapiHelper.SetProperty(omi, MapiProperty.PidTagInternetMessageId, this._Id);
Dean@1224
  1877
                }
Dean@1224
  1878
                catch { }
Dean@1095
  1879
Dean@1113
  1880
                // Conversation information
Dean@1113
  1881
                try
Dean@1113
  1882
                {
Dean@1113
  1883
                    /* Note: PidTagConversationId cannot be set even through the MAPI accessor.
Dean@1113
  1884
                     * This is by design since this property is computed automatically from other properties.
Dean@1113
  1885
                     * See: https://msdn.microsoft.com/en-us/library/ee204279.aspx
Dean@1113
  1886
                     */
Dean@1350
  1887
                    bytes = MapiHelper.StringToPtypBinary(this._ConversationIndex);
Dean@1217
  1888
                    if ((bytes != null) &&
Dean@1217
  1889
                        (bytes.Length > 0))
Dean@1113
  1890
                    {
Dean@1350
  1891
                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndex, bytes);
Dean@1113
  1892
                    }
Dean@1113
  1893
Dean@1350
  1894
                    MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationIndexTracking, false);
Dean@1409
  1895
Dean@1409
  1896
                    if (string.IsNullOrEmpty(this._ConversationTopic))
Dean@1409
  1897
                    {
Dean@1409
  1898
                        // Clear the property value even if null
Dean@1409
  1899
                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationTopic, string.Empty);
Dean@1409
  1900
                    }
Dean@1409
  1901
                    else
Dean@1409
  1902
                    {
Dean@1409
  1903
                        MapiHelper.SetProperty(omi, MapiProperty.PidTagConversationTopic, this._ConversationTopic);
Dean@1409
  1904
                    }
Dean@1113
  1905
                }
Dean@1409
  1906
                catch
Dean@1113
  1907
                {
Dean@1409
  1908
                    Log.Warning("PEPMessage.ApplyTo: Failure setting conversation information.");
Dean@1113
  1909
                }
Dean@1113
  1910
Dean@1094
  1911
                /* Add internal properties
Dean@1154
  1912
                 * Note: there is no need to check for defaults as it's all handled within the SetInterpretedProperty method.
Dean@1154
  1913
                 * Also, .Save() must never be called here as the .ApplyTo() method can be used on MailItems that need to change properties before save.
Dean@1094
  1914
                 */
Thomas@1299
  1915
                if (setInternalHeaderFields)
Dean@543
  1916
                {
Dean@1303
  1917
                    // Note: ignore return status
Dean@1303
  1918
                    omi.SetPEPProperty(MailItemExtensions.PEPProperty.KeyList, this._KeyList);
Thomas@1632
  1919
Thomas@1632
  1920
                    // Only store rating once and never change it
Thomas@1632
  1921
                    object storedRating = null;
Thomas@1632
  1922
                    omi.GetPEPProperty(MailItemExtensions.PEPProperty.Rating, out storedRating);
Thomas@1632
  1923
                    if ((pEpRating)storedRating == pEpRating.pEpRatingUndefined)
Thomas@1632
  1924
                    {
Thomas@1632
  1925
                        omi.SetPEPProperty(MailItemExtensions.PEPProperty.Rating, this._Rating);
Thomas@1632
  1926
                    }
Dean@543
  1927
                }
Dean@1094
  1928
Dean@1303
  1929
                // Note: ignore return status
Dean@1393
  1930
                omi.SetPEPProperty(MailItemExtensions.PEPProperty.AutoConsume, this._AutoConsume);
Thomas@1848
  1931
                omi.SetPEPProperty(MailItemExtensions.PEPProperty.ForceProtection, this._ForceProtectionId);
Dean@1303
  1932
                omi.SetPEPProperty(MailItemExtensions.PEPProperty.NeverUnsecure, this._NeverUnsecure);
Dean@1303
  1933
                omi.SetPEPProperty(MailItemExtensions.PEPProperty.PEPProtocolVersion, this._PEPProtocolVersion);
Dean@408
  1934
            }
Dean@545
  1935
            catch (Exception ex)
Dean@545
  1936
            {
Dean@910
  1937
                status = Globals.ReturnStatus.Failure;
Dean@1249
  1938
                Log.Error("PEPMessage.ApplyTo: Failure occured, " + ex.ToString());
Thomas@1673
  1939
                throw;
Dean@545
  1940
            }
Dean@543
  1941
            finally
Dean@543
  1942
            {
Dean@543
  1943
                if (attachments != null)
Dean@466
  1944
                {
vb@1516
  1945
                    // Marshal.ReleaseComObject(attachments);
Dean@543
  1946
                    attachments = null;
Dean@543
  1947
                }
Dean@408
  1948
Dean@543
  1949
                if (newRecipient != null)
Dean@543
  1950
                {
vb@1516
  1951
                    // Marshal.ReleaseComObject(newRecipient);
Dean@543
  1952
                    newRecipient = null;
Dean@543
  1953
                }
Dean@543
  1954
Dean@543
  1955
                if (recipients != null)
Dean@543
  1956
                {
vb@1516
  1957
                    // Marshal.ReleaseComObject(recipients);
Dean@543
  1958
                    recipients = null;
Dean@543
  1959
                }
Dean@543
  1960
Dean@543
  1961
                if (currAccount != null)
Dean@543
  1962
                {
vb@1507
  1963
                    // Marshal.ReleaseComObject(currAccount);
Dean@543
  1964
                    currAccount = null;
Dean@543
  1965
                }
Dean@543
  1966
Dean@543
  1967
                if (sendUsingAccount != null)
Dean@543
  1968
                {
vb@1516
  1969
                    // Marshal.ReleaseComObject(sendUsingAccount);
Dean@543
  1970
                    sendUsingAccount = null;
Dean@543
  1971
                }
Dean@543
  1972
Dean@543
  1973
                if (accounts != null)
Dean@543
  1974
                {
vb@1507
  1975
                    // Marshal.ReleaseComObject(accounts);
Dean@543
  1976
                    accounts = null;
Dean@543
  1977
                }
Thomas@1119
  1978
Thomas@1119
  1979
                if (fromRecipient != null)
Thomas@1119
  1980
                {
vb@1516
  1981
                    // Marshal.ReleaseComObject(fromRecipient);
Thomas@1119
  1982
                    fromRecipient = null;
Thomas@1119
  1983
                }
Thomas@1467
  1984
Thomas@1467
  1985
                if (ns != null)
Thomas@1467
  1986
                {
vb@1507
  1987
                    // Marshal.ReleaseComObject(ns);
Thomas@1467
  1988
                    ns = null;
Thomas@1467
  1989
                }
Dean@408
  1990
            }
Dean@408
  1991
Dean@910
  1992
            return (status);
Dean@384
  1993
        }
Dean@384
  1994
Dean@1236
  1995
        /// <summary>
Dean@1236
  1996
        /// Converts this message into a single PGP/MIME attachment.
Dean@1236
  1997
        /// This is necessary in order for Outlook and MAPI to correctly transport PGP/MIME messages.
Dean@1236
  1998
        /// The attachment will report itself as S/MIME to MAPI, S/MIME attachments are passed-through as unmodified text.
Dean@1236
  1999
        /// Since we can insert unmodified text, this allows us to build a correct PGP/MIME message from existing attachments.
Dean@1236
  2000
        /// Warning: This can return null if a failure occured.
Dean@1236
  2001
        /// </summary>
Dean@1236
  2002
        /// <returns>This message converted to a single PGP/MIME attachment, otherwise null.</returns>
Dean@1236
  2003
        private PEPAttachment ConvertToPGPMIMEAttachment()
markus@1221
  2004
        {
Dean@1236
  2005
            string boundary;
Dean@1236
  2006
            byte[] bytes;
Dean@1236
  2007
            bool versionInfoFound = false;
Dean@1236
  2008
            bool contentFound = false;
Dean@1236
  2009
            PEPAttachment newAttachment = null;
Dean@1236
  2010
            List<byte> data = new List<byte>();
markus@1221
  2011
Dean@1236
  2012
            if (this._Attachments.Count == 2)
markus@1221
  2013
            {
Dean@1236
  2014
                boundary = "----=_NextPart_" + Guid.NewGuid().ToString().Replace('-', '_');
markus@1221
  2015
Dean@1236
  2016
                /* See below for an example PGP/MIME formatted message.
Dean@1236
  2017
                 * this is from RFC 3156.  
Dean@1236
  2018
                 *    
Dean@1236
  2019
                 *  Content-Type: multipart/encrypted; boundary=foo;
Dean@1236
  2020
                 *     protocol="application/pgp-encrypted"
Dean@1236
  2021
                 * 
Dean@1236
  2022
                 *  --foo
Dean@1236
  2023
                 *  Content-Type: application/pgp-encrypted
Dean@1236
  2024
                 * 
Dean@1236
  2025
                 *  Version: 1
Dean@1236
  2026
                 * 
Dean@1236
  2027
                 *  --foo
Dean@1236
  2028
                 *  Content-Type: application/octet-stream
Dean@1236
  2029
                 * 
Dean@1236
  2030
                 *  -----BEGIN PGP MESSAGE-----
Dean@1236
  2031
                 *  Version: 2.6.2
Dean@1236
  2032
                 * 
Dean@1236
  2033
                 *  hIwDY32hYGCE8MkBA/wOu7d45aUxF4Q0RKJprD3v5Z9K1YcRJ2fve87lMlDlx4Oj
Dean@1236
  2034
                 *  eW4GDdBfLbJE7VUpp13N19GL8e/AqbyyjHH4aS0YoTk10QQ9nnRvjY8nZL3MPXSZ
Dean@1236
  2035
                 *  g9VGQxFeGqzykzmykU6A26MSMexR4ApeeON6xzZWfo+0yOqAq6lb46wsvldZ96YA
Dean@1236
  2036
                 *  AABH78hyX7YX4uT1tNCWEIIBoqqvCeIMpp7UQ2IzBrXg6GtukS8NxbukLeamqVW3
Dean@1236
  2037
                 *  1yt21DYOjuLzcMNe/JNsD9vDVCvOOG3OCi8=
Dean@1236
  2038
                 *  =zzaA
Dean@1236
  2039
                 *  -----END PGP MESSAGE-----
Dean@1236
  2040
                 * 
Dean@1236
  2041
                 *  --foo--
Dean@1236
  2042
                 */
Dean@1236
  2043
Dean@1236
  2044
                // Add internet headers (these are not added by default for S/MIME messages which allows them to be customized)
Dean@1240
  2045
                bytes = Encoding.UTF8.GetBytes("MIME-Version: 1.0" + Environment.NewLine +
Dean@1240
  2046
                                               "Content-Type: multipart/encrypted;" + Environment.NewLine +
Dean@1240
  2047
                                               "\tprotocol=\"application/pgp-encrypted\";" + Environment.NewLine +
Dean@1240
  2048
                                               "\tboundary=\"" + boundary + "\"" + Environment.NewLine);
Dean@1236
  2049
                data.AddRange(bytes);
Dean@1236
  2050
Dean@1236
  2051
                // Add the version identification attachment
Dean@1240
  2052
                bytes = Encoding.UTF8.GetBytes(Environment.NewLine +
Dean@1240
  2053
                                               "--" + boundary + Environment.NewLine +
Dean@1240
  2054
                                               "Content-Type: application/pgp-encrypted" + Environment.NewLine +
Dean@1285
  2055
                                               "Content-Description: PGP/MIME version identification" + Environment.NewLine +
Dean@1240
  2056
                                               Environment.NewLine);
Dean@1236
  2057
                data.AddRange(bytes);
Dean@1236
  2058
Dean@1236
  2059
                foreach (PEPAttachment attach in this._Attachments)
markus@1221
  2060
                {
Thomas@1736
  2061
                    if (attach.IsPGPMIMEVersionInfoFormat)
Dean@1236
  2062
                    {
Dean@1236
  2063
                        data.AddRange(attach.Data);
Dean@1236
  2064
                        versionInfoFound = true;
Dean@1236
  2065
                        break;
Dean@1236
  2066
                    }
markus@1221
  2067
                }
markus@1221
  2068
Dean@1236
  2069
                // Add the content attachment
Dean@1240
  2070
                bytes = Encoding.UTF8.GetBytes(Environment.NewLine +
Dean@1240
  2071
                                               Environment.NewLine +
Dean@1240
  2072
                                               "--" + boundary + Environment.NewLine +
Dean@1285
  2073
                                               "Content-Type: application/octet-stream;" + Environment.NewLine +
Dean@1285
  2074
                                               "\tname=\"msg.asc\"" + Environment.NewLine +
Dean@1240
  2075
                                               Environment.NewLine);
Dean@1236
  2076
                data.AddRange(bytes);
Dean@1236
  2077
Dean@1236
  2078
                foreach (PEPAttachment attach in this._Attachments)
markus@1221
  2079
                {
Thomas@1736
  2080
                    if (attach.IsPGPMIMEContentFormat)
Dean@1236
  2081
                    {
Dean@1236
  2082
                        data.AddRange(attach.Data);
Dean@1236
  2083
                        contentFound = true;
Dean@1236
  2084
                        break;
Dean@1236
  2085
                    }
markus@1221
  2086
                }
Dean@1236
  2087
Dean@1240
  2088
                bytes = Encoding.UTF8.GetBytes(Environment.NewLine +
Dean@1240
  2089
                                               "--" + boundary + "--" + Environment.NewLine);
Dean@1236
  2090
                data.AddRange(bytes);
Dean@1236
  2091
Dean@1236
  2092
                // Create the new attachment
Dean@1236
  2093
                if (versionInfoFound && contentFound)
markus@1221
  2094
                {
Dean@1236
  2095
                    newAttachment = new PEPAttachment()
Dean@1236
  2096
                    {
Dean@1236
  2097
                        Data = data.ToArray(),
Dean@1359
  2098
                        MimeType = "multipart/signed",
Dean@1350
  2099
                        Tag = MapiPropertyValue.PidTagAttachTagMIME
Dean@1236
  2100
                    };
markus@1221
  2101
                }
markus@1221
  2102
            }
markus@1221
  2103
Dean@1236
  2104
            return (newAttachment);
markus@1221
  2105
        }
markus@1221
  2106
Dean@398
  2107
        /// <summary>
Dean@1348
  2108
        /// Recursivley converts all "Bcc", "Cc", and "To" identities into a 'flat' list of any members.
Dean@398
  2109
        /// This will remove groups (hierarchy) and convert a group into it's members.
Dean@398
  2110
        /// </summary>
Dean@398
  2111
        public void FlattenAllRecipientIdentities()
Dean@398
  2112
        {
Dean@1348
  2113
            this._Bcc = PEPIdentity.ToFlatList(this._Bcc);
Dean@1348
  2114
            this._Cc = PEPIdentity.ToFlatList(this._Cc);
Dean@398
  2115
            this._To = PEPIdentity.ToFlatList(this._To);
Dean@398
  2116
Dean@398
  2117
            return;
Dean@398
  2118
        }
Dean@413
  2119
Thomas@1988
  2120
        /// <summary>
Thomas@1988
  2121
        /// Add a disclaimer to the message if needed.
Thomas@1988
  2122
        /// Note: This should only be applied to outgoing messages. As the method doesn't 
Thomas@1988
  2123
        /// save the mail item after adding a disclaimer, it's the caller's responsibility
Thomas@1988
  2124
        /// to save if necessary.
Thomas@1988
  2125
        /// </summary>
Thomas@1988
  2126
        /// <param name="outgoingRating">The outgoing rating for this message.</param>
Thomas@1988
  2127
        public void AddDisclaimer(pEpRating outgoingRating)
Thomas@1988
  2128
        {
Thomas@1988
  2129
            // We only add disclaimers to outgoing messages
Thomas@1988
  2130
            if (this.Direction == pEpMsgDirection.pEpDirOutgoing)
Thomas@1988
  2131
            {
Thomas@1988
  2132
                try
Thomas@1988
  2133
                {
Thomas@1988
  2134
                    // Get settings for From account
Thomas@1988
  2135
                    var accountSettings = Globals.ThisAddIn.Settings.GetAccountSettings(this.From?.Address);
Thomas@1988
  2136
Thomas@1988
  2137
                    /* Add disclaimer if needed:
Thomas@1988
  2138
                     *      - if set to add to all messages
Thomas@1988
  2139
                     *      - if set to add to encrypted messages and outgoing rating is
Thomas@1988
  2140
                     *        at least reliable.
Thomas@1988
  2141
                     */
Thomas@1988
  2142
                    if ((accountSettings.AddDisclaimer == PEPSettings.Disclaimer.AllMessages) ||
Thomas@1988
  2143
                        ((accountSettings.AddDisclaimer == PEPSettings.Disclaimer.OnlyEncryptedMessages) && outgoingRating >= pEpRating.pEpRatingReliable))
Thomas@1988
  2144
                    {
Thomas@1988
  2145
                        // Add to plain text
Thomas@1988
  2146
                        if (string.IsNullOrEmpty(this._LongMsg) == false)
Thomas@1988
  2147
                        {
Thomas@1988
  2148
                            this._LongMsg += Environment.NewLine +
Thomas@1988
  2149
                                             Environment.NewLine +
Thomas@1988
  2150
                                             accountSettings.DisclaimerText;
Thomas@1988
  2151
                        }
Thomas@1988
  2152
Thomas@1988
  2153
                        // Add to html
Thomas@1988
  2154
                        if (string.IsNullOrEmpty(this._LongMsgFormattedHtml) == false)
Thomas@1988
  2155
                        {
Thomas@1988
  2156
                            this._LongMsgFormattedHtml += "<br><br><p>" +
Thomas@1988
  2157
                                                          accountSettings.DisclaimerText +
Thomas@1988
  2158
                                                          "</p>";
Thomas@1988
  2159
                        }
Thomas@1988
  2160
Thomas@1988
  2161
                        // Add to Rtf
Thomas@1988
  2162
                        if (string.IsNullOrEmpty(this._LongMsgFormattedRtf) == false)
Thomas@1988
  2163
                        {
Thomas@1988
  2164
                            System.Windows.Forms.RichTextBox rtb = new System.Windows.Forms.RichTextBox();
Thomas@1988
  2165
                            rtb.Text = this._LongMsgFormattedRtf;
Thomas@1988
  2166
                            rtb.AppendText(Environment.NewLine +
Thomas@1988
  2167
                                           Environment.NewLine +
Thomas@1988
  2168
                                           accountSettings.DisclaimerText);
Thomas@1988
  2169
                            this._LongMsgFormattedRtf = rtb.ToString();
Thomas@1988
  2170
                        }
Thomas@1988
  2171
                    }
Thomas@1988
  2172
                }
Thomas@1988
  2173
                catch (Exception ex)
Thomas@1988
  2174
                {
Thomas@1988
  2175
                    Log.Error("AddDisclaimer: Error adding disclaimer to message. " + ex.ToString());
Thomas@1988
  2176
                }
Thomas@1988
  2177
            }
Thomas@1988
  2178
            else
Thomas@1988
  2179
            {
Thomas@1988
  2180
                Log.Verbose("AddDisclaimer: Skipped. Message is incoming.");
Thomas@1988
  2181
            }
Thomas@1988
  2182
        }
Thomas@1988
  2183
Dean@927
  2184
        /**************************************************************
Dean@927
  2185
         * 
Dean@927
  2186
         * Static Methods
Dean@927
  2187
         * 
Dean@927
  2188
         *************************************************************/
Dean@927
  2189
Dean@927
  2190
        /// <summary>
markus@1337
  2191
        /// Constructs a new message from the given pEp engine TextMessage.
Dean@927
  2192
        /// The output will never be null.
Dean@927
  2193
        /// </summary>
markus@1337
  2194
        /// <param name="msg">The TextMessage to construct from.</param>
Dean@927
  2195
        /// <param name="createdMessage">The output newly created message (will never be null).</param>
Dean@927
  2196
        /// <returns>The status of the method.</returns>
markus@954
  2197
        /// <remarks>In some contexts which call this message, a partial conversion of the
markus@1337
  2198
        /// <see cref="TextMessage"/> is acceptable, non-critical, and better than failure (e. G. displaying
markus@954
  2199
        /// a preview to the user). Thus, this method will always create a <see cref="PEPMessage"/>
markus@954
  2200
        /// which is "best effort", and return the <see cref="Globals.ReturnStatus"/> which can be evaluated
markus@954
  2201
        /// in the more critical contexts. Callers of that message need to be aware of this
markus@954
  2202
        /// and check the result if appropriate.</remarks>
markus@1337
  2203
        public static Globals.ReturnStatus Create(TextMessage msg,
Dean@927
  2204
                                                  out PEPMessage createdMessage)
Dean@927
  2205
        {
Dean@927
  2206
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@927
  2207
            PEPMessage newMessage = new PEPMessage();
Dean@927
  2208
Dean@927
  2209
            try
Dean@927
  2210
            {
markus@1337
  2211
                /* Note: Skip the following properties which are not supported in the TextMessage
Dean@1113
  2212
                 *   • ConversationID
Dean@1113
  2213
                 *   • ConversationIndex
Dean@1113
  2214
                 *   • ConversationTopic
Thomas@1817
  2215
                 *   • EnableProtection
Dean@1095
  2216
                 *   • ForceUnencrypted
Dean@1354
  2217
                 *   • LongMsgFormattedRtf
Dean@1095
  2218
                 * 
Thomas@1841
  2219
                 * Also note the following are handled as optional fields
Thomas@1531
  2220
                 *   • AutoConsume
Thomas@1819
  2221
                 *   • ForceProtection
Dean@1095
  2222
                 *   • KeyList
Dean@1104
  2223
                 *   • NeverUnsecure
Dean@1212
  2224
                 *   • PEPProtocolVersion
Thomas@1531
  2225
                 *   • Rating
Dean@1095
  2226
                 * 
markus@1337
  2227
                 * This also skips a number of TextMessage properties currently unsupported in PEPMessage.
Dean@1095
  2228
                 */
Dean@1095
  2229
Dean@927
  2230
                // Attachments
Dean@927
  2231
                newMessage.Attachments.Clear();
markus@1347
  2232
                if (msg.Attachments != null)
Dean@927
  2233
                {
markus@1347
  2234
                    for (int i = 0; i < msg.Attachments.Length; i++)
Dean@927
  2235
                    {
markus@1347
  2236
                        newMessage.Attachments.Add(new PEPAttachment((Blob)msg.Attachments.GetValue(i)));
Dean@927
  2237
                    }
Dean@927
  2238
                }
Dean@927
  2239
Dean@1348
  2240
                // Bcc
Dean@1348
  2241
                newMessage.Bcc.Clear();
markus@1347
  2242
                if (msg.Bcc != null)
Dean@927
  2243
                {
markus@1347
  2244
                    for (int i = 0; i < msg.Bcc.Length; i++)
Dean@927
  2245
                    {
Dean@1348
  2246
                        newMessage.Bcc.Add(new PEPIdentity((pEpIdentity)msg.Bcc.GetValue(i)));
Dean@927
  2247
                    }
Dean@927
  2248
                }
Dean@927
  2249
Dean@1348
  2250
                // Cc
Dean@1348
  2251
                newMessage.Cc.Clear();
markus@1347
  2252
                if (msg.Cc != null)
Dean@927
  2253
                {
markus@1347
  2254
                    for (int i = 0; i < msg.Cc.Length; i++)
Dean@927
  2255
                    {
Dean@1348
  2256
                        newMessage.Cc.Add(new PEPIdentity((pEpIdentity)msg.Cc.GetValue(i)));
Dean@927
  2257
                    }
Dean@927
  2258
                }
Dean@927
  2259
markus@1347
  2260
                newMessage.Direction = msg.Dir;
markus@1347
  2261
                newMessage.From = new PEPIdentity(msg.From);
Dean@1348
  2262
                newMessage.Id = msg.Id;
Dean@927
  2263
Dean@927
  2264
                // Keywords
Dean@927
  2265
                newMessage.Keywords.Clear();
markus@1347
  2266
                if (msg.Keywords != null)
Dean@927
  2267
                {
markus@1347
  2268
                    for (int i = 0; i < msg.Keywords.Length; i++)
Dean@927
  2269
                    {
markus@1347
  2270
                        newMessage.Keywords.Add((string)msg.Keywords.GetValue(i));
Dean@927
  2271
                    }
Dean@927
  2272
                }
Dean@927
  2273
markus@1356
  2274
                newMessage.LongMsg = msg.LongMsg;
markus@1356
  2275
                newMessage.LongMsgFormattedHtml = msg.LongMsgFormatted;
Dean@927
  2276
Dean@927
  2277
                // Optional properties
markus@1347
  2278
                if (msg.OptFields != null)
Dean@927
  2279
                {
markus@1347
  2280
                    foreach (StringPair optField in msg.OptFields)
Dean@927
  2281
                    {
markus@1347
  2282
                        if (optField.Name != null)
Dean@1094
  2283
                        {
markus@1347
  2284
                            switch (optField.Name)
Dean@1094
  2285
                            {
Dean@1393
  2286
                                case PEPMessage.PR_PEP_AUTO_CONSUME_NAME:
Dean@1393
  2287
                                    {
Dean@1393
  2288
                                        newMessage.AutoConsume = optField.Value;
Dean@1393
  2289
                                        break;
Dean@1393
  2290
                                    }
Thomas@1819
  2291
                                case PEPMessage.PR_PEP_FORCE_PROTECTION_NAME:
Thomas@1819
  2292
                                    {
Thomas@1848
  2293
                                        newMessage.ForceProtectionId = optField.Value;
Thomas@1819
  2294
                                        break;
Thomas@1819
  2295
                                    }
Dean@1393
  2296
                                case PEPMessage.PR_KEY_LIST_NAME:
Dean@1393
  2297
                                    {
Dean@1393
  2298
                                        newMessage.KeyList = optField.Value;
Dean@1393
  2299
                                        break;
Dean@1393
  2300
                                    }
Dean@1393
  2301
                                case PEPMessage.PR_PEP_NEVER_UNSECURE_NAME:
Dean@1393
  2302
                                    {
Dean@1393
  2303
                                        // If it exists it's true, value doesn't matter
Dean@1393
  2304
                                        newMessage.NeverUnsecure = true;
Dean@1393
  2305
                                        break;
Dean@1393
  2306
                                    }
Dean@1393
  2307
                                case PEPMessage.PR_PEP_PROTOCOL_VERSION_NAME:
Dean@1393
  2308
                                    {
Dean@1393
  2309
                                        newMessage.PEPProtocolVersion = optField.Value;
Dean@1393
  2310
                                        break;
Dean@1393
  2311
                                    }
Dean@1393
  2312
                                case PEPMessage.PR_ENC_STATUS_NAME:
Dean@1095
  2313
                                    {
Dean@1095
  2314
                                        try
Dean@1095
  2315
                                        {
markus@1347
  2316
                                            newMessage.Rating = AdapterExtensions.ParseRatingString(optField.Value);
Dean@1095
  2317
                                        }
Dean@1095
  2318
                                        catch
Dean@1095
  2319
                                        {
markus@1337
  2320
                                            newMessage.Rating = pEpRating.pEpRatingUndefined;
Dean@1095
  2321
                                        }
Dean@1095
  2322
                                        break;
Dean@1095
  2323
                                    }
Dean@1094
  2324
                            }
Dean@1094
  2325
                        }
Dean@927
  2326
                    }
Dean@927
  2327
                }
Dean@927
  2328
Dean@927
  2329
                // ReceivedOn
markus@1347
  2330
                if (msg.Recv > 0)
Dean@927
  2331
                {
Thomas@1649
  2332
                    DateTime receivedOnUtc = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(msg.Recv);
Thomas@1649
  2333
                    try
Thomas@1649
  2334
                    {
Thomas@1649
  2335
                        newMessage.ReceivedOn = TimeZoneInfo.ConvertTimeFromUtc(receivedOnUtc, TimeZoneInfo.Local);
Thomas@1649
  2336
                    }
Thomas@1936
  2337
                    catch (Exception ex)
Thomas@1649
  2338
                    {
Thomas@1936
  2339
                        Log.Error("PEPMessage.Create: Error converting received time to local time. " + ex.ToString());
Thomas@1649
  2340
                        newMessage.ReceivedOn = new DateTime(1970, 1, 1).AddSeconds(msg.Recv);
Thomas@1649
  2341
                    }
Dean@927
  2342
                }
Dean@927
  2343
                else
Dean@927
  2344
                {
Dean@927
  2345
                    newMessage.ReceivedOn = null;
Dean@927
  2346
                }
Dean@927
  2347
Dean@927
  2348
                // SentOn
markus@1347
  2349
                if (msg.Sent > 0)
Dean@927
  2350
                {
Thomas@1649
  2351
                    DateTime sentOnUtc = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(msg.Sent);
Thomas@1649
  2352
                    try
Thomas@1649
  2353
                    {
Thomas@1649
  2354
                        newMessage.SentOn = TimeZoneInfo.ConvertTimeFromUtc(sentOnUtc, TimeZoneInfo.Local);
Thomas@1649
  2355
                    }
Thomas@1936
  2356
                    catch (Exception ex)
Thomas@1649
  2357
                    {
Thomas@1936
  2358
                        Log.Error("PEPMessage.Create: Error converting sent time to local time. " + ex.ToString());
Thomas@1649
  2359
                        newMessage.SentOn = new DateTime(1970, 1, 1).AddSeconds(msg.Sent);
Thomas@1649
  2360
                    }
Dean@927
  2361
                }
Dean@927
  2362
                else
Dean@927
  2363
                {
Dean@927
  2364
                    newMessage.SentOn = null;
Dean@927
  2365
                }
Dean@927
  2366
markus@1356
  2367
                newMessage.ShortMsg = msg.ShortMsg;
Dean@927
  2368
Dean@927
  2369
                // To
Dean@927
  2370
                newMessage.To.Clear();
markus@1347
  2371
                if (msg.To != null)
Dean@927
  2372
                {
markus@1347
  2373
                    for (int i = 0; i < msg.To.Length; i++)
Dean@927
  2374
                    {
markus@1347
  2375
                        newMessage.To.Add(new PEPIdentity((pEpIdentity)msg.To.GetValue(i)));
Dean@927
  2376
                    }
Dean@927
  2377
                }
Dean@927
  2378
            }
Dean@927
  2379
            catch (Exception ex)
Dean@927
  2380
            {
Dean@927
  2381
                status = Globals.ReturnStatus.Failure;
Dean@1249
  2382
                Log.Error("PEPMessage.Create: Failure occured, " + ex.ToString());
Dean@927
  2383
            }
Dean@927
  2384
Dean@927
  2385
            createdMessage = newMessage;
Dean@927
  2386
            return (status);
Dean@927
  2387
        }
Dean@927
  2388
Dean@927
  2389
        /// <summary>
Dean@927
  2390
        /// Contructs a new message from the given outlook mail item.
Dean@927
  2391
        /// The output will never be null.
Dean@927
  2392
        /// </summary>
Dean@927
  2393
        /// <param name="omi">The outlook mail item to create the message from.</param>
Dean@927
  2394
        /// <param name="createdMessage">The output newly created message (will never be null).</param>
Thomas@1999
  2395
        /// <param name="onlyRecipientsAndDirection">Whether to only set recipients and direction. Only set to
Thomas@1999
  2396
        /// true in special cases, e.g. if the message is only needed to calculate the outgoing rating.</param>
Thomas@2005
  2397
        /// <param name="createContacts">Whether or not to create contacts from the mail items's recipients during
Thomas@2005
  2398
        /// processing of the message. Only set to false in special cases like for outgoing rating.</param>
Dean@927
  2399
        /// <returns>The status of the method.</returns>
markus@954
  2400
        /// <remarks>In some contexts which call this message, a partial conversion of the
markus@1337
  2401
        /// <see cref="TextMessage"/> is acceptable, non-critical, and better than failure (e. G. displaying
markus@954
  2402
        /// a preview to the user). Thus, this method will always create a <see cref="PEPMessage"/>
markus@954
  2403
        /// which is "best effort", and return the <see cref="Globals.ReturnStatus"/> which can be evaluated
markus@954
  2404
        /// in the more critical contexts. Callers of that message need to be aware of this
markus@954
  2405
        /// and check the result if appropriate.</remarks>
Dean@927
  2406
        public static Globals.ReturnStatus Create(Outlook.MailItem omi,
Dean@927
  2407
                                                  out PEPMessage createdMessage,
Thomas@2005
  2408
                                                  bool onlyRecipientsAndDirection = false,
Thomas@2005
  2409
                                                  bool createContacts = true)
Dean@927
  2410
        {
Dean@927
  2411
            byte[] rtfBody;
Dean@927
  2412
            string delim;
Dean@927
  2413
            string[] keywords;
Dean@927
  2414
            DateTime? receivedOn = null;
Dean@927
  2415
            DateTime? sentOn = null;
Dean@927
  2416
            PEPIdentity ident;
Dean@927
  2417
            Outlook.Attachment currAttachment = null;
Dean@927
  2418
            Outlook.Attachments attachments = null;
Dean@927
  2419
            Outlook.Recipient currRecipient = null;
Dean@927
  2420
            Outlook.Recipients recipients = null;
Dean@927
  2421
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@927
  2422
            Globals.ReturnStatus sts;
Dean@927
  2423
            PEPMessage newMessage = new PEPMessage();
Dean@927
  2424
Dean@927
  2425
            try
Dean@927
  2426
            {
Thomas@2004
  2427
                Log.Verbose("PEPMessage.Create: Creating new PEPMessage from OMI started.");
Thomas@2004
  2428
Thomas@2004
  2429
                newMessage.Direction = omi.GetIsIncoming() ? pEpMsgDirection.pEpDirIncoming : pEpMsgDirection.pEpDirOutgoing;
Thomas@2004
  2430
                Log.Verbose("PEPMessage.Create: direction calculated.");
Dean@927
  2431
Dean@927
  2432
                // Calculate recipients
Dean@1348
  2433
                newMessage.Bcc.Clear();
Dean@1348
  2434
                newMessage.Cc.Clear();
Dean@927
  2435
                newMessage.To.Clear();
Dean@927
  2436
                recipients = omi.Recipients;
Dean@927
  2437
                for (int i = 1; i <= recipients.Count; i++)
Dean@927
  2438
                {
Dean@927
  2439
                    currRecipient = recipients[i];
Dean@927
  2440
Dean@927
  2441
                    switch ((Outlook.OlMailRecipientType)currRecipient.Type)
Dean@927
  2442
                    {
Dean@927
  2443
                        case Outlook.OlMailRecipientType.olBCC:
Dean@1095
  2444
                            {
Dean@1202
  2445
                                sts = PEPIdentity.Create(currRecipient, out ident);
Dean@1095
  2446
                                if (sts == Globals.ReturnStatus.Success)
Dean@1095
  2447
                                {
Dean@1348
  2448
                                    newMessage.Bcc.Add(ident);
Dean@1095
  2449
                                }
Dean@1095
  2450
                                else