PEPMessage.cs
author Dean Looyengoed
Wed, 13 Apr 2016 23:30:48 +0200
changeset 808 ac5dbfafb662
parent 795 afef14b08666
child 843 6fdef7166ea3
permissions -rw-r--r--
Add NormalizeContentIDs() to PEPMessage and implement in the message processor.
This will fix embedded images in Outlook only.
Dean@384
     1
´╗┐using Microsoft.Win32;
Dean@384
     2
using pEpCOMServerAdapterLib;
Dean@384
     3
using System;
Dean@384
     4
using System.Collections.Generic;
Dean@384
     5
using System.IO;
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@389
    14
    public class PEPMessage : Interfaces.ICopy<PEPMessage>
Dean@384
    15
    {
Dean@572
    16
        // pEp properties
Dean@586
    17
        public const string PR_OPT_FIELD     = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/";
Dean@572
    18
        public const string PR_X_ENC_STATUS  = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-EncStatus";
Dean@572
    19
        public const string PR_X_KEY_LIST    = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-KeyList";
Dean@572
    20
        public const string PR_X_PEP_VERSION = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-pEp-Version";
Dean@572
    21
Dean@586
    22
        public const string PR_X_ENC_STATUS_NAME  = "X-EncStatus";
Dean@586
    23
        public const string PR_X_KEY_LIST_NAME    = "X-KeyList";
Dean@586
    24
        public const string PR_X_PEP_VERSION_NAME = "X-pEp-Version";
Dean@780
    25
Dean@384
    26
        private List<PEPAttachment> _Attachments;
Dean@384
    27
        private List<PEPIdentity>   _BCC;
Dean@384
    28
        private List<PEPIdentity>   _CC;
Dean@384
    29
        private _pEp_msg_direction  _Direction;
Dean@384
    30
        private PEPIdentity         _From;
Dean@384
    31
        private string              _ID;
Dean@384
    32
        private List<string>        _Keywords;
Dean@384
    33
        private string              _LongMsg;
Dean@697
    34
        private string              _LongMsgFormattedHTML;
Dean@697
    35
        private string              _LongMsgFormattedRTF;
Dean@572
    36
        private List<opt_field>     _OptionalProperties;
Dean@721
    37
        private DateTime?           _ReceivedOn;
Dean@721
    38
        private DateTime?           _SentOn;
Dean@384
    39
        private string              _ShortMsg;
Dean@384
    40
        private List<PEPIdentity>   _To;
Dean@384
    41
Dean@384
    42
        /**************************************************************
Dean@384
    43
         * 
Dean@384
    44
         * Constructors
Dean@384
    45
         * 
Dean@384
    46
         *************************************************************/
Dean@384
    47
Dean@384
    48
        /// <summary>
Dean@384
    49
        /// Default constructor.
Dean@384
    50
        /// </summary>
Dean@384
    51
        public PEPMessage()
Dean@384
    52
        {
Dean@384
    53
            this._Attachments = new List<PEPAttachment>();
Dean@384
    54
            this._BCC = new List<PEPIdentity>();
Dean@384
    55
            this._CC = new List<PEPIdentity>();
Dean@384
    56
            this._Direction = _pEp_msg_direction.pEp_dir_incoming;
Dean@384
    57
            this._From = null;
Dean@384
    58
            this._ID = null;
Dean@384
    59
            this._Keywords = new List<string>();
Dean@384
    60
            this._LongMsg = null;
Dean@697
    61
            this._LongMsgFormattedHTML = null;
Dean@697
    62
            this._LongMsgFormattedRTF = null;
Dean@572
    63
            this._OptionalProperties = new List<opt_field>();
Dean@721
    64
            this._ReceivedOn = null;
Dean@721
    65
            this._SentOn = null;
Dean@384
    66
            this._ShortMsg = null;
Dean@384
    67
            this._To = new List<PEPIdentity>();
Dean@384
    68
        }
Dean@384
    69
Dean@384
    70
        /// <summary>
Dean@384
    71
        /// Constructs a new message from the given pEp engine text_message.
Dean@384
    72
        /// </summary>
Dean@384
    73
        /// <param name="msg">The text_message to construct from.</param>
Dean@384
    74
        public PEPMessage(text_message msg)
Dean@384
    75
        {
Dean@384
    76
            // Attachments
Dean@384
    77
            this._Attachments = new List<PEPAttachment>();
Dean@384
    78
            if (msg.attachments != null)
Dean@384
    79
            {
Dean@384
    80
                for (int i = 0; i < msg.attachments.Length; i++)
Dean@384
    81
                {
Dean@384
    82
                    this._Attachments.Add(new PEPAttachment((blob)msg.attachments.GetValue(i)));
Dean@384
    83
                }
Dean@384
    84
            }
Dean@384
    85
Dean@384
    86
            // BCC
Dean@384
    87
            this._BCC = new List<PEPIdentity>();
Dean@384
    88
            if (msg.bcc != null)
Dean@384
    89
            {
Dean@384
    90
                for (int i = 0; i < msg.bcc.Length; i++)
Dean@384
    91
                {
Dean@384
    92
                    this._BCC.Add(new PEPIdentity((pEp_identity_s)msg.bcc.GetValue(i)));
Dean@384
    93
                }
Dean@384
    94
            }
Dean@384
    95
Dean@384
    96
            // CC
Dean@384
    97
            this._CC = new List<PEPIdentity>();
Dean@384
    98
            if (msg.cc != null)
Dean@384
    99
            {
Dean@384
   100
                for (int i = 0; i < msg.cc.Length; i++)
Dean@384
   101
                {
Dean@384
   102
                    this._CC.Add(new PEPIdentity((pEp_identity_s)msg.cc.GetValue(i)));
Dean@384
   103
                }
Dean@384
   104
            }
Dean@384
   105
Dean@384
   106
            this._Direction = msg.dir;
Dean@384
   107
            this._From = new PEPIdentity(msg.from);
Dean@384
   108
            this._ID = msg.id;
Dean@384
   109
Dean@384
   110
            // Keywords
Dean@384
   111
            this._Keywords = new List<string>();
Dean@384
   112
            if (msg.keywords != null)
Dean@384
   113
            {
Dean@384
   114
                for (int i = 0; i < msg.keywords.Length; i++)
Dean@384
   115
                {
Dean@384
   116
                    this._Keywords.Add((string)msg.keywords.GetValue(i));
Dean@384
   117
                }
Dean@384
   118
            }
Dean@384
   119
Dean@384
   120
            this._LongMsg = msg.longmsg;
Dean@697
   121
            this._LongMsgFormattedHTML = msg.longmsg_formatted;
Dean@697
   122
            this._LongMsgFormattedRTF = null;
Dean@384
   123
Dean@572
   124
            // Optional properties
Dean@572
   125
            this._OptionalProperties = new List<opt_field>();
Dean@384
   126
            if (msg.opt_fields != null)
Dean@384
   127
            {
Dean@384
   128
                for (int i = 0; i < msg.opt_fields.Length; i++)
Dean@384
   129
                {
Dean@572
   130
                    this._OptionalProperties.Add((opt_field)msg.opt_fields.GetValue(i));
Dean@384
   131
                }
Dean@384
   132
            }
Dean@384
   133
Dean@721
   134
            // ReceivedOn
Dean@721
   135
            if (msg.recv > 0)
Dean@721
   136
            {
Dean@721
   137
                this._ReceivedOn = new DateTime(1970, 1, 1).AddSeconds(msg.recv);
Dean@721
   138
            }
Dean@721
   139
            else
Dean@721
   140
            {
Dean@721
   141
                this._ReceivedOn = null;
Dean@721
   142
            }
Dean@721
   143
Dean@721
   144
            // SentOn
Dean@721
   145
            if (msg.sent > 0)
Dean@721
   146
            {
Dean@721
   147
                this._SentOn = new DateTime(1970, 1, 1).AddSeconds(msg.sent);
Dean@721
   148
            }
Dean@721
   149
            else
Dean@721
   150
            {
Dean@721
   151
                this._SentOn = null;
Dean@721
   152
            }
Dean@721
   153
Dean@384
   154
            this._ShortMsg = msg.shortmsg;
Dean@384
   155
Dean@384
   156
            // To
Dean@384
   157
            this._To = new List<PEPIdentity>();
Dean@384
   158
            if (msg.to != null)
Dean@384
   159
            {
Dean@384
   160
                for (int i = 0; i < msg.to.Length; i++)
Dean@384
   161
                {
Dean@384
   162
                    this._To.Add(new PEPIdentity((pEp_identity_s)msg.to.GetValue(i)));
Dean@384
   163
                }
Dean@384
   164
            }
Dean@384
   165
        }
Dean@384
   166
Dean@384
   167
        /// <summary>
Dean@384
   168
        /// Contructs a new message from the given outlook mail item.
Dean@384
   169
        /// </summary>
Dean@384
   170
        /// <param name="omi">The outlook mail item to create the message from.</param>
Dean@586
   171
        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
Dean@586
   172
        /// and optional properties.</param>
Dean@384
   173
        public PEPMessage(Outlook.MailItem omi,
Dean@384
   174
                          bool createWithoutContent = false)
Dean@384
   175
        {
Dean@698
   176
            byte[] rtfBody;
Dean@384
   177
            string delim;
Dean@384
   178
            string bodyLong = null;
Dean@697
   179
            string bodyLongFormattedHTML = null;
Dean@697
   180
            string bodyLongFormattedRTF = null;
Dean@586
   181
            object propertyValue;
Dean@586
   182
            opt_field newProp;
Dean@721
   183
            DateTime? receivedOn = null;
Dean@721
   184
            DateTime? sentOn = null;
Dean@384
   185
            List<string> keywordList = new List<string>();
Dean@384
   186
            List<PEPIdentity> toList = new List<PEPIdentity>();
Dean@384
   187
            List<PEPIdentity> ccList = new List<PEPIdentity>();
Dean@384
   188
            List<PEPIdentity> bccList = new List<PEPIdentity>();
Dean@384
   189
            List<PEPAttachment> attachmentList = new List<PEPAttachment>();
Dean@586
   190
            List<opt_field> optionalPropertyList = new List<opt_field>();
Dean@384
   191
            Outlook.Account acct = null;
Dean@551
   192
            Outlook.Attachment currAttachment = null;
Dean@551
   193
            Outlook.Attachments attachments = null;
Dean@551
   194
            Outlook.Recipient currRecipient = null;
Dean@551
   195
            Outlook.Recipients recipients = null;
Dean@499
   196
Dean@759
   197
            Global.LogVerbose("PEPMessage: Creating new PEPMessage started, calculating recipients.");
Dean@740
   198
Dean@384
   199
            // Calculate recipients
Dean@551
   200
            recipients = omi.Recipients;
Dean@551
   201
            for (int i = 1; i <= recipients.Count; i++)
Dean@384
   202
            {
Dean@551
   203
                currRecipient = recipients[i];
Dean@551
   204
Dean@551
   205
                switch ((Outlook.OlMailRecipientType)currRecipient.Type)
Dean@384
   206
                {
Dean@384
   207
                    case Outlook.OlMailRecipientType.olTo:
Dean@551
   208
                        toList.Add(PEPIdentity.ToIdentity(currRecipient));
Dean@384
   209
                        break;
Dean@384
   210
                    case Outlook.OlMailRecipientType.olCC:
Dean@551
   211
                        ccList.Add(PEPIdentity.ToIdentity(currRecipient));
Dean@384
   212
                        break;
Dean@384
   213
                    case Outlook.OlMailRecipientType.olBCC:
Dean@551
   214
                        bccList.Add(PEPIdentity.ToIdentity(currRecipient));
Dean@384
   215
                        break;
Dean@384
   216
                }
Dean@551
   217
Dean@551
   218
                Marshal.ReleaseComObject(currRecipient);
Dean@551
   219
                currRecipient = null;
Dean@384
   220
            }
Dean@384
   221
Dean@759
   222
            Global.LogVerbose("PEPMessage: Recipients calculated, calculating date & times.");
Dean@740
   223
Dean@721
   224
            /* Date & Times
Dean@721
   225
             * 
Dean@721
   226
             * Note: The mail item date can be invalid:
Dean@703
   227
             * For incoming this commonly occurs when creating a mirror -- it's created without a received time.
Dean@703
   228
             * For outgoing this commonly occurs for unsent mail.
Dean@703
   229
             * In these cases, the invalid date and time will be returned as 1/1/4501 at 12:00AM
Dean@703
   230
             * This situation is filtered here and the date is set as null.
Dean@703
   231
             */
Dean@721
   232
            receivedOn = omi.ReceivedTime;
Dean@721
   233
            if ((receivedOn != null) &&
Dean@721
   234
                (((DateTime)receivedOn).Year > 4000)) // ~2000 years from now, no issue
Dean@703
   235
            {
Dean@721
   236
                receivedOn = null;
Dean@721
   237
            }
Dean@721
   238
Dean@721
   239
            sentOn = omi.SentOn;
Dean@721
   240
            if ((sentOn != null) &&
Dean@721
   241
                (((DateTime)sentOn).Year > 4000)) // ~2000 years from now, no issue
Dean@721
   242
            {
Dean@721
   243
                sentOn = null;
Dean@691
   244
            }
Dean@691
   245
Dean@759
   246
            Global.LogVerbose("PEPMessage: Date & times calculated, calculating body and attachments.");
Dean@740
   247
Dean@384
   248
            // Calculate text body and attachments
Dean@384
   249
            if (createWithoutContent == false)
Dean@384
   250
            {
Dean@384
   251
                // Body
Dean@384
   252
                if (omi.Body != null)
Dean@384
   253
                {
Dean@384
   254
                    bodyLong = omi.Body.Replace("\r\n", "\n");
Dean@384
   255
Dean@697
   256
                    // Save as RTF
Dean@722
   257
                    try
Dean@722
   258
                    {
Dean@722
   259
                        rtfBody = omi.RTFBody;
Dean@722
   260
                        bodyLongFormattedRTF = System.Text.Encoding.ASCII.GetString(rtfBody, 0, rtfBody.Length);
Dean@722
   261
                    }
Dean@722
   262
                    catch
Dean@722
   263
                    {
Dean@759
   264
                        Global.Log("PEPMessage: Unable to read RTF body in MailItem.");
Dean@722
   265
                    }
Dean@697
   266
Dean@384
   267
                    // Force rich text into HTML
Dean@384
   268
                    if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatRichText)
Dean@384
   269
                    {
Dean@384
   270
                        omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
Dean@384
   271
                    }
Dean@384
   272
Dean@384
   273
                    if (omi.BodyFormat == Outlook.OlBodyFormat.olFormatHTML)
Dean@384
   274
                    {
Dean@697
   275
                        bodyLongFormattedHTML = omi.HTMLBody;
Dean@384
   276
                    }
Dean@384
   277
                }
Dean@384
   278
Dean@384
   279
                // Attachments
Dean@551
   280
                attachments = omi.Attachments;
Dean@551
   281
                for (int i = 1; i <= attachments.Count; i++)
Dean@384
   282
                {
Dean@551
   283
                    currAttachment = attachments[i];
Dean@551
   284
Dean@384
   285
                    try
Dean@384
   286
                    {
Dean@551
   287
                        attachmentList.Add(new PEPAttachment(currAttachment));
Dean@384
   288
                    }
Dean@384
   289
                    catch { }
Dean@551
   290
Dean@551
   291
                    Marshal.ReleaseComObject(currAttachment);
Dean@551
   292
                    currAttachment = null;
Dean@384
   293
                }
Dean@384
   294
Dean@384
   295
                // Keywords
Dean@384
   296
                if (omi.Categories != null)
Dean@384
   297
                {
Dean@384
   298
                    using (RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Control Panel\\International"))
Dean@384
   299
                    {
Dean@384
   300
                        delim = key1.GetValue("sList").ToString();
Dean@384
   301
                        keywordList = new List<string>(omi.Categories.Split(delim.ToCharArray()));
Dean@384
   302
                    }
Dean@384
   303
                }
Dean@572
   304
Dean@586
   305
                // Optional properties
Dean@586
   306
                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_ENC_STATUS);
Dean@586
   307
                if (propertyValue != null)
Dean@586
   308
                {
Dean@586
   309
                    newProp = new opt_field();
Dean@586
   310
                    newProp.name = PEPMessage.PR_X_ENC_STATUS_NAME;
Dean@586
   311
                    newProp.value = propertyValue.ToString();
Dean@586
   312
Dean@586
   313
                    optionalPropertyList.Add(newProp);
Dean@586
   314
                }
Dean@586
   315
Dean@586
   316
                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_KEY_LIST);
Dean@586
   317
                if (propertyValue != null)
Dean@586
   318
                {
Dean@586
   319
                    newProp = new opt_field();
Dean@586
   320
                    newProp.name = PEPMessage.PR_X_KEY_LIST_NAME;
Dean@586
   321
                    newProp.value = propertyValue.ToString();
Dean@586
   322
Dean@586
   323
                    optionalPropertyList.Add(newProp);
Dean@586
   324
                }
Dean@586
   325
Dean@586
   326
                propertyValue = MAPIHelper.GetProperty(omi, PEPMessage.PR_X_PEP_VERSION);
Dean@586
   327
                if (propertyValue != null)
Dean@586
   328
                {
Dean@586
   329
                    newProp = new opt_field();
Dean@586
   330
                    newProp.name = PEPMessage.PR_X_PEP_VERSION_NAME;
Dean@586
   331
                    newProp.value = propertyValue.ToString();
Dean@586
   332
Dean@586
   333
                    optionalPropertyList.Add(newProp);
Dean@586
   334
                }
Dean@384
   335
            }
Dean@384
   336
Dean@384
   337
            // Set properties
Dean@384
   338
            this._Attachments = attachmentList;
Dean@384
   339
            this._BCC = bccList;
Dean@384
   340
            this._CC = ccList;
Dean@384
   341
            this._Direction = CryptableMailItem.GetIsIncoming(omi) ? _pEp_msg_direction.pEp_dir_incoming : _pEp_msg_direction.pEp_dir_outgoing;
Dean@643
   342
            this._From = PEPIdentity.GetFromIdentity(omi);
Dean@384
   343
            this._ID = CryptableMailItem.GetMessageID(omi);
Dean@384
   344
            this._Keywords = keywordList;
Dean@384
   345
            this._LongMsg = bodyLong;
Dean@697
   346
            this._LongMsgFormattedHTML = bodyLongFormattedHTML;
Dean@697
   347
            this._LongMsgFormattedRTF = bodyLongFormattedRTF;
Dean@586
   348
            this._OptionalProperties = optionalPropertyList;
Dean@721
   349
            this._ReceivedOn = receivedOn;
Dean@721
   350
            this._SentOn = sentOn;
Dean@384
   351
            this._ShortMsg = omi.Subject;
Dean@384
   352
            this._To = toList;
Dean@384
   353
Dean@384
   354
            // Free resources
Dean@384
   355
            if (acct != null)
Dean@384
   356
            {
Dean@384
   357
                Marshal.ReleaseComObject(acct);
Dean@384
   358
                acct = null;
Dean@384
   359
            }
Dean@384
   360
Dean@551
   361
            if (currAttachment != null)
Dean@551
   362
            {
Dean@551
   363
                Marshal.ReleaseComObject(currAttachment);
Dean@551
   364
                currAttachment = null;
Dean@551
   365
            }
Dean@551
   366
Dean@551
   367
            if (attachments != null)
Dean@551
   368
            {
Dean@551
   369
                Marshal.ReleaseComObject(attachments);
Dean@551
   370
                attachments = null;
Dean@551
   371
            }
Dean@551
   372
Dean@551
   373
            if (currRecipient != null)
Dean@551
   374
            {
Dean@551
   375
                Marshal.ReleaseComObject(currRecipient);
Dean@551
   376
                currRecipient = null;
Dean@551
   377
            }
Dean@551
   378
Dean@551
   379
            if (recipients != null)
Dean@551
   380
            {
Dean@551
   381
                Marshal.ReleaseComObject(recipients);
Dean@551
   382
                recipients = null;
Dean@551
   383
            }
Dean@551
   384
Dean@759
   385
            Global.LogVerbose("PEPMessage: New PEPMessage created.");
Dean@740
   386
Dean@384
   387
            return;
Dean@384
   388
        }
Dean@384
   389
Dean@384
   390
        /**************************************************************
Dean@384
   391
         * 
Dean@384
   392
         * Property Accessors
Dean@384
   393
         * 
Dean@384
   394
         *************************************************************/
Dean@384
   395
Dean@384
   396
        /// <summary>
Dean@384
   397
        /// Gets the list of attachements for this message.
Dean@384
   398
        /// </summary>
Dean@384
   399
        public List<PEPAttachment> Attachments
Dean@384
   400
        {
Dean@384
   401
            get { return (this._Attachments); }
Dean@384
   402
        }
Dean@384
   403
Dean@384
   404
        /// <summary>
Dean@387
   405
        /// Gets the list of identities to be blind carbon copied on the message.
Dean@384
   406
        /// </summary>
Dean@384
   407
        public List<PEPIdentity> BCC
Dean@384
   408
        {
Dean@384
   409
            get { return (this._BCC); }
Dean@384
   410
        }
Dean@384
   411
Dean@384
   412
        /// <summary>
Dean@384
   413
        /// Gets the list of identities to be carbon copied on the message.
Dean@384
   414
        /// </summary>
Dean@384
   415
        public List<PEPIdentity> CC
Dean@384
   416
        {
Dean@384
   417
            get { return (this._CC); }
Dean@384
   418
        }
Dean@384
   419
Dean@384
   420
        /// <summary>
Dean@721
   421
        /// Gets the date and time when the message was either sent or received.
Dean@721
   422
        /// This corresponds with the SentOn and ReceivedOn properties.
Dean@691
   423
        /// </summary>
Dean@691
   424
        public DateTime? DateTimeSentOrReceived
Dean@691
   425
        {
Dean@721
   426
            get
Dean@721
   427
            {
Dean@721
   428
                if (this._Direction == _pEp_msg_direction.pEp_dir_incoming)
Dean@721
   429
                {
Dean@721
   430
                    return (this._ReceivedOn);
Dean@721
   431
                }
Dean@721
   432
                else
Dean@721
   433
                {
Dean@721
   434
                    return (this._SentOn);
Dean@721
   435
                }
Dean@721
   436
            }
Dean@691
   437
        }
Dean@691
   438
Dean@691
   439
        /// <summary>
Dean@384
   440
        /// Gets or sets the direction (incoming or outgoing) of the message.
Dean@384
   441
        /// </summary>
Dean@384
   442
        public _pEp_msg_direction Direction
Dean@384
   443
        {
Dean@384
   444
            get { return (this._Direction); }
Dean@384
   445
            set { this._Direction = value; }
Dean@384
   446
        }
Dean@384
   447
Dean@384
   448
        /// <summary>
Dean@384
   449
        /// Gets or sets the from identity of the message.
Dean@384
   450
        /// Warning: this value can be null.
Dean@384
   451
        /// </summary>
Dean@384
   452
        public PEPIdentity From
Dean@384
   453
        {
Dean@384
   454
            get { return (this._From); }
Dean@384
   455
            set { this._From = value; }
Dean@384
   456
        }
Dean@384
   457
Dean@384
   458
        /// <summary>
Dean@384
   459
        /// Gets or sets the ID of the message.
Dean@384
   460
        /// Warning: this value can be null.
Dean@384
   461
        /// </summary>
Dean@384
   462
        public string ID
Dean@384
   463
        {
Dean@384
   464
            get { return (this._ID); }
Dean@384
   465
            set { this._ID = value; }
Dean@384
   466
        }
Dean@384
   467
Dean@384
   468
        /// <summary>
Dean@384
   469
        /// Gets the list of keywords associated with the message.
Dean@384
   470
        /// </summary>
Dean@384
   471
        public List<string> Keywords
Dean@384
   472
        {
Dean@384
   473
            get { return (this._Keywords); }
Dean@384
   474
        }
Dean@384
   475
Dean@384
   476
        /// <summary>
Dean@384
   477
        /// Gets or sets the long-form (body) of the message.
Dean@384
   478
        /// This should be plain text.
Dean@384
   479
        /// Warning: this value can be null.
Dean@384
   480
        /// </summary>
Dean@384
   481
        public string LongMsg
Dean@384
   482
        {
Dean@384
   483
            get { return (this._LongMsg); }
Dean@384
   484
            set { this._LongMsg = value; }
Dean@384
   485
        }
Dean@384
   486
Dean@384
   487
        /// <summary>
Dean@697
   488
        /// Gets or sets the HTML formatted long-form (body) of the message.
Dean@384
   489
        /// Warning: this value can be null.
Dean@384
   490
        /// </summary>
Dean@697
   491
        public string LongMsgFormattedHTML
Dean@384
   492
        {
Dean@697
   493
            get { return (this._LongMsgFormattedHTML); }
Dean@697
   494
            set { this._LongMsgFormattedHTML = value; }
Dean@697
   495
        }
Dean@697
   496
Dean@697
   497
        /// <summary>
Dean@697
   498
        /// Gets or sets the RTF formatted long-form (body) of the message.
Dean@697
   499
        /// Warning: this value can be null.
Dean@697
   500
        /// </summary>
Dean@697
   501
        public string LongMsgFormattedRTF
Dean@697
   502
        {
Dean@697
   503
            get { return (this._LongMsgFormattedRTF); }
Dean@697
   504
            set { this._LongMsgFormattedRTF = value; }
Dean@384
   505
        }
Dean@384
   506
Dean@384
   507
        /// <summary>
Dean@572
   508
        /// Gets the list of optional properties associated with the message.
Dean@384
   509
        /// </summary>
Dean@572
   510
        public List<opt_field> OptionalProperties
Dean@384
   511
        {
Dean@572
   512
            get { return (this._OptionalProperties); }
Dean@384
   513
        }
Dean@384
   514
Dean@384
   515
        /// <summary>
Dean@721
   516
        /// Gets or sets the date and time when the message was received.
Dean@721
   517
        /// </summary>
Dean@721
   518
        public DateTime? ReceivedOn
Dean@721
   519
        {
Dean@721
   520
            get { return (this._ReceivedOn); }
Dean@721
   521
            set { this._ReceivedOn = value; }
Dean@721
   522
        }
Dean@721
   523
Dean@721
   524
        /// <summary>
Dean@721
   525
        /// Gets or sets the date and time when the message was sent.
Dean@721
   526
        /// </summary>
Dean@721
   527
        public DateTime? SentOn
Dean@721
   528
        {
Dean@721
   529
            get { return (this._SentOn); }
Dean@721
   530
            set { this._SentOn = value; }
Dean@721
   531
        }
Dean@721
   532
Dean@721
   533
        /// <summary>
Dean@384
   534
        /// Gets or sets the short-form (subject) of the message.
Dean@384
   535
        /// Warning: this value can be null.
Dean@384
   536
        /// </summary>
Dean@384
   537
        public string ShortMsg
Dean@384
   538
        {
Dean@384
   539
            get { return (this._ShortMsg); }
Dean@384
   540
            set { this._ShortMsg = value; }
Dean@384
   541
        }
Dean@384
   542
Dean@384
   543
        /// <summary>
Dean@384
   544
        /// Gets the list of identities to receive the message.
Dean@384
   545
        /// </summary>
Dean@384
   546
        public List<PEPIdentity> To
Dean@384
   547
        {
Dean@384
   548
            get { return (this._To); }
Dean@384
   549
        }
Dean@384
   550
Dean@625
   551
        /// <summary>
Dean@625
   552
        /// Gets the total number of all recipients in the message (BCC, CC &amp; To).
Dean@625
   553
        /// </summary>
Dean@625
   554
        public int RecipientCount
Dean@625
   555
        {
Dean@625
   556
            get { return (this._BCC.Count + this._CC.Count + this._To.Count); }
Dean@625
   557
        }
Dean@625
   558
Dean@625
   559
        /// <summary>
Dean@625
   560
        /// Gets a list of all recipients in the message (BCC, CC &amp; To).
Dean@625
   561
        /// Each recipient in the returned list is a copy.
Dean@625
   562
        /// </summary>
Dean@625
   563
        public PEPIdentity[] Recipients
Dean@625
   564
        {
Dean@625
   565
            get
Dean@625
   566
            {
Dean@625
   567
                List<PEPIdentity> recipients = new List<PEPIdentity>();
Dean@625
   568
Dean@625
   569
                // BCC
Dean@625
   570
                for (int i = 0; i < this._BCC.Count; i++)
Dean@625
   571
                {
Dean@625
   572
                    recipients.Add(this._BCC[i].Copy());
Dean@625
   573
                }
Dean@625
   574
Dean@625
   575
                // CC
Dean@625
   576
                for (int i = 0; i < this._CC.Count; i++)
Dean@625
   577
                {
Dean@625
   578
                    recipients.Add(this._CC[i].Copy());
Dean@625
   579
                }
Dean@625
   580
Dean@625
   581
                // To
Dean@625
   582
                for (int i = 0; i < this._To.Count; i++)
Dean@625
   583
                {
Dean@625
   584
                    recipients.Add(this._To[i].Copy());
Dean@625
   585
                }
Dean@625
   586
Dean@625
   587
                return (recipients.ToArray());
Dean@625
   588
            }
Dean@625
   589
        }
Dean@625
   590
Dean@384
   591
        /**************************************************************
Dean@384
   592
         * 
Dean@384
   593
         * Methods
Dean@384
   594
         * 
Dean@384
   595
         *************************************************************/
Dean@384
   596
Dean@384
   597
        /// <summary>
Dean@384
   598
        /// Returns this pEp message as a new pEp engine text_message.
Dean@384
   599
        /// </summary>
Dean@384
   600
        /// <returns>A pEp engine identity.</returns>
Dean@384
   601
        public text_message ToCOMType()
Dean@384
   602
        {
Dean@384
   603
            List<blob> attachments = new List<blob>();
Dean@384
   604
            List<pEp_identity_s> bcc = new List<pEp_identity_s>();
Dean@384
   605
            List<pEp_identity_s> cc = new List<pEp_identity_s>();
Dean@384
   606
            List<pEp_identity_s> to = new List<pEp_identity_s>();
Dean@384
   607
            text_message result = new text_message();
Dean@384
   608
Dean@388
   609
            // Convert attachments
Dean@384
   610
            for (int i = 0; i < this._Attachments.Count; i++)
Dean@384
   611
            {
Dean@384
   612
                attachments.Add(this._Attachments[i].ToCOMType());
Dean@384
   613
            }
Dean@398
   614
Dean@388
   615
            // Convert BCC
Dean@384
   616
            for (int i = 0; i < this._BCC.Count; i++)
Dean@384
   617
            {
Dean@384
   618
                bcc.Add(this._BCC[i].ToCOMType());
Dean@384
   619
            }
Dean@398
   620
Dean@388
   621
            // Convert CC
Dean@384
   622
            for (int i = 0; i < this._CC.Count; i++)
Dean@384
   623
            {
Dean@384
   624
                cc.Add(this._CC[i].ToCOMType());
Dean@384
   625
            }
Dean@398
   626
Dean@388
   627
            // Convert To
Dean@388
   628
            for (int i = 0; i < this._To.Count; i++)
Dean@388
   629
            {
Dean@388
   630
                to.Add(this._To[i].ToCOMType());
Dean@388
   631
            }
Dean@388
   632
Dean@697
   633
            /* Set properties
Dean@697
   634
             * 
Dean@697
   635
             * Note: Skip DateTimeSentOrReceived and LongMsgFormattedRTF which
Dean@697
   636
             * are not supported in the pEp engine.
Dean@697
   637
             */
Dean@388
   638
            result.attachments = attachments.ToArray();
Dean@388
   639
            result.bcc = bcc.ToArray();
Dean@384
   640
            result.cc = cc.ToArray();
Dean@384
   641
            result.dir = this._Direction;
Dean@384
   642
            result.from = (this._From == null ? new pEp_identity_s() : this._From.ToCOMType());
Dean@384
   643
            result.id = this._ID;
Dean@384
   644
            result.keywords = this._Keywords.ToArray();
Dean@384
   645
            result.longmsg = this._LongMsg;
Dean@697
   646
            result.longmsg_formatted = this._LongMsgFormattedHTML;
Dean@572
   647
            result.opt_fields = this._OptionalProperties.ToArray();
Dean@384
   648
            result.shortmsg = this._ShortMsg;
Dean@384
   649
            result.to = to.ToArray();
Dean@384
   650
Dean@384
   651
            return (result);
Dean@384
   652
        }
Dean@384
   653
Dean@384
   654
        /// <summary>
Dean@389
   655
        /// Gets a deep copy of the object and all it's data.
Dean@389
   656
        /// </summary>
Dean@389
   657
        /// <returns>The deep copy of the object.</returns>
Dean@389
   658
        public PEPMessage Copy()
Dean@389
   659
        {
Dean@390
   660
            return (this.Copy(false));
Dean@390
   661
        }
Dean@390
   662
Dean@390
   663
        /// <summary>
Dean@390
   664
        /// Gets a copy of the PEPMessage with or without data.
Dean@390
   665
        /// </summary>
Dean@586
   666
        /// <param name="createWithoutContent">Whether to include content such as text body, attachments 
Dean@586
   667
        /// and optional properties.</param>
Dean@390
   668
        /// <returns>The copy of the PEPMessage.</returns>
Dean@390
   669
        public PEPMessage Copy(bool createWithoutContent = false)
Dean@390
   670
        {
Dean@389
   671
            PEPMessage copy = new PEPMessage();
Dean@389
   672
Dean@389
   673
            // Attachments
Dean@389
   674
            copy.Attachments.Clear();
Dean@390
   675
            if (createWithoutContent == false)
Dean@389
   676
            {
Dean@390
   677
                for (int i = 0; i < this._Attachments.Count; i++)
Dean@390
   678
                {
Dean@390
   679
                    copy.Attachments.Add(this._Attachments[i].Copy());
Dean@390
   680
                }
Dean@389
   681
            }
Dean@389
   682
Dean@389
   683
            // BCC
Dean@389
   684
            copy.BCC.Clear();
Dean@389
   685
            for (int i = 0; i < this._BCC.Count; i++)
Dean@389
   686
            {
Dean@389
   687
                copy.BCC.Add(this._BCC[i].Copy());
Dean@389
   688
            }
Dean@389
   689
Dean@389
   690
            // CC
Dean@389
   691
            copy.CC.Clear();
Dean@389
   692
            for (int i = 0; i < this._CC.Count; i++)
Dean@389
   693
            {
Dean@389
   694
                copy.CC.Add(this._CC[i].Copy());
Dean@389
   695
            }
Dean@389
   696
Dean@389
   697
            copy.Direction = this._Direction;
Dean@389
   698
            copy.From = (this._From == null ? null : this._From.Copy());
Dean@389
   699
            copy.ID = this._ID;
Dean@389
   700
Dean@389
   701
            // Keywords
Dean@389
   702
            copy.Keywords.Clear();
Dean@389
   703
            for (int i = 0; i < this._Keywords.Count; i++)
Dean@389
   704
            {
Dean@389
   705
                copy.Keywords.Add(this._Keywords[i]);
Dean@389
   706
            }
Dean@398
   707
Dean@390
   708
            // Body
Dean@390
   709
            if (createWithoutContent == false)
Dean@390
   710
            {
Dean@390
   711
                copy.LongMsg = this._LongMsg;
Dean@697
   712
                copy.LongMsgFormattedHTML = this._LongMsgFormattedHTML;
Dean@697
   713
                copy.LongMsgFormattedRTF = this._LongMsgFormattedRTF;
Dean@390
   714
            }
Dean@390
   715
            else
Dean@390
   716
            {
Dean@390
   717
                copy.LongMsg = null;
Dean@697
   718
                copy.LongMsgFormattedHTML = null;
Dean@697
   719
                copy.LongMsgFormattedRTF = null;
Dean@390
   720
            }
Dean@389
   721
Dean@389
   722
            // OptionalFields
Dean@572
   723
            copy.OptionalProperties.Clear();
Dean@586
   724
            if (createWithoutContent == false)
Dean@389
   725
            {
Dean@586
   726
                for (int i = 0; i < this._OptionalProperties.Count; i++)
Dean@586
   727
                {
Dean@586
   728
                    copy.OptionalProperties.Add(this._OptionalProperties[i]);
Dean@586
   729
                }
Dean@389
   730
            }
Dean@604
   731
Dean@721
   732
            // ReceivedOn
Dean@721
   733
            if (this._ReceivedOn != null)
Dean@721
   734
            {
Dean@721
   735
                copy.ReceivedOn = new DateTime(((DateTime)this._ReceivedOn).Ticks);
Dean@721
   736
            }
Dean@721
   737
            else
Dean@721
   738
            {
Dean@721
   739
                copy.ReceivedOn = null;
Dean@721
   740
            }
Dean@721
   741
Dean@721
   742
            // SentOn
Dean@721
   743
            if (this._SentOn != null)
Dean@721
   744
            {
Dean@721
   745
                copy.SentOn = new DateTime(((DateTime)this._SentOn).Ticks);
Dean@721
   746
            }
Dean@721
   747
            else
Dean@721
   748
            {
Dean@721
   749
                copy.SentOn = null;
Dean@721
   750
            }
Dean@721
   751
Dean@389
   752
            copy.ShortMsg = this._ShortMsg;
Dean@389
   753
Dean@389
   754
            // To
Dean@389
   755
            copy.To.Clear();
Dean@389
   756
            for (int i = 0; i < this._To.Count; i++)
Dean@389
   757
            {
Dean@389
   758
                copy.To.Add(this._To[i].Copy());
Dean@389
   759
            }
Dean@389
   760
Dean@389
   761
            return (copy);
Dean@389
   762
        }
Dean@389
   763
Dean@389
   764
        /// <summary>
Dean@384
   765
        /// Applies this pEp message's data to the given Outlook item.
Dean@384
   766
        /// </summary>
Dean@384
   767
        /// <param name="omi">The Outlook mail item to apply this pEp message's data to.</param>
Dean@586
   768
        /// <param name="includeOptionalProperties">Whether to include optional properites such as 
Dean@586
   769
        /// color rating, pEp version etc...</param>
Dean@586
   770
        public void ApplyTo(Outlook.MailItem omi,
Dean@586
   771
                            bool includeOptionalProperties = false)
Dean@384
   772
        {
Dean@384
   773
            string tempDir;
Dean@384
   774
            string tempFile;
Dean@543
   775
            Outlook.Attachment newAttachment = null;
Dean@543
   776
            Outlook.Attachments attachments = null;
Dean@543
   777
            Outlook.Recipient newRecipient = null;
Dean@543
   778
            Outlook.Recipients recipients = null;
Dean@543
   779
            Outlook.Account currAccount = null;
Dean@543
   780
            Outlook.Account sendUsingAccount = null;
Dean@543
   781
            Outlook.Accounts accounts = null;
Dean@408
   782
Dean@543
   783
            try
Dean@408
   784
            {
Dean@543
   785
                // Remove all recipients
Dean@543
   786
                recipients = omi.Recipients;
Dean@543
   787
                while (recipients.Count > 0)
Dean@543
   788
                {
Dean@543
   789
                    recipients.Remove(1);
Dean@543
   790
                }
Dean@543
   791
Dean@543
   792
                // Set recipients
Dean@543
   793
                for (int i = 0; i < this._BCC.Count; i++)
Dean@543
   794
                {
Dean@795
   795
                    if (string.IsNullOrWhiteSpace(this._BCC[i].Address) == false)
Dean@543
   796
                    {
Dean@795
   797
                        // Add by address
Dean@543
   798
                        newRecipient = recipients.Add(this._BCC[i].Address);
Dean@543
   799
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Dean@543
   800
Dean@543
   801
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   802
                        newRecipient = null;
Dean@543
   803
                    }
Dean@795
   804
                    else if (string.IsNullOrWhiteSpace(this._BCC[i].Username) == false)
Dean@795
   805
                    {
Dean@795
   806
                        // Add by username (required for distribution lists)
Dean@795
   807
                        newRecipient = recipients.Add(this._BCC[i].Username);
Dean@795
   808
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olBCC;
Dean@795
   809
Dean@795
   810
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   811
                        newRecipient = null;
Dean@795
   812
                    }
Dean@543
   813
                }
Dean@543
   814
Dean@543
   815
                for (int i = 0; i < this._CC.Count; i++)
Dean@543
   816
                {
Dean@795
   817
                    if (string.IsNullOrWhiteSpace(this._CC[i].Address) == false)
Dean@543
   818
                    {
Dean@795
   819
                        // Add by address
Dean@543
   820
                        newRecipient = recipients.Add(this._CC[i].Address);
Dean@543
   821
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Dean@543
   822
Dean@543
   823
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   824
                        newRecipient = null;
Dean@543
   825
                    }
Dean@795
   826
                    else if (string.IsNullOrWhiteSpace(this._CC[i].Username) == false)
Dean@795
   827
                    {
Dean@795
   828
                        // Add by username (required for distribution lists)
Dean@795
   829
                        newRecipient = recipients.Add(this._CC[i].Username);
Dean@795
   830
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olCC;
Dean@795
   831
Dean@795
   832
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   833
                        newRecipient = null;
Dean@795
   834
                    }
Dean@543
   835
                }
Dean@543
   836
Dean@543
   837
                for (int i = 0; i < this._To.Count; i++)
Dean@543
   838
                {
Dean@795
   839
                    if (string.IsNullOrWhiteSpace(this._To[i].Address) == false)
Dean@543
   840
                    {
Dean@795
   841
                        // Add by address
Dean@543
   842
                        newRecipient = recipients.Add(this._To[i].Address);
Dean@543
   843
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@543
   844
Dean@543
   845
                        Marshal.ReleaseComObject(newRecipient);
Dean@543
   846
                        newRecipient = null;
Dean@543
   847
                    }
Dean@795
   848
                    else if (string.IsNullOrWhiteSpace(this._To[i].Username) == false)
Dean@795
   849
                    {
Dean@795
   850
                        // Add by username (required for distribution lists)
Dean@795
   851
                        newRecipient = recipients.Add(this._To[i].Username);
Dean@795
   852
                        newRecipient.Type = (int)Outlook.OlMailRecipientType.olTo;
Dean@795
   853
Dean@795
   854
                        Marshal.ReleaseComObject(newRecipient);
Dean@795
   855
                        newRecipient = null;
Dean@795
   856
                    }
Dean@543
   857
                }
Dean@543
   858
Dean@543
   859
                recipients.ResolveAll();
Dean@543
   860
Dean@543
   861
                /* Set sender
Dean@543
   862
                 * Note that if fails, will be empty which eventually will use the default send account
Dean@543
   863
                 * If the send using account is already populated, this cannot be re-set.
Dean@543
   864
                 * So far this doesn't appear to be an issue as it occurs when applying unencrypted data to a mirror.
Dean@543
   865
                 * However, the mirror SendUsingAccount is already correct at this point and doesn't need to be set.
Dean@543
   866
                 */
Dean@543
   867
                sendUsingAccount = omi.SendUsingAccount;
Dean@543
   868
Dean@543
   869
                if ((this._From != null) &&
Dean@543
   870
                    (this._From.Address != null) &&
Dean@543
   871
                    (sendUsingAccount == null))
Dean@543
   872
                {
Dean@543
   873
                    accounts = Globals.ThisAddIn.Application.Session.Accounts;
Dean@543
   874
Dean@543
   875
                    // Note: Index starts at 1
Dean@543
   876
                    for (int i = 1; i <= accounts.Count; i++)
Dean@543
   877
                    {
Dean@543
   878
                        currAccount = accounts[i];
Dean@543
   879
Dean@543
   880
                        if ((currAccount.SmtpAddress != null) &&
Dean@543
   881
                            (currAccount.SmtpAddress.ToUpper() == this._From.Address.ToUpper()))
Dean@543
   882
                        {
Dean@543
   883
                            /* Try to set the SendUsingAccount
Dean@543
   884
                             * This will fail if the mail item is already marked as sent or the SendUsingAccount is not null, etc...
Dean@564
   885
                             * If it fails, Outlook will in the end just use the default account.
Dean@564
   886
                             * This property should ideally be set before a mail item is saved.
Dean@543
   887
                             */
Dean@543
   888
                            try
Dean@543
   889
                            {
Dean@564
   890
                                omi.SendUsingAccount = currAccount;
Dean@543
   891
                            }
Dean@543
   892
                            catch { }
Dean@543
   893
Dean@543
   894
                            Marshal.ReleaseComObject(currAccount);
Dean@543
   895
                            currAccount = null;
Dean@543
   896
Dean@543
   897
                            break;
Dean@543
   898
                        }
Dean@543
   899
Dean@543
   900
                        Marshal.ReleaseComObject(currAccount);
Dean@543
   901
                        currAccount = null;
Dean@543
   902
                    }
Dean@543
   903
                }
Dean@543
   904
Dean@543
   905
                // Set the subject
Dean@543
   906
                omi.Subject = this._ShortMsg;
Dean@543
   907
Dean@697
   908
                // Set the body (skip RTF format, only use HTML which is what the engine uses)
Dean@697
   909
                if (string.IsNullOrWhiteSpace(this._LongMsgFormattedHTML))
Dean@543
   910
                {
Dean@543
   911
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
Dean@543
   912
                    omi.Body = this._LongMsg;
Dean@543
   913
                }
Dean@543
   914
                else
Dean@543
   915
                {
Dean@543
   916
                    omi.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
Dean@697
   917
                    omi.HTMLBody = this._LongMsgFormattedHTML;
Dean@543
   918
                }
Dean@543
   919
Dean@754
   920
                /* Set the encoding to UTF-8
Dean@754
   921
                 * See: https://msdn.microsoft.com/en-us/library/office/ff860730.aspx
Dean@754
   922
                 * All PEPMessages should be UTF even those coming from the engine.
Dean@754
   923
                 */
Dean@754
   924
                try
Dean@754
   925
                {
Dean@790
   926
                    MAPIHelper.SetProperty(omi, MAPIProperty.PidTagInternetCodepage, 65001);
Dean@790
   927
                    MAPIHelper.SetProperty(omi, MAPIProperty.PidTagMessageCodepage, 65001);
Dean@754
   928
                }
Dean@754
   929
                catch
Dean@754
   930
                {
Dean@759
   931
                    Global.Log("PEPMessage.ApplyTo: Failed to set UTF-8 encoding.");
Dean@754
   932
                }
Dean@754
   933
Dean@543
   934
                // Remove any previous attachments
Dean@543
   935
                attachments = omi.Attachments;
Dean@543
   936
                while (attachments.Count > 0)
Dean@543
   937
                {
Dean@543
   938
                    attachments.Remove(1);
Dean@543
   939
                }
Dean@543
   940
Dean@543
   941
                // Create temp directory for attachments
Dean@543
   942
                tempDir = Path.GetTempFileName() + ".dir";
Dean@543
   943
                Directory.CreateDirectory(tempDir);
Dean@543
   944
Dean@543
   945
                // Add new attachments
Dean@543
   946
                for (int i = 0; i < this._Attachments.Count; i++)
Dean@543
   947
                {
Dean@543
   948
                    // Write current attachment to disk
Dean@543
   949
                    tempFile = tempDir + "\\";
Dean@543
   950
                    if (string.IsNullOrWhiteSpace(this._Attachments[i].FileName))
Dean@543
   951
                    {
Dean@543
   952
                        tempFile += "attachment" + i.ToString();
Dean@543
   953
                    }
Dean@543
   954
                    else
Dean@543
   955
                    {
Dean@543
   956
                        tempFile += this._Attachments[i].FileName;
Dean@543
   957
                    }
Dean@543
   958
                    File.WriteAllBytes(tempFile, this._Attachments[i].Data);
Dean@543
   959
Dean@808
   960
                    // Create a new attachment from the file on disk (also sets the file name)
Dean@543
   961
                    newAttachment = attachments.Add(tempFile);
Dean@543
   962
Dean@543
   963
                    if (string.IsNullOrWhiteSpace(this._Attachments[i].MIMEType))
Dean@543
   964
                    {
Dean@543
   965
                        // Undefined
Dean@790
   966
                        MAPIHelper.SetProperty(newAttachment, MAPIProperty.PidTagAttachMimeTag, "application/octet-stream");
Dean@543
   967
                    }
Dean@543
   968
                    else
Dean@543
   969
                    {
Dean@790
   970
                        MAPIHelper.SetProperty(newAttachment, MAPIProperty.PidTagAttachMimeTag, this._Attachments[i].MIMEType);
Dean@543
   971
                    }
Dean@543
   972
Dean@808
   973
                    // Set the content ID
Dean@808
   974
                    if (string.IsNullOrWhiteSpace(this._Attachments[i].ContentID) == false)
Dean@808
   975
                    {
Dean@808
   976
                        MAPIHelper.SetProperty(newAttachment, MAPIProperty.PidTagAttachContentId, this._Attachments[i].ContentID);
Dean@808
   977
                    }
Dean@808
   978
Dean@543
   979
                    Marshal.ReleaseComObject(newAttachment);
Dean@543
   980
                    newAttachment = null;
Dean@543
   981
                }
Dean@543
   982
Dean@543
   983
                // Delete temp directory for attachments
Dean@543
   984
                Directory.Delete(tempDir, true);
Dean@543
   985
Dean@572
   986
                // Optional properties
Dean@586
   987
                if (includeOptionalProperties)
Dean@543
   988
                {
Dean@586
   989
                    for (int i = 0; i < this._OptionalProperties.Count; i++)
Dean@586
   990
                    {
Dean@586
   991
                        MAPIHelper.SetProperty(omi,
Dean@586
   992
                                               PEPMessage.PR_OPT_FIELD + this._OptionalProperties[i].name,
Dean@586
   993
                                               this._OptionalProperties[i].value);
Dean@586
   994
                    }
Dean@543
   995
                }
Dean@408
   996
            }
Dean@545
   997
            catch (Exception ex)
Dean@545
   998
            {
Dean@660
   999
                Global.StopAndSendCrashReport(ex);
Dean@545
  1000
            }
Dean@543
  1001
            finally
Dean@543
  1002
            {
Dean@543
  1003
                if (newAttachment != null)
Dean@543
  1004
                {
Dean@543
  1005
                    Marshal.ReleaseComObject(newAttachment);
Dean@543
  1006
                    newAttachment = null;
Dean@543
  1007
                }
Dean@408
  1008
Dean@543
  1009
                if (attachments != null)
Dean@466
  1010
                {
Dean@543
  1011
                    Marshal.ReleaseComObject(attachments);
Dean@543
  1012
                    attachments = null;
Dean@543
  1013
                }
Dean@408
  1014
Dean@543
  1015
                if (newRecipient != null)
Dean@543
  1016
                {
Dean@466
  1017
                    Marshal.ReleaseComObject(newRecipient);
Dean@543
  1018
                    newRecipient = null;
Dean@543
  1019
                }
Dean@543
  1020
Dean@543
  1021
                if (recipients != null)
Dean@543
  1022
                {
Dean@543
  1023
                    Marshal.ReleaseComObject(recipients);
Dean@543
  1024
                    recipients = null;
Dean@543
  1025
                }
Dean@543
  1026
Dean@543
  1027
                if (currAccount != null)
Dean@543
  1028
                {
Dean@543
  1029
                    Marshal.ReleaseComObject(currAccount);
Dean@543
  1030
                    currAccount = null;
Dean@543
  1031
                }
Dean@543
  1032
Dean@543
  1033
                if (sendUsingAccount != null)
Dean@543
  1034
                {
Dean@543
  1035
                    Marshal.ReleaseComObject(sendUsingAccount);
Dean@543
  1036
                    sendUsingAccount = null;
Dean@543
  1037
                }
Dean@543
  1038
Dean@543
  1039
                if (accounts != null)
Dean@543
  1040
                {
Dean@543
  1041
                    Marshal.ReleaseComObject(accounts);
Dean@543
  1042
                    accounts = null;
Dean@543
  1043
                }
Dean@408
  1044
            }
Dean@408
  1045
Dean@384
  1046
            return;
Dean@384
  1047
        }
Dean@384
  1048
Dean@398
  1049
        /// <summary>
Dean@398
  1050
        /// Recursivley converts all "BCC", "CC", and "To" identities into a 'flat' list of any members.
Dean@398
  1051
        /// This will remove groups (hierarchy) and convert a group into it's members.
Dean@398
  1052
        /// </summary>
Dean@398
  1053
        public void FlattenAllRecipientIdentities()
Dean@398
  1054
        {
Dean@398
  1055
            this._BCC = PEPIdentity.ToFlatList(this._BCC);
Dean@398
  1056
            this._CC = PEPIdentity.ToFlatList(this._CC);
Dean@398
  1057
            this._To = PEPIdentity.ToFlatList(this._To);
Dean@398
  1058
Dean@398
  1059
            return;
Dean@398
  1060
        }
Dean@413
  1061
Dean@808
  1062
        /// <summary>
Dean@808
  1063
        /// Processes all content IDs in the image attachments as well as HTML body.
Dean@808
  1064
        /// This will convert the CID's to the image filename only.
Dean@808
  1065
        /// </summary>
Dean@808
  1066
        public void NormalizeContentIDs()
Dean@808
  1067
        {
Dean@808
  1068
            int currImgTagIndex;
Dean@808
  1069
            int currImgTagStopIndex;
Dean@808
  1070
            int currImgTagCIDIndex;
Dean@808
  1071
            int currImgTagCIDStopIndex;
Dean@808
  1072
            string currCID;
Dean@808
  1073
            string newCID;
Dean@808
  1074
            string beginning;
Dean@808
  1075
            string ending;
Dean@808
  1076
            string currFileName;
Dean@808
  1077
            string workingHTML;
Dean@808
  1078
            Dictionary<string, string> modifiedCIDs = new Dictionary<string, string>();
Dean@808
  1079
Dean@808
  1080
            // Modify CIDs for all attachments and store modified CIDs in the dictionary
Dean@808
  1081
            for (int i = 0; i < this._Attachments.Count; i++)
Dean@808
  1082
            {
Dean@808
  1083
                currCID = this._Attachments[i].ContentID;
Dean@808
  1084
                currFileName = this._Attachments[i].FileName;
Dean@808
  1085
Dean@808
  1086
                if (string.IsNullOrEmpty(currCID))
Dean@808
  1087
                {
Dean@808
  1088
                    // Just use the file name (even if file name is null or empty)
Dean@808
  1089
                    // It's doesn't matter as it won't be replaced in HTML
Dean@808
  1090
                    newCID = currFileName;
Dean@808
  1091
                }
Dean@808
  1092
                else
Dean@808
  1093
                {
Dean@808
  1094
                    if (string.IsNullOrEmpty(currFileName))
Dean@808
  1095
                    {
Dean@808
  1096
                        // A name must exist for HTML so create one
Dean@808
  1097
                        newCID = "attachment" + i.ToString();
Dean@808
  1098
                    }
Dean@808
  1099
                    else
Dean@808
  1100
                    {
Dean@808
  1101
                        newCID = currFileName; 
Dean@808
  1102
                    }
Dean@808
  1103
Dean@808
  1104
                    modifiedCIDs.Add(currCID, newCID);
Dean@808
  1105
                }
Dean@808
  1106
Dean@808
  1107
                this._Attachments[i].ContentID = newCID;
Dean@808
  1108
            }
Dean@808
  1109
Dean@808
  1110
            /* Process the HTML body replacing all modified CIDs
Dean@808
  1111
             * Since no HTML document library is provided in standard C#, text operations are done.
Dean@808
  1112
             * This should work ok, but there are some potential issue with malformed HTML that might render correctly.
Dean@808
  1113
             * Only " is supported instead of ' as well.
Dean@808
  1114
             * This shouldn't be an issue since the method is primarily run on mail items generated internally.
Dean@808
  1115
             */
Dean@808
  1116
            workingHTML = this._LongMsgFormattedHTML;
Dean@808
  1117
            if (string.IsNullOrEmpty(workingHTML) == false)
Dean@808
  1118
            {
Dean@808
  1119
                currImgTagIndex = workingHTML.IndexOf("<img", 0) + 4;
Dean@808
  1120
Dean@808
  1121
                while (currImgTagIndex > -1)
Dean@808
  1122
                {
Dean@808
  1123
                    currImgTagCIDIndex = workingHTML.IndexOf("src=\"cid:", currImgTagIndex) + 9;
Dean@808
  1124
                    currImgTagCIDStopIndex = workingHTML.IndexOf("\"", currImgTagCIDIndex);
Dean@808
  1125
                    currImgTagStopIndex = workingHTML.IndexOf(">", currImgTagIndex);
Dean@808
  1126
                    
Dean@808
  1127
                    // Validate relative index positions
Dean@808
  1128
                    if ((currImgTagCIDIndex < currImgTagStopIndex) &&
Dean@808
  1129
                        (currImgTagCIDStopIndex < currImgTagStopIndex) &&
Dean@808
  1130
                        ((currImgTagCIDStopIndex - currImgTagCIDIndex) >= 1))
Dean@808
  1131
                    {
Dean@808
  1132
                        // Split the HTML at the CID and modify if necessary
Dean@808
  1133
                        beginning = workingHTML.Substring(0, currImgTagCIDIndex);
Dean@808
  1134
                        ending = workingHTML.Substring(currImgTagCIDStopIndex);
Dean@808
  1135
                        currCID = workingHTML.Substring(currImgTagCIDIndex, (currImgTagCIDStopIndex - currImgTagCIDIndex));
Dean@808
  1136
Dean@808
  1137
                        // Lookup the new CID
Dean@808
  1138
                        newCID = null;
Dean@808
  1139
                        try
Dean@808
  1140
                        {
Dean@808
  1141
                            newCID = modifiedCIDs[currCID];
Dean@808
  1142
                        }
Dean@808
  1143
                        catch
Dean@808
  1144
                        {
Dean@808
  1145
                            newCID = null;
Dean@808
  1146
                        }
Dean@808
  1147
Dean@808
  1148
                        // Replace
Dean@808
  1149
                        if (string.IsNullOrEmpty(newCID) == false)
Dean@808
  1150
                        {
Dean@808
  1151
                            workingHTML = beginning + newCID + ending;
Dean@808
  1152
                        }
Dean@808
  1153
                    }
Dean@808
  1154
Dean@808
  1155
                    currImgTagIndex = workingHTML.IndexOf("<img", currImgTagIndex);
Dean@808
  1156
                }
Dean@808
  1157
            }
Dean@808
  1158
            this._LongMsgFormattedHTML = workingHTML;
Dean@808
  1159
Dean@808
  1160
            return;
Dean@808
  1161
        }
Dean@384
  1162
    }
Dean@384
  1163
}