/// <summary> /// Saves the mailbox entry. /// </summary> /// <param name="entry">The entry.</param> void SaveMailboxEntry(MailboxEntry entry) { try { //load template var body = string.Format("<div >Sent by:{1} on: {2}<br/>{0}</div>", entry.Content.Trim(), entry.From, entry.Date); if (Config.BodyTemplate.Trim().Length > 0) { var data = new Dictionary <string, object> { { "MailboxEntry", entry } }; body = NotificationManager.GenerateNotificationContent(Config.BodyTemplate, data); } var projectId = entry.ProjectMailbox.ProjectId; var mailIssue = IssueManager.GetDefaultIssueByProjectId( projectId, entry.Title.Trim(), body.Trim(), entry.ProjectMailbox.AssignToUserName, Config.ReportingUserName); if (!IssueManager.SaveOrUpdate(mailIssue)) { return; } entry.IssueId = mailIssue.Id; entry.WasProcessed = true; var project = ProjectManager.GetById(projectId); var projectFolderPath = Path.Combine(Config.UploadsFolderPath, project.UploadPath); var doc = new HtmlDocument(); doc.LoadHtml(mailIssue.Description); // load the issue body to we can process it for inline images (if exist) //If there is an attached file present then add it to the database //and copy it to the directory specified in the web.config file foreach (MIME_Entity mimeEntity in entry.MailAttachments) { string fileName; var isInline = false; var contentType = mimeEntity.ContentType.Type.ToLower(); var attachment = new IssueAttachment { Id = 0, Description = "File attached by mailbox reader", DateCreated = DateTime.Now, ContentType = mimeEntity.ContentType.TypeWithSubtype, CreatorDisplayName = Config.ReportingUserName, CreatorUserName = Config.ReportingUserName, IssueId = mailIssue.Id, ProjectFolderPath = projectFolderPath }; switch (contentType) { case "application": attachment.Attachment = ((MIME_b_SinglepartBase)mimeEntity.Body).Data; break; case "attachment": case "image": case "video": case "audio": attachment.Attachment = ((MIME_b_SinglepartBase)mimeEntity.Body).Data; break; case "message": // we need to pull the actual email message out of the entity, and strip the "content type" out so that // email programs will read the file properly var messageBody = mimeEntity.ToString().Replace(mimeEntity.Header.ToString(), ""); if (messageBody.StartsWith("\r\n")) { messageBody = messageBody.Substring(2); } attachment.Attachment = Encoding.UTF8.GetBytes(messageBody); break; default: LogWarning(string.Format("MailboxReader: Attachment type could not be processed {0}", mimeEntity.ContentType.Type)); break; } if (contentType.Equals("attachment")) // this is an attached email { fileName = mimeEntity.ContentDisposition.Param_FileName; } else if (contentType.Equals("message")) // message has no filename so we create one { fileName = string.Format("Attached_Message_{0}.eml", entry.AttachmentsSavedCount); } else { isInline = true; fileName = string.IsNullOrWhiteSpace(mimeEntity.ContentType.Param_Name) ? string.Format("untitled.{0}", mimeEntity.ContentType.SubType) : mimeEntity.ContentType.Param_Name; } attachment.FileName = fileName; var saveFile = IsAllowedFileExtension(fileName); var fileSaved = false; // can we save the file? if (saveFile) { fileSaved = IssueAttachmentManager.SaveOrUpdate(attachment); if (fileSaved) { entry.AttachmentsSavedCount++; } else { LogWarning("MailboxReader: Attachment could not be saved, please see previous logs"); } } if (!entry.IsHtml || !isInline) { continue; } if (string.IsNullOrWhiteSpace(mimeEntity.ContentID)) { continue; } var contentId = mimeEntity.ContentID.Replace("<", "").Replace(">", "").Replace("[", "").Replace("]", ""); // this is pretty greedy but since people might be sending screenshots I doubt they will send in dozens of images // embedded in the email. one would hope foreach (var node in doc.DocumentNode.SelectNodes(XpathElementCaseInsensitive("img")).ToList()) { var attr = node.Attributes.FirstOrDefault(p => p.Name.ToLowerInvariant() == "src");// get the src attribute if (attr == null) { continue; // image has no src attribute } if (!attr.Value.Contains(contentId)) { continue; // is the attribute value the content id? } // swap out the content of the parent node html will our link to the image var anchor = string.Format("<span class='inline-mail-attachment'>Inline Attachment: <a href='DownloadAttachment.axd?id={0}' target='_blank'>{1}</a></span>", attachment.Id, fileName); // for each image in the body if the file was saved swap out the inline link for a link to the saved attachment // otherwise blank out the content link so we don't get a missing image link node.ParentNode.InnerHtml = fileSaved ? anchor : ""; } mailIssue.Description = doc.DocumentNode.InnerHtml; mailIssue.LastUpdateUserName = mailIssue.OwnerUserName; mailIssue.LastUpdate = DateTime.Now; IssueManager.SaveOrUpdate(mailIssue); } } catch (Exception ex) { LogException(ex); throw; } }