static void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var filter = new BestEncodingFilter(); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) { break; } switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: if (attachment != null) { builder.Attachments.Add(attachment); } attachment = new MimePart(); break; case TnefAttributeTag.Attachment: if (attachment == null) { break; } while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString(); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString(); if (Uri.IsWellFormedUriString(text, UriKind.Absolute)) { attachment.ContentLocation = new Uri(text, UriKind.Absolute); } else if (Uri.IsWellFormedUriString(text, UriKind.Relative)) { attachment.ContentLocation = new Uri(text, UriKind.Relative); } break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString(); attachment.ContentBase = new Uri(text, UriKind.Absolute); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString(); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString(); if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(text); } else { attachment.ContentDisposition.Disposition = text; } break; case TnefPropertyId.AttachData: // TODO: implement this... break; } } break; case TnefAttributeTag.AttachData: if (attachment == null) { break; } attachData = prop.ReadValueAsBytes(); filter.Flush(attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.EightBit); attachment.ContentObject = new ContentObject(new MemoryStream(attachData, false), ContentEncoding.Default); filter.Reset(); break; } if (attachment != null) { builder.Attachments.Add(attachment); } } while (reader.ReadNextAttribute()); }
static void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var attachMethod = TnefAttachMethod.ByValue; var filter = new BestEncodingFilter(); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; TnefAttachFlags flags; string[] mimeType; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) { break; } switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachMethod = TnefAttachMethod.ByValue; attachment = new MimePart(); break; case TnefAttributeTag.Attachment: if (attachment == null) { break; } attachData = null; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString(); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefPropertyId.AttachContentLocation: attachment.ContentLocation = prop.ReadValueAsUri(); break; case TnefPropertyId.AttachContentBase: attachment.ContentBase = prop.ReadValueAsUri(); break; case TnefPropertyId.AttachContentId: text = prop.ReadValueAsString(); var buffer = CharsetUtils.UTF8.GetBytes(text); int index = 0; if (ParseUtils.TryParseMsgId(buffer, ref index, buffer.Length, false, false, out string msgid)) { attachment.ContentId = msgid; } break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString(); if (ContentDisposition.TryParse(text, out ContentDisposition disposition)) { attachment.ContentDisposition = disposition; } break; case TnefPropertyId.AttachData: attachData = prop.ReadValueAsBytes(); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod)prop.ReadValueAsInt32(); break; case TnefPropertyId.AttachMimeTag: mimeType = prop.ReadValueAsString().Split('/'); if (mimeType.Length == 2) { attachment.ContentType.MediaType = mimeType[0].Trim(); attachment.ContentType.MediaSubtype = mimeType[1].Trim(); } break; case TnefPropertyId.AttachFlags: flags = (TnefAttachFlags)prop.ReadValueAsInt32(); if ((flags & TnefAttachFlags.RenderedInBody) != 0) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(ContentDisposition.Inline); } else { attachment.ContentDisposition.Disposition = ContentDisposition.Inline; } } break; case TnefPropertyId.AttachSize: if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.Size = prop.ReadValueAsInt64(); break; case TnefPropertyId.DisplayName: attachment.ContentType.Name = prop.ReadValueAsString(); break; } } if (attachData != null) { int count = attachData.Length; int index = 0; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { attachment.ContentTransferEncoding = ContentEncoding.Base64; attachment = PromoteToTnefPart(attachment); count -= 16; index = 16; } else { filter.Flush(attachData, index, count, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.SevenBit); filter.Reset(); } attachment.Content = new MimeContent(new MemoryStream(attachData, index, count, false)); builder.Attachments.Add(attachment); } break; case TnefAttributeTag.AttachCreateDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachModifyDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachTitle: if (attachment != null && string.IsNullOrEmpty(attachment.FileName)) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefAttributeTag.AttachMetaFile: if (attachment == null) { break; } // TODO: what to do with the meta data? break; case TnefAttributeTag.AttachData: if (attachment == null || attachMethod != TnefAttachMethod.ByValue) { break; } attachData = prop.ReadValueAsBytes(); filter.Flush(attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.SevenBit); attachment.Content = new MimeContent(new MemoryStream(attachData, false)); filter.Reset(); builder.Attachments.Add(attachment); break; } } while (reader.ReadNextAttribute()); }
public async Task<Message> OpenTnef(StorageFile datFile) { var message = new MimeMessage(); var bodyFile = default(StorageFile); var targetFilesCollection = new List<FileInfo>(); using (var stream = await datFile.OpenStreamForReadAsync()) { using (var tnefReader = new TnefReader(stream)) { message = ExtractTnefMessage(tnefReader); if (message.Sender == null) { message.Sender = new MailboxAddress(string.Empty, "Sender unknown"); } foreach (MimePart mimePart in message.Attachments) { var isoFile = await LastExtractedFilesProvider.WriteFileToIsoStorage(mimePart.FileName, mimePart.ContentObject.Open()); var basicProperties = await isoFile.GetBasicPropertiesAsync(); var thumb = this.GetVectorThumbnailByType(isoFile.FileType); var size = FileSizeString((double)basicProperties.Size); targetFilesCollection.Add(new FileInfo(isoFile, thumb, size, datFile.DisplayName)); } var body = Enumerable.FirstOrDefault<TextPart>(Enumerable.OfType<TextPart>(message.BodyParts)); if (body != null && !String.IsNullOrEmpty(body.Text)) { string bodyFileName = "Message_Body."; if (body.IsHtml) { bodyFileName += "html"; } else if (body.IsPlain) { bodyFileName += "txt"; } else if (body.IsRichText) { bodyFileName += "rtf"; } bodyFile = await LastExtractedFilesProvider.WriteFileToIsoStorage(bodyFileName, body.Text); } } } var targetMessage = new Message(message.Subject, message.Sender.ToString(), string.Empty, message.Date.ToString(), bodyFile, targetFilesCollection); return targetMessage; }
internal TnefPropertyReader(TnefReader tnef) { propertyTag = TnefPropertyTag.Null; propertyName = new TnefNameId (); rawValueOffset = 0; rawValueLength = 0; propertyIndex = 0; propertyCount = 0; valueIndex = 0; valueCount = 0; rowIndex = 0; rowCount = 0; reader = tnef; }
static MimeMessage ExtractTnefMessage(TnefReader reader) { var builder = new BodyBuilder(); var message = new MimeMessage(); while (reader.ReadNextAttribute()) { if (reader.AttributeLevel == TnefAttributeLevel.Attachment) { break; } var prop = reader.TnefPropertyReader; switch (reader.AttributeTag) { case TnefAttributeTag.RecipientTable: ExtractRecipientTable(reader, message); break; case TnefAttributeTag.MapiProperties: ExtractMapiProperties(reader, message, builder); break; case TnefAttributeTag.DateSent: message.Date = prop.ReadValueAsDateTime(); break; case TnefAttributeTag.Body: builder.TextBody = prop.ReadValueAsString(); break; } } if (reader.AttributeLevel == TnefAttributeLevel.Attachment) { ExtractAttachments(reader, builder); } message.Body = builder.ToMessageBody(); return(message); }
static void ExtractRecipientTable (TnefReader reader, MimeMessage message) { var prop = reader.TnefPropertyReader; // Note: The RecipientTable uses rows of properties... while (prop.ReadNextRow ()) { InternetAddressList list = null; string name = null, addr = null; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.RecipientType: int recipientType = prop.ReadValueAsInt32 (); switch (recipientType) { case 1: list = message.To; break; case 2: list = message.Cc; break; case 3: list = message.Bcc; break; } break; case TnefPropertyId.TransmitableDisplayName: if (string.IsNullOrEmpty (name)) name = prop.ReadValueAsString (); break; case TnefPropertyId.DisplayName: name = prop.ReadValueAsString (); break; case TnefPropertyId.EmailAddress: if (string.IsNullOrEmpty (addr)) addr = prop.ReadValueAsString (); break; case TnefPropertyId.SmtpAddress: // The SmtpAddress, if it exists, should take precedence over the EmailAddress // (since the SmtpAddress is meant to be used in the RCPT TO command). addr = prop.ReadValueAsString (); break; } } if (list != null && !string.IsNullOrEmpty (addr)) list.Add (new MailboxAddress (name, addr)); } }
/// <summary> /// Converts the TNEF content into a <see cref="MimeKit.MimeMessage"/>. /// </summary> /// <remarks> /// TNEF data often contains properties that map to <see cref="MimeKit.MimeMessage"/> /// headers. TNEF data also often contains file attachments which will be /// mapped to MIME parts. /// </remarks> /// <returns>A message representing the TNEF data in MIME format.</returns> /// <exception cref="System.InvalidOperationException"> /// The <see cref="MimeKit.MimePart.Content"/> property is <c>null</c>. /// </exception> public MimeMessage ConvertToMessage() { if (Content == null) { throw new InvalidOperationException("Cannot parse null TNEF data."); } int codepage = 0; if (!string.IsNullOrEmpty(ContentType.Charset)) { if ((codepage = CharsetUtils.GetCodePage(ContentType.Charset)) == -1) { codepage = 0; } } using (var reader = new TnefReader(Content.Open(), codepage, TnefComplianceMode.Loose)) { return(ExtractTnefMessage(reader)); } }
/// <summary> /// Initializes a new instance of the <see cref="MimeKit.Tnef.TnefReaderStream"/> class. /// </summary> /// <remarks> /// Creates a stream for reading a raw value from the <see cref="TnefReader"/>. /// </remarks> /// <param name="tnefReader">The <see cref="TnefReader"/>.</param> /// <param name="endOffset">The end offset.</param> public TnefReaderStream(TnefReader tnefReader, int endOffset) { valueEndOffset = endOffset; reader = tnefReader; }
static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString(); } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString(); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart("rtf"); rtf.ContentType.Name = "body.rtf"; rtf.Text = prop.ReadValueAsString(); builder.Attachments.Add(rtf); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart("html"); html.ContentType.Name = "body.html"; html.Text = prop.ReadValueAsString(); builder.Attachments.Add(html); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart("plain"); plain.ContentType.Name = "body.txt"; plain.Text = prop.ReadValueAsString(); builder.Attachments.Add(plain); } break; } } }
private void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var tnefAttachMethod = TnefAttachMethod.ByValue; var bestEncodingFilter = new BestEncodingFilter(); var tnefPropertyReader = reader.TnefPropertyReader; MimePart mimePart = null; do { int outputIndex; int outputLength; switch (reader.AttributeTag) { case TnefAttributeTag.AttachData: if (mimePart != null && tnefAttachMethod == TnefAttachMethod.ByValue) { byte[] numArray = tnefPropertyReader.ReadValueAsBytes(); bestEncodingFilter.Flush(numArray, 0, numArray.Length, out outputIndex, out outputLength); mimePart.ContentTransferEncoding = bestEncodingFilter.GetBestEncoding(EncodingConstraint.SevenBit, 78); mimePart.ContentObject = new ContentObject(new MemoryStream(numArray, false), ContentEncoding.Default); bestEncodingFilter.Reset(); builder.Attachments.Add(mimePart); break; } break; case TnefAttributeTag.AttachRenderData: tnefAttachMethod = TnefAttachMethod.ByValue; mimePart = new MimePart(); break; case TnefAttributeTag.Attachment: if (mimePart != null) { while (tnefPropertyReader.ReadNextProperty()) { switch (tnefPropertyReader.PropertyTag.Id) { case TnefPropertyId.AttachData: using (var rawValueReadStream = tnefPropertyReader.GetRawValueReadStream()) { using (var memoryStream = new MemoryStream()) { byte[] buffer = new byte[16]; if (tnefAttachMethod == TnefAttachMethod.EmbeddedMessage) { TnefPart tnefPart = new TnefPart(); foreach (Parameter parameter in mimePart.ContentType.Parameters) { tnefPart.ContentType.Parameters[parameter.Name] = parameter.Value; } if (mimePart.ContentDisposition != null) { tnefPart.ContentDisposition = mimePart.ContentDisposition; } mimePart = tnefPart; } rawValueReadStream.Read(buffer, 0, 16); rawValueReadStream.CopyTo(memoryStream, 4096); byte[] input = memoryStream.ToArray(); bestEncodingFilter.Flush(input, 0, (int)memoryStream.Length, out outputIndex, out outputLength); mimePart.ContentTransferEncoding = bestEncodingFilter.GetBestEncoding(EncodingConstraint.SevenBit, 78); mimePart.ContentObject = new ContentObject(memoryStream, ContentEncoding.Default); bestEncodingFilter.Reset(); builder.Attachments.Add(mimePart); } } continue; case TnefPropertyId.AttachFilename: if (String.IsNullOrEmpty(mimePart.FileName)) { mimePart.FileName = tnefPropertyReader.ReadValueAsString(); continue; } continue; case TnefPropertyId.AttachMethod: tnefAttachMethod = (TnefAttachMethod)tnefPropertyReader.ReadValueAsInt32(); continue; case TnefPropertyId.AttachLongFilename: mimePart.FileName = tnefPropertyReader.ReadValueAsString(); continue; case TnefPropertyId.AttachMimeTag: string[] strArray = tnefPropertyReader.ReadValueAsString().Split('/'); if (strArray.Length == 2) { mimePart.ContentType.MediaType = strArray[0].Trim(); mimePart.ContentType.MediaSubtype = strArray[1].Trim(); continue; } continue; case TnefPropertyId.AttachContentBase: var uriString = tnefPropertyReader.ReadValueAsString(); mimePart.ContentBase = new Uri(uriString, UriKind.Absolute); continue; case TnefPropertyId.AttachContentId: mimePart.ContentId = tnefPropertyReader.ReadValueAsString(); continue; case TnefPropertyId.AttachContentLocation: var uriString2 = tnefPropertyReader.ReadValueAsString(); if (Uri.IsWellFormedUriString(uriString2, UriKind.Absolute)) { mimePart.ContentLocation = new Uri(uriString2, UriKind.Absolute); continue; } if (Uri.IsWellFormedUriString(uriString2, UriKind.Relative)) { mimePart.ContentLocation = new Uri(uriString2, UriKind.Relative); continue; } continue; case TnefPropertyId.AttachFlags: if ((tnefPropertyReader.ReadValueAsInt32() & 4) != 0) { if (mimePart.ContentDisposition == null) { mimePart.ContentDisposition = new ContentDisposition("inline"); continue; } mimePart.ContentDisposition.Disposition = "inline"; continue; } continue; case TnefPropertyId.AttachDisposition: var disposition = tnefPropertyReader.ReadValueAsString(); if (mimePart.ContentDisposition == null) { mimePart.ContentDisposition = new ContentDisposition(disposition); continue; } mimePart.ContentDisposition.Disposition = disposition; continue; case TnefPropertyId.AttachSize: if (mimePart.ContentDisposition == null) { mimePart.ContentDisposition = new ContentDisposition(); } mimePart.ContentDisposition.Size = new long?(tnefPropertyReader.ReadValueAsInt64()); continue; case TnefPropertyId.DisplayName: mimePart.ContentType.Name = tnefPropertyReader.ReadValueAsString(); continue; default: continue; } } break; } break; case TnefAttributeTag.AttachTitle: var name = tnefPropertyReader.ReadValueAsString(); if (mimePart != null && String.IsNullOrEmpty(mimePart.FileName)) { mimePart.FileName = name; break; } break; case TnefAttributeTag.AttachCreateDate: var creationDateTime = tnefPropertyReader.ReadValueAsDateTime(); if (mimePart != null) { if (mimePart.ContentDisposition == null) { mimePart.ContentDisposition = new ContentDisposition(); } mimePart.ContentDisposition.CreationDate = new DateTimeOffset(creationDateTime); break; } break; case TnefAttributeTag.AttachModifyDate: var modifyDateTime = tnefPropertyReader.ReadValueAsDateTime(); if (mimePart != null) { if (mimePart.ContentDisposition == null) { mimePart.ContentDisposition = new ContentDisposition(); } mimePart.ContentDisposition.ModificationDate = new DateTimeOffset(modifyDateTime); break; } break; } } while (reader.ReadNextAttribute()); }
static void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var filter = new BestEncodingFilter (); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; byte[] attachData; string text; Console.WriteLine ("Extracting attachments..."); do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) Assert.Fail ("Expected attachment attribute level: {0}", reader.AttributeLevel); switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachment = new MimePart (); builder.Attachments.Add (attachment); break; case TnefAttributeTag.Attachment: if (attachment == null) break; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.FileName); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.FileName); } else { Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, prop.ReadValueAsString ()); } break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) attachment.ContentLocation = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) attachment.ContentLocation = new Uri (text, UriKind.Relative); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString (); attachment.ContentBase = new Uri (text, UriKind.Absolute); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.ContentId); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (text); else attachment.ContentDisposition.Disposition = text; Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachData: if (prop.IsEmbeddedMessage) { Console.WriteLine ("Attachment Property: {0} is an EmbeddedMessage", prop.PropertyTag.Id); var stream = prop.GetRawValueReadStream (); using (var tnef = new TnefReader (stream, reader.MessageCodepage, reader.ComplianceMode)) { var embedded = ExtractTnefMessage (tnef); Console.WriteLine ("embedded attachments = {0}", embedded.BodyParts.Count ()); foreach (var part in embedded.BodyParts) builder.Attachments.Add (part); } } else { Console.WriteLine ("Attachment Property: {0} is not an EmbeddedMessage", prop.PropertyTag.Id); } break; default: Console.WriteLine ("Attachment Property (unhandled): {0} = {1}", prop.PropertyTag.Id, prop.ReadValue ()); break; } } break; case TnefAttributeTag.AttachData: if (attachment == null) break; attachData = prop.ReadValueAsBytes (); filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.ContentObject = new ContentObject (new MemoryStream (attachData, false)); filter.Reset (); break; default: Console.WriteLine ("Attachment Attribute (unhandled): {0} = {1}", reader.AttributeTag, prop.ReadValue ()); break; } } while (reader.ReadNextAttribute ()); }
private void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var tnefPropertyReader = reader.TnefPropertyReader; while (tnefPropertyReader.ReadNextProperty()) { switch (tnefPropertyReader.PropertyTag.Id) { case TnefPropertyId.RtfCompressed: var memoryStream = new MemoryStream(); if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var textPart = new TextPart("rtf"); textPart.ContentType.Name = "body.rtf"; RtfCompressedToRtf rtfCompressedToRtf = new RtfCompressedToRtf(); //var memoryStream = new MemoryStream(); using (var filteredStream = new FilteredStream(memoryStream)) { filteredStream.Add(rtfCompressedToRtf); using (Stream rawValueReadStream = tnefPropertyReader.GetRawValueReadStream()) { rawValueReadStream.CopyTo(filteredStream, 4096); filteredStream.Flush(); } } textPart.ContentObject = new ContentObject(memoryStream, ContentEncoding.Default); memoryStream.Position = 0L; builder.Attachments.Add(textPart); continue; } memoryStream.Dispose(); continue; case TnefPropertyId.BodyHtml: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var textPart = new TextPart("html"); textPart.ContentType.Name = "body.html"; textPart.Text = tnefPropertyReader.ReadValueAsString(); builder.Attachments.Add(textPart); continue; } continue; case TnefPropertyId.InternetMessageId: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = tnefPropertyReader.ReadValueAsString(); continue; } continue; case TnefPropertyId.Subject: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = tnefPropertyReader.ReadValueAsString(); continue; } continue; case TnefPropertyId.Body: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var textPart = new TextPart("plain"); textPart.ContentType.Name = "body.txt"; textPart.Text = tnefPropertyReader.ReadValueAsString(); builder.Attachments.Add(textPart); continue; } continue; case TnefPropertyId.ConversationTopic: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = tnefPropertyReader.ReadValueAsString(); continue; } continue; case TnefPropertyId.SenderName: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { var sender = new MailboxAddress(string.Empty, tnefPropertyReader.ReadValueAsString()); message.Sender = sender; } continue; case (TnefPropertyId)Mapi.ID.PR_PRIMARY_SEND_ACCOUNT: if (tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.String8 || tnefPropertyReader.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { var senderEmail = new MailboxAddress(string.Empty, tnefPropertyReader.ReadValueAsString()); message.Sender = senderEmail; } continue; default: try { tnefPropertyReader.ReadValue(); continue; } catch { continue; } } } }
/// <summary> /// Initializes a new instance of the <see cref="MimeKit.Tnef.TnefReaderStream"/> class. /// </summary> /// <remarks> /// Creates a stream for reading a raw value from the <see cref="TnefReader"/>. /// </remarks> /// <param name="tnefReader">The <see cref="TnefReader"/>.</param> /// <param name="endOffset">The end offset.</param> public TnefReaderStream (TnefReader tnefReader, int endOffset) { valueEndOffset = endOffset; reader = tnefReader; }
static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; var recipient = new EmailAddress(); var sender = new EmailAddress(); string normalizedSubject = null; string subjectPrefix = null; MailboxAddress mailbox; var msgid = false; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString(); msgid = true; } break; case TnefPropertyId.TnefCorrelationKey: // According to MSDN, PidTagTnefCorrelationKey is a unique key that is // meant to be used to tie the TNEF attachment to the encapsulating // message. It can be a string or a binary blob. It seems that most // implementations use the Message-Id string, so if this property // value looks like a Message-Id, then us it as one (unless we get a // InternetMessageId property, in which case we use that instead. if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { if (!msgid) { var value = prop.ReadValueAsString(); if (value.Length > 5 && value[0] == '<' && value[value.Length - 1] == '>' && value.IndexOf('@') != -1) { message.MessageId = value; } } } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString(); } break; case TnefPropertyId.SubjectPrefix: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { subjectPrefix = prop.ReadValueAsString(); } break; case TnefPropertyId.NormalizedSubject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { normalizedSubject = prop.ReadValueAsString(); } break; case TnefPropertyId.SenderName: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { sender.Name = prop.ReadValueAsString(); } break; case TnefPropertyId.SenderEmailAddress: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { sender.Addr = prop.ReadValueAsString(); } break; case TnefPropertyId.SenderSearchKey: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { sender.SearchKey = prop.ReadValueAsString(); } break; case TnefPropertyId.SenderAddrtype: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { sender.AddrType = prop.ReadValueAsString(); } break; case TnefPropertyId.ReceivedByName: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { recipient.Name = prop.ReadValueAsString(); } break; case TnefPropertyId.ReceivedByEmailAddress: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { recipient.Addr = prop.ReadValueAsString(); } break; case TnefPropertyId.ReceivedBySearchKey: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { recipient.SearchKey = prop.ReadValueAsString(); } break; case TnefPropertyId.ReceivedByAddrtype: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { recipient.AddrType = prop.ReadValueAsString(); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart("rtf"); var converter = new RtfCompressedToRtf(); var content = new MemoryBlockStream(); using (var filtered = new FilteredStream(content)) { filtered.Add(converter); using (var compressed = prop.GetRawValueReadStream()) { compressed.CopyTo(filtered, 4096); filtered.Flush(); } } rtf.Content = new MimeContent(content); content.Position = 0; builder.Attachments.Add(rtf); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart("html"); Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) { encoding = Encoding.GetEncoding(reader.MessageCodepage); } else { encoding = CharsetUtils.UTF8; } html.SetText(encoding, prop.ReadValueAsString()); builder.Attachments.Add(html); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart("plain"); Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) { encoding = Encoding.GetEncoding(reader.MessageCodepage); } else { encoding = CharsetUtils.UTF8; } plain.SetText(encoding, prop.ReadValueAsString()); builder.Attachments.Add(plain); } break; case TnefPropertyId.Importance: // https://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx switch (prop.ReadValueAsInt32()) { case 2: message.Importance = MessageImportance.High; break; case 1: message.Importance = MessageImportance.Normal; break; case 0: message.Importance = MessageImportance.Low; break; } break; case TnefPropertyId.Priority: // https://msdn.microsoft.com/en-us/library/ee159473(v=exchg.80).aspx switch (prop.ReadValueAsInt32()) { case 1: message.Priority = MessagePriority.Urgent; break; case 0: message.Priority = MessagePriority.Normal; break; case -1: message.Priority = MessagePriority.NonUrgent; break; } break; case TnefPropertyId.Sensitivity: // https://msdn.microsoft.com/en-us/library/ee217353(v=exchg.80).aspx // https://tools.ietf.org/html/rfc2156#section-5.3.4 switch (prop.ReadValueAsInt32()) { case 1: message.Headers[HeaderId.Sensitivity] = "Personal"; break; case 2: message.Headers[HeaderId.Sensitivity] = "Private"; break; case 3: message.Headers[HeaderId.Sensitivity] = "Company-Confidential"; break; case 0: message.Headers.Remove(HeaderId.Sensitivity); break; } break; } } if (string.IsNullOrEmpty(message.Subject) && !string.IsNullOrEmpty(normalizedSubject)) { if (!string.IsNullOrEmpty(subjectPrefix)) { message.Subject = subjectPrefix + normalizedSubject; } else { message.Subject = normalizedSubject; } } if (sender.TryGetMailboxAddress(out mailbox)) { message.From.Add(mailbox); } if (recipient.TryGetMailboxAddress(out mailbox)) { message.To.Add(mailbox); } }
static void ExtractRecipientTable(TnefReader reader, MimeMessage message) { var prop = reader.TnefPropertyReader; // Note: The RecipientTable uses rows of properties... while (prop.ReadNextRow()) { string transmitableDisplayName = null; string recipientDisplayName = null; string displayName = string.Empty; InternetAddressList list = null; string addr = null; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.RecipientType: int recipientType = prop.ReadValueAsInt32(); switch (recipientType) { case 1: list = message.To; break; case 2: list = message.Cc; break; case 3: list = message.Bcc; break; } break; case TnefPropertyId.TransmitableDisplayName: transmitableDisplayName = prop.ReadValueAsString(); break; case TnefPropertyId.RecipientDisplayName: recipientDisplayName = prop.ReadValueAsString(); break; case TnefPropertyId.DisplayName: displayName = prop.ReadValueAsString(); break; case TnefPropertyId.EmailAddress: if (string.IsNullOrEmpty(addr)) { addr = prop.ReadValueAsString(); } break; case TnefPropertyId.SmtpAddress: // The SmtpAddress, if it exists, should take precedence over the EmailAddress // (since the SmtpAddress is meant to be used in the RCPT TO command). addr = prop.ReadValueAsString(); break; } } if (list != null && !string.IsNullOrEmpty(addr)) { var name = recipientDisplayName ?? transmitableDisplayName ?? displayName; list.Add(new MailboxAddress(name, addr)); } } }
private MimeMessage ExtractTnefMessage(TnefReader reader) { var tnefReader = reader.TnefPropertyReader; var builder = new BodyBuilder(); var message = new MimeMessage(); while (reader.ReadNextAttribute() && reader.AttributeLevel == TnefAttributeLevel.Message) { switch (reader.AttributeTag) { case TnefAttributeTag.MapiProperties: this.ExtractMapiProperties(reader, message, builder); continue; case TnefAttributeTag.DateReceived: message.Date = tnefReader.ReadValueAsDateTime(); continue; default: continue; } } if (reader.AttributeLevel == TnefAttributeLevel.Attachment) { ExtractAttachments(reader, builder); } message.Body = builder.ToMessageBody(); return message; }
static MimeMessage ParseTnefMessage(string path, TnefComplianceStatus expected) { using (var reader = new TnefReader (File.OpenRead (path), 0, TnefComplianceMode.Loose)) { var message = ExtractTnefMessage (reader); Assert.AreEqual (expected, reader.ComplianceStatus, "Unexpected compliance status."); return message; } }
static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString (); } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString (); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart ("rtf"); rtf.ContentType.Name = "body.rtf"; var converter = new RtfCompressedToRtf (); var content = new MemoryStream (); using (var filtered = new FilteredStream (content)) { filtered.Add (converter); using (var compressed = prop.GetRawValueReadStream ()) { compressed.CopyTo (filtered, 4096); filtered.Flush (); } } rtf.ContentObject = new ContentObject (content); content.Position = 0; builder.Attachments.Add (rtf); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart ("html"); html.ContentType.Name = "body.html"; html.Text = prop.ReadValueAsString (); builder.Attachments.Add (html); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart ("plain"); plain.ContentType.Name = "body.txt"; plain.Text = prop.ReadValueAsString (); builder.Attachments.Add (plain); } break; } } }
static MimeMessage ExtractTnefMessage(TnefReader reader) { var builder = new BodyBuilder (); var message = new MimeMessage (); while (reader.ReadNextAttribute ()) { if (reader.AttributeLevel == TnefAttributeLevel.Attachment) break; if (reader.AttributeLevel != TnefAttributeLevel.Message) Assert.Fail ("Unknown attribute level."); var prop = reader.TnefPropertyReader; switch (reader.AttributeTag) { case TnefAttributeTag.RecipientTable: ExtractRecipientTable (reader, message); break; case TnefAttributeTag.MapiProperties: ExtractMapiProperties (reader, message, builder); break; case TnefAttributeTag.DateSent: message.Date = prop.ReadValueAsDateTime (); Console.WriteLine ("Message Attribute: {0} = {1}", reader.AttributeTag, message.Date); break; case TnefAttributeTag.Body: builder.TextBody = prop.ReadValueAsString (); Console.WriteLine ("Message Attribute: {0} = {1}", reader.AttributeTag, builder.TextBody); break; case TnefAttributeTag.TnefVersion: Console.WriteLine ("Message Attribute: {0} = {1}", reader.AttributeTag, prop.ReadValueAsInt32 ()); break; case TnefAttributeTag.OemCodepage: int codepage = prop.ReadValueAsInt32 (); try { var encoding = Encoding.GetEncoding (codepage); Console.WriteLine ("Message Attribute: OemCodepage = {0}", encoding.HeaderName); } catch { Console.WriteLine ("Message Attribute: OemCodepage = {0}", codepage); } break; default: Console.WriteLine ("Message Attribute (unhandled): {0} = {1}", reader.AttributeTag, prop.ReadValue ()); break; } } if (reader.AttributeLevel == TnefAttributeLevel.Attachment) { ExtractAttachments (reader, builder); } else { Console.WriteLine ("no attachments"); } message.Body = builder.ToMessageBody (); return message; }
static void ExtractRecipientTable(TnefReader reader, MimeMessage message) { var prop = reader.TnefPropertyReader; // Note: The RecipientTable uses rows of properties... while (prop.ReadNextRow ()) { InternetAddressList list = null; string name = null, addr = null; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.RecipientType: int recipientType = prop.ReadValueAsInt32 (); switch (recipientType) { case 1: list = message.To; break; case 2: list = message.Cc; break; case 3: list = message.Bcc; break; default: Assert.Fail ("Invalid recipient type."); break; } Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, recipientType); break; case TnefPropertyId.TransmitableDisplayName: if (string.IsNullOrEmpty (name)) { name = prop.ReadValueAsString (); Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, name); } else { Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, prop.ReadValueAsString ()); } break; case TnefPropertyId.DisplayName: name = prop.ReadValueAsString (); Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, name); break; case TnefPropertyId.EmailAddress: if (string.IsNullOrEmpty (addr)) { addr = prop.ReadValueAsString (); Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, addr); } else { Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, prop.ReadValueAsString ()); } break; case TnefPropertyId.SmtpAddress: // The SmtpAddress, if it exists, should take precedence over the EmailAddress // (since the SmtpAddress is meant to be used in the RCPT TO command). addr = prop.ReadValueAsString (); Console.WriteLine ("RecipientTable Property: {0} = {1}", prop.PropertyTag.Id, addr); break; default: Console.WriteLine ("RecipientTable Property (unhandled): {0} = {1}", prop.PropertyTag.Id, prop.ReadValue ()); break; } } Assert.IsNotNull (list, "The recipient type was never specified."); Assert.IsNotNull (addr, "The address was never specified."); if (list != null) list.Add (new MailboxAddress (name, addr)); } }
static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString (); Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, message.MessageId); } else { Assert.Fail ("Unknown property type for Message-Id: {0}", prop.PropertyTag.ValueTnefType); } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString (); Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, message.Subject); } else { Assert.Fail ("Unknown property type for Subject: {0}", prop.PropertyTag.ValueTnefType); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart ("rtf"); rtf.ContentType.Name = "body.rtf"; var converter = new RtfCompressedToRtf (); var content = new MemoryStream (); using (var filtered = new FilteredStream (content)) { filtered.Add (converter); using (var compressed = prop.GetRawValueReadStream ()) { compressed.CopyTo (filtered, 4096); filtered.Flush (); } } rtf.ContentObject = new ContentObject (content); content.Position = 0; builder.Attachments.Add (rtf); Console.WriteLine ("Message Property: {0} = <compressed rtf data>", prop.PropertyTag.Id); } else { Assert.Fail ("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart ("html"); html.ContentType.Name = "body.html"; html.Text = prop.ReadValueAsString (); builder.Attachments.Add (html); Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, html.Text); } else { Assert.Fail ("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart ("plain"); plain.ContentType.Name = "body.txt"; plain.Text = prop.ReadValueAsString (); builder.Attachments.Add (plain); Console.WriteLine ("Message Property: {0} = {1}", prop.PropertyTag.Id, plain.Text); } else { Assert.Fail ("Unknown property type for {0}: {1}", prop.PropertyTag.Id, prop.PropertyTag.ValueTnefType); } break; default: Console.WriteLine ("Message Property (unhandled): {0} = {1}", prop.PropertyTag.Id, prop.ReadValue ()); break; } } }
static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString(); } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString(); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart("rtf"); var converter = new RtfCompressedToRtf(); var content = new MemoryBlockStream(); using (var filtered = new FilteredStream(content)) { filtered.Add(converter); using (var compressed = prop.GetRawValueReadStream()) { compressed.CopyTo(filtered, 4096); filtered.Flush(); } } rtf.Content = new MimeContent(content); content.Position = 0; builder.Attachments.Add(rtf); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart("html"); Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) { encoding = Encoding.GetEncoding(reader.MessageCodepage); } else { encoding = CharsetUtils.UTF8; } html.SetText(encoding, prop.ReadValueAsString()); builder.Attachments.Add(html); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart("plain"); Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) { encoding = Encoding.GetEncoding(reader.MessageCodepage); } else { encoding = CharsetUtils.UTF8; } plain.SetText(encoding, prop.ReadValueAsString()); builder.Attachments.Add(plain); } break; case TnefPropertyId.Importance: switch (prop.ReadValueAsInt32()) { case 2: message.Importance = MessageImportance.High; break; case 0: message.Importance = MessageImportance.Low; break; } break; case TnefPropertyId.Priority: switch (prop.ReadValueAsInt32()) { case 2: message.Priority = MessagePriority.Urgent; break; case 0: message.Priority = MessagePriority.NonUrgent; break; } break; } } }
/// <summary> /// Converts the TNEF content into a <see cref="MimeKit.MimeMessage"/>. /// </summary> /// <remarks> /// TNEF data often contains properties that map to <see cref="MimeKit.MimeMessage"/> /// headers. TNEF data also often contains file attachments which will be /// mapped to MIME parts. /// </remarks> /// <returns>A message representing the TNEF data in MIME format.</returns> /// <exception cref="System.InvalidOperationException"> /// The <see cref="MimeKit.MimePart.ContentObject"/> property is <c>null</c>. /// </exception> public MimeMessage ConvertToMessage () { if (ContentObject == null) throw new InvalidOperationException ("Cannot parse TNEF data without a ContentObject."); int codepage = 0; if (!string.IsNullOrEmpty (ContentType.Charset)) { if ((codepage = CharsetUtils.GetCodePage (ContentType.Charset)) == -1) codepage = 0; } using (var reader = new TnefReader (ContentObject.Open (), codepage, TnefComplianceMode.Loose)) { return ExtractTnefMessage (reader); } }
static void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var attachMethod = TnefAttachMethod.ByValue; var filter = new BestEncodingFilter(); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; TnefAttachFlags flags; string[] mimeType; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) { break; } switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachMethod = TnefAttachMethod.ByValue; attachment = new MimePart(); break; case TnefAttributeTag.Attachment: if (attachment == null) { break; } while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString(); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString(); if (Uri.IsWellFormedUriString(text, UriKind.Absolute)) { attachment.ContentLocation = new Uri(text, UriKind.Absolute); } else if (Uri.IsWellFormedUriString(text, UriKind.Relative)) { attachment.ContentLocation = new Uri(text, UriKind.Relative); } break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString(); attachment.ContentBase = new Uri(text, UriKind.Absolute); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString(); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString(); if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(text); } else { attachment.ContentDisposition.Disposition = text; } break; case TnefPropertyId.AttachData: var stream = prop.GetRawValueReadStream(); var content = new MemoryStream(); var guid = new byte[16]; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { var tnef = new TnefPart(); foreach (var param in attachment.ContentType.Parameters) { tnef.ContentType.Parameters[param.Name] = param.Value; } if (attachment.ContentDisposition != null) { tnef.ContentDisposition = attachment.ContentDisposition; } attachment = tnef; } // read the GUID stream.Read(guid, 0, 16); // the rest is content using (var filtered = new FilteredStream(content)) { filtered.Add(filter); stream.CopyTo(filtered, 4096); filtered.Flush(); } content.Position = 0; attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.SevenBit); attachment.Content = new MimeContent(content); filter.Reset(); builder.Attachments.Add(attachment); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod)prop.ReadValueAsInt32(); break; case TnefPropertyId.AttachMimeTag: mimeType = prop.ReadValueAsString().Split('/'); if (mimeType.Length == 2) { attachment.ContentType.MediaType = mimeType[0].Trim(); attachment.ContentType.MediaSubtype = mimeType[1].Trim(); } break; case TnefPropertyId.AttachFlags: flags = (TnefAttachFlags)prop.ReadValueAsInt32(); if ((flags & TnefAttachFlags.RenderedInBody) != 0) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(ContentDisposition.Inline); } else { attachment.ContentDisposition.Disposition = ContentDisposition.Inline; } } break; case TnefPropertyId.AttachSize: if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.Size = prop.ReadValueAsInt64(); break; case TnefPropertyId.DisplayName: attachment.ContentType.Name = prop.ReadValueAsString(); break; } } break; case TnefAttributeTag.AttachCreateDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachModifyDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachTitle: if (attachment != null && string.IsNullOrEmpty(attachment.FileName)) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefAttributeTag.AttachMetaFile: if (attachment == null) { break; } // TODO: what to do with the meta data? break; case TnefAttributeTag.AttachData: if (attachment == null || attachMethod != TnefAttachMethod.ByValue) { break; } attachData = prop.ReadValueAsBytes(); filter.Flush(attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.EightBit); attachment.Content = new MimeContent(new MemoryStream(attachData, false)); filter.Reset(); builder.Attachments.Add(attachment); break; } } while (reader.ReadNextAttribute()); }
static void ExtractAttachments (TnefReader reader, BodyBuilder builder) { var attachMethod = TnefAttachMethod.ByValue; var filter = new BestEncodingFilter (); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; TnefAttachFlags flags; string[] mimeType; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) break; switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachMethod = TnefAttachMethod.ByValue; attachment = new MimePart (); break; case TnefAttributeTag.Attachment: if (attachment == null) break; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString (); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) attachment.FileName = prop.ReadValueAsString (); break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) attachment.ContentLocation = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) attachment.ContentLocation = new Uri (text, UriKind.Relative); break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString (); attachment.ContentBase = new Uri (text, UriKind.Absolute); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString (); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (text); else attachment.ContentDisposition.Disposition = text; break; case TnefPropertyId.AttachData: var stream = prop.GetRawValueReadStream (); var content = new MemoryStream (); var guid = new byte[16]; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { var tnef = new TnefPart (); foreach (var param in attachment.ContentType.Parameters) tnef.ContentType.Parameters[param.Name] = param.Value; if (attachment.ContentDisposition != null) tnef.ContentDisposition = attachment.ContentDisposition; attachment = tnef; } // read the GUID stream.Read (guid, 0, 16); // the rest is content using (var filtered = new FilteredStream (content)) { filtered.Add (filter); stream.CopyTo (filtered, 4096); filtered.Flush (); } content.Position = 0; attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.ContentObject = new ContentObject (content); filter.Reset (); builder.Attachments.Add (attachment); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod) prop.ReadValueAsInt32 (); break; case TnefPropertyId.AttachMimeTag: mimeType = prop.ReadValueAsString ().Split ('/'); if (mimeType.Length == 2) { attachment.ContentType.MediaType = mimeType[0].Trim (); attachment.ContentType.MediaSubtype = mimeType[1].Trim (); } break; case TnefPropertyId.AttachFlags: flags = (TnefAttachFlags) prop.ReadValueAsInt32 (); if ((flags & TnefAttachFlags.RenderedInBody) != 0) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (ContentDisposition.Inline); else attachment.ContentDisposition.Disposition = ContentDisposition.Inline; } break; case TnefPropertyId.AttachSize: if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.Size = prop.ReadValueAsInt64 (); break; case TnefPropertyId.DisplayName: attachment.ContentType.Name = prop.ReadValueAsString (); break; } } break; case TnefAttributeTag.AttachCreateDate: if (attachment != null) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime (); } break; case TnefAttributeTag.AttachModifyDate: if (attachment != null) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime (); } break; case TnefAttributeTag.AttachTitle: if (attachment != null && string.IsNullOrEmpty (attachment.FileName)) attachment.FileName = prop.ReadValueAsString (); break; case TnefAttributeTag.AttachMetaFile: if (attachment == null) break; // TODO: what to do with the meta data? break; case TnefAttributeTag.AttachData: if (attachment == null || attachMethod != TnefAttachMethod.ByValue) break; attachData = prop.ReadValueAsBytes (); filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.EightBit); attachment.ContentObject = new ContentObject (new MemoryStream (attachData, false)); filter.Reset (); builder.Attachments.Add (attachment); break; } } while (reader.ReadNextAttribute ()); }
/// <summary> /// Initialize a new instance of the <see cref="TnefReaderStream"/> class. /// </summary> /// <remarks> /// Creates a stream for reading a raw value from the <see cref="TnefReader"/>. /// </remarks> /// <param name="tnefReader">The <see cref="TnefReader"/>.</param> /// <param name="dataEndOffset">The end offset of the data.</param> /// <param name="valueEndOffset">The end offset of the container value.</param> public TnefReaderStream(TnefReader tnefReader, int dataEndOffset, int valueEndOffset) { this.valueEndOffset = valueEndOffset; this.dataEndOffset = dataEndOffset; reader = tnefReader; }
static void ExtractMapiProperties(TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.InternetMessageId: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString(); } break; case TnefPropertyId.Subject: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.Subject = prop.ReadValueAsString(); } break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart("rtf"); rtf.ContentType.Name = "body.rtf"; var converter = new RtfCompressedToRtf(); var content = new MemoryBlockStream(); using (var filtered = new FilteredStream(content)) { filtered.Add(converter); using (var compressed = prop.GetRawValueReadStream()) { compressed.CopyTo(filtered, 4096); filtered.Flush(); } } rtf.ContentObject = new ContentObject(content); content.Position = 0; builder.Attachments.Add(rtf); } break; case TnefPropertyId.BodyHtml: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart("html"); html.ContentType.Name = "body.html"; html.Text = prop.ReadValueAsString(); builder.Attachments.Add(html); } break; case TnefPropertyId.Body: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart("plain"); plain.ContentType.Name = "body.txt"; plain.Text = prop.ReadValueAsString(); builder.Attachments.Add(plain); } break; } } }
static void ExtractAttachments (TnefReader reader, BodyBuilder builder) { var filter = new BestEncodingFilter (); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) break; switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachment = new MimePart (); builder.Attachments.Add (attachment); break; case TnefAttributeTag.Attachment: if (attachment == null) break; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString (); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) attachment.FileName = prop.ReadValueAsString (); break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) attachment.ContentLocation = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) attachment.ContentLocation = new Uri (text, UriKind.Relative); break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString (); attachment.ContentBase = new Uri (text, UriKind.Absolute); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString (); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (text); else attachment.ContentDisposition.Disposition = text; break; case TnefPropertyId.AttachData: // TODO: implement this... break; } } break; case TnefAttributeTag.AttachData: if (attachment == null) break; attachData = prop.ReadValueAsBytes (); filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.EightBit); attachment.ContentObject = new ContentObject (new MemoryStream (attachData, false)); filter.Reset (); break; } } while (reader.ReadNextAttribute ()); }
static void ExtractAttachments (TnefReader reader, BodyBuilder builder) { var attachMethod = TnefAttachMethod.ByValue; var filter = new BestEncodingFilter (); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; TnefAttachFlags flags; string[] mimeType; byte[] attachData; DateTime time; string text; Console.WriteLine ("Extracting attachments..."); do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) Assert.Fail ("Expected attachment attribute level: {0}", reader.AttributeLevel); switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: Console.WriteLine ("Attachment Attribute: {0}", reader.AttributeTag); attachMethod = TnefAttachMethod.ByValue; attachment = new MimePart (); break; case TnefAttributeTag.Attachment: Console.WriteLine ("Attachment Attribute: {0}", reader.AttributeTag); if (attachment == null) break; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.FileName); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.FileName); } else { Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, prop.ReadValueAsString ()); } break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) attachment.ContentLocation = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) attachment.ContentLocation = new Uri (text, UriKind.Relative); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString (); attachment.ContentBase = new Uri (text, UriKind.Absolute); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.ContentId); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (text); else attachment.ContentDisposition.Disposition = text; Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod) prop.ReadValueAsInt32 (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachMethod); break; case TnefPropertyId.AttachMimeTag: text = prop.ReadValueAsString (); mimeType = text.Split ('/'); if (mimeType.Length == 2) { attachment.ContentType.MediaType = mimeType[0].Trim (); attachment.ContentType.MediaSubtype = mimeType[1].Trim (); } Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachFlags: flags = (TnefAttachFlags) prop.ReadValueAsInt32 (); if ((flags & TnefAttachFlags.RenderedInBody) != 0) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (ContentDisposition.Inline); else attachment.ContentDisposition.Disposition = ContentDisposition.Inline; } Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, flags); break; case TnefPropertyId.AttachData: var stream = prop.GetRawValueReadStream (); var content = new MemoryStream (); var guid = new byte[16]; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { var tnef = new TnefPart (); foreach (var param in attachment.ContentType.Parameters) tnef.ContentType.Parameters[param.Name] = param.Value; if (attachment.ContentDisposition != null) tnef.ContentDisposition = attachment.ContentDisposition; attachment = tnef; } stream.Read (guid, 0, 16); stream.CopyTo (content, 4096); var buffer = content.GetBuffer (); filter.Flush (buffer, 0, (int) content.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.ContentObject = new ContentObject (content); filter.Reset (); Console.WriteLine ("Attachment Property: {0} has GUID {1}", prop.PropertyTag.Id, new Guid (guid)); builder.Attachments.Add (attachment); break; case TnefPropertyId.DisplayName: attachment.ContentType.Name = prop.ReadValueAsString (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.ContentType.Name); break; case TnefPropertyId.AttachSize: if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.Size = prop.ReadValueAsInt64 (); Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.ContentDisposition.Size.Value); break; default: Console.WriteLine ("Attachment Property (unhandled): {0} = {1}", prop.PropertyTag.Id, prop.ReadValue ()); break; } } break; case TnefAttributeTag.AttachData: Console.WriteLine ("Attachment Attribute: {0}", reader.AttributeTag); if (attachment == null || attachMethod != TnefAttachMethod.ByValue) break; attachData = prop.ReadValueAsBytes (); filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.ContentObject = new ContentObject (new MemoryStream (attachData, false)); filter.Reset (); builder.Attachments.Add (attachment); break; case TnefAttributeTag.AttachCreateDate: time = prop.ReadValueAsDateTime (); if (attachment != null) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.CreationDate = time; } Console.WriteLine ("Attachment Attribute: {0} = {1}", reader.AttributeTag, time); break; case TnefAttributeTag.AttachModifyDate: time = prop.ReadValueAsDateTime (); if (attachment != null) { if (attachment.ContentDisposition == null) attachment.ContentDisposition = new ContentDisposition (); attachment.ContentDisposition.ModificationDate = time; } Console.WriteLine ("Attachment Attribute: {0} = {1}", reader.AttributeTag, time); break; case TnefAttributeTag.AttachTitle: text = prop.ReadValueAsString (); if (attachment != null && string.IsNullOrEmpty (attachment.FileName)) attachment.FileName = text; Console.WriteLine ("Attachment Attribute: {0} = {1}", reader.AttributeTag, text); break; default: Console.WriteLine ("Attachment Attribute (unhandled): {0} = {1}", reader.AttributeTag, prop.ReadValue ()); break; } } while (reader.ReadNextAttribute ()); }
static MimeMessage ExtractTnefMessage (TnefReader reader) { var builder = new BodyBuilder (); var message = new MimeMessage (); while (reader.ReadNextAttribute ()) { if (reader.AttributeLevel == TnefAttributeLevel.Attachment) break; var prop = reader.TnefPropertyReader; switch (reader.AttributeTag) { case TnefAttributeTag.RecipientTable: ExtractRecipientTable (reader, message); break; case TnefAttributeTag.MapiProperties: ExtractMapiProperties (reader, message, builder); break; case TnefAttributeTag.DateSent: message.Date = prop.ReadValueAsDateTime (); break; case TnefAttributeTag.Body: builder.TextBody = prop.ReadValueAsString (); break; } } if (reader.AttributeLevel == TnefAttributeLevel.Attachment) ExtractAttachments (reader, builder); message.Body = builder.ToMessageBody (); return message; }
static void ExtractAttachments(TnefReader reader, BodyBuilder builder) { var attachMethod = TnefAttachMethod.ByValue; var filter = new BestEncodingFilter(); var prop = reader.TnefPropertyReader; MimePart attachment = null; int outIndex, outLength; byte[] attachData; string text; do { if (reader.AttributeLevel != TnefAttributeLevel.Attachment) { break; } switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: attachMethod = TnefAttachMethod.ByValue; attachment = new MimePart(); break; case TnefAttributeTag.Attachment: if (attachment == null) { break; } while (prop.ReadNextProperty()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: attachment.FileName = prop.ReadValueAsString(); break; case TnefPropertyId.AttachFilename: if (attachment.FileName == null) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefPropertyId.AttachContentLocation: text = prop.ReadValueAsString(); if (Uri.IsWellFormedUriString(text, UriKind.Absolute)) { attachment.ContentLocation = new Uri(text, UriKind.Absolute); } else if (Uri.IsWellFormedUriString(text, UriKind.Relative)) { attachment.ContentLocation = new Uri(text, UriKind.Relative); } break; case TnefPropertyId.AttachContentBase: text = prop.ReadValueAsString(); attachment.ContentBase = new Uri(text, UriKind.Absolute); break; case TnefPropertyId.AttachContentId: attachment.ContentId = prop.ReadValueAsString(); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString(); if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(text); } else { attachment.ContentDisposition.Disposition = text; } break; case TnefPropertyId.AttachData: var stream = prop.GetRawValueReadStream(); var content = new MemoryStream(); var guid = new byte[16]; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { var tnef = new TnefPart(); foreach (var param in attachment.ContentType.Parameters) { tnef.ContentType.Parameters.Add(param.Name, param.Value); } if (attachment.ContentDisposition != null) { tnef.ContentDisposition = attachment.ContentDisposition; } attachment = tnef; } // read the GUID stream.Read(guid, 0, 16); // the rest is content stream.CopyTo(content, 4096); #if !PORTABLE var buffer = content.GetBuffer(); #else var buffer = content.ToArray(); #endif filter.Flush(buffer, 0, (int)content.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.SevenBit); attachment.ContentObject = new ContentObject(content); filter.Reset(); builder.Attachments.Add(attachment); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod)prop.ReadValueAsInt32(); break; case TnefPropertyId.AttachSize: if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.Size = prop.ReadValueAsInt64(); break; case TnefPropertyId.DisplayName: attachment.ContentType.Name = prop.ReadValueAsString(); break; } } break; case TnefAttributeTag.AttachCreateDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.CreationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachModifyDate: if (attachment != null) { if (attachment.ContentDisposition == null) { attachment.ContentDisposition = new ContentDisposition(); } attachment.ContentDisposition.ModificationDate = prop.ReadValueAsDateTime(); } break; case TnefAttributeTag.AttachTitle: if (attachment != null && string.IsNullOrEmpty(attachment.FileName)) { attachment.FileName = prop.ReadValueAsString(); } break; case TnefAttributeTag.AttachMetaFile: if (attachment == null) { break; } // TODO: what to do with the meta data? break; case TnefAttributeTag.AttachData: if (attachment == null || attachMethod != TnefAttachMethod.ByValue) { break; } attachData = prop.ReadValueAsBytes(); filter.Flush(attachData, 0, attachData.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding(EncodingConstraint.EightBit); attachment.ContentObject = new ContentObject(new MemoryStream(attachData, false)); filter.Reset(); builder.Attachments.Add(attachment); break; } } while (reader.ReadNextAttribute()); }