This class provides the basic functionality for handling attachments
Пример #1
0
        /// <summary>
        /// Parses the ms-tnef stream from the provided <see cref="System.IO.Stream" />.
        /// </summary>
        /// <param name="path">A <see cref="System.String" /> specifying the path on which to save the attachments found. Specify the <b>null</b> reference to save them in memory as  <see cref="System.IO.MemoryStream" /> instances instead.</param>
        /// <returns><b>true</b> if parsing is successful. <b>false</b> otherwise.</returns>
        public bool Parse(String path)
        {
            if (_reader == null || !_reader.BaseStream.CanRead)
                return false;
            int sig = ReadInt();
            if (sig != TnefSignature)
            {
                return false;
            }
            bool error = false;
            Attachments = new List<SharpAttachment>();
            ushort key = ReadUInt16();
            System.Text.Encoding enc = SharpMimeHeader.EncodingDefault;
            SharpAttachment attachment_cur = null;
            for (Byte cur = ReadByte(); cur != Byte.MinValue; cur = ReadByte())
            {
                TnefLvlType lvl = (TnefLvlType)SharpMimeTools.ParseEnum(typeof(TnefLvlType), cur, TnefLvlType.Unknown);
                // Type
                int type = ReadInt();
                // Size
                int size = ReadInt();
                // Attibute name and type
                TnefAttribute att_n = (TnefAttribute)SharpMimeTools.ParseEnum(typeof(TnefAttribute), (ushort)((type << 16) >> 16), TnefAttribute.Unknown);
                TnefDataType att_t = (TnefDataType)SharpMimeTools.ParseEnum(typeof(TnefDataType), (ushort)(type >> 16), TnefDataType.Unknown);
                if (lvl == TnefLvlType.Unknown || att_n == TnefAttribute.Unknown || att_t == TnefDataType.Unknown)
                {
                    error = true;
                    break;
                }
                // Read data
                Byte[] buffer = ReadBytes(size);
                // Read checkSum
                ushort checksum = ReadUInt16();
                // Verify checksum
                if (!VerifyChecksum(buffer, checksum))
                {
                    error = true;
                    break;
                }
                size = buffer.Length;
                if (lvl == TnefLvlType.Message)
                {
                    // Text body
                    if (att_n == TnefAttribute.Body)
                    {
                        if (att_t == TnefDataType.atpString)
                        {
                            _body = enc.GetString(buffer, 0, size);
                        }
                        // Message mapi props (html body, rtf body, ...)
                    }
                    else if (att_n == TnefAttribute.MapiProps)
                    {
                        ReadMapi(buffer);
                        // Stream Codepage
                    }
                    else if (att_n == TnefAttribute.OEMCodepage)
                    {
                        uint codepage1 = (uint)(buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24));
                        if (codepage1 > 0)
                        {
                            try
                            {
                                enc = System.Text.Encoding.GetEncoding((int)codepage1);
                            }
                            catch (Exception e)
                            {
                                Trace.Fail(e.Message, e.StackTrace);
                            }
                        }
                    }
                }
                else if (lvl == TnefLvlType.Attachment)
                {
                    // Attachment start
                    if (att_n == TnefAttribute.AttachRendData)
                    {
                        String name = String.Concat("generated_", key, "_", (Attachments.Count + 1), ".binary");
                        if (path == null)
                        {
                            attachment_cur = new SharpAttachment();
                        }
                        else
                        {
                            attachment_cur = new SharpAttachment(new FileInfo(Path.Combine(path, name)));
                        }

                        // Attachment name
                        attachment_cur.Name = name;
                    }
                    else if (att_n == TnefAttribute.AttachTitle)
                    {
                        if (attachment_cur != null && att_t == TnefDataType.atpString && buffer != null)
                        {
                            // NULL terminated string
                            if (buffer[size - 1] == '\0')
                            {
                                size--;
                            }
                            if (size > 0)
                            {
                                String name = enc.GetString(buffer, 0, size);
                                if (name.Length > 0)
                                {
                                    attachment_cur.Name = name;
                                    // Content already saved, so we have to rename
                                    if (attachment_cur.SavedFile != null && attachment_cur.SavedFile.Exists)
                                    {
                                        try
                                        {
                                            attachment_cur.SavedFile.MoveTo(Path.Combine(path, attachment_cur.Name));
                                        }
                                        catch (Exception e)
                                        {
                                            Trace.Fail(e.Message, e.StackTrace);
                                        }
                                    }
                                }
                            }
                        }
                        // Modification and creation date
                    }
                    else if (att_n == TnefAttribute.AttachModifyDate || att_n == TnefAttribute.AttachCreateDate)
                    {
                        if (attachment_cur != null && att_t == TnefDataType.atpDate && buffer != null && size == 14)
                        {
                            int pos = 0;
                            DateTime date = new DateTime((buffer[pos++] + (buffer[pos++] << 8)), (buffer[pos++] + (buffer[pos++] << 8)), (buffer[pos++] + (buffer[pos++] << 8)), (buffer[pos++] + (buffer[pos++] << 8)), (buffer[pos++] + (buffer[pos++] << 8)), (buffer[pos++] + (buffer[pos++] << 8)));
                            if (att_n == TnefAttribute.AttachModifyDate)
                            {
                                attachment_cur.LastWriteTime = date;
                            }
                            else if (att_n == TnefAttribute.AttachCreateDate)
                            {
                                attachment_cur.CreationTime = date;
                            }
                        }
                        // Attachment data
                    }
                    else if (att_n == TnefAttribute.AttachData)
                    {
                        if (attachment_cur != null && att_t == TnefDataType.atpByte && buffer != null)
                        {
                            if (attachment_cur.SavedFile != null)
                            {
                                FileStream stream = null;
                                try
                                {
                                    stream = attachment_cur.SavedFile.OpenWrite();
                                }
                                catch (Exception e)
                                {
                                    error = true;
                                    break;
                                }
                                stream.Write(buffer, 0, size);
                                stream.Flush();
                                attachment_cur.Size = stream.Length;
                                stream.Close();
                                stream = null;
                                attachment_cur.SavedFile.Refresh();
                                // Is name has changed, we have to rename
                                if (attachment_cur.SavedFile.Name != attachment_cur.Name)
                                    try
                                    {
                                        attachment_cur.SavedFile.MoveTo(Path.Combine(path, attachment_cur.Name));
                                    }
                                    catch (Exception e)
                                    {
                                        Trace.Fail(e.Message, e.StackTrace);
                                    }
                            }
                            else
                            {
                                attachment_cur.Stream.Write(buffer, 0, size);
                                attachment_cur.Stream.Flush();
                                if (attachment_cur.Stream.CanSeek)
                                    attachment_cur.Stream.Seek(0, SeekOrigin.Begin);
                                attachment_cur.Size = attachment_cur.Stream.Length;
                            }
                            Attachments.Add(attachment_cur);
                        }
                        // Attachment mapi props
                    }
                    else if (att_n == TnefAttribute.Attachment)
                    {
                        ReadMapi(buffer);
                    }
                }
            }
            if (Attachments.Count == 0)
                Attachments = null;
            return !error;
        }
Пример #2
0
 private String ReplaceUrlTokens(String url, SharpAttachment attachment)
 {
     if (url == null || url.Length == 0 || url.IndexOf('[') == -1 || url.IndexOf(']') == -1)
         return url;
     if (url.IndexOf("[MessageID]") != -1)
     {
         url = url.Replace("[MessageID]", HttpUtility.UrlEncode(SharpMimeTools.Rfc2392Url(MessageID)));
     }
     if (attachment != null && attachment.ContentID != null)
     {
         if (url.IndexOf("[ContentID]") != -1)
         {
             url = url.Replace("[ContentID]", HttpUtility.UrlEncode(SharpMimeTools.Rfc2392Url(attachment.ContentID)));
         }
         if (url.IndexOf("[Name]") != -1)
         {
             if (attachment.SavedFile != null)
             {
                 url = url.Replace("[Name]", HttpUtility.UrlEncode(attachment.SavedFile.Name));
             }
             else
             {
                 url = url.Replace("[Name]", HttpUtility.UrlEncode(attachment.Name));
             }
         }
     }
     return url;
 }
Пример #3
0
 private void UuDecode(String path)
 {
     if (_body.Length == 0 || _body.IndexOf("begin ") == -1 || _body.IndexOf("end") == -1)
         return;
     StringBuilder sb = new StringBuilder();
     using (StringReader reader = new StringReader(_body))
     {
         Stream stream = null;
         SharpAttachment attachment = null;
         for (String line = reader.ReadLine(); line != null; line = reader.ReadLine())
         {
             if (stream == null)
             {
                 // Found the start point of uuencoded content
                 if (line.Length > 10 && line[0] == 'b' && line[1] == 'e' && line[2] == 'g' && line[3] == 'i' && line[4] == 'n' && line[5] == ' ' && line[9] == ' ')
                 {
                     String name = Path.GetFileName(line.Substring(10));
                     // In-Memory decoding
                     if (path == null)
                     {
                         attachment = new SharpAttachment();
                         stream = attachment.Stream;
                         // Filesystem decoding
                     }
                     else
                     {
                         attachment = new SharpAttachment(new FileInfo(Path.Combine(path, name)));
                         stream = attachment.SavedFile.OpenWrite();
                     }
                     attachment.Name = name;
                     // Not uuencoded line, so add it to new body
                 }
                 else
                 {
                     sb.Append(line);
                     sb.Append(Environment.NewLine);
                 }
             }
             else
             {
                 // Content finished
                 if (line.Length == 3 && line == "end")
                 {
                     stream.Flush();
                     if (stream.Length > 0)
                     {
                         attachment.Size = stream.Length;
                         Attachments.Add(attachment);
                     }
                     // When decoding to a file, close the stream.
                     if (attachment.SavedFile != null || stream.Length == 0)
                     {
                         stream.Close();
                     }
                     attachment = null;
                     stream = null;
                     // Decode and write uuencoded line
                 }
                 else
                 {
                     SharpMimeTools.UuDecodeLine(line, stream);
                 }
             }
         }
         if (stream != null && stream.CanRead)
         {
             stream.Close();
             stream = null;
         }
     }
     _body = sb.ToString();
     sb = null;
 }
Пример #4
0
 private void ParseMessage(SharpMimeMessage part, MimeTopLevelMediaType types, bool html, SharpDecodeOptions options, String preferredtextsubtype, String path)
 {
     if ((types & part.Header.TopLevelMediaType) != part.Header.TopLevelMediaType)
     {
         return;
     }
     switch (part.Header.TopLevelMediaType)
     {
         case MimeTopLevelMediaType.multipart:
         case MimeTopLevelMediaType.message:
             // TODO: allow other subtypes of "message"
             if (part.Header.TopLevelMediaType.Equals(MimeTopLevelMediaType.message))
             {
                 // Only message/rfc822 allowed, other subtypes ignored
                 if (part.Header.SubType == "rfc822")
                 {
                     // If NotRecursiveRfc822 option is set, handle part as an attachment
                     if ((options & SharpDecodeOptions.NotRecursiveRfc822) == SharpDecodeOptions.NotRecursiveRfc822)
                     {
                         goto case anmar.SharpMimeTools.MimeTopLevelMediaType.application;
                     }
                 }
                 else
                 {
                     break;
                 }
             }
             if (part.Header.SubType.Equals("alternative") && part.PartsCount > 0)
             {
                 SharpMimeMessage altenative = null;
                 // Get the first mime part of the alternatives that has a accepted Mime-Type
                 for (int i = part.PartsCount; i > 0; i--)
                 {
                     SharpMimeMessage item = part.GetPart(i - 1);
                     if ((types & part.Header.TopLevelMediaType) != part.Header.TopLevelMediaType
                         || (!html && item.Header.TopLevelMediaType.Equals(MimeTopLevelMediaType.text) && item.Header.SubType.Equals("html"))
                         )
                     {
                         continue;
                     }
                     // First allowed one.
                     if (altenative == null)
                     {
                         altenative = item;
                         // We don't have to select body part based on subtype if not asked for, or not a text one
                         // or it's already the preferred one
                         if (preferredtextsubtype == null || item.Header.TopLevelMediaType != MimeTopLevelMediaType.text || (preferredtextsubtype != null && item.Header.SubType == preferredtextsubtype))
                         {
                             break;
                         }
                         // This one is preferred over the last part
                     }
                     else if (preferredtextsubtype != null && item.Header.TopLevelMediaType == MimeTopLevelMediaType.text && item.Header.SubType == preferredtextsubtype)
                     {
                         altenative = item;
                         break;
                     }
                 }
                 if (altenative != null)
                 {
                     // If message body as html is allowed and part has a Content-ID field
                     // add an anchor to mark this body part
                     if (html && part.Header.Contains("Content-ID") && (options & SharpDecodeOptions.NamedAnchors) == SharpDecodeOptions.NamedAnchors)
                     {
                         // There is a previous text body, so enclose it in <pre>
                         if (!HasHtmlBody && _body.Length > 0)
                         {
                             _body = String.Concat("<pre>", HttpUtility.HtmlEncode(_body), "</pre>");
                             HasHtmlBody = true;
                         }
                         // Add the anchor
                         _body = String.Concat(_body, "<a name=\"", SharpMimeTools.Rfc2392Url(MessageID), "_", SharpMimeTools.Rfc2392Url(part.Header.ContentID), "\"></a>");
                     }
                     ParseMessage(altenative, types, html, options, preferredtextsubtype, path);
                 }
                 // TODO: Take into account each subtype of "multipart" and "message"
             }
             else if (part.PartsCount > 0)
             {
                 foreach (SharpMimeMessage item in part)
                 {
                     ParseMessage(item, types, html, options, preferredtextsubtype, path);
                 }
             }
             break;
         case MimeTopLevelMediaType.text:
             if ((part.Disposition == null || !part.Disposition.Equals("attachment"))
                 && (part.Header.SubType.Equals("plain") || part.Header.SubType.Equals("html")))
             {
                 bool body_was_html = HasHtmlBody;
                 // HTML content not allowed
                 if (part.Header.SubType.Equals("html"))
                 {
                     if (!html)
                         break;
                     else
                         HasHtmlBody = true;
                 }
                 if (html && part.Header.Contains("Content-ID") && (options & SharpDecodeOptions.NamedAnchors) == SharpDecodeOptions.NamedAnchors)
                 {
                     HasHtmlBody = true;
                 }
                 if (HasHtmlBody && !body_was_html && !String.IsNullOrEmpty(_body))
                 {
                     _body = String.Concat("<pre>", HttpUtility.HtmlEncode(_body), "</pre>");
                 }
                 // If message body is html and this part has a Content-ID field
                 // add an anchor to mark this body part
                 if (HasHtmlBody && part.Header.Contains("Content-ID") && (options & SharpDecodeOptions.NamedAnchors) == SharpDecodeOptions.NamedAnchors)
                 {
                     _body = String.Concat(_body, "<a name=\"", SharpMimeTools.Rfc2392Url(MessageID), "_", SharpMimeTools.Rfc2392Url(part.Header.ContentID), "\"></a>");
                 }
                 if (HasHtmlBody && part.Header.SubType.Equals("plain"))
                 {
                     _body = String.Concat(_body, "<pre>", HttpUtility.HtmlEncode(part.BodyDecoded), "</pre>");
                 }
                 else
                     _body = String.Concat(_body, part.BodyDecoded);
             }
             else
             {
                 if ((types & MimeTopLevelMediaType.application) != MimeTopLevelMediaType.application)
                 {
                     return;
                 }
                 goto case anmar.SharpMimeTools.MimeTopLevelMediaType.application;
             }
             break;
         case MimeTopLevelMediaType.application:
         case MimeTopLevelMediaType.audio:
         case MimeTopLevelMediaType.image:
         case MimeTopLevelMediaType.video:
             // Attachments not allowed.
             if ((options & SharpDecodeOptions.AllowAttachments) != SharpDecodeOptions.AllowAttachments)
                 break;
             SharpAttachment attachment = null;
             // Save to a file
             if (path != null)
             {
                 FileInfo file = part.DumpBody(path, true);
                 if (file != null)
                 {
                     attachment = new SharpAttachment(file);
                     attachment.Name = file.Name;
                     attachment.Size = file.Length;
                 }
                 // Save to a stream
             }
             else
             {
                 using (MemoryStream stream = new MemoryStream())
                 {
                     if (part.DumpBody(stream))
                     {
                         if (stream != null && stream.CanSeek)
                             stream.Seek(0, SeekOrigin.Begin);
                         attachment = new SharpAttachment(stream);
                         if (part.Name != null)
                             attachment.Name = part.Name;
                         else
                             attachment.Name = String.Concat("generated_", part.GetHashCode(), ".", part.Header.SubType);
                         attachment.Size = stream.Length;
                     }
                 }
             }
             if (attachment != null && part.Header.SubType == "ms-tnef" && (options & SharpDecodeOptions.DecodeTnef) == SharpDecodeOptions.DecodeTnef)
             {
                 // Try getting attachments form a tnef stream
                 Stream stream = attachment.Stream;
                 SharpTnefMessage tnef = new SharpTnefMessage(stream);
                 if (tnef.Parse(path))
                 {
                     if (tnef.Attachments != null)
                     {
                         Attachments.AddRange(tnef.Attachments);
                     }
                     attachment.Close();
                     // Delete the raw tnef file
                     if (attachment.SavedFile != null)
                     {
                         if (stream != null && stream.CanRead)
                         {
                             stream.Close();
                             stream = null;
                         }
                         attachment.SavedFile.Delete();
                     }
                     attachment = null;
                     tnef.Close();
                 }
                 else
                 {
                     // The read-only stream is no longer needed and locks the file
                     if (attachment.SavedFile != null && stream != null && stream.CanRead)
                     {
                         stream.Close();
                         stream = null;
                     }
                 }
                 stream = null;
                 tnef = null;
             }
             if (attachment != null)
             {
                 if (part.Disposition != null && part.Disposition == "inline")
                 {
                     attachment.Inline = true;
                 }
                 attachment.MimeTopLevelMediaType = part.Header.TopLevelMediaType;
                 attachment.MimeMediaSubType = part.Header.SubType;
                 // Store attachment's CreationTime
                 if (part.Header.ContentDispositionParameters.ContainsKey("creation-date"))
                     attachment.CreationTime = SharpMimeTools.parseDate(part.Header.ContentDispositionParameters["creation-date"]);
                 // Store attachment's LastWriteTime
                 if (part.Header.ContentDispositionParameters.ContainsKey("modification-date"))
                     attachment.LastWriteTime = SharpMimeTools.parseDate(part.Header.ContentDispositionParameters["modification-date"]);
                 if (part.Header.Contains("Content-ID"))
                     attachment.ContentID = part.Header.ContentID;
                 Attachments.Add(attachment);
             }
             break;
         default:
             break;
     }
 }