private static string GetPlainTextBody(Item message)
        {
            // When there's no text whatsoever in the email, EWS may return null rather than an empty string. We normalize
            // to empty string to avoid repeated null checks later on, since empty string represents the same meaning as null
            // in our context.
            var text = message.Body.Text ?? string.Empty;

            return(message.Body.BodyType == BodyType.Text ? text : EmailBodyProcessingUtils.ConvertHtmlMessageToPlainText(text));
        }
Esempio n. 2
0
        /// <param name="workItemId">The ID of the work item to modify </param>
        /// <param name="comment">Comment to add to description</param>
        /// <param name="commentIsHtml"></param>
        /// <param name="values">List of fields to change</param>
        /// <param name="attachments"></param>
        public void ModifyWorkItem(int workItemId, string comment, bool commentIsHtml, Dictionary <string, string> values, MessageAttachmentCollection attachments)
        {
            if (workItemId <= 0)
            {
                return;
            }

            var workItem = _tfsStore.GetWorkItem(workItemId);

            workItem.Open();

            if (commentIsHtml)
            {
                workItem.History = EmailBodyProcessingUtils.UpdateEmbeddedImageLinks(comment, attachments.Attachments);
            }
            else
            {
                workItem.History = comment.Replace("\n", "<br>");
            }

            foreach (var key in values.Keys)
            {
                TryApplyFieldValue(workItem, key, values[key]);
            }

            if (attachments != null)
            {
                string GetAttachmentKey(string fileName, long length)
                {
                    return($"{fileName}|{length}");
                }

                var existingAttachments = new HashSet <string>(workItem.Attachments
                                                               .OfType <Attachment>()
                                                               .Select(attachment => GetAttachmentKey(attachment.Name, attachment.Length)));

                foreach (var attachment in attachments.Attachments)
                {
                    var    localFileInfo = new FileInfo(attachment.FilePath);
                    string key           = GetAttachmentKey(localFileInfo.Name, localFileInfo.Length);

                    // If there's already an attachment with the same file name and size, don't bother re-uploading it
                    // TODO: this may break embedded images for html replies since we update the img tag above to point to a local path we don't upload
                    // However, we haven't confirmed this breaks and replying with an identical image is unlikely, so we ignore this for now
                    if (!existingAttachments.Contains(key))
                    {
                        workItem.Attachments.Add(new Attachment(attachment.FilePath));
                    }
                }
            }

            ValidateAndSaveWorkItem(workItem);

            workItem.Save();
        }
Esempio n. 3
0
        private static string GetPlainTextBody(Item message)
        {
            string plainTextBody;

            if (!message.TryGetProperty(EWSExtendedProperty.PidTagBody, out plainTextBody))
            {
                plainTextBody = EmailBodyProcessingUtils.ConvertHtmlMessageToPlainText(message.Body.Text); // Fallback
            }

            // When there's no text whatsoever in the email, EWS may return null rather than an empty string. We normalize
            // to empty string to avoid repeated null checks later on, since empty string represents the same meaning as null
            // in our context.
            return(plainTextBody ?? string.Empty);
        }
Esempio n. 4
0
        public void TestGetLastMessageTextBasic()
        {
            var message = new IncomingEmailMessageMock();

            var lastMessageText = RandomDataHelper.GetBody(_rand.Next());
            var numOfReplies    = _rand.Next(0, 100);
            var bodyBuilder     = new StringBuilder(lastMessageText);

            for (var i = 0; i < numOfReplies; i++)
            {
                bodyBuilder.AppendLine(RandomDataHelper.GetRandomMessageSeparator(_rand.Next()));
                bodyBuilder.Append(RandomDataHelper.GetBody(_rand.Next()));
            }
            message.PlainTextBody = bodyBuilder.ToString();

            Assert.AreEqual(lastMessageText, EmailBodyProcessingUtils.GetLastMessageText(message), "Verifying extracted last message text correctness");
        }
Esempio n. 5
0
        public void TestConvertHtmlMessageToHtmlRegression()
        {
            const string regressionMessagesFolder = "RegressionMessages";

            foreach (var originalFilename in Directory.GetFiles(regressionMessagesFolder, "*.orig"))
            {
                Trace.WriteLine(string.Format("Processing regression file {0}", originalFilename));

                var baseFilename     = Path.GetFileNameWithoutExtension(originalFilename);
                var expectedFilename = Path.Combine(regressionMessagesFolder, baseFilename + ".expected");

                var html          = File.ReadAllText(originalFilename);
                var expectedText  = Normalize(File.ReadAllText(expectedFilename));
                var convertedHtml = Normalize(EmailBodyProcessingUtils.ConvertHtmlMessageToPlainText(html));

                Assert.AreEqual(expectedText, convertedHtml);
            }
        }
Esempio n. 6
0
        public void TestConvertHtmlMessageToPlainTextBasic()
        {
            var properties = new StringProperties();

            properties.MinNumberOfCodePoints = 20;
            RandomDataHelper.Ranges.ForEach(properties.UnicodeRanges.Add);
            properties.UnicodeRanges.Remove(new UnicodeRange('<', '<'));
            properties.UnicodeRanges.Remove(new UnicodeRange('>', '>'));

            // Can't have '<' or '>' chars in the content, since it breaks the HTML processing. This is OK, since real HTML should never have these
            // chracters either (they will be escaped as &lt; and &gt;)
            var expectedText =
                StringFactory.GenerateRandomString(properties, _rand.Next()).Trim().Replace("<", "").Replace(">", "");
            var htmlText  = string.Format("<html><head></head><body><p>{0}</p></body></html>", expectedText);
            var plainText = EmailBodyProcessingUtils.ConvertHtmlMessageToPlainText(htmlText);

            Assert.AreEqual(plainText, expectedText);
        }
        public void TestGetLastMessageText_NoPrevious()
        {
            string original = @"<html>
<body>
This is a boring email.
</body>
</html>";

            // Note: it's acceptable to not preserve whitespace / insert empty HTML tags because we're
            // manipulating HTML, not plain text. As long as the rendered page isn't impacted, all is well
            string expected = @"<html><head></head><body>
This is a boring email.

</body></html>";

            string actual = EmailBodyProcessingUtils.GetLastMessageText_Html(original);

            Assert.AreEqual(Normalize(expected), Normalize(actual));
        }
Esempio n. 8
0
        public void TestGetLastMessageText_Previous_FromColon()
        {
            string original = @"<html>
<body>
<div class=""wrapppingBothMessageAndReply"">
    <p class=""customStyling"">This is random text with some custom styling and outlook-generated elements.<o:p></o:p></p>
    <div>
        <div style=""border:none;border-top:solid"">
            <p class=""customStyling""><b>From:</b> someAddress;<br><b>Subject:</b> RE: Build error<o:p></o:p>
            </p>
        </div>
    </div>
    <p class=""customStyling"">
        <o:p>&nbsp;</o:p>
    </p>
    <p class=""customStyling"">text of the reply
    </p>
</div>
<div>Something after the containing div</div>
</body>
</html>";

            // Note: it's acceptable to not preserve whitespace because it's
            // manipulating HTML, not plain text. As long as the rendered page isn't impacted, all is well
            // Note that we expect that both
            // 1. Elements following the latest message are removed
            // 2. Anything in the same element as the latest message but after the start of the previous should be cleared out
            string expected = @"<html><head></head><body>
<div class=""wrapppingBothMessageAndReply"">
    <p class=""customStyling"">This is random text with some custom styling and outlook-generated elements.<o:p></o:p></p>
    <div>
        <div style=""border:none;border-top:solid"">
            <p class=""customStyling""><b></b></p></div></div></div></body></html>";

            string actual = EmailBodyProcessingUtils.GetLastMessageText_Html(original);

            Assert.AreEqual(Normalize(expected), Normalize(actual));
        }
        public void TestGetLastMessageText_EmailClientsSchemas()
        {
            const string schemasFolder = "LastMessageSchemas";

            foreach (var originalFilename in Directory.GetFiles(schemasFolder, "*.orig"))
            {
                Trace.WriteLine(string.Format("Processing email schema file {0}", originalFilename));

                var baseFilename     = Path.GetFileNameWithoutExtension(originalFilename);
                var expectedFilename = Path.Combine(schemasFolder, baseFilename + ".expected");

                var original = File.ReadAllText(originalFilename);
                var expected = Normalize(File.ReadAllText(expectedFilename));
                var actual   = Normalize(EmailBodyProcessingUtils.GetLastMessageText_Html(original));

                // Note: it's acceptable to not preserve whitespace because it's
                // manipulating HTML, not plain text. As long as the rendered page isn't impacted, all is well
                // Note that we expect that both
                // 1. Elements following the latest message are removed
                // 2. Anything in the same element as the latest message but after the start of the previous should be cleared out
                Assert.AreEqual(expected, actual);
            }
        }
Esempio n. 10
0
        private void InitWorkItemFields(IIncomingEmailMessage message, Dictionary <string, string> workItemUpdates, MessageAttachmentCollection attachments)
        {
            var resolver = new SpecialValueResolver(message, _workItemManager.GetNameResolver());

            workItemUpdates["Title"] = resolver.Subject;
            var rawConversationIndex = message.ConversationId;

            workItemUpdates[_config.WorkItemSettings.ConversationIndexFieldName] =
                rawConversationIndex.Substring(0, Math.Min(rawConversationIndex.Length, TfsTextFieldMaxLength));

            bool enableImgUpdating = _config.WorkItemSettings.EnableExperimentalHtmlFeatures;

            foreach (var defaultFieldValue in _config.WorkItemSettings.DefaultFieldValues)
            {
                var result = resolver.Resolve(defaultFieldValue.Value);
                if (enableImgUpdating && message.IsHtmlBody && defaultFieldValue.Value == SpecialValueResolver.RawMessageBodyKeyword)
                {
                    result = EmailBodyProcessingUtils.UpdateEmbeddedImageLinks(result, attachments.Attachments);
                }

                workItemUpdates[defaultFieldValue.Field] = result;
            }
        }
        public void TestUpdateEmbeddedImageLinks_Basic()
        {
            string original = @"<html>
<body>
<img src=""cid:123"" >
</body>
</html>";

            IReadOnlyCollection <MessageAttachmentInfo> attachmentInfo = new List <MessageAttachmentInfo>
            {
                new MessageAttachmentInfo(@"x:\image.png", "123"),
            };

            // Note: it's acceptable to not preserve whitespace / insert empty HTML tags because we're
            // manipulating HTML, not plain text. As long as the rendered page isn't impacted, all is well
            string expected = @"<html><head></head><body>
<img src=""file:///x:/image.png"">

</body></html>";

            string actual = EmailBodyProcessingUtils.UpdateEmbeddedImageLinks(original, attachmentInfo);

            Assert.AreEqual(Normalize(expected), Normalize(actual));
        }
Esempio n. 12
0
 private static string GetPlainTextBody(Item message)
 {
     return(message.Body.BodyType == BodyType.Text ?
            message.Body.Text :
            EmailBodyProcessingUtils.ConvertHtmlMessageToPlainText(message.Body.Text));
 }
Esempio n. 13
0
 public string GetLastMessageText()
 {
     return(EmailBodyProcessingUtils.GetLastMessageText(this));
 }
Esempio n. 14
0
 public string GetLastMessageText(bool enableExperimentalHtmlFeatures)
 {
     return(EmailBodyProcessingUtils.GetLastMessageText(this, enableExperimentalHtmlFeatures));
 }