PEPMessage.cs
author Dean
Tue, 26 Jul 2016 18:01:56 +0200
changeset 1095 edb18344895b
parent 1094 6866b9e8bd9a
child 1104 e7ef441d14ac
permissions -rw-r--r--
Maintain KeepConfidential specifically through message processing.
Dean@384
     1
using Microsoft.Win32;
Dean@384
     2
using pEpCOMServerAdapterLib;
Dean@384
     3
using System;
Dean@384
     4
using System.Collections.Generic;
Dean@1094
     5
using System.ComponentModel;
Dean@384
     6
using System.Runtime.InteropServices;
Dean@384
     7
using Outlook = Microsoft.Office.Interop.Outlook;
Dean@384
     8
Dean@384
     9
namespace pEp
Dean@384
    10
{
Dean@384
    11
    /// <summary>
Dean@389
    12
    /// Class for a completely in-memory message based on the pEp engine text_message.
Dean@384
    13
    /// </summary>
Dean@1094
    14
    internal class PEPMessage : INotifyPropertyChanged,
Dean@1094
    15
                                Interfaces.ICopy<PEPMessage>,
Dean@1094
    16
                                Interfaces.IReset
Dean@384
    17
    {
Dean@1094
    18
        /// <summary>
Dean@1094
    19
        /// Event raised when a property is changed on a component.
Dean@1094
    20
        /// </summary>
Dean@1094
    21
        public event PropertyChangedEventHandler PropertyChanged;
Dean@1094
    22
Dean@572
    23
        // pEp properties
Dean@1093
    24
        public const string PR_OPT_FIELD               = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/";
Dean@1093
    25
        public const string PR_X_ENC_STATUS            = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-EncStatus";
Dean@1093
    26
        public const string PR_X_KEY_LIST              = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-KeyList";
Dean@1093
    27
        public const string PR_X_PEP_KEEP_CONFIDENTIAL = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-pEp-Keep-Confidential";
Dean@1093
    28
        public const string PR_X_PEP_VERSION           = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-pEp-Version";
Dean@572
    29
Dean@1093
    30
        public const string PR_X_ENC_STATUS_NAME            = "X-EncStatus";
Dean@1093
    31
        public const string PR_X_KEY_LIST_NAME              = "X-KeyList";
Dean@1093
    32
        public const string PR_X_PEP_KEEP_CONFIDENTIAL_NAME = "X-pEp-Keep-Confidential";
Dean@1093
    33
        public const string PR_X_PEP_VERSION_NAME           = "X-pEp-Version";
Dean@780
    34
Dean@384
    35
        private List<PEPAttachment> _Attachments;
Dean@1094
    36
        private bool                _AttachOwnKey;
Dean@384
    37
        private List<PEPIdentity>   _BCC;
Dean@384
    38
        private List<PEPIdentity>   _CC;
Dean@1094
    39
        private _pEp_color          _ColorRating;
Dean@384
    40
        private _pEp_msg_direction  _Direction;
Dean@1094
    41
        private bool                _ForceUnencrypted;
Dean@384
    42
        private PEPIdentity         _From;
Dean@384
    43
        private string              _ID;
Dean@1094
    44
        private bool                _KeepConfidential;
Dean@1094
    45
        private string              _KeyList;
Dean@384
    46
        private List<string>        _Keywords;
Dean@384
    47
        private string              _LongMsg;
Dean@697
    48
        private string              _LongMsgFormattedHTML;
Dean@697
    49
        private string              _LongMsgFormattedRTF;
Dean@1094
    50
        private string              _PEPVersion;
Dean@721
    51
        private DateTime?           _ReceivedOn;
Dean@721
    52
        private DateTime?           _SentOn;
Dean@384
    53
        private string              _ShortMsg;
Dean@384
    54
        private List<PEPIdentity>   _To;
Dean@384
    55
Dean@384
    56
        /**************************************************************
Dean@384
    57
         * 
Dean@384
    58
         * Constructors
Dean@384
    59
         * 
Dean@384
    60
         *************************************************************/
Dean@384
    61
Dean@384
    62
        /// <summary>
Dean@384
    63
        /// Default constructor.
Dean@384
    64
        /// </summary>
Dean@384
    65
        public PEPMessage()
Dean@384
    66
        {
Dean@1094
    67
            this.Reset();
Dean@384
    68
        }
Dean@384
    69
Dean@384
    70
        /**************************************************************
Dean@384
    71
         * 
Dean@384
    72
         * Property Accessors
Dean@384
    73
         * 
Dean@384
    74
         *************************************************************/
Dean@384
    75
Dean@910
    76
        #region Property Accessors
Dean@910
    77
Dean@384
    78
        /// <summary>
Dean@384
    79
        /// Gets the list of attachements for this message.
Dean@1094
    80
        ///          MailItem : Corresponds to property 'Attachments' which contains 'Attachment'
Dean@1094
    81
        /// CryptableMailItem : not exposed
Dean@1094
    82
        ///      text_message : Corresponds to property 'attachments' which contains 'blob'
Dean@384
    83
        /// </summary>
Dean@384
    84
        public List<PEPAttachment> Attachments
Dean@384
    85
        {
Dean@384
    86
            get { return (this._Attachments); }
Dean@384
    87
        }
Dean@384
    88
Dean@384
    89
        /// <summary>
Dean@1094
    90
        /// Gets or sets whether to attach the senders own public key to the message.
Dean@1094
    91
        /// This should only be used with outgoing messages, for incoming it is ignored..
Dean@1094
    92
        ///          MailItem : Corresponds to UserProperty USER_PROPERTY_KEY_ATTACH_OWN_KEY
Dean@1094
    93
        /// CryptableMailItem : Corresponds to property 'AttachOwnKeyBool'
Dean@1094
    94
        ///      text_message : not supported
Dean@1094
    95
        /// </summary>
Dean@1094
    96
        public bool AttachOwnKey
Dean@1094
    97
        {
Dean@1094
    98
            get { return (this._AttachOwnKey); }
Dean@1094
    99
            set
Dean@1094
   100
            {
Dean@1094
   101
                this._AttachOwnKey = value;
Dean@1094
   102
                this.RaisePropertyChangedEvent("AttachOwnKey");
Dean@1094
   103
            }
Dean@1094
   104
        }
Dean@1094
   105
Dean@1094
   106
        /// <summary>
Dean@387
   107
        /// Gets the list of identities to be blind carbon copied on the message.
Dean@1094
   108
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   109
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1094
   110
        ///      text_message : Corresponds to property 'bcc'
Dean@384
   111
        /// </summary>
Dean@384
   112
        public List<PEPIdentity> BCC
Dean@384
   113
        {
Dean@384
   114
            get { return (this._BCC); }
Dean@384
   115
        }
Dean@384
   116
Dean@384
   117
        /// <summary>
Dean@384
   118
        /// Gets the list of identities to be carbon copied on the message.
Dean@1094
   119
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   120
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1094
   121
        ///      text_message : Corresponds to property 'cc'
Dean@384
   122
        /// </summary>
Dean@384
   123
        public List<PEPIdentity> CC
Dean@384
   124
        {
Dean@384
   125
            get { return (this._CC); }
Dean@384
   126
        }
Dean@384
   127
Dean@384
   128
        /// <summary>
Dean@1094
   129
        /// Gets or sets the color rating of the message.
Dean@1094
   130
        /// This should corresponds primarily with the decryption color rating.
Dean@1094
   131
        /// Warning: Since this is stored as a header field, care must be taken not to apply this to a MailItem on an 
Dean@1094
   132
        /// untrusted server or on an outgoing message.
Dean@1094
   133
        ///          MailItem : Corresponds to MAPI Property PR_X_ENC_STATUS (Header field)
Dean@1094
   134
        /// CryptableMailItem : not exposed (processed internally)
Dean@1094
   135
        ///      text_message : Corresponds with the key PR_X_ENC_STATUS_NAME within 'opt_fields' array
Dean@1094
   136
        /// </summary>
Dean@1094
   137
        public _pEp_color ColorRating
Dean@1094
   138
        {
Dean@1094
   139
            get { return (this._ColorRating); }
Dean@1094
   140
            set
Dean@1094
   141
            {
Dean@1094
   142
                this._ColorRating = value;
Dean@1094
   143
                this.RaisePropertyChangedEvent("ColorRating");
Dean@1094
   144
            }
Dean@1094
   145
        }
Dean@1094
   146
Dean@1094
   147
        /// <summary>
Dean@721
   148
        /// Gets the date and time when the message was either sent or received.
Dean@1094
   149
        /// This corresponds with the SentOn and ReceivedOn properties defined separately.
Dean@691
   150
        /// </summary>
Dean@691
   151
        public DateTime? DateTimeSentOrReceived
Dean@691
   152
        {
Dean@721
   153
            get
Dean@721
   154
            {
Dean@721
   155
                if (this._Direction == _pEp_msg_direction.pEp_dir_incoming)
Dean@721
   156
                {
Dean@721
   157
                    return (this._ReceivedOn);
Dean@721
   158
                }
Dean@721
   159
                else
Dean@721
   160
                {
Dean@721
   161
                    return (this._SentOn);
Dean@721
   162
                }
Dean@721
   163
            }
Dean@691
   164
        }
Dean@691
   165
Dean@691
   166
        /// <summary>
Dean@384
   167
        /// Gets or sets the direction (incoming or outgoing) of the message.
Dean@1094
   168
        ///          MailItem : not supported (calculated from various properties)
Dean@1094
   169
        /// CryptableMailItem : Corresponds 1-to-1 with property 'IsIncoming'
Dean@1094
   170
        ///      text_message : Corresponds to property 'dir'
Dean@384
   171
        /// </summary>
Dean@384
   172
        public _pEp_msg_direction Direction
Dean@384
   173
        {
Dean@384
   174
            get { return (this._Direction); }
Dean@1094
   175
            set
Dean@1094
   176
            {
Dean@1094
   177
                this._Direction = value;
Dean@1094
   178
                this.RaisePropertyChangedEvent("Direction");
Dean@1094
   179
            }
Dean@1094
   180
        }
Dean@1094
   181
Dean@1094
   182
        /// <summary>
Dean@1094
   183
        /// Gets or sets the force unencrypted status.
Dean@1094
   184
        ///          MailItem : Corresponds to UserProperty USER_PROPERTY_KEY_FORCE_UNENCRYPTED
Dean@1094
   185
        /// CryptableMailItem : Corresponds to property 'ForceUnencryptedBool'
Dean@1094
   186
        ///      text_message : not supported
Dean@1094
   187
        /// </summary>
Dean@1094
   188
        public bool ForceUnencrypted
Dean@1094
   189
        {
Dean@1094
   190
            get { return (this._ForceUnencrypted); }
Dean@1094
   191
            set
Dean@1094
   192
            {
Dean@1094
   193
                this._ForceUnencrypted = value;
Dean@1094
   194
                this.RaisePropertyChangedEvent("ForceUnencrypted");
Dean@1094
   195
            }
Dean@384
   196
        }
Dean@384
   197
Dean@384
   198
        /// <summary>
Dean@384
   199
        /// Gets or sets the from identity of the message.
Dean@384
   200
        /// Warning: this value can be null.
Dean@1094
   201
        ///          MailItem : not supported (calculated from various properties)
Dean@1094
   202
        /// CryptableMailItem : Corresponds to property 'From'
Dean@1094
   203
        ///      text_message : Corresponds to property 'from'
Dean@384
   204
        /// </summary>
Dean@384
   205
        public PEPIdentity From
Dean@384
   206
        {
Dean@384
   207
            get { return (this._From); }
Dean@1094
   208
            set
Dean@1094
   209
            {
Dean@1094
   210
                this._From = value;
Dean@1094
   211
                this.RaisePropertyChangedEvent("From");
Dean@1094
   212
            }
Dean@384
   213
        }
Dean@384
   214
Dean@384
   215
        /// <summary>
Dean@384
   216
        /// Gets or sets the ID of the message.
Dean@384
   217
        /// Warning: this value can be null.
Dean@1095
   218
        ///          MailItem : Corresponds to MAPI property PidTagInternetMessageId
Dean@1095
   219
        /// CryptableMailItem : not supported
Dean@1094
   220
        ///      text_message : Corresponds to property 'id'
Dean@384
   221
        /// </summary>
Dean@384
   222
        public string ID
Dean@384
   223
        {
Dean@384
   224
            get { return (this._ID); }
Dean@1094
   225
            set
Dean@1094
   226
            {
Dean@1094
   227
                this._ID = value;
Dean@1094
   228
                this.RaisePropertyChangedEvent("ID");
Dean@1094
   229
            }
Dean@384
   230
        }
Dean@384
   231
Dean@384
   232
        /// <summary>
Dean@927
   233
        /// Gets whether this message is encrypted.
Dean@927
   234
        /// This will forward the call to the static method of the same purpose.
Dean@927
   235
        /// </summary>
Dean@927
   236
        public bool IsEncrypted
Dean@927
   237
        {
Dean@927
   238
            get { return (PEPMessage.GetIsEncrypted(this)); }
Dean@927
   239
        }
Dean@927
   240
Dean@927
   241
        /// <summary>
Dean@1094
   242
        /// Gets or sets whether this message is marked to keep confidential.
Dean@1094
   243
        /// Note: While this is stored as a header field, it is OK to apply to any MailItem and outgoing messages.
Dean@1094
   244
        /// It's intended function is to flag a message to keep it encrypted.
Dean@1094
   245
        ///          MailItem : Corresponds to MAPI Property PR_X_PEP_KEEP_CONFIDENTIAL (Header field)
Dean@1094
   246
        /// CryptableMailItem : Corresponds to property 'KeepConfidential'
Dean@1094
   247
        ///      text_message : not supported
Dean@1094
   248
        /// </summary>
Dean@1094
   249
        public bool KeepConfidential
Dean@1094
   250
        {
Dean@1094
   251
            get { return (this._KeepConfidential); }
Dean@1094
   252
            set
Dean@1094
   253
            {
Dean@1094
   254
                this._KeepConfidential = value;
Dean@1094
   255
                this.RaisePropertyChangedEvent("KeepConfidential");
Dean@1094
   256
            }
Dean@1094
   257
        }
Dean@1094
   258
Dean@1094
   259
        /// <summary>
Dean@1094
   260
        /// Gets or sets the list of keys associated with this message.
Dean@1094
   261
        /// Commonly this contains the list of decryption keys.
Dean@1094
   262
        /// Warning: Since this is stored as a header field, care must be taken not to apply this to a MailItem on an 
Dean@1094
   263
        /// untrusted server or on an outgoing message.
Dean@1094
   264
        ///          MailItem : Corresponds to MAPI Property PR_X_KEY_LIST (Header field)
Dean@1094
   265
        /// CryptableMailItem : Corresponds to property 'Keylist'
Dean@1094
   266
        ///      text_message : Corresponds with the key PR_X_KEY_LIST_NAME within 'opt_fields' array. 
Dean@1094
   267
        ///                     This is also an out parameter of the decrypt function.
Dean@1094
   268
        /// </summary>
Dean@1094
   269
        public string KeyList
Dean@1094
   270
        {
Dean@1094
   271
            get { return (this._KeyList); }
Dean@1094
   272
            set
Dean@1094
   273
            {
Dean@1094
   274
                this._KeyList = value;
Dean@1094
   275
                this.RaisePropertyChangedEvent("KeyList");
Dean@1094
   276
            }
Dean@1094
   277
        }
Dean@1094
   278
Dean@1094
   279
        /// <summary>
Dean@384
   280
        /// Gets the list of keywords associated with the message.
Dean@1094
   281
        ///          MailItem : Corresponds to property 'Categories'
Dean@1094
   282
        /// CryptableMailItem : not supported
Dean@1094
   283
        ///      text_message : Corresponds to property 'keywords'
Dean@384
   284
        /// </summary>
Dean@384
   285
        public List<string> Keywords
Dean@384
   286
        {
Dean@384
   287
            get { return (this._Keywords); }
Dean@384
   288
        }
Dean@384
   289
Dean@384
   290
        /// <summary>
Dean@1094
   291
        /// Gets or sets the plain text long-form (body) of the message.
Dean@384
   292
        /// Warning: this value can be null.
Dean@1094
   293
        ///          MailItem : Corresponds to property 'Body' (also BodyFormat)
Dean@1094
   294
        /// CryptableMailItem : not exposed (processed internally)
Dean@1094
   295
        ///      text_message : Corresponds to property 'longmsg'
Dean@384
   296
        /// </summary>
Dean@384
   297
        public string LongMsg
Dean@384
   298
        {
Dean@384
   299
            get { return (this._LongMsg); }
Dean@1094
   300
            set
Dean@1094
   301
            {
Dean@1094
   302
                this._LongMsg = value;
Dean@1094
   303
                this.RaisePropertyChangedEvent("LongMsg");
Dean@1094
   304
            }
Dean@384
   305
        }
Dean@384
   306
Dean@384
   307
        /// <summary>
Dean@697
   308
        /// Gets or sets the HTML formatted long-form (body) of the message.
Dean@384
   309
        /// Warning: this value can be null.
Dean@1094
   310
        ///          MailItem : Corresponds to property 'HTMLBody' (also BodyFormat)
Dean@1094
   311
        /// CryptableMailItem : not exposed (processed internally)
Dean@1094
   312
        ///      text_message : Corresponds to property 'longmsg_formatted'
Dean@384
   313
        /// </summary>
Dean@697
   314
        public string LongMsgFormattedHTML
Dean@384
   315
        {
Dean@697
   316
            get { return (this._LongMsgFormattedHTML); }
Dean@1094
   317
            set
Dean@1094
   318
            {
Dean@1094
   319
                this._LongMsgFormattedHTML = value;
Dean@1094
   320
                this.RaisePropertyChangedEvent("LongMsgFormattedHTML");
Dean@1094
   321
            }
Dean@697
   322
        }
Dean@697
   323
Dean@697
   324
        /// <summary>
Dean@697
   325
        /// Gets or sets the RTF formatted long-form (body) of the message.
Dean@1094
   326
        /// Warning: this value can be null, it is only supported when creating from a MailItem. It is
Dean@1094
   327
        /// not applied to a MailItem during .ApplyTo as it's unsupported by the engine.
Dean@1094
   328
        ///          MailItem : Corresponds to property 'RTFBody' (also BodyFormat)
Dean@1094
   329
        /// CryptableMailItem : not exposed (processed internally)
Dean@1094
   330
        ///      text_message : not supported
Dean@697
   331
        /// </summary>
Dean@697
   332
        public string LongMsgFormattedRTF
Dean@697
   333
        {
Dean@697
   334
            get { return (this._LongMsgFormattedRTF); }
Dean@1094
   335
            set
Dean@1094
   336
            {
Dean@1094
   337
                this._LongMsgFormattedRTF = value;
Dean@1094
   338
                this.RaisePropertyChangedEvent("LongMsgFormattedRTF");
Dean@1094
   339
            }
Dean@384
   340
        }
Dean@384
   341
Dean@384
   342
        /// <summary>
Dean@1094
   343
        /// Gets or sets the version of the pEp engine used for processing this message.
Dean@1094
   344
        /// This is commonly set after decryption.
Dean@1094
   345
        /// Note: While this is stored as a header field, it is OK to apply to any MailItem and outgoing messages.
Dean@1094
   346
        /// It's intended function is just to show the version of pEp last used to process the message.
Dean@1094
   347
        ///          MailItem : Corresponds to MAPI Property PR_X_PEP_VERSION (Header field)
Dean@1094
   348
        /// CryptableMailItem : not supported
Dean@1094
   349
        ///      text_message : Corresponds with the key PR_X_PEP_VERSION_NAME within 'opt_fields' array. 
Dean@384
   350
        /// </summary>
Dean@1094
   351
        public string PEPVersion
Dean@384
   352
        {
Dean@1094
   353
            get { return (this._PEPVersion); }
Dean@1094
   354
            set
Dean@1094
   355
            {
Dean@1094
   356
                this._PEPVersion = value;
Dean@1094
   357
                this.RaisePropertyChangedEvent("PEPVersion");
Dean@1094
   358
            }
Dean@384
   359
        }
Dean@384
   360
Dean@384
   361
        /// <summary>
Dean@721
   362
        /// Gets or sets the date and time when the message was received.
Dean@1094
   363
        ///          MailItem : Corresponds to property 'ReceivedTime'
Dean@1094
   364
        /// CryptableMailItem : not supported
Dean@1094
   365
        ///      text_message : Corresponds to property 'recv'
Dean@721
   366
        /// </summary>
Dean@721
   367
        public DateTime? ReceivedOn
Dean@721
   368
        {
Dean@721
   369
            get { return (this._ReceivedOn); }
Dean@1094
   370
            set
Dean@1094
   371
            {
Dean@1094
   372
                this._ReceivedOn = value;
Dean@1094
   373
                this.RaisePropertyChangedEvent("ReceivedOn");
Dean@1094
   374
            }
Dean@721
   375
        }
Dean@721
   376
Dean@721
   377
        /// <summary>
Dean@721
   378
        /// Gets or sets the date and time when the message was sent.
Dean@1094
   379
        ///          MailItem : Corresponds to property 'SentOn'
Dean@1094
   380
        /// CryptableMailItem : not supported
Dean@1094
   381
        ///      text_message : Corresponds to property 'sent'
Dean@721
   382
        /// </summary>
Dean@721
   383
        public DateTime? SentOn
Dean@721
   384
        {
Dean@721
   385
            get { return (this._SentOn); }
Dean@1094
   386
            set
Dean@1094
   387
            {
Dean@1094
   388
                this._SentOn = value;
Dean@1094
   389
                this.RaisePropertyChangedEvent("SentOn");
Dean@1094
   390
            }
Dean@721
   391
        }
Dean@721
   392
Dean@721
   393
        /// <summary>
Dean@384
   394
        /// Gets or sets the short-form (subject) of the message.
Dean@384
   395
        /// Warning: this value can be null.
Dean@1094
   396
        ///          MailItem : Corresponds to property 'Subject'
Dean@1094
   397
        /// CryptableMailItem : not supported
Dean@1094
   398
        ///      text_message : Corresponds to property 'shortmsg'
Dean@384
   399
        /// </summary>
Dean@384
   400
        public string ShortMsg
Dean@384
   401
        {
Dean@384
   402
            get { return (this._ShortMsg); }
Dean@1094
   403
            set
Dean@1094
   404
            {
Dean@1094
   405
                this._ShortMsg = value;
Dean@1094
   406
                this.RaisePropertyChangedEvent("ShortMsg");
Dean@1094
   407
            }
Dean@384
   408
        }
Dean@384
   409
Dean@384
   410
        /// <summary>
Dean@384
   411
        /// Gets the list of identities to receive the message.
Dean@1094
   412
        ///          MailItem : Component of property 'Recipients' which contains 'Recipient'
Dean@1094
   413
        /// CryptableMailItem : not exposed directly (part of Recipients)
Dean@1094
   414
        ///      text_message : Corresponds to property 'to'
Dean@384
   415
        /// </summary>
Dean@384
   416
        public List<PEPIdentity> To
Dean@384
   417
        {
Dean@384
   418
            get { return (this._To); }
Dean@384
   419
        }
Dean@384
   420
Dean@625
   421
        /// <summary>
Dean@625
   422
        /// Gets the total number of all recipients in the message (BCC, CC &amp; To).
Dean@625
   423
        /// </summary>
Dean@625
   424
        public int RecipientCount
Dean@625
   425
        {
Dean@625
   426
            get { return (this._BCC.Count + this._CC.Count + this._To.Count); }
Dean@625
   427
        }
Dean@625
   428
Dean@625
   429
        /// <summary>
Dean@625
   430
        /// Gets a list of all recipients in the message (BCC, CC &amp; To).
Dean@625
   431
        /// Each recipient in the returned list is a copy.
Dean@625
   432
        /// </summary>
Dean@625
   433
        public PEPIdentity[] Recipients
Dean@625
   434
        {
Dean@625
   435
            get
Dean@625
   436
            {
Dean@625
   437
                List<PEPIdentity> recipients = new List<PEPIdentity>();
Dean@625
   438
Dean@625
   439
                // BCC
Dean@625
   440
                for (int i = 0; i < this._BCC.Count; i++)
Dean@625
   441
                {
Dean@625
   442
                    recipients.Add(this._BCC[i].Copy());
Dean@625
   443
                }
Dean@625
   444
Dean@625
   445
                // CC
Dean@625
   446
                for (int i = 0; i < this._CC.Count; i++)
Dean@625
   447
                {
Dean@625
   448
                    recipients.Add(this._CC[i].Copy());
Dean@625
   449
                }
Dean@625
   450
Dean@625
   451
                // To
Dean@625
   452
                for (int i = 0; i < this._To.Count; i++)
Dean@625
   453
                {
Dean@625
   454
                    recipients.Add(this._To[i].Copy());
Dean@625
   455
                }
Dean@625
   456
Dean@625
   457
                return (recipients.ToArray());
Dean@625
   458
            }
Dean@625
   459
        }
Dean@625
   460
Dean@910
   461
        #endregion
Dean@910
   462
Dean@384
   463
        /**************************************************************
Dean@384
   464
         * 
Dean@384
   465
         * Methods
Dean@384
   466
         * 
Dean@384
   467
         *************************************************************/
Dean@384
   468
Dean@384
   469
        /// <summary>
Dean@1094
   470
        /// Raises the property changed event, if possible, with the given arguments.
Dean@1094
   471
        /// </summary>
Dean@1094
   472
        /// <param name="propertyName">The name of the property that changed.</param>
Dean@1094
   473
        private void RaisePropertyChangedEvent(string propertyName)
Dean@1094
   474
        {
Dean@1094
   475
            if (this.PropertyChanged != null)
Dean@1094
   476
            {
Dean@1094
   477
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
Dean@1094
   478
            }
Dean@1094
   479
            return;
Dean@1094
   480
        }
Dean@1094
   481
Dean@1094
   482
        /// <summary>
Dean@1094
   483
        /// Returns this pEp message as a new pEp engine text_message struct.
Dean@910
   484
        /// Warning: Any identity members (groups) are lost, call FlattenAllRecipientIdentities() before this method.
Dean@384
   485
        /// </summary>
Dean@1094
   486
        /// <param name="alwaysAddOptFields">Whether to always add optional fields (default is false). When false, 
Dean@1094
   487
        /// optional fields will not be added if they are undefined/null/empty in the PEPMessage. This is to prevent 
Dean@1094
   488
        /// against adding optional fields when they have never been set.
Dean@1094
   489
        /// </param>
Dean@384
   490
        /// <returns>A pEp engine identity.</returns>
Dean@1094
   491
        public text_message ToCOMType(bool alwaysAddOptFields = false)
Dean@384
   492
        {
Dean@1095
   493
            long recvSec;
Dean@1095
   494
            long sentSec;
Dean@1095
   495
            TimeSpan span;
Dean@384
   496
            List<blob> attachments = new List<blob>();
Dean@384
   497
            List<pEp_identity_s> bcc = new List<pEp_identity_s>();
Dean@384
   498
            List<pEp_identity_s> cc = new List<pEp_identity_s>();
Dean@384
   499
            List<pEp_identity_s> to = new List<pEp_identity_s>();
Dean@1094
   500
            List<opt_field> optionalFields = new List<opt_field>();
Dean@1094
   501
            opt_field field;
Dean@384
   502
            text_message result = new text_message();
Dean@384
   503
Dean@388
   504
            // Convert attachments
Dean@384
   505
            for (int i = 0; i < this._Attachments.Count; i++)
Dean@384
   506
            {
Dean@384
   507
                attachments.Add(this._Attachments[i].ToCOMType());
Dean@384
   508
            }
Dean@398
   509
Dean@388
   510
            // Convert BCC
Dean@384
   511
            for (int i = 0; i < this._BCC.Count; i++)
Dean@384
   512
            {
Dean@384
   513
                bcc.Add(this._BCC[i].ToCOMType());
Dean@384
   514
            }
Dean@398
   515
Dean@388
   516
            // Convert CC
Dean@384
   517
            for (int i = 0; i < this._CC.Count; i++)
Dean@384
   518
            {
Dean@384
   519
                cc.Add(this._CC[i].ToCOMType());
Dean@384
   520
            }
Dean@398
   521
Dean@388
   522
            // Convert To
Dean@388
   523
            for (int i = 0; i < this._To.Count; i++)
Dean@388
   524
            {
Dean@388
   525
                to.Add(this._To[i].ToCOMType());
Dean@388
   526
            }
Dean@388
   527
Dean@1094
   528
            // Create optional fields
Dean@1094
   529
            if ((alwaysAddOptFields) ||
Dean@1094
   530
                (this._ColorRating != _pEp_color.pEp_rating_undefined))
Dean@1094
   531
            {
Dean@1094
   532
                field = new opt_field();
Dean@1094
   533
                field.name = PEPMessage.PR_X_ENC_STATUS_NAME;
Dean@1094
   534
                field.value = this._ColorRating.ToString().Remove(0, 11); // Remove the 'pEp_rating_' text
Dean@1094
   535
                optionalFields.Add(field);
Dean@1094
   536
            }
Dean@1094
   537
Dean@1094
   538
            if ((alwaysAddOptFields) ||
Dean@1094
   539
                (string.IsNullOrEmpty(this._KeyList) == false))
Dean@1094
   540
            {
Dean@1094
   541
                field = new opt_field();
Dean@1094
   542
                field.name = PEPMessage.PR_X_KEY_LIST_NAME;
Dean@1094
   543
                field.value = this._KeyList;
Dean@1094
   544
                optionalFields.Add(field);
Dean@1094
   545
            }
Dean@1094
   546
Dean@1094
   547
            if ((alwaysAddOptFields) ||
Dean@1095
   548
                (this._KeepConfidential == true))
Dean@1095
   549
            {
Dean@1095
   550
                field = new opt_field();
Dean@1095
   551
                field.name = PEPMessage.PR_X_PEP_KEEP_CONFIDENTIAL_NAME;
Dean@1095
   552
                field.value = "1";
Dean@1095
   553
                optionalFields.Add(field);
Dean@1095
   554
            }
Dean@1095
   555
Dean@1095
   556
            if ((alwaysAddOptFields) ||
Dean@1094
   557
                (string.IsNullOrEmpty(this._PEPVersion) == false))
Dean@1094
   558
            {
Dean@1094
   559
                field = new opt_field();
Dean@1094
   560
                field.name = PEPMessage.PR_X_PEP_VERSION_NAME;
Dean@1094
   561
                field.value = this._PEPVersion;
Dean@1094
   562
                optionalFields.Add(field);
Dean@1094
   563
            }
Dean@1094
   564
Dean@1095
   565
            // ReceivedOn
Dean@1095
   566
            recvSec = -1;
Dean@1095
   567
            if (this._ReceivedOn != null)
Dean@1095
   568
            {
Dean@1095
   569
                span = (DateTime)this._ReceivedOn - new DateTime(1970, 1, 1);
Dean@1095
   570
                recvSec = (long)span.TotalSeconds;
Dean@1095
   571
            }
Dean@1095
   572
Dean@1095
   573
            // SentOn
Dean@1095
   574
            sentSec = -1;
Dean@1095
   575
            if (this._SentOn != null)
Dean@1095
   576
            {
Dean@1095
   577
                span = (DateTime)this._SentOn - new DateTime(1970, 1, 1);
Dean@1095
   578
                sentSec = (long)span.TotalSeconds;
Dean@1095
   579
            }
Dean@1095
   580
Dean@1095
   581
            /* Note: Skip the following properties which are not supported in text_message
Dean@1094
   582
             *   • AttachOwnKey
Dean@1094
   583
             *   • ForceUnencrypted
Dean@1095
   584
             *   • LongMsgFormattedRTF
Dean@1095
   585
             * 
Dean@1095
   586
             * Also not the following are handled as optional fields
Dean@1095
   587
             *   • ColorRating
Dean@1094
   588
             *   • KeepConfidential
Dean@1095
   589
             *   • KeyList
Dean@1095
   590
             *   • PEPVersion
Dean@1095
   591
             * 
Dean@1095
   592
             * This also skips a number of text_message properties currently unsupported in PEPMessage.
Dean@697
   593
             */
Dean@388
   594
            result.attachments = attachments.ToArray();
Dean@388
   595
            result.bcc = bcc.ToArray();
Dean@384
   596
            result.cc = cc.ToArray();
Dean@384
   597
            result.dir = this._Direction;
Dean@1095
   598
            result.from = (this._From != null ? this._From.ToCOMType() : result.from);
Dean@384
   599
            result.id = this._ID;
Dean@384
   600
            result.keywords = this._Keywords.ToArray();
Dean@384
   601
            result.longmsg = this._LongMsg;
Dean@697
   602
            result.longmsg_formatted = this._LongMsgFormattedHTML;
Dean@1094
   603
            result.opt_fields = optionalFields.ToArray();
Dean@1095
   604
            result.recv = ((recvSec >= 0) ? recvSec : result.recv);
Dean@1095
   605
            result.sent = ((sentSec >= 0) ? sentSec : result.sent);
Dean@384
   606
            result.shortmsg = this._ShortMsg;
Dean@384
   607
            result.to = to.ToArray();
Dean@384
   608
Dean@384
   609
            return (result);
Dean@384
   610
        }
Dean@384
   611
Dean@384
   612
        /// <summary>
Dean@389
   613
        /// Gets a deep copy of the object and all it's data.
Dean@389
   614
        /// </summary>
Dean@389
   615
        /// <returns>The deep copy of the object.</returns>
Dean@389
   616
        public PEPMessage Copy()
Dean@389
   617
        {
Dean@390
   618
            return (this.Copy(false));
Dean@390
   619
        }
Dean@390
   620
Dean@390
   621
        /// <summary>
Dean@390
   622
        /// Gets a copy of the PEPMessage with or without data.
Dean@390
   623
        /// </summary>
Dean@586
   624
        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
Dean@586
   625
        /// and optional properties.</param>
Dean@390
   626
        /// <returns>The copy of the PEPMessage.</returns>
Dean@390
   627
        public PEPMessage Copy(bool createWithoutContent = false)
Dean@390
   628
        {
Dean@389
   629
            PEPMessage copy = new PEPMessage();
Dean@389
   630
Dean@389
   631
            // Attachments
Dean@389
   632
            copy.Attachments.Clear();
Dean@390
   633
            if (createWithoutContent == false)
Dean@389
   634
            {
Dean@390
   635
                for (int i = 0; i < this._Attachments.Count; i++)
Dean@390
   636
                {
Dean@390
   637
                    copy.Attachments.Add(this._Attachments[i].Copy());
Dean@390
   638
                }
Dean@389
   639
            }
Dean@389
   640
Dean@1094
   641
            copy.AttachOwnKey = this._AttachOwnKey;
Dean@1094
   642
Dean@389
   643
            // BCC
Dean@389
   644
            copy.BCC.Clear();
Dean@389
   645
            for (int i = 0; i < this._BCC.Count; i++)
Dean@389
   646
            {
Dean@389
   647
                copy.BCC.Add(this._BCC[i].Copy());
Dean@389
   648
            }
Dean@389
   649
Dean@389
   650
            // CC
Dean@389
   651
            copy.CC.Clear();
Dean@389
   652
            for (int i = 0; i < this._CC.Count; i++)
Dean@389
   653
            {
Dean@389
   654
                copy.CC.Add(this._CC[i].Copy());
Dean@389
   655
            }
Dean@389
   656
Dean@1094
   657
            copy.ColorRating = this._ColorRating;
Dean@389
   658
            copy.Direction = this._Direction;
Dean@1094
   659
            copy.ForceUnencrypted = this._ForceUnencrypted;
Dean@389
   660
            copy.From = (this._From == null ? null : this._From.Copy());
Dean@389
   661
            copy.ID = this._ID;
Dean@1094
   662
            copy.KeepConfidential = this._KeepConfidential;
Dean@1094
   663
            copy.KeyList = this._KeyList;
Dean@389
   664
Dean@389
   665
            // Keywords
Dean@389
   666
            copy.Keywords.Clear();
Dean@389
   667
            for (int i = 0; i < this._Keywords.Count; i++)
Dean@389
   668
            {
Dean@389
   669
                copy.Keywords.Add(this._Keywords[i]);
Dean@389
   670
            }
Dean@398
   671
Dean@390
   672
            // Body
Dean@390
   673
            if (createWithoutContent == false)
Dean@390
   674
            {
Dean@390
   675
                copy.LongMsg = this._LongMsg;
Dean@697
   676
                copy.LongMsgFormattedHTML = this._LongMsgFormattedHTML;
Dean@697
   677
                copy.LongMsgFormattedRTF = this._LongMsgFormattedRTF;
Dean@390
   678
            }
Dean@390
   679
            else
Dean@390
   680
            {
Dean@390
   681
                copy.LongMsg = null;
Dean@697
   682
                copy.LongMsgFormattedHTML = null;
Dean@697
   683
                copy.LongMsgFormattedRTF = null;
Dean@390
   684
            }
Dean@389
   685
Dean@1094
   686
            copy.PEPVersion = this._PEPVersion;
Dean@604
   687
Dean@721
   688
            // ReceivedOn
Dean@721
   689
            if (this._ReceivedOn != null)
Dean@721
   690
            {
Dean@721
   691
                copy.ReceivedOn = new DateTime(((DateTime)this._ReceivedOn).Ticks);
Dean@721
   692
            }
Dean@721
   693
            else
Dean@721
   694
            {
Dean@721
   695
                copy.ReceivedOn = null;
Dean@721
   696
            }
Dean@721
   697
Dean@721
   698
            // SentOn
Dean@721
   699
            if (this._SentOn != null)
Dean@721
   700
            {
Dean@721
   701
                copy.SentOn = new DateTime(((DateTime)this._SentOn).Ticks);
Dean@721
   702
            }
Dean@721
   703
            else
Dean@721
   704
            {
Dean@721
   705
                copy.SentOn = null;
Dean@721
   706
            }
Dean@721
   707
Dean@389
   708
            copy.ShortMsg = this._ShortMsg;
Dean@389
   709
Dean@389
   710
            // To
Dean@389
   711
            copy.To.Clear();
Dean@389
   712
            for (int i = 0; i < this._To.Count; i++)
Dean@389
   713
            {
Dean@389
   714
                copy.To.Add(this._To[i].Copy());
Dean@389
   715
            }
Dean@389
   716
Dean@389
   717
            return (copy);
Dean@389
   718
        }
Dean@389
   719
Dean@389
   720
        /// <summary>
Dean@1094
   721
        /// Resets the object to it's default state/values.
Dean@1094
   722
        /// </summary>
Dean@1094
   723
        public void Reset()
Dean@1094
   724
        {
Dean@1094
   725
            this._Attachments = new List<PEPAttachment>();
Dean@1094
   726
            this._AttachOwnKey = false;
Dean@1094
   727
            this._BCC = new List<PEPIdentity>();
Dean@1094
   728
            this._CC = new List<PEPIdentity>();
Dean@1094
   729
            this._ColorRating = _pEp_color.pEp_rating_undefined;
Dean@1094
   730
            this._Direction = _pEp_msg_direction.pEp_dir_incoming;
Dean@1094
   731
            this._ForceUnencrypted = false;
Dean@1094
   732
            this._From = null;
Dean@1094
   733
            this._ID = null;
Dean@1094
   734
            this._KeepConfidential = false;
Dean@1094
   735
            this._KeyList = null;
Dean@1094
   736
            this._Keywords = new List<string>();
Dean@1094
   737
            this._LongMsg = null;
Dean@1094
   738
            this._LongMsgFormattedHTML = null;
Dean@1094
   739
            this._LongMsgFormattedRTF = null;
Dean@1094
   740
            this._PEPVersion = null;
Dean@1094
   741
            this._ReceivedOn = null;
Dean@1094
   742
            this._SentOn = null;
Dean@1094
   743
            this._ShortMsg = null;
Dean@1094
   744
            this._To = new List<PEPIdentity>();
Dean@1094
   745
Dean@1094
   746
            this.RaisePropertyChangedEvent("Attachments");
Dean@1094
   747
            this.RaisePropertyChangedEvent("AttachOwnKey");
Dean@1094
   748
            this.RaisePropertyChangedEvent("BCC");
Dean@1094
   749
            this.RaisePropertyChangedEvent("CC");
Dean@1094
   750
            this.RaisePropertyChangedEvent("ColorRating");
Dean@1094
   751
            this.RaisePropertyChangedEvent("Direction");
Dean@1094
   752
            this.RaisePropertyChangedEvent("ForceUnencrypted");
Dean@1094
   753
            this.RaisePropertyChangedEvent("From");
Dean@1094
   754
            this.RaisePropertyChangedEvent("ID");
Dean@1094
   755
            this.RaisePropertyChangedEvent("KeepConfidential");
Dean@1094
   756
            this.RaisePropertyChangedEvent("KeyList");
Dean@1094
   757
            this.RaisePropertyChangedEvent("Keywords");
Dean@1094
   758
            this.RaisePropertyChangedEvent("LongMsg");
Dean@1094
   759
            this.RaisePropertyChangedEvent("LongMsgFormattedHTML");
Dean@1094
   760
            this.RaisePropertyChangedEvent("LongMsgFormattedRTF");
Dean@1094
   761
            this.RaisePropertyChangedEvent("PEPVersion");
Dean@1094
   762
            this.RaisePropertyChangedEvent("ReceivedOn");
Dean@1094
   763
            this.RaisePropertyChangedEvent("SentOn");
Dean@1094
   764
            this.RaisePropertyChangedEvent("ShortMsg");
Dean@1094
   765
            this.RaisePropertyChangedEvent("To");
Dean@1094
   766
Dean@1094
   767
            return;
Dean@1094
   768
        }
Dean@1094
   769
Dean@1094
   770
        /// <summary>
Dean@1095
   771
        /// Copies main properties that are unsupported by the engine from the given message into this message.
Dean@1095
   772
        /// This is commonly used to restore information that would otherwise be lost in converstions to/from 
Dean@1095
   773
        /// text_message during engine processing.
Dean@1095
   774
        /// Key properties that should be set separately for encryption concerns (such as LongMsgFormattedRTF) are ignored.
Dean@1095
   775
        /// </summary>
Dean@1095
   776
        /// <param name="msg">The message to copy over properties from.</param>
Dean@1095
   777
        public void SetNonEnginePropertiesFrom(PEPMessage msg)
Dean@1095
   778
        {
Dean@1095
   779
            /* Include the following properties:
Dean@1095
   780
             *   • AttachOwnKey
Dean@1095
   781
             *   • ForceUnencrypted
Dean@1095
   782
             *   • KeepConfidential
Dean@1095
   783
             * 
Dean@1095
   784
             * Also note:
Dean@1095
   785
             *         ColorRating: This is handled by the decrypt function of the engine only. It should not be
Dean@1095
   786
             *                      added back separately so is skipped.
Dean@1095
   787
             *             KeyList: This is handled by the decrypt function of the engine only. It should not be
Dean@1095
   788
             *                      added back separately so is skipped.
Dean@1095
   789
             * LongMsgFormattedRTF: This is completely unsupported by the engine but otherwise should be encrypted.
Dean@1095
   790
             *                      Due to this, it's completely skipped.
Dean@1095
   791
             *          PEPVersion: This is handled in both the decrypt and encrypt functions of the engine.
Dean@1095
   792
             *                      It should almost always be set within the text_message there isn't needed to add back.
Dean@1095
   793
             */
Dean@1095
   794
Dean@1095
   795
            if (msg != null)
Dean@1095
   796
            {
Dean@1095
   797
                this._AttachOwnKey = msg.AttachOwnKey;
Dean@1095
   798
                this._ForceUnencrypted = msg.ForceUnencrypted;
Dean@1095
   799
                this._KeepConfidential = msg.KeepConfidential;
Dean@1095
   800
Dean@1095
   801
                this.RaisePropertyChangedEvent("AttachOwnKey");
Dean@1095
   802
                this.RaisePropertyChangedEvent("ForceUnencrypted");
Dean@1095
   803
                this.RaisePropertyChangedEvent("KeepConfidential");
Dean@1095
   804
            }
Dean@1095
   805
Dean@1095
   806
            return;
Dean@1095
   807
        }
Dean@1095
   808
Dean@1095
   809
        /// <summary>
Dean@384
   810
        /// Applies this pEp message's data to the given Outlook item.
Dean@384
   811
        /// </summary>
Dean@384
   812
        /// <param name="omi">The Outlook mail item to apply this pEp message's data to.</param>
Dean@1094
   813
        /// <param name="includeInternalHeaderFields">Whether to include internal header fields (Stored as MAPI properites) such as 
Dean@1094
   814
        /// ColorRating and KeyList. Warning: Never apply these to outgoing messages -- used only for mirrors or internal MailItems.
Dean@1094
   815
        /// Note that some header fields will be applied regardless such as KeepConfidential or PEPVersion. 
Dean@1094
   816
        /// That is because these are not considered internal only and don't contain sensitive information.</param>
Dean@910
   817
        /// <returns>The status of the method.</returns>
Dean@910
   818
        public Globals.ReturnStatus ApplyTo(Outlook.MailItem omi,
Dean@1094
   819
                                            bool includeInternalHeaderFields = false)
Dean@384
   820
        {
Dean@543
   821
            Outlook.Attachments attachments = null;
Dean@543
   822
            Outlook.Recipient newRecipient = null;
Dean@543
   823
            Outlook.Recipients recipients = null;
Dean@543
   824
            Outlook.Account currAccount = null;
Dean@543
   825
            Outlook.Account sendUsingAccount = null;
Dean@543
   826
            Outlook.Accounts accounts = null;
Dean@910
   827
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@408
   828
Dean@543
   829
            try
Dean@408
   830
            {
Dean@1094
   831
                // Remove all existing recipients
Dean@543
   832
                recipients = omi.Recipients;
Dean@543
   833
                while (recipients.Count > 0)
Dean@543
   834
                {
Dean@543
   835
                    recipients.Remove(1);
Dean@543
   836
                }
Dean@543
   837
Dean@543
   838
                // Set recipients
Dean@543
   839
                for (int i = 0; i < this._BCC.Count; i++)
Dean@543
   840
                {
Dean@795
   841
                    if (string.IsNullOrWhiteSpace(this._BCC[i].Address) == false)
Dean@543
   842
                    {
Dean@795
   843
                        // Add by address
Dean@543
   844
                        newRecipient = recipients.Add(this._BCC[i].Address);
Dean@543
   845
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Dean@543
   846
Dean@543
   847
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   848
                        newRecipient = null;
Dean@543
   849
                    }
Dean@795
   850
                    else if (string.IsNullOrWhiteSpace(this._BCC[i].Username) == false)
Dean@795
   851
                    {
Dean@795
   852
                        // Add by username (required for distribution lists)
Dean@795
   853
                        newRecipient = recipients.Add(this._BCC[i].Username);
Dean@795
   854
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Dean@795
   855
Dean@795
   856
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   857
                        newRecipient = null;
Dean@795
   858
                    }
Dean@543
   859
                }
Dean@543
   860
Dean@543
   861
                for (int i = 0; i < this._CC.Count; i++)
Dean@543
   862
                {
Dean@795
   863
                    if (string.IsNullOrWhiteSpace(this._CC[i].Address) == false)
Dean@543
   864
                    {
Dean@795
   865
                        // Add by address
Dean@543
   866
                        newRecipient = recipients.Add(this._CC[i].Address);
Dean@543
   867
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Dean@543
   868
Dean@543
   869
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   870
                        newRecipient = null;
Dean@543
   871
                    }
Dean@795
   872
                    else if (string.IsNullOrWhiteSpace(this._CC[i].Username) == false)
Dean@795
   873
                    {
Dean@795
   874
                        // Add by username (required for distribution lists)
Dean@795
   875
                        newRecipient = recipients.Add(this._CC[i].Username);
Dean@795
   876
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Dean@795
   877
Dean@795
   878
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   879
                        newRecipient = null;
Dean@795
   880
                    }
Dean@543
   881
                }
Dean@543
   882
Dean@543
   883
                for (int i = 0; i < this._To.Count; i++)
Dean@543
   884
                {
Dean@795
   885
                    if (string.IsNullOrWhiteSpace(this._To[i].Address) == false)
Dean@543
   886
                    {
Dean@795
   887
                        // Add by address
Dean@543
   888
                        newRecipient = recipients.Add(this._To[i].Address);
Dean@543
   889
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@543
   890
Dean@543
   891
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   892
                        newRecipient = null;
Dean@543
   893
                    }
Dean@795
   894
                    else if (string.IsNullOrWhiteSpace(this._To[i].Username) == false)
Dean@795
   895
                    {
Dean@795
   896
                        // Add by username (required for distribution lists)
Dean@795
   897
                        newRecipient = recipients.Add(this._To[i].Username);
Dean@795
   898
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@795
   899
Dean@795
   900
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   901
                        newRecipient = null;
Dean@795
   902
                    }
Dean@543
   903
                }
Dean@543
   904
Dean@910
   905
                try
Dean@910
   906
                {
Dean@910
   907
                    recipients.ResolveAll();
Dean@910
   908
                }
Dean@910
   909
                catch { }
Dean@543
   910
Dean@543
   911
                /* Set sender
Dean@543
   912
                 * Note that if fails, will be empty which eventually will use the default send account
Dean@543
   913
                 * If the send using account is already populated, this cannot be re-set.
Dean@543
   914
                 * So far this doesn't appear to be an issue as it occurs when applying unencrypted data to a mirror.
Dean@543
   915
                 * However, the mirror SendUsingAccount is already correct at this point and doesn't need to be set.
Dean@543
   916
                 */
Dean@543
   917
                sendUsingAccount = omi.SendUsingAccount;
Dean@543
   918
Dean@543
   919
                if ((this._From != null) &&
Dean@543
   920
                    (this._From.Address != null) &&
Dean@543
   921
                    (sendUsingAccount == null))
Dean@543
   922
                {
Dean@543
   923
                    accounts = Globals.ThisAddIn.Application.Session.Accounts;
Dean@543
   924
Dean@543
   925
                    // Note: Index starts at 1
Dean@543
   926
                    for (int i = 1; i <= accounts.Count; i++)
Dean@543
   927
                    {
Dean@543
   928
                        currAccount = accounts[i];
Dean@543
   929
Dean@543
   930
                        if ((currAccount.SmtpAddress != null) &&
Dean@543
   931
                            (currAccount.SmtpAddress.ToUpper() == this._From.Address.ToUpper()))
Dean@543
   932
                        {
Dean@543
   933
                            /* Try to set the SendUsingAccount
Dean@543
   934
                             * This will fail if the mail item is already marked as sent or the SendUsingAccount is not null, etc...
Dean@564
   935
                             * If it fails, Outlook will in the end just use the default account.
Dean@564
   936
                             * This property should ideally be set before a mail item is saved.
Dean@543
   937
                             */
Dean@543
   938
                            try
Dean@543
   939
                            {
Dean@564
   940
                                omi.SendUsingAccount = currAccount;
Dean@543
   941
                            }
Dean@543
   942
                            catch { }
Dean@543
   943
Dean@543
   944
                            Marshal.ReleaseComObject(currAccount);
Dean@543
   945
                            currAccount = null;
Dean@543
   946
Dean@543
   947
                            break;
Dean@543
   948
                        }
Dean@543
   949
Dean@543
   950
                        Marshal.ReleaseComObject(currAccount);
Dean@543
   951
                        currAccount = null;
Dean@543
   952
                    }
Dean@543
   953
                }
Dean@543
   954
Dean@1056
   955
                /* Set the encoding to UTF-8
Dean@1056
   956
                 * See: https://msdn.microsoft.com/en-us/library/office/ff860730.aspx
Dean@1058
   957
                 * All PEPMessages should be UTF especially those coming from the engine.
Dean@1058
   958
                 * 
Dean@1058
   959
                 * It is important that the encoding is set BEFORE the body and other text of the 
Dean@1058
   960
                 * mail item. This is necessary to avoid character encoding issues where
Dean@1058
   961
                 * Outlook will not respect the UTF encoding of strings set to the body/subject/etc.
Dean@1058
   962
                 * It will instead try to use the strings with the encoding of the codepage.
Dean@1056
   963
                 */
Dean@1056
   964
                try
Dean@1056
   965
                {
Dean@1056
   966
                    MAPIHelper.SetProperty(omi, MAPIProperty.PidTagInternetCodepage, 65001);
Dean@1056
   967
                    MAPIHelper.SetProperty(omi, MAPIProperty.PidTagMessageCodepage, 65001);
Dean@1056
   968
                }
Dean@1056
   969
                catch
Dean@1056
   970
                {
Dean@1056
   971
                    Globals.Log("PEPMessage.ApplyTo: Failed to set UTF-8 encoding.");
Dean@1056
   972
                }
Dean@1056
   973
Dean@543
   974
                // Set the subject
Dean@543
   975
                omi.Subject = this._ShortMsg;
Dean@543
   976
Dean@697
   977
                // Set the body (skip RTF format, only use HTML which is what the engine uses)
Dean@697
   978
                if (string.IsNullOrWhiteSpace(this._LongMsgFormattedHTML))
Dean@543
   979
                {
Dean@543
   980
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
Dean@543
   981
                    omi.Body = this._LongMsg;
Dean@543
   982
                }
Dean@543
   983
                else
Dean@543
   984
                {
Dean@543
   985
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
Dean@697
   986
                    omi.HTMLBody = this._LongMsgFormattedHTML;
Dean@543
   987
                }
Dean@543
   988
Dean@543
   989
                // Remove any previous attachments
Dean@543
   990
                attachments = omi.Attachments;
Dean@543
   991
                while (attachments.Count > 0)
Dean@543
   992
                {
Dean@543
   993
                    attachments.Remove(1);
Dean@543
   994
                }
Dean@543
   995
Dean@543
   996
                // Add new attachments
Dean@543
   997
                for (int i = 0; i < this._Attachments.Count; i++)
Dean@543
   998
                {
Dean@843
   999
                    this._Attachments[i].AddTo(attachments, ("attachment" + i.ToString()));
Dean@543
  1000
                }
Dean@543
  1001
Dean@1095
  1002
                // ID
Dean@1095
  1003
                MAPIHelper.SetProperty(omi, MAPIProperty.PidTagInternetMessageId, this._ID);
Dean@1095
  1004
Dean@1094
  1005
                /* Add internal properties
Dean@1094
  1006
                 * Note: there is no need to check for defaults and then not set as it's all handled within
Dean@1094
  1007
                 * the SetInterpretedProperty method.
Dean@1094
  1008
                 */
Dean@1094
  1009
                if (includeInternalHeaderFields)
Dean@543
  1010
                {
Dean@1094
  1011
                    // ColorRating, ignore return status
Dean@1094
  1012
                    CryptableMailItem.SetInterpretedProperty(omi,
Dean@1094
  1013
                                                             PEPMessage.PR_X_ENC_STATUS,
Dean@1094
  1014
                                                             this._ColorRating);
Dean@1094
  1015
Dean@1094
  1016
                    // KeyList, ignore return status
Dean@1094
  1017
                    CryptableMailItem.SetInterpretedProperty(omi,
Dean@1094
  1018
                                                             PEPMessage.PR_X_KEY_LIST,
Dean@1094
  1019
                                                             this._KeyList);
Dean@543
  1020
                }
Dean@1094
  1021
Dean@1094
  1022
                // KeepConfidential, ignore return status
Dean@1094
  1023
                CryptableMailItem.SetInterpretedProperty(omi,
Dean@1094
  1024
                                                         PEPMessage.PR_X_PEP_KEEP_CONFIDENTIAL,
Dean@1094
  1025
                                                         this._KeepConfidential);
Dean@1094
  1026
Dean@1094
  1027
                // PEPVersion, ignore return status
Dean@1094
  1028
                CryptableMailItem.SetInterpretedProperty(omi,
Dean@1094
  1029
                                                         PEPMessage.PR_X_PEP_VERSION,
Dean@1094
  1030
                                                         this._PEPVersion);
Dean@408
  1031
            }
Dean@545
  1032
            catch (Exception ex)
Dean@545
  1033
            {
Dean@910
  1034
                status = Globals.ReturnStatus.Failure;
Dean@910
  1035
                Globals.Log("PEPMessage.ApplyTo: Failure occured, " + ex.ToString());
Dean@545
  1036
            }
Dean@543
  1037
            finally
Dean@543
  1038
            {
Dean@543
  1039
                if (attachments != null)
Dean@466
  1040
                {
Dean@543
  1041
                    Marshal.ReleaseComObject(attachments);
Dean@543
  1042
                    attachments = null;
Dean@543
  1043
                }
Dean@408
  1044
Dean@543
  1045
                if (newRecipient != null)
Dean@543
  1046
                {
Dean@466
  1047
                    Marshal.ReleaseComObject(newRecipient);
Dean@543
  1048
                    newRecipient = null;
Dean@543
  1049
                }
Dean@543
  1050
Dean@543
  1051
                if (recipients != null)
Dean@543
  1052
                {
Dean@543
  1053
                    Marshal.ReleaseComObject(recipients);
Dean@543
  1054
                    recipients = null;
Dean@543
  1055
                }
Dean@543
  1056
Dean@543
  1057
                if (currAccount != null)
Dean@543
  1058
                {
Dean@543
  1059
                    Marshal.ReleaseComObject(currAccount);
Dean@543
  1060
                    currAccount = null;
Dean@543
  1061
                }
Dean@543
  1062
Dean@543
  1063
                if (sendUsingAccount != null)
Dean@543
  1064
                {
Dean@543
  1065
                    Marshal.ReleaseComObject(sendUsingAccount);
Dean@543
  1066
                    sendUsingAccount = null;
Dean@543
  1067
                }
Dean@543
  1068
Dean@543
  1069
                if (accounts != null)
Dean@543
  1070
                {
Dean@543
  1071
                    Marshal.ReleaseComObject(accounts);
Dean@543
  1072
                    accounts = null;
Dean@543
  1073
                }
Dean@408
  1074
            }
Dean@408
  1075
Dean@910
  1076
            return (status);
Dean@384
  1077
        }
Dean@384
  1078
Dean@398
  1079
        /// <summary>
Dean@398
  1080
        /// Recursivley converts all "BCC", "CC", and "To" identities into a 'flat' list of any members.
Dean@398
  1081
        /// This will remove groups (hierarchy) and convert a group into it's members.
Dean@398
  1082
        /// </summary>
Dean@398
  1083
        public void FlattenAllRecipientIdentities()
Dean@398
  1084
        {
Dean@398
  1085
            this._BCC = PEPIdentity.ToFlatList(this._BCC);
Dean@398
  1086
            this._CC = PEPIdentity.ToFlatList(this._CC);
Dean@398
  1087
            this._To = PEPIdentity.ToFlatList(this._To);
Dean@398
  1088
Dean@398
  1089
            return;
Dean@398
  1090
        }
Dean@413
  1091
Dean@808
  1092
        /// <summary>
Dean@808
  1093
        /// Processes all content IDs in the image attachments as well as HTML body.
Dean@808
  1094
        /// This will convert the CID's to the image filename only.
Dean@808
  1095
        /// </summary>
Dean@808
  1096
        public void NormalizeContentIDs()
Dean@808
  1097
        {
Dean@808
  1098
            int currImgTagIndex;
Dean@808
  1099
            int currImgTagStopIndex;
Dean@808
  1100
            int currImgTagCIDIndex;
Dean@808
  1101
            int currImgTagCIDStopIndex;
Dean@920
  1102
            int tempIndex;
Dean@808
  1103
            string currCID;
Dean@808
  1104
            string newCID;
Dean@808
  1105
            string beginning;
Dean@808
  1106
            string ending;
Dean@808
  1107
            string currFileName;
Dean@808
  1108
            string workingHTML;
Dean@808
  1109
            Dictionary<string, string> modifiedCIDs = new Dictionary<string, string>();
Dean@808
  1110
Dean@808
  1111
            // Modify CIDs for all attachments and store modified CIDs in the dictionary
Dean@808
  1112
            for (int i = 0; i < this._Attachments.Count; i++)
Dean@808
  1113
            {
Dean@808
  1114
                currCID = this._Attachments[i].ContentID;
Dean@808
  1115
                currFileName = this._Attachments[i].FileName;
Dean@808
  1116
Dean@808
  1117
                if (string.IsNullOrEmpty(currCID))
Dean@808
  1118
                {
Dean@920
  1119
                    /* Just use the file name (even if file name is null or empty)
Dean@920
  1120
                     * It's doesn't matter as it shouldn't be replaced in HTML.
Dean@920
  1121
                     * This situation should mean either the attachment isn't an embedded image, or
Dean@920
  1122
                     * the filename is already used as the CID in the HTML.
Dean@920
  1123
                     */
Dean@808
  1124
                    newCID = currFileName;
Dean@808
  1125
                }
Dean@808
  1126
                else
Dean@808
  1127
                {
Dean@808
  1128
                    if (string.IsNullOrEmpty(currFileName))
Dean@808
  1129
                    {
Dean@808
  1130
                        // A name must exist for HTML so create one
Dean@808
  1131
                        newCID = "attachment" + i.ToString();
Dean@808
  1132
                    }
Dean@808
  1133
                    else
Dean@808
  1134
                    {
Dean@843
  1135
                        newCID = currFileName;
Dean@808
  1136
                    }
Dean@808
  1137
Dean@808
  1138
                    modifiedCIDs.Add(currCID, newCID);
Dean@808
  1139
                }
Dean@808
  1140
Dean@808
  1141
                this._Attachments[i].ContentID = newCID;
Dean@808
  1142
            }
Dean@808
  1143
Dean@808
  1144
            /* Process the HTML body replacing all modified CIDs
Dean@808
  1145
             * Since no HTML document library is provided in standard C#, text operations are done.
Dean@808
  1146
             * This should work ok, but there are some potential issue with malformed HTML that might render correctly.
Dean@808
  1147
             * Only " is supported instead of ' as well.
Dean@808
  1148
             * This shouldn't be an issue since the method is primarily run on mail items generated internally.
Dean@808
  1149
             */
Dean@808
  1150
            workingHTML = this._LongMsgFormattedHTML;
Dean@808
  1151
            if (string.IsNullOrEmpty(workingHTML) == false)
Dean@808
  1152
            {
Dean@920
  1153
                tempIndex = workingHTML.IndexOf("<img", 0);
Dean@920
  1154
                currImgTagIndex = (tempIndex > -1 ? (tempIndex + 4) : -1); // MUST start index after "<img"
Dean@808
  1155
Dean@808
  1156
                while (currImgTagIndex > -1)
Dean@808
  1157
                {
Dean@920
  1158
                    try
Dean@920
  1159
                    {
Dean@920
  1160
                        tempIndex = workingHTML.IndexOf("src=\"cid:", currImgTagIndex);
Dean@920
  1161
                        currImgTagCIDIndex = (tempIndex > -1 ? (tempIndex + 9) : -1);
Dean@920
  1162
                        currImgTagCIDStopIndex = workingHTML.IndexOf("\"", currImgTagCIDIndex);
Dean@920
  1163
                        currImgTagStopIndex = workingHTML.IndexOf(">", currImgTagIndex);
Dean@920
  1164
                    }
Dean@920
  1165
                    catch
Dean@920
  1166
                    {
Dean@920
  1167
                        Globals.Log("NormalizeContentIDs: Incorrect index detected when calculating CID position, skipping current img.");
Dean@920
  1168
Dean@920
  1169
                        // Likely System.ArgumentOutOfRangeException from incorrect index
Dean@920
  1170
                        // Just invalidate all locations and will not change this <img>
Dean@920
  1171
                        currImgTagCIDIndex = -1;
Dean@920
  1172
                        currImgTagCIDStopIndex = -1;
Dean@920
  1173
                        currImgTagStopIndex = -1;
Dean@920
  1174
                    }
Dean@843
  1175
Dean@808
  1176
                    // Validate relative index positions
Dean@808
  1177
                    if ((currImgTagCIDIndex < currImgTagStopIndex) &&
Dean@808
  1178
                        (currImgTagCIDStopIndex < currImgTagStopIndex) &&
Dean@808
  1179
                        ((currImgTagCIDStopIndex - currImgTagCIDIndex) >= 1))
Dean@808
  1180
                    {
Dean@808
  1181
                        // Split the HTML at the CID and modify if necessary
Dean@920
  1182
                        try
Dean@920
  1183
                        {
Dean@920
  1184
                            beginning = workingHTML.Substring(0, currImgTagCIDIndex);
Dean@920
  1185
                            ending = workingHTML.Substring(currImgTagCIDStopIndex);
Dean@920
  1186
                            currCID = workingHTML.Substring(currImgTagCIDIndex, (currImgTagCIDStopIndex - currImgTagCIDIndex));
Dean@920
  1187
                        }
Dean@920
  1188
                        catch
Dean@920
  1189
                        {
Dean@920
  1190
                            Globals.Log("NormalizeContentIDs: Error splitting HTML at CID, skipping current img.");
Dean@920
  1191
Dean@920
  1192
                            beginning = null;
Dean@920
  1193
                            ending = null;
Dean@920
  1194
                            currCID = null;
Dean@920
  1195
                        }
Dean@808
  1196
Dean@808
  1197
                        // Lookup the new CID
Dean@808
  1198
                        newCID = null;
Dean@808
  1199
                        try
Dean@808
  1200
                        {
Dean@920
  1201
                            if (currCID != null)
Dean@920
  1202
                            {
Dean@920
  1203
                                newCID = modifiedCIDs[currCID];
Dean@920
  1204
                            }
Dean@808
  1205
                        }
Dean@808
  1206
                        catch
Dean@808
  1207
                        {
Dean@808
  1208
                            newCID = null;
Dean@808
  1209
                        }
Dean@808
  1210
Dean@808
  1211
                        // Replace
Dean@920
  1212
                        if ((beginning != null) &&
Dean@920
  1213
                            (string.IsNullOrEmpty(newCID) == false) &&
Dean@920
  1214
                            (ending != null))
Dean@808
  1215
                        {
Dean@808
  1216
                            workingHTML = beginning + newCID + ending;
Dean@808
  1217
                        }
Dean@808
  1218
                    }
Dean@808
  1219
Dean@920
  1220
                    try
Dean@920
  1221
                    {
Dean@920
  1222
                        tempIndex = workingHTML.IndexOf("<img", currImgTagIndex);
Dean@920
  1223
                        currImgTagIndex = (tempIndex > -1 ? (tempIndex + 4) : -1); // MUST start index after "<img"
Dean@920
  1224
                    }
Dean@920
  1225
                    catch
Dean@920
  1226
                    {
Dean@920
  1227
                        Globals.Log("NormalizeContentIDs: Incorrect index detected, stopping calculation.");
Dean@920
  1228
Dean@920
  1229
                        // Likely System.ArgumentOutOfRangeException from incorrect index
Dean@920
  1230
                        // Stop processing the HTML and use whatever is processed up to this point
Dean@920
  1231
                        currImgTagIndex = -1;
Dean@920
  1232
                    }
Dean@808
  1233
                }
Dean@808
  1234
            }
Dean@808
  1235
            this._LongMsgFormattedHTML = workingHTML;
Dean@808
  1236
Dean@808
  1237
            return;
Dean@808
  1238
        }
Dean@927
  1239
Dean@927
  1240
        /**************************************************************
Dean@927
  1241
         * 
Dean@927
  1242
         * Static Methods
Dean@927
  1243
         * 
Dean@927
  1244
         *************************************************************/
Dean@927
  1245
Dean@927
  1246
        /// <summary>
Dean@927
  1247
        /// Constructs a new message from the given pEp engine text_message.
Dean@927
  1248
        /// The output will never be null.
Dean@927
  1249
        /// </summary>
Dean@927
  1250
        /// <param name="msg">The text_message to construct from.</param>
Dean@927
  1251
        /// <param name="createdMessage">The output newly created message (will never be null).</param>
Dean@927
  1252
        /// <returns>The status of the method.</returns>
markus@954
  1253
        /// <remarks>In some contexts which call this message, a partial conversion of the
markus@954
  1254
        /// <paramref name="text_message"/> is acceptable, non-critical, and better than failure (e. G. displaying
markus@954
  1255
        /// a preview to the user). Thus, this method will always create a <see cref="PEPMessage"/>
markus@954
  1256
        /// which is "best effort", and return the <see cref="Globals.ReturnStatus"/> which can be evaluated
markus@954
  1257
        /// in the more critical contexts. Callers of that message need to be aware of this
markus@954
  1258
        /// and check the result if appropriate.</remarks>
Dean@927
  1259
        public static Globals.ReturnStatus Create(text_message msg,
Dean@927
  1260
                                                  out PEPMessage createdMessage)
Dean@927
  1261
        {
Dean@927
  1262
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@927
  1263
            PEPMessage newMessage = new PEPMessage();
Dean@927
  1264
Dean@927
  1265
            try
Dean@927
  1266
            {
Dean@1095
  1267
                /* Note: Skip the following properties which are not supported in the text_message
Dean@1095
  1268
                 *   • AttachOwnKey
Dean@1095
  1269
                 *   • ForceUnencrypted
Dean@1095
  1270
                 *   • LongMsgFormattedRTF
Dean@1095
  1271
                 * 
Dean@1095
  1272
                 * Also not the following are handled as optional fields
Dean@1095
  1273
                 *   • ColorRating
Dean@1095
  1274
                 *   • KeepConfidential
Dean@1095
  1275
                 *   • KeyList
Dean@1095
  1276
                 *   • PEPVersion
Dean@1095
  1277
                 * 
Dean@1095
  1278
                 * This also skips a number of text_message properties currently unsupported in PEPMessage.
Dean@1095
  1279
                 */
Dean@1095
  1280
Dean@927
  1281
                // Attachments
Dean@927
  1282
                newMessage.Attachments.Clear();
Dean@927
  1283
                if (msg.attachments != null)
Dean@927
  1284
                {
Dean@927
  1285
                    for (int i = 0; i < msg.attachments.Length; i++)
Dean@927
  1286
                    {
Dean@927
  1287
                        newMessage.Attachments.Add(new PEPAttachment((blob)msg.attachments.GetValue(i)));
Dean@927
  1288
                    }
Dean@927
  1289
                }
Dean@927
  1290
Dean@927
  1291
                // BCC
Dean@927
  1292
                newMessage.BCC.Clear();
Dean@927
  1293
                if (msg.bcc != null)
Dean@927
  1294
                {
Dean@927
  1295
                    for (int i = 0; i < msg.bcc.Length; i++)
Dean@927
  1296
                    {
Dean@927
  1297
                        newMessage.BCC.Add(new PEPIdentity((pEp_identity_s)msg.bcc.GetValue(i)));
Dean@927
  1298
                    }
Dean@927
  1299
                }
Dean@927
  1300
Dean@927
  1301
                // CC
Dean@927
  1302
                newMessage.CC.Clear();
Dean@927
  1303
                if (msg.cc != null)
Dean@927
  1304
                {
Dean@927
  1305
                    for (int i = 0; i < msg.cc.Length; i++)
Dean@927
  1306
                    {
Dean@927
  1307
                        newMessage.CC.Add(new PEPIdentity((pEp_identity_s)msg.cc.GetValue(i)));
Dean@927
  1308
                    }
Dean@927
  1309
                }
Dean@927
  1310
Dean@927
  1311
                newMessage.Direction = msg.dir;
Dean@927
  1312
                newMessage.From = new PEPIdentity(msg.from);
Dean@927
  1313
                newMessage.ID = msg.id;
Dean@927
  1314
Dean@927
  1315
                // Keywords
Dean@927
  1316
                newMessage.Keywords.Clear();
Dean@927
  1317
                if (msg.keywords != null)
Dean@927
  1318
                {
Dean@927
  1319
                    for (int i = 0; i < msg.keywords.Length; i++)
Dean@927
  1320
                    {
Dean@927
  1321
                        newMessage.Keywords.Add((string)msg.keywords.GetValue(i));
Dean@927
  1322
                    }
Dean@927
  1323
                }
Dean@927
  1324
Dean@927
  1325
                newMessage.LongMsg = msg.longmsg;
Dean@927
  1326
                newMessage.LongMsgFormattedHTML = msg.longmsg_formatted;
Dean@927
  1327
Dean@927
  1328
                // Optional properties
Dean@927
  1329
                if (msg.opt_fields != null)
Dean@927
  1330
                {
Dean@927
  1331
                    for (int i = 0; i < msg.opt_fields.Length; i++)
Dean@927
  1332
                    {
Dean@1094
  1333
                        if (msg.opt_fields[i].name != null)
Dean@1094
  1334
                        {
Dean@1094
  1335
                            switch (msg.opt_fields[i].name)
Dean@1094
  1336
                            {
Dean@1094
  1337
                                case (PEPMessage.PR_X_ENC_STATUS_NAME):
Dean@1095
  1338
                                    {
Dean@1095
  1339
                                        try
Dean@1095
  1340
                                        {
Dean@1095
  1341
                                            // Note: ignore character case when parsing
Dean@1095
  1342
                                            newMessage.ColorRating = (_pEp_color)Enum.Parse(typeof(_pEp_color), ("pEp_rating_" + msg.opt_fields[i].value), true);
Dean@1095
  1343
                                        }
Dean@1095
  1344
                                        catch
Dean@1095
  1345
                                        {
Dean@1095
  1346
                                            newMessage.ColorRating = _pEp_color.pEp_rating_undefined;
Dean@1095
  1347
                                        }
Dean@1095
  1348
                                        break;
Dean@1095
  1349
                                    }
Dean@1094
  1350
                                case (PEPMessage.PR_X_KEY_LIST_NAME):
Dean@1095
  1351
                                    {
Dean@1095
  1352
                                        newMessage.KeyList = msg.opt_fields[i].value;
Dean@1095
  1353
                                        break;
Dean@1095
  1354
                                    }
Dean@1094
  1355
                                case (PEPMessage.PR_X_PEP_KEEP_CONFIDENTIAL_NAME):
Dean@1095
  1356
                                    {
Dean@1095
  1357
                                        // If it exists it's true, value doesn't matter
Dean@1095
  1358
                                        newMessage.KeepConfidential = true;
Dean@1095
  1359
                                        break;
Dean@1095
  1360
                                    }
Dean@1094
  1361
                                case (PEPMessage.PR_X_PEP_VERSION_NAME):
Dean@1095
  1362
                                    {
Dean@1095
  1363
                                        newMessage.PEPVersion = msg.opt_fields[i].value;
Dean@1095
  1364
                                        break;
Dean@1095
  1365
                                    }
Dean@1094
  1366
                            }
Dean@1094
  1367
                        }
Dean@927
  1368
                    }
Dean@927
  1369
                }
Dean@927
  1370
Dean@927
  1371
                // ReceivedOn
Dean@927
  1372
                if (msg.recv > 0)
Dean@927
  1373
                {
Dean@927
  1374
                    newMessage.ReceivedOn = new DateTime(1970, 1, 1).AddSeconds(msg.recv);
Dean@927
  1375
                }
Dean@927
  1376
                else
Dean@927
  1377
                {
Dean@927
  1378
                    newMessage.ReceivedOn = null;
Dean@927
  1379
                }
Dean@927
  1380
Dean@927
  1381
                // SentOn
Dean@927
  1382
                if (msg.sent > 0)
Dean@927
  1383
                {
Dean@927
  1384
                    newMessage.SentOn = new DateTime(1970, 1, 1).AddSeconds(msg.sent);
Dean@927
  1385
                }
Dean@927
  1386
                else
Dean@927
  1387
                {
Dean@927
  1388
                    newMessage.SentOn = null;
Dean@927
  1389
                }
Dean@927
  1390
Dean@927
  1391
                newMessage.ShortMsg = msg.shortmsg;
Dean@927
  1392
Dean@927
  1393
                // To
Dean@927
  1394
                newMessage.To.Clear();
Dean@927
  1395
                if (msg.to != null)
Dean@927
  1396
                {
Dean@927
  1397
                    for (int i = 0; i < msg.to.Length; i++)
Dean@927
  1398
                    {
Dean@927
  1399
                        newMessage.To.Add(new PEPIdentity((pEp_identity_s)msg.to.GetValue(i)));
Dean@927
  1400
                    }
Dean@927
  1401
                }
Dean@927
  1402
            }
Dean@927
  1403
            catch (Exception ex)
Dean@927
  1404
            {
Dean@927
  1405
                status = Globals.ReturnStatus.Failure;
Dean@927
  1406
                Globals.Log("PEPMessage.Create: Failure occured, " + ex.ToString());
Dean@927
  1407
            }
Dean@927
  1408
Dean@927
  1409
            createdMessage = newMessage;
Dean@927
  1410
            return (status);
Dean@927
  1411
        }
Dean@927
  1412
Dean@927
  1413
        /// <summary>
Dean@927
  1414
        /// Contructs a new message from the given outlook mail item.
Dean@927
  1415
        /// The output will never be null.
Dean@927
  1416
        /// </summary>
Dean@927
  1417
        /// <param name="omi">The outlook mail item to create the message from.</param>
Dean@927
  1418
        /// <param name="createdMessage">The output newly created message (will never be null).</param>
Dean@927
  1419
        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
Dean@927
  1420
        /// and optional properties.</param>
Dean@927
  1421
        /// <returns>The status of the method.</returns>
markus@954
  1422
        /// <remarks>In some contexts which call this message, a partial conversion of the
markus@954
  1423
        /// <paramref name="text_message"/> is acceptable, non-critical, and better than failure (e. G. displaying
markus@954
  1424
        /// a preview to the user). Thus, this method will always create a <see cref="PEPMessage"/>
markus@954
  1425
        /// which is "best effort", and return the <see cref="Globals.ReturnStatus"/> which can be evaluated
markus@954
  1426
        /// in the more critical contexts. Callers of that message need to be aware of this
markus@954
  1427
        /// and check the result if appropriate.</remarks>
Dean@927
  1428
        public static Globals.ReturnStatus Create(Outlook.MailItem omi,
Dean@927
  1429
                                                  out PEPMessage createdMessage,
Dean@927
  1430
                                                  bool createWithoutContent = false)
Dean@927
  1431
        {
Dean@927
  1432
            byte[] rtfBody;
Dean@927
  1433
            string delim;
Dean@927
  1434
            string[] keywords;
Dean@1094
  1435
            object propValue;
Dean@927
  1436
            DateTime? receivedOn = null;
Dean@927
  1437
            DateTime? sentOn = null;
Dean@927
  1438
            PEPIdentity ident;
Dean@927
  1439
            Outlook.Attachment currAttachment = null;
Dean@927
  1440
            Outlook.Attachments attachments = null;
Dean@927
  1441
            Outlook.Recipient currRecipient = null;
Dean@927
  1442
            Outlook.Recipients recipients = null;
Dean@927
  1443
            Globals.ReturnStatus status = Globals.ReturnStatus.Success;
Dean@927
  1444
            Globals.ReturnStatus sts;
Dean@927
  1445
            PEPMessage newMessage = new PEPMessage();
Dean@927
  1446
Dean@927
  1447
            try
Dean@927
  1448
            {
Dean@927
  1449
                Globals.LogVerbose("PEPMessage.Create: Creating new PEPMessage from OMI started, calculating recipients.");
Dean@927
  1450
Dean@1095
  1451
                /* Note: Skip the following properties which are not supported in the MailItem
Dean@1095
  1452
                 *   • Direction
Dean@1095
  1453
                 */
Dean@1095
  1454
Dean@927
  1455
                // Calculate recipients
Dean@927
  1456
                newMessage.BCC.Clear();
Dean@927
  1457
                newMessage.CC.Clear();
Dean@927
  1458
                newMessage.To.Clear();
Dean@927
  1459
                recipients = omi.Recipients;
Dean@927
  1460
                for (int i = 1; i <= recipients.Count; i++)
Dean@927
  1461
                {
Dean@927
  1462
                    currRecipient = recipients[i];
Dean@927
  1463
Dean@927
  1464
                    switch ((Outlook.OlMailRecipientType)currRecipient.Type)
Dean@927
  1465
                    {
Dean@927
  1466
                        case Outlook.OlMailRecipientType.olBCC:
Dean@1095
  1467
                            {
Dean@1095
  1468
                                sts = PEPIdentity.ToIdentity(currRecipient, out ident);
Dean@1095
  1469
                                if (sts == Globals.ReturnStatus.Success)
Dean@1095
  1470
                                {
Dean@1095
  1471
                                    newMessage.BCC.Add(ident);
Dean@1095
  1472
                                }
Dean@1095
  1473
                                else
Dean@1095
  1474
                                {
Dean@1095
  1475
                                    // Update the status, only the first failure type is recorded
Dean@1095
  1476
                                    if (status == Globals.ReturnStatus.Success)
Dean@1095
  1477
                                    {
Dean@1095
  1478
                                        status = sts;
Dean@1095
  1479
                                    }
Dean@1095
  1480
                                }
Dean@927
  1481
Dean@1095
  1482
                                break;
Dean@1095
  1483
                            }
Dean@1095
  1484
                        case Outlook.OlMailRecipientType.olCC:
Dean@927
  1485
                            {
Dean@1095
  1486
                                sts = PEPIdentity.ToIdentity(currRecipient, out ident);
Dean@1095
  1487
                                if (sts == Globals.ReturnStatus.Success)
Dean@1095
  1488
                                {
Dean@1095
  1489
                                    newMessage.CC.Add(ident);
Dean@1095
  1490
                                }
Dean@1095
  1491
                                else
Dean@1095
  1492
                                {
Dean@1095
  1493
                                    // Update the status, only the first failure type is recorded
Dean@1095
  1494
                                    if (status == Globals.ReturnStatus.Success)
Dean@1095
  1495
                                    {
Dean@1095
  1496
                                        status = sts;
Dean@1095
  1497
                                    }
Dean@1095
  1498
                                }
Dean@1095
  1499
Dean@1095
  1500
                                break;
Dean@927
  1501
                            }
Dean@1095
  1502
                        case Outlook.OlMailRecipientType.olTo:
Dean@927
  1503
                            {
Dean@1095
  1504
                                sts = PEPIdentity.ToIdentity(currRecipient, out ident);
Dean@1095
  1505
                                if (sts == Globals.ReturnStatus.Success)
Dean@927
  1506
                                {
Dean@1095
  1507
                                    newMessage.To.Add(ident);
Dean@927
  1508
                                }
Dean@1095
  1509
                                else
Dean@1095
  1510
                                {
Dean@1095
  1511
                                    // Update the status, only the first failure type is recorded
Dean@1095
  1512
                                    if (status == Globals.ReturnStatus.Success)
Dean@1095
  1513
                                    {
Dean@1095
  1514
                                        status = sts;
Dean@1095
  1515
                                    }
Dean@1095
  1516
                                }
Dean@1095
  1517
Dean@1095
  1518
                                break;
Dean@927
  1519
                            }
Dean@927
  1520
                    }
Dean@927
  1521
Dean@927
  1522
                    Marshal.ReleaseComObject(currRecipient);
Dean@927
  1523
                    currRecipient = null;
Dean@927
  1524
                }
Dean@927
  1525
Dean@927
  1526
                Globals.LogVerbose("PEPMessage.Create: Recipients calculated, calculating main properties.");
Dean@927
  1527
Dean@927
  1528
                newMessage.Direction = CryptableMailItem.GetIsIncoming(omi) ? _pEp_msg_direction.pEp_dir_incoming : _pEp_msg_direction.pEp_dir_outgoing;
Dean@927
  1529
Dean@927
  1530
                // From
Dean@927
  1531
                sts = PEPIdentity.GetFromIdentity(omi, out ident);
Dean@927
  1532
                if (sts == Globals.ReturnStatus.Success)
Dean@927
  1533
                {
Dean@927
  1534
                    newMessage.From = ident;
Dean@927
  1535
                }
Dean@927
  1536
                else
Dean@927
  1537
                {
Dean@927
  1538
                    // Update the status, only the first failure type is recorded
Dean@927
  1539
                    if (status == Globals.ReturnStatus.Success)
Dean@927
  1540
                    {
Dean@927
  1541
                        status = sts;
Dean@927
  1542
                    }
Dean@927
  1543
                }
Dean@927
  1544
Dean@927
  1545
                newMessage.ID = (string)MAPIHelper.GetProperty(omi, MAPIProperty.PidTagInternetMessageId, "");
Dean@927
  1546
                newMessage.ShortMsg = omi.Subject;
Dean@927
  1547
Dean@927
  1548
                /* Date & Times
Dean@927
  1549
                 * 
Dean@927
  1550
                 * Note: The mail item date can be invalid:
Dean@927
  1551
                 * For incoming this commonly occurs when creating a mirror -- it's created without a received time.
Dean@927
  1552
                 * For outgoing this commonly occurs for unsent mail.
Dean@927
  1553
                 * In these cases, the invalid date and time will be returned as 1/1/4501 at 12:00AM
Dean@927
  1554
                 * This situation is filtered here and the date is set as null.
Dean@927
  1555
                 */
Dean@927
  1556
                receivedOn = omi.ReceivedTime;
Dean@927
  1557
                if ((receivedOn != null) &&
Dean@927
  1558
                    (((DateTime)receivedOn).Year > 4000)) // ~2000 years from now, no issue
Dean@927
  1559
                {
Dean@927
  1560
                    receivedOn = null;
Dean@927
  1561
                }
Dean@927
  1562
                newMessage.ReceivedOn = receivedOn;
Dean@927
  1563
Dean@927
  1564
                sentOn = omi.SentOn;
Dean@927
  1565
                if ((sentOn != null) &&
Dean@927
  1566
                    (((DateTime)sentOn).Year > 4000)) // ~2000 years from now, no issue
Dean@927
  1567
                {
Dean@927
  1568
                    sentOn = null;
Dean@927
  1569
                }
Dean@927
  1570
                newMessage.SentOn = sentOn;
Dean@927
  1571
Dean@1095
  1572
                // AttachOwnKey
Dean@1095
  1573
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1574
                                                         CryptableMailItem.USER_PROPERTY_KEY_ATTACH_OWN_KEY,
Dean@1095
  1575
                                                         out propValue);
Dean@1095
  1576
                newMessage.AttachOwnKey = (bool)propValue;
Dean@1095
  1577
Dean@1095
  1578
                // ForceUnencrypted
Dean@1095
  1579
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1580
                                                         CryptableMailItem.USER_PROPERTY_KEY_FORCE_UNENCRYPTED,
Dean@1095
  1581
                                                         out propValue);
Dean@1095
  1582
                newMessage.ForceUnencrypted = (bool)propValue;
Dean@1095
  1583
Dean@1095
  1584
                // ColorRating
Dean@1095
  1585
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1586
                                                         PEPMessage.PR_X_ENC_STATUS,
Dean@1095
  1587
                                                         out propValue);
Dean@1095
  1588
                newMessage.ColorRating = (_pEp_color)propValue;
Dean@1095
  1589
Dean@1095
  1590
                // KeyList
Dean@1095
  1591
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1592
                                                         PEPMessage.PR_X_KEY_LIST,
Dean@1095
  1593
                                                         out propValue);
Dean@1095
  1594
                newMessage.KeyList = (string)propValue;
Dean@1095
  1595
Dean@1095
  1596
                // KeepConfidential
Dean@1095
  1597
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1598
                                                         PEPMessage.PR_X_PEP_KEEP_CONFIDENTIAL,
Dean@1095
  1599
                                                         out propValue);
Dean@1095
  1600
                newMessage.KeepConfidential = (bool)propValue;
Dean@1095
  1601
Dean@1095
  1602
                // PEPVersion
Dean@1095
  1603
                CryptableMailItem.GetInterpretedProperty(omi,
Dean@1095
  1604
                                                         PEPMessage.PR_X_PEP_VERSION,
Dean@1095
  1605
                                                         out propValue);
Dean@1095
  1606
                newMessage.PEPVersion = (string)propValue;
Dean@1095
  1607
Dean@927
  1608
                Globals.LogVerbose("PEPMessage.Create: Main properties calculated, calculating body and attachments.");
Dean@927
  1609
Dean@927
  1610
                // Calculate text body and attachments
Dean@927
  1611
                if (createWithoutContent == false)
Dean@927
  1612
                {
Dean@927
  1613
                    // Body
Dean@927
  1614
                    if (omi.Body != null)
Dean@927
  1615
                    {
Dean@927
  1616
                        newMessage.LongMsg = omi.Body.Replace("\r\n", "\n");
Dean@927
  1617
Dean@927
  1618
                        // Save as RTF
Dean@927
  1619
                        try
Dean@927
  1620
                        {
Dean@927
  1621
                            rtfBody = omi.RTFBody;
Dean@927
  1622
                            newMessage.LongMsgFormattedRTF = System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length);
Dean@927
  1623
                        }
Dean@927
  1624
                        catch
Dean@927
  1625
                        {
Dean@927
  1626
                            Globals.Log("PEPMessage.Create: Unable to read RTF body in MailItem.");
Dean@927
  1627
                        }
Dean@927
  1628
Dean@1095
  1629
                        // Force any rich text into HTML
Dean@927
  1630
                        // WARNING: This is technically a modifcation of the original MailItem
Dean@927
  1631
                        // It should be further investigated if this can be removed in the future.
Dean@927
  1632
                        if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatRichText)
Dean@927
  1633
                        {
Dean@927
  1634
                            omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
Dean@927
  1635
                        }
Dean@927
  1636
Dean@927
  1637
                        if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatHTML)
Dean@927
  1638
                        {
Dean@927
  1639
                            newMessage.LongMsgFormattedHTML = omi.HTMLBody;
Dean@927
  1640
                        }
Dean@927
  1641
                    }
Dean@927
  1642
Dean@927
  1643
                    // Attachments
Dean@927
  1644
                    newMessage.Attachments.Clear();
Dean@927
  1645
                    attachments = omi.Attachments;
Dean@927
  1646
                    for (int i = 1; i <= attachments.Count; i++)
Dean@927
  1647
                    {
Dean@927
  1648
                        currAttachment = attachments[i];
Dean@927
  1649
Dean@927
  1650
                        try
Dean@927
  1651
                        {
Dean@927
  1652
                            newMessage.Attachments.Add(new PEPAttachment(currAttachment));
Dean@927
  1653
                        }
Dean@927
  1654
                        catch { }
Dean@927
  1655
Dean@927
  1656
                        Marshal.ReleaseComObject(currAttachment);
Dean@927
  1657
                        currAttachment = null;
Dean@927
  1658
                    }
Dean@927
  1659
Dean@927
  1660
                    // Keywords
Dean@927
  1661
                    if (omi.Categories != null)
Dean@927
  1662
                    {
Dean@927
  1663
                        try
Dean@927
  1664
                        {
Dean@927
  1665
                            newMessage.Keywords.Clear();
Dean@927
  1666
Dean@927
  1667
                            using (RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Control Panel\\International"))
Dean@927
  1668
                            {
Dean@927
  1669
                                delim = key1.GetValue("sList").ToString();
Dean@927
  1670
                                keywords = omi.Categories.Split(delim.ToCharArray());
Dean@927
  1671
Dean@927
  1672
                                for (int i = 0; i < keywords.Length; i++)
Dean@927
  1673
                                {
Dean@927
  1674
                                    newMessage.Keywords.Add(keywords[i]);
Dean@927
  1675
                                }
Dean@927
  1676
                            }
Dean@927
  1677
                        }
Dean@927
  1678
                        catch
Dean@927
  1679
                        {
Dean@927
  1680
                            newMessage.Keywords.Clear();
Dean@927
  1681
                            Globals.Log("PEPMessage.Create: Unable to set keywords.");
Dean@927
  1682
                        }
Dean@927
  1683
                    }
Dean@927
  1684
                }
Dean@927
  1685
Dean@927
  1686
                Globals.LogVerbose("PEPMessage.Create: New PEPMessage created from OMI.");
Dean@927
  1687
            }
Dean@927
  1688
            catch (Exception ex)
Dean@927
  1689
            {
Dean@927
  1690
                status = Globals.ReturnStatus.Failure;
Dean@927
  1691
                Globals.Log("PEPMessage.Create: failure occured, " + ex.ToString());
Dean@927
  1692
            }
Dean@927
  1693
            finally
Dean@927
  1694
            {
Dean@927
  1695
                // Free resources
Dean@927
  1696
                if (currAttachment != null)
Dean@927
  1697
                {
Dean@927
  1698
                    Marshal.ReleaseComObject(currAttachment);
Dean@927
  1699
                    currAttachment = null;
Dean@927
  1700
                }
Dean@927
  1701
Dean@927
  1702
                if (attachments != null)
Dean@927
  1703
                {
Dean@927
  1704
                    Marshal.ReleaseComObject(attachments);
Dean@927
  1705
                    attachments = null;
Dean@927
  1706
                }
Dean@927
  1707
Dean@927
  1708
                if (currRecipient != null)
Dean@927
  1709
                {
Dean@927
  1710
                    Marshal.ReleaseComObject(currRecipient);
Dean@927
  1711
                    currRecipient = null;
Dean@927
  1712
                }
Dean@927
  1713
Dean@927
  1714
                if (recipients != null)
Dean@927
  1715
                {
Dean@927
  1716
                    Marshal.ReleaseComObject(recipients);
Dean@927
  1717
                    recipients = null;
Dean@927
  1718
                }
Dean@927
  1719
            }
Dean@927
  1720
Dean@927
  1721
            createdMessage = newMessage;
Dean@972
  1722
Dean@972
  1723
            Globals.LogVerbose("PEPMessage.Create: ReturnStatus=" + status.ToString());
Dean@927
  1724
            return (status);
Dean@927
  1725
        }
Dean@927
  1726
Dean@927
  1727
        /// <summary>
Dean@927
  1728
        /// Determines if the given text is PGP text based on starting text sequence.
Dean@927
  1729
        /// The starting sequence must be "-----BEGIN PGP MESSAGE-----"
Dean@927
  1730
        /// </summary>
Dean@927
  1731
        /// <param name="text">The text to test if it is PGP text.</param>
Dean@927
  1732
        /// <returns>True if the given text is PGP text, otherwise false.</returns>
Dean@927
  1733
        public static bool IsPGPText(string text)
Dean@927
  1734
        {
Dean@927
  1735
            if (string.IsNullOrEmpty(text) == false)
Dean@927
  1736
            {
Dean@927
  1737
                string pgp_text = text.Trim();
Dean@927
  1738
                return (pgp_text.StartsWith("-----BEGIN PGP MESSAGE-----"));
Dean@927
  1739
            }
Dean@927
  1740
            else
Dean@927
  1741
            {
Dean@927
  1742
                return (false);
Dean@927
  1743
            }
Dean@927
  1744
        }
Dean@927
  1745
Dean@927
  1746
        /// <summary>
Dean@927
  1747
        /// Determines if the given outlook mail item is encrypted.
Dean@927
  1748
        /// Currently, only PGP encrypted messages will be detected.
Dean@927
  1749
        /// </summary>
Dean@927
  1750
        /// <param name="omi">The outlook mail item to check encryption for.</param>
Dean@927
  1751
        /// <returns>True if the given outlook mail item is encrypted, otherwise false.</returns>
Dean@927
  1752
        public static bool GetIsEncrypted(Outlook.MailItem omi)
Dean@927
  1753
        {
Dean@927
  1754
            byte[] data;
Dean@927
  1755
            byte[] copy;
Dean@927
  1756
            string ignored1 = "";
Dean@927
  1757
            string ignored2 = "";
Dean@927
  1758
Dean@927
  1759
            if (omi != null)
Dean@927
  1760
            {
Dean@927
  1761
                // Plain PGP message
Dean@927
  1762
                if (omi.Body != null && PEPMessage.IsPGPText(omi.Body))
Dean@927
  1763
                {
Dean@927
  1764
                    return (true);
Dean@927
  1765
                }
Dean@927
  1766
Dean@927
  1767
                // PGP/MIME
Dean@927
  1768
                if (omi.Attachments.Count == 2)
Dean@927
  1769
                {
Dean@927
  1770
                    try
Dean@927
  1771
                    {
Dean@927
  1772
                        // Note: attachment index starts at 1 for a MailItem
Dean@927
  1773
                        data = PEPAttachment.GetData(omi.Attachments[2], ref ignored1, ref ignored2);
Dean@927
  1774
Dean@927
  1775
                        // Data must be at least 100 bytes long
Dean@927
  1776
                        if ((data == null) ||
Dean@927
  1777
                            (data.Length < 100))
Dean@927
  1778
                        {
Dean@927
  1779
                            return (false);
Dean@927
  1780
                        }
Dean@927
  1781
Dean@927
  1782
                        // Create a copy
Dean@927
  1783
                        copy = new byte[100];
Dean@927
  1784
                        for (int i = 0; i < 100; i++)
Dean@927
  1785
                        {
Dean@927
  1786
                            copy[i] = data[i];
Dean@927
  1787
                        }
Dean@927
  1788
Dean@927
  1789
                        // Check for PGP text after converting to string
Dean@927
  1790
                        if (PEPMessage.IsPGPText(System.Text.Encoding.ASCII.GetString(copy)))
Dean@927
  1791
                        {
Dean@927
  1792
                            return (true);
Dean@927
  1793
                        }
Dean@927
  1794
                    }
Dean@927
  1795
                    catch { }
Dean@927
  1796
                }
Dean@927
  1797
            }
Dean@927
  1798
Dean@927
  1799
            return (false);
Dean@927
  1800
        }
Dean@927
  1801
Dean@927
  1802
        /// <summary>
Dean@927
  1803
        /// Determines if the given PEPMessage is encrypted.
Dean@927
  1804
        /// Currently, only PGP encrypted messages will be detected.
Dean@927
  1805
        /// </summary>
Dean@927
  1806
        /// <param name="msg">The message to check encryption for.</param>
Dean@927
  1807
        /// <returns>True if the given message is encrypted, otherwise false.</returns>
Dean@927
  1808
        public static bool GetIsEncrypted(PEPMessage msg)
Dean@927
  1809
        {
Dean@927
  1810
            byte[] data;
Dean@927
  1811
            byte[] copy;
Dean@927
  1812
Dean@927
  1813
            if (msg != null)
Dean@927
  1814
            {
Dean@927
  1815
                // Plain PGP message
Dean@927
  1816
                if (msg.LongMsg != null && PEPMessage.IsPGPText(msg.LongMsg))
Dean@927
  1817
                {
Dean@927
  1818
                    return (true);
Dean@927
  1819
                }
Dean@927
  1820
Dean@927
  1821
                // PGP/MIME
Dean@927
  1822
                if (msg.Attachments.Count == 2)
Dean@927
  1823
                {
Dean@927
  1824
                    try
Dean@927
  1825
                    {
Dean@927
  1826
                        // Note: attachment index starts at 0 for a PEPMessage
Dean@927
  1827
                        data = msg.Attachments[1].Data;
Dean@927
  1828
Dean@927
  1829
                        // Data must be at least 100 bytes long
Dean@927
  1830
                        if ((data == null) ||
Dean@927
  1831
                            (data.Length < 100))
Dean@927
  1832
                        {
Dean@927
  1833
                            return (false);
Dean@927
  1834
                        }
Dean@927
  1835
Dean@927
  1836
                        // Create a copy
Dean@927
  1837
                        copy = new byte[100];
Dean@927
  1838
                        for (int i = 0; i < 100; i++)
Dean@927
  1839
                        {
Dean@927
  1840
                            copy[i] = data[i];
Dean@927
  1841
                        }
Dean@927
  1842
Dean@927
  1843
                        // Check for PGP text after converting to string
Dean@927
  1844
                        if (PEPMessage.IsPGPText(System.Text.Encoding.ASCII.GetString(copy)))
Dean@927
  1845
                        {
Dean@927
  1846
                            return (true);
Dean@927
  1847
                        }
Dean@927
  1848
                    }
Dean@927
  1849
                    catch { }
Dean@927
  1850
                }
Dean@927
  1851
            }
Dean@927
  1852
Dean@927
  1853
            return (false);
Dean@927
  1854
        }
Dean@384
  1855
    }
Dean@384
  1856
}