예제 #1
0
        /// <summary>
        ///     Writes all the properties that are part of the <see cref="Email"/> object either as <see cref="CFStorage"/>'s
        ///     or <see cref="CFStream"/>'s to the <see cref="CompoundFile.RootStorage"/>
        /// </summary>
        internal void WriteToStorage()
        {
            var rootStorage = CompoundFile.RootStorage;

            if (Class == MessageClass.Unknown)
            {
                Class = MessageClass.IPM_Note;
            }

            MessageSize += Recipients.WriteToStorage(rootStorage);
            MessageSize += Attachments.WriteToStorage(rootStorage);

            var recipientCount  = Recipients.Count;
            var attachmentCount = Attachments.Count;

            TopLevelProperties.RecipientCount   = recipientCount;
            TopLevelProperties.AttachmentCount  = attachmentCount;
            TopLevelProperties.NextRecipientId  = recipientCount;
            TopLevelProperties.NextAttachmentId = attachmentCount;

            TopLevelProperties.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId());
            TopLevelProperties.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey());
            TopLevelProperties.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_STORE_UNICODE_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_ALTERNATE_RECIPIENT_ALLOWED, true, PropertyFlags.PROPATTR_READABLE);
            TopLevelProperties.AddProperty(PropertyTags.PR_HASATTACH, attachmentCount > 0);

            if (TransportMessageHeaders != null)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_TRANSPORT_MESSAGE_HEADERS_W, TransportMessageHeaders.ToString());

                if (!string.IsNullOrWhiteSpace(TransportMessageHeaders.MessageId))
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, TransportMessageHeaders.MessageId);
                }

                if (TransportMessageHeaders.References.Any())
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_REFERENCES_W, TransportMessageHeaders.References.Last());
                }

                if (TransportMessageHeaders.InReplyTo.Any())
                {
                    TopLevelProperties.AddProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, TransportMessageHeaders.InReplyTo.Last());
                }
            }

            if (!string.IsNullOrWhiteSpace(InternetMessageId))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId);
            }

            if (!string.IsNullOrWhiteSpace(InternetReferences))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_REFERENCES_W, InternetReferences);
            }

            if (!string.IsNullOrWhiteSpace(InReplyToId))
            {
                TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, InReplyToId);
            }

            var messageFlags = MessageFlags.MSGFLAG_UNMODIFIED;

            if (attachmentCount > 0)
            {
                messageFlags |= MessageFlags.MSGFLAG_HASATTACH;
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_CPID, Encoding.UTF8.CodePage);

            TopLevelProperties.AddProperty(PropertyTags.PR_BODY_W, BodyText);

            if (!string.IsNullOrEmpty(BodyHtml) && !Draft)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_HTML, BodyHtml);
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, false);
            }
            else if (string.IsNullOrWhiteSpace(BodyRtf) && !string.IsNullOrWhiteSpace(BodyHtml))
            {
                BodyRtf           = Strings.GetEscapedRtf(BodyHtml);
                BodyRtfCompressed = true;
            }

            if (!string.IsNullOrWhiteSpace(BodyRtf))
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_COMPRESSED, new RtfCompressor().Compress(Encoding.ASCII.GetBytes(BodyRtf)));
                TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, BodyRtfCompressed);
            }

            if (MessageEditorFormat != MessageEditorFormat.EDITOR_FORMAT_DONTKNOW)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_MSG_EDITOR_FORMAT, MessageEditorFormat);
            }

            if (!SentOn.HasValue)
            {
                SentOn = DateTime.UtcNow;
            }

            if (ReceivedOn.HasValue)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_DELIVERY_TIME, ReceivedOn.Value.ToUniversalTime());
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn.Value.ToUniversalTime());
            TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS, MapiAccess.MAPI_ACCESS_DELETE | MapiAccess.MAPI_ACCESS_MODIFY | MapiAccess.MAPI_ACCESS_READ);
            TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS_LEVEL, MapiAccess.MAPI_ACCESS_MODIFY);
            TopLevelProperties.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_MESSAGE);

            SetSubject();
            TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_W, Subject);
            TopLevelProperties.AddProperty(PropertyTags.PR_NORMALIZED_SUBJECT_W, SubjectNormalized);
            TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_PREFIX_W, SubjectPrefix);
            TopLevelProperties.AddProperty(PropertyTags.PR_CONVERSATION_TOPIC_W, SubjectNormalized);

            // http://www.meridiandiscovery.com/how-to/e-mail-conversation-index-metadata-computer-forensics/
            // http://stackoverflow.com/questions/11860540/does-outlook-embed-a-messageid-or-equivalent-in-its-email-elements
            //propertiesStream.AddProperty(PropertyTags.PR_CONVERSATION_INDEX, Subject);

            // TODO: Change modification time when this message is opened and only modified
            var utcNow = DateTime.UtcNow;

            TopLevelProperties.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow);
            TopLevelProperties.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow);
            TopLevelProperties.AddProperty(PropertyTags.PR_PRIORITY, Priority);
            TopLevelProperties.AddProperty(PropertyTags.PR_IMPORTANCE, Importance);
            TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_LOCALE_ID, CultureInfo.CurrentCulture.LCID);

            if (Draft)
            {
                messageFlags |= MessageFlags.MSGFLAG_UNSENT;
                IconIndex     = MessageIconIndex.UnsentMail;
            }

            if (ReadRecipient)
            {
                TopLevelProperties.AddProperty(PropertyTags.PR_READ_RECEIPT_REQUESTED, true);
                var reportTag = new ReportTag {
                    ANSIText = Subject
                };
                TopLevelProperties.AddProperty(PropertyTags.PR_REPORT_TAG, reportTag.ToByteArray());
            }

            TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags);
            TopLevelProperties.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex);

            Sender?.WriteProperties(TopLevelProperties);
            Receiving?.WriteProperties(TopLevelProperties);
            Representing?.WriteProperties(TopLevelProperties);
            ReceivingRepresenting?.WriteProperties(TopLevelProperties);

            if (recipientCount > 0)
            {
                var displayTo  = new List <string>();
                var displayCc  = new List <string>();
                var displayBcc = new List <string>();

                foreach (var recipient in Recipients)
                {
                    switch (recipient.RecipientType)
                    {
                    case RecipientType.To:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayTo.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayTo.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Cc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayCc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayCc.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Bcc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayBcc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayBcc.Add(recipient.Email);
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                var replyToRecipients = new List <string>();

                foreach (var recipient in ReplyToRecipients)
                {
                    replyToRecipients.Add(recipient.Email);
                }

                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_TO_W, string.Join(";", displayTo), PropertyFlags.PROPATTR_READABLE);
                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_CC_W, string.Join(";", displayCc), PropertyFlags.PROPATTR_READABLE);
                TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_BCC_W, string.Join(";", displayBcc), PropertyFlags.PROPATTR_READABLE);
                TopLevelProperties.AddProperty(PropertyTags.PR_REPLY_RECIPIENT_NAMES_W, string.Join(";", replyToRecipients), PropertyFlags.PROPATTR_READABLE);
            }
        }
예제 #2
0
        /// <summary>
        ///     Converts an EML file to MSG format
        /// </summary>
        /// <param name="emlFileName">The EML (MIME) file</param>
        /// <param name="msgFileName">The MSG file</param>
        public static void ConvertEmlToMsg(string emlFileName, string msgFileName)
        {
            var eml    = MimeMessage.Load(emlFileName);
            var sender = new Sender(string.Empty, string.Empty);

            if (eml.From.Count > 0)
            {
                var mailAddress = ((MailboxAddress)eml.From[0]);
                sender = new Sender(mailAddress.Address, mailAddress.Name);
            }

            var representing = new Representing(string.Empty, string.Empty);

            if (eml.ResentSender != null)
            {
                representing = new Representing(eml.ResentSender.Address, eml.ResentSender.Name);
            }

            var msg = new Email(sender, representing, eml.Subject)
            {
                SentOn            = eml.Date.UtcDateTime,
                InternetMessageId = eml.MessageId
            };

            switch (eml.Priority)
            {
            case MessagePriority.NonUrgent:
                msg.Priority = Enums.MessagePriority.PRIO_NONURGENT;
                break;

            case MessagePriority.Normal:
                msg.Priority = Enums.MessagePriority.PRIO_NORMAL;
                break;

            case MessagePriority.Urgent:
                msg.Priority = Enums.MessagePriority.PRIO_URGENT;
                break;
            }

            switch (eml.Importance)
            {
            case MessageImportance.Low:
                msg.Importance = Enums.MessageImportance.IMPORTANCE_LOW;
                break;

            case MessageImportance.Normal:
                msg.Importance = Enums.MessageImportance.IMPORTANCE_NORMAL;
                break;

            case MessageImportance.High:
                msg.Importance = Enums.MessageImportance.IMPORTANCE_HIGH;
                break;
            }

            foreach (var to in eml.To)
            {
                var mailAddress = ((MailboxAddress)to);
                msg.Recipients.AddTo(mailAddress.Address, mailAddress.Name);
            }

            foreach (var cc in eml.Cc)
            {
                var mailAddress = ((MailboxAddress)cc);
                msg.Recipients.AddCc(mailAddress.Address, mailAddress.Name);
            }

            foreach (var bcc in eml.Bcc)
            {
                var mailAddress = ((MailboxAddress)bcc);
                msg.Recipients.AddBcc(mailAddress.Address, mailAddress.Name);
            }

            using (var headerStream = new MemoryStream())
            {
                eml.Headers.WriteTo(headerStream);
                headerStream.Position       = 0;
                msg.TransportMessageHeaders = Encoding.ASCII.GetString(headerStream.ToArray());
            }

            msg.BodyHtml = eml.HtmlBody;
            msg.BodyText = eml.TextBody;

            var skipFirst = true;

            foreach (var bodyPart in eml.BodyParts)
            {
                // We always skip the first bodypart because that is normaly the html, text or rtf body
                if (skipFirst)
                {
                    skipFirst = false;
                    continue;
                }

                var attachmentStream = new MemoryStream();
                var fileName         = bodyPart.ContentType.Name;
                var extension        = string.Empty;

                if (bodyPart is MessagePart)
                {
                    var part = (MessagePart)bodyPart;
                    part.Message.WriteTo(attachmentStream);
                    if (part.Message != null)
                    {
                        fileName = part.Message.Subject;
                    }

                    extension = ".eml";
                }
                else if (bodyPart is MessageDispositionNotification)
                {
                    var part = (MessageDispositionNotification)bodyPart;
                    fileName = part.FileName;
                }
                else if (bodyPart is MessageDeliveryStatus)
                {
                    var part = (MessageDeliveryStatus)bodyPart;
                    fileName  = "details";
                    extension = ".txt";
                    part.WriteTo(FormatOptions.Default, attachmentStream, true);
                }
                else
                {
                    var part = (MimePart)bodyPart;
                    part.ContentObject.DecodeTo(attachmentStream);
                    fileName = part.FileName;
                    bodyPart.WriteTo(attachmentStream);
                }

                fileName = string.IsNullOrWhiteSpace(fileName)
                    ? "Nameless"
                    : FileManager.RemoveInvalidFileNameChars(fileName);

                if (!string.IsNullOrEmpty(extension))
                {
                    fileName += extension;
                }

                var inline = bodyPart.ContentDisposition != null &&
                             bodyPart.ContentDisposition.Disposition.Equals("inline",
                                                                            StringComparison.InvariantCultureIgnoreCase);

                attachmentStream.Position = 0;
                msg.Attachments.Add(attachmentStream, fileName, -1, inline, bodyPart.ContentId);
            }

            msg.Save(msgFileName);
        }
예제 #3
0
        /// <summary>
        ///     Writes all the properties that are part of the <see cref="Email"/> object either as <see cref="CFStorage"/>'s
        ///     or <see cref="CFStream"/>'s to the <see cref="CompoundFile.RootStorage"/>
        /// </summary>
        private void WriteToStorage()
        {
            var  rootStorage = CompoundFile.RootStorage;
            long messageSize = 0;

            messageSize += Recipients.WriteToStorage(rootStorage);
            messageSize += Attachments.WriteToStorage(rootStorage);

            var recipientCount   = Recipients.Count;
            var attachmentCount  = Attachments.Count;
            var propertiesStream = new TopLevelProperties(recipientCount,
                                                          attachmentCount,
                                                          recipientCount,
                                                          attachmentCount);

            if (!string.IsNullOrEmpty(InternetMessageId))
            {
                propertiesStream.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId);
            }

            propertiesStream.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId());
            propertiesStream.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey());
            propertiesStream.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            propertiesStream.AddProperty(PropertyTags.PR_STORE_UNICODE_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE);
            propertiesStream.AddProperty(PropertyTags.PR_ALTERNATE_RECIPIENT_ALLOWED, true, PropertyFlags.PROPATTR_READABLE);
            propertiesStream.AddProperty(PropertyTags.PR_HASATTACH, attachmentCount > 0);

            var messageFlags = MessageFlags.MSGFLAG_UNMODIFIED;

            if (Draft)
            {
                messageFlags |= MessageFlags.MSGFLAG_UNSENT | MessageFlags.MSGFLAG_FROMME;
                IconIndex     = MessageIconIndex.UnsentMail;
            }

            if (attachmentCount > 0)
            {
                messageFlags |= MessageFlags.MSGFLAG_HASATTACH;
            }

            if (!SentOn.HasValue)
            {
                SentOn = DateTime.UtcNow;
            }

            propertiesStream.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn);
            propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags);
            propertiesStream.AddProperty(PropertyTags.PR_ACCESS, MapiAccess.MAPI_ACCESS_DELETE | MapiAccess.MAPI_ACCESS_MODIFY | MapiAccess.MAPI_ACCESS_READ);
            propertiesStream.AddProperty(PropertyTags.PR_ACCESS_LEVEL, MapiAccess.MAPI_ACCESS_MODIFY);
            propertiesStream.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_MESSAGE);

            SetSubject();
            propertiesStream.AddProperty(PropertyTags.PR_SUBJECT_W, Subject);
            propertiesStream.AddProperty(PropertyTags.PR_NORMALIZED_SUBJECT_W, SubjectNormalized);
            propertiesStream.AddProperty(PropertyTags.PR_SUBJECT_PREFIX_W, SubjectPrefix);
            propertiesStream.AddProperty(PropertyTags.PR_CONVERSATION_TOPIC_W, SubjectNormalized);

            // http://www.meridiandiscovery.com/how-to/e-mail-conversation-index-metadata-computer-forensics/
            // http://stackoverflow.com/questions/11860540/does-outlook-embed-a-messageid-or-equivalent-in-its-email-elements
            //propertiesStream.AddProperty(PropertyTags.PR_CONVERSATION_INDEX, Subject);

            // TODO: Change modification time when this message is opened and only modified
            var utcNow = DateTime.UtcNow;

            propertiesStream.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow);
            propertiesStream.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow);
            propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_CLASS_W, "IPM.Note");
            propertiesStream.AddProperty(PropertyTags.PR_PRIORITY, Priority);
            propertiesStream.AddProperty(PropertyTags.PR_IMPORTANCE, Importance);
            propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_LOCALE_ID, CultureInfo.CurrentCulture.LCID);
            propertiesStream.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex);

            if (Sender != null)
            {
                Sender.WriteProperties(propertiesStream);
            }
            if (Receiving != null)
            {
                Receiving.WriteProperties(propertiesStream);
            }
            if (Representing != null)
            {
                Representing.WriteProperties(propertiesStream);
            }
            if (ReceivingRepresenting != null)
            {
                ReceivingRepresenting.WriteProperties(propertiesStream);
            }

            if (recipientCount > 0)
            {
                var displayTo  = new List <string>();
                var displayCc  = new List <string>();
                var displayBcc = new List <string>();

                foreach (var recipient in Recipients)
                {
                    switch (recipient.RecipientType)
                    {
                    case RecipientType.To:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayTo.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayTo.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Cc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayCc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayCc.Add(recipient.Email);
                        }
                        break;

                    case RecipientType.Bcc:
                        if (!string.IsNullOrWhiteSpace(recipient.DisplayName))
                        {
                            displayBcc.Add(recipient.DisplayName);
                        }
                        else if (!string.IsNullOrWhiteSpace(recipient.Email))
                        {
                            displayBcc.Add(recipient.Email);
                        }
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_TO_W, string.Join(";", displayTo), PropertyFlags.PROPATTR_READABLE);
                propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_CC_W, string.Join(";", displayCc), PropertyFlags.PROPATTR_READABLE);
                propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_BCC_W, string.Join(";", displayBcc), PropertyFlags.PROPATTR_READABLE);
            }

            propertiesStream.AddProperty(PropertyTags.PR_INTERNET_CPID, Encoding.UTF8.CodePage);
            propertiesStream.AddProperty(PropertyTags.PR_BODY_W, BodyText);
            if (!string.IsNullOrEmpty(BodyHtml))
            {
                propertiesStream.AddProperty(PropertyTags.PR_HTML, BodyHtml);
            }

            // This is experimental code
            if (string.IsNullOrWhiteSpace(BodyRtf) && !string.IsNullOrWhiteSpace(BodyHtml))
            {
                BodyRtf           = "{\\rtf1\\ansi\\ansicpg1252\\fromhtml1 " + BodyHtml + "}";
                BodyRtfCompressed = true;
            }

            if (!string.IsNullOrEmpty(BodyRtf) && BodyRtfCompressed)
            {
                propertiesStream.AddProperty(PropertyTags.PR_RTF_COMPRESSED, RtfCompressor.Compress(Encoding.ASCII.GetBytes(BodyRtf)));
                propertiesStream.AddProperty(PropertyTags.PR_RTF_IN_SYNC, true);
            }

            propertiesStream.WriteProperties(rootStorage, messageSize);
        }