private static MimePart GetMimePart(AttachmentBase item) { var mimeType = item.ContentType.ToString(); var contentType = ContentType.Parse(mimeType); var attachment = item as Attachment; MimePart part; if (contentType.MediaType.Equals("text", StringComparison.OrdinalIgnoreCase)) { // Original: part = new TextPart(contentType); // Due to constructor of TextPart(ContentType contentType) being internal, // mimic the instantiation by using MimePart(ContentType contentType) part = new MimePart(contentType); } else { part = new MimePart(contentType); } if (attachment != null) { var disposition = attachment.ContentDisposition.ToString(); part.ContentDisposition = ContentDisposition.Parse(disposition); } switch (item.TransferEncoding) { case TransferEncoding.QuotedPrintable: part.ContentTransferEncoding = ContentEncoding.QuotedPrintable; break; case TransferEncoding.Base64: part.ContentTransferEncoding = ContentEncoding.Base64; break; case TransferEncoding.SevenBit: part.ContentTransferEncoding = ContentEncoding.SevenBit; break; case TransferEncoding.EightBit: part.ContentTransferEncoding = ContentEncoding.EightBit; break; } if (item.ContentId != null) { part.ContentId = item.ContentId; } var stream = new MemoryBlockStream(); item.ContentStream.CopyTo(stream); stream.Position = 0; part.ContentObject = new ContentObject(stream); return(part); }
public void TestArgumentExceptions () { var disposition = new ContentDisposition (); Assert.Throws<ArgumentNullException> (() => disposition.Disposition = null, "Setting the disposition to null value should throw."); Assert.Throws<ArgumentException> (() => disposition.Disposition = string.Empty, "Setting the disposition to an empty value should throw."); Assert.Throws<ArgumentException> (() => disposition.Disposition = "žádost", "Setting the disposition to a non-ascii value should throw."); Assert.Throws<ArgumentException> (() => disposition.Disposition = "two atoms", "Setting the disposition to multiple atom tokens should throw."); }
private static MimePart GetMimePart(AttachmentBase item) { var mimeType = item.ContentType.ToString(); var contentType = ContentType.Parse(mimeType); var attachment = item as Attachment; var part = new MimePart(contentType); // if (attachment != null) { var disposition = attachment.ContentDisposition.ToString(); part.ContentDisposition = ContentDisposition.Parse(disposition); } // Adjust the transfer encoding switch (item.TransferEncoding) { case TransferEncoding.QuotedPrintable: part.ContentTransferEncoding = ContentEncoding.QuotedPrintable; break; case TransferEncoding.Base64: part.ContentTransferEncoding = ContentEncoding.Base64; break; case TransferEncoding.SevenBit: part.ContentTransferEncoding = ContentEncoding.SevenBit; break; case TransferEncoding.EightBit: part.ContentTransferEncoding = ContentEncoding.EightBit; break; case TransferEncoding.Unknown: break; default: throw new ArgumentOutOfRangeException(); } // Adjust the attachment content identifier if (item.ContentId != null) { part.ContentId = item.ContentId; } // Copy the content of the attachment var stream = new MemoryBlockStream(); item.ContentStream.CopyTo(stream); stream.Position = 0; part.Content = new MimeContent(stream); // Done return(part); }
static void AssertParseResults (ContentDisposition disposition, ContentDisposition expected) { if (expected == null) { Assert.IsNull (disposition); return; } Assert.AreEqual (expected.Disposition, disposition.Disposition, "Disposition"); Assert.AreEqual (expected.Parameters.Count, disposition.Parameters.Count, "Parameter count"); for (int i = 0; i < expected.Parameters.Count; i++) { var encoding = expected.Parameters[i].Encoding; var value = expected.Parameters[i].Value; var name = expected.Parameters[i].Name; Assert.AreEqual (name, disposition.Parameters[i].Name); Assert.AreEqual (encoding.EncodingName, disposition.Parameters[i].Encoding.EncodingName); Assert.AreEqual (value, disposition.Parameters[i].Value); Assert.IsTrue (disposition.Parameters.Contains (name)); Assert.AreEqual (expected.Parameters[name], disposition.Parameters[name]); } }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the specified buffer. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> public static bool TryParse (ParserOptions options, byte[] buffer, out ContentDisposition disposition) { if (options == null) throw new ArgumentNullException ("options"); if (buffer == null) throw new ArgumentNullException ("buffer"); int index = 0; return TryParse (options, buffer, ref index, buffer.Length, false, out disposition); }
public void TestChineseFilename2047 () { const string expected = " attachment; filename=\"=?gb18030?b?suLK1M7Esb4udHh0?=\"\n"; var disposition = new ContentDisposition (ContentDisposition.Attachment); disposition.Parameters.Add ("GB18030", "filename", "测试文本.txt"); var format = FormatOptions.Default.Clone (); format.ParameterEncodingMethod = ParameterEncodingMethod.Rfc2047; format.NewLineFormat = NewLineFormat.Unix; var encoded = disposition.Encode (format, Encoding.UTF8); Parameter param; Assert.AreEqual (expected, encoded, "The encoded Chinese filename parameter does not match the expected value."); Assert.IsTrue (ContentDisposition.TryParse (encoded, out disposition), "Failed to parse Content-Disposition"); Assert.AreEqual ("测试文本.txt", disposition.FileName, "The decoded Chinese filename does not match."); Assert.IsTrue (disposition.Parameters.TryGetValue ("filename", out param), "Failed to locate filename parameter."); Assert.AreEqual ("GB18030", param.Encoding.HeaderName, "The filename encoding did not match."); }
public void TestDispositionParameters () { const string expected = "Content-Disposition: attachment; filename=document.doc;\n" + "\tcreation-date=\"Sat, 04 Jan 1997 15:22:17 -0400\";\n" + "\tmodification-date=\"Thu, 04 Jan 2007 15:22:17 -0400\";\n" + "\tread-date=\"Wed, 04 Jan 2012 15:22:17 -0400\"; size=37001"; var ctime = new DateTimeOffset (1997, 1, 4, 15, 22, 17, new TimeSpan (-4, 0, 0)); var mtime = new DateTimeOffset (2007, 1, 4, 15, 22, 17, new TimeSpan (-4, 0, 0)); var atime = new DateTimeOffset (2012, 1, 4, 15, 22, 17, new TimeSpan (-4, 0, 0)); var disposition = new ContentDisposition (); var format = FormatOptions.Default.Clone (); const long size = 37001; Parameter param; string encoded; format.NewLineFormat = NewLineFormat.Unix; Assert.AreEqual (ContentDisposition.Attachment, disposition.Disposition, "The disposition should be 'attachment'."); Assert.IsTrue (disposition.IsAttachment, "IsAttachment should be true by default."); Assert.IsNull (disposition.FileName, "The filename should default to null."); Assert.IsNull (disposition.CreationDate, "The creation-date should default to null."); Assert.IsNull (disposition.ModificationDate, "The modification-date should default to null."); Assert.IsNull (disposition.ReadDate, "The read-date should default to null."); Assert.IsNull (disposition.Size, "The size should default to null."); disposition.FileName = "document.doc"; disposition.CreationDate = ctime; disposition.ModificationDate = mtime; disposition.ReadDate = atime; disposition.Size = size; encoded = disposition.ToString (format, Encoding.UTF8, true); Assert.AreEqual (expected, encoded, "The encoded Content-Disposition does not match."); disposition = ContentDisposition.Parse (encoded.Substring ("Content-Disposition:".Length)); Assert.AreEqual ("document.doc", disposition.FileName, "The filename parameter does not match."); Assert.AreEqual (ctime, disposition.CreationDate, "The creation-date parameter does not match."); Assert.AreEqual (mtime, disposition.ModificationDate, "The modification-date parameter does not match."); Assert.AreEqual (atime, disposition.ReadDate, "The read-date parameter does not match."); Assert.AreEqual (size, disposition.Size, "The size parameter does not match."); disposition.CreationDate = null; Assert.IsFalse (disposition.Parameters.TryGetValue ("creation-date", out param), "The creation-date parameter should have been removed."); disposition.ModificationDate = null; Assert.IsFalse (disposition.Parameters.TryGetValue ("modification-date", out param), "The modification-date parameter should have been removed."); disposition.ReadDate = null; Assert.IsFalse (disposition.Parameters.TryGetValue ("read-date", out param), "The read-date parameter should have been removed."); disposition.FileName = null; Assert.IsFalse (disposition.Parameters.TryGetValue ("filename", out param), "The filename parameter should have been removed."); disposition.Size = null; Assert.IsFalse (disposition.Parameters.TryGetValue ("size", out param), "The size parameter should have been removed."); disposition.IsAttachment = false; Assert.AreEqual (ContentDisposition.Inline, disposition.Disposition, "The disposition should be 'inline'."); Assert.IsFalse (disposition.IsAttachment, "IsAttachment should be false."); }
public void TestMistakenlyQuotedEncodedParameterValues () { const string text = "attachment;\n filename*0*=\"ISO-8859-2''%C8%50%50%20%2D%20%BE%E1%64%6F%73%74%20%6F%20%61%6B%63%65\";\n " + "filename*1*=\"%70%74%61%63%69%20%73%6D%6C%6F%75%76%79%20%31%32%2E%31%32%2E\";\n " + "filename*2*=\"%64%6F%63\""; const string filename = "ČPP - žádost o akceptaci smlouvy 12.12.doc"; var expected = new ContentDisposition ("attachment"); expected.Parameters.Add (Encoding.GetEncoding ("ISO-8859-2"), "filename", filename); AssertParse (text, expected); }
public void TestInvalidDataAfterMDisposition () { var expected = new ContentDisposition ("attachment"); const string text = "attachment x"; // TryParse will return false but will have a value to use AssertParse (text, expected, false, 11, 11); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="length">The number of bytes in the input buffer to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="buffer"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> and <paramref name="length"/> do not specify /// a valid range in the byte array. /// </exception> public static bool TryParse(byte[] buffer, int startIndex, int length, out ContentDisposition disposition) { return(TryParse(ParserOptions.Default, buffer, startIndex, length, out disposition)); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the specified buffer. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="buffer">The input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="buffer"/> is <c>null</c>. /// </exception> public static bool TryParse(byte[] buffer, out ContentDisposition disposition) { return(TryParse(ParserOptions.Default, buffer, out disposition)); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the specified buffer. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> public static bool TryParse (ParserOptions options, byte[] buffer, out ContentDisposition disposition) { ParseUtils.ValidateArguments (options, buffer); int index = 0; return TryParse (options, buffer, ref index, buffer.Length, false, out disposition); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the specified buffer. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="buffer">The input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="buffer"/> is <c>null</c>. /// </exception> public static bool TryParse (byte[] buffer, out ContentDisposition disposition) { return TryParse (ParserOptions.Default, buffer, out disposition); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="length">The number of bytes in the input buffer to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> and <paramref name="length"/> do not specify /// a valid range in the byte array. /// </exception> public static bool TryParse (ParserOptions options, byte[] buffer, int startIndex, int length, out ContentDisposition disposition) { ParseUtils.ValidateArguments (options, buffer, startIndex, length); int index = startIndex; return TryParse (options, buffer, ref index, startIndex + length, false, out disposition); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="length">The number of bytes in the input buffer to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="buffer"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> and <paramref name="length"/> do not specify /// a valid range in the byte array. /// </exception> public static bool TryParse (byte[] buffer, int startIndex, int length, out ContentDisposition disposition) { return TryParse (ParserOptions.Default, buffer, startIndex, length, out disposition); }
internal static bool TryParse (ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ContentDisposition disposition) { string type; int atom; disposition = null; if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) return false; atom = index; if (!ParseUtils.SkipAtom (text, ref index, endIndex)) { if (throwOnError) throw new ParseException (string.Format ("Invalid atom token at position {0}", atom), atom, index); return false; } type = Encoding.ASCII.GetString (text, atom, index - atom); if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) return false; disposition = new ContentDisposition (); disposition.disposition = type; if (index >= endIndex) return true; if (text[index] != (byte) ';') { if (throwOnError) throw new ParseException (string.Format ("Expected ';' at position {0}", index), index, index); return false; } index++; if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) return false; if (index >= endIndex) return true; ParameterList parameters; if (!ParameterList.TryParse (options, text, ref index, endIndex, throwOnError, out parameters)) return false; disposition.Parameters = parameters; return true; }
/// <summary> /// Called when the headers change in some way. /// </summary> /// <remarks> /// <para>Whenever a header is added, changed, or removed, this method will /// be called in order to allow custom <see cref="MimeEntity"/> subclasses /// to update their state.</para> /// <para>Overrides of this method should call the base method so that their /// superclass may also update its own state.</para> /// </remarks> /// <param name="action">The type of change.</param> /// <param name="header">The header being added, changed or removed.</param> protected virtual void OnHeadersChanged (HeaderListChangedAction action, Header header) { MailboxAddress mailbox; int index = 0; string text; switch (action) { case HeaderListChangedAction.Added: case HeaderListChangedAction.Changed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; if (ContentDisposition.TryParse (Headers.Options, header.RawValue, out disposition)) disposition.Changed += ContentDispositionChanged; break; case HeaderId.ContentLocation: text = header.Value.Trim (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) location = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) location = new Uri (text, UriKind.Relative); else location = null; break; case HeaderId.ContentBase: text = header.Value.Trim (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) baseUri = new Uri (text, UriKind.Absolute); else baseUri = null; break; case HeaderId.ContentId: if (MailboxAddress.TryParse (Headers.Options, header.RawValue, ref index, header.RawValue.Length, false, out mailbox)) contentId = mailbox.Address; else contentId = null; break; } break; case HeaderListChangedAction.Removed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; break; case HeaderId.ContentLocation: location = null; break; case HeaderId.ContentBase: baseUri = null; break; case HeaderId.ContentId: contentId = null; break; } break; case HeaderListChangedAction.Cleared: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; contentId = null; location = null; baseUri = null; break; default: throw new ArgumentOutOfRangeException (nameof (action)); } }
/// <summary> /// Tries to parse the given text into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied text. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="text">The text to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="text"/> is <c>null</c>. /// </exception> public static bool TryParse (string text, out ContentDisposition disposition) { if (text == null) throw new ArgumentNullException ("text"); var buffer = Encoding.UTF8.GetBytes (text); int index = 0; return TryParse (ParserOptions.Default, buffer, ref index, buffer.Length, false, out disposition); }
/// <summary> /// Tries to parse the given text into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied text. /// </remarks> /// <returns><c>true</c> if the disposition was successfully parsed; otherwise, <c>false</c>.</returns> /// <param name="text">The text to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="text"/> is <c>null</c>. /// </exception> public static bool TryParse(string text, out ContentDisposition disposition) { return(TryParse(ParserOptions.Default, text, out disposition)); }
/// <summary> /// Tries to parse the given text into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied text. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="text">The text to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="text"/> is <c>null</c>.</para> /// </exception> public static bool TryParse (ParserOptions options, string text, out ContentDisposition disposition) { ParseUtils.ValidateArguments (options, text); var buffer = Encoding.UTF8.GetBytes (text); int index = 0; return TryParse (ParserOptions.Default, buffer, ref index, buffer.Length, false, out disposition); }
internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ContentDisposition disposition) { string type; int atom; disposition = null; if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } atom = index; if (!ParseUtils.SkipAtom(text, ref index, endIndex)) { if (throwOnError) { throw new ParseException(string.Format("Invalid atom token at position {0}", atom), atom, index); } return(false); } type = Encoding.ASCII.GetString(text, atom, index - atom); if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } disposition = new ContentDisposition(); disposition.disposition = type; if (index >= endIndex) { return(true); } if (text[index] != (byte)';') { if (throwOnError) { throw new ParseException(string.Format("Expected ';' at position {0}", index), index, index); } return(false); } index++; if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } if (index >= endIndex) { return(true); } ParameterList parameters; if (!ParameterList.TryParse(options, text, ref index, endIndex, throwOnError, out parameters)) { return(false); } disposition.Parameters = parameters; return(true); }
/// <summary> /// Tries to parse the given text into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied text. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="text">The text to parse.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="text"/> is <c>null</c>. /// </exception> public static bool TryParse (string text, out ContentDisposition disposition) { return TryParse (ParserOptions.Default, text, out disposition); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> is out of range. /// </exception> public static bool TryParse(ParserOptions options, byte[] buffer, int startIndex, out ContentDisposition disposition) { if (options == null) { throw new ArgumentNullException("options"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (startIndex < 0 || startIndex >= buffer.Length) { throw new ArgumentOutOfRangeException("startIndex"); } int index = startIndex; return(TryParse(options, buffer, ref index, buffer.Length, false, out disposition)); }
static ContentDisposition ParseContentDisposition(ImapEngine engine, CancellationToken cancellationToken) { var token = engine.ReadToken (cancellationToken); if (token.Type == ImapTokenType.Nil) return null; if (token.Type != ImapTokenType.OpenParen) throw ImapEngine.UnexpectedToken (token, false); var dsp = ReadStringToken (engine, cancellationToken); var disposition = new ContentDisposition (dsp); token = engine.ReadToken (cancellationToken); if (token.Type == ImapTokenType.OpenParen) ParseParameterList (disposition.Parameters, engine, cancellationToken); else if (token.Type != ImapTokenType.Nil) throw ImapEngine.UnexpectedToken (token, false); token = engine.ReadToken (cancellationToken); if (token.Type != ImapTokenType.CloseParen) throw ImapEngine.UnexpectedToken (token, false); return disposition; }
public void TestMultipleParametersWithIdenticalNames () { const string text1 = "inline;\n filename=\"Filename.doc\";\n filename*0*=UTF-8''UnicodeFile;\n filename*1*=name.doc"; const string text2 = "inline;\n filename*0*=UTF-8''UnicodeFile;\n filename*1*=name.doc;\n filename=\"Filename.doc\""; const string text3 = "inline;\n filename*0*=UTF-8''UnicodeFile;\n filename=\"Filename.doc\";\n filename*1*=name.doc"; var expected = new ContentDisposition ("inline"); expected.Parameters.Add ("filename", "UnicodeFilename.doc"); AssertParse (text1, expected); AssertParse (text2, expected); AssertParse (text3, expected); }
static bool TryParse (string text, ref int index, out ContentDisposition disposition) { IList<Parameter> parameters; string value; disposition = null; while (index < text.Length && text[index] == ' ') index++; if (index >= text.Length) return false; if (text[index] != '(') { if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") { index += 3; return true; } return false; } index++; if (!TryParse (text, ref index, out value)) return false; if (!TryParse (text, ref index, out parameters)) return false; if (index >= text.Length || text[index] != ')') return false; index++; disposition = new ContentDisposition (value); foreach (var param in parameters) disposition.Parameters.Add (param); return true; }
public void TestUnquotedFilenameParameterValues () { const string text = " attachment; filename=Partnership Marketing Agreement\n Form - Mega Brands - Easter Toys - Week 11.pdf"; const string filename = "Partnership Marketing Agreement Form - Mega Brands - Easter Toys - Week 11.pdf"; var expected = new ContentDisposition ("attachment"); expected.Parameters.Add ("filename", filename); AssertParse (text, expected); }
static void AssertParse (string text, ContentDisposition expected, bool result = true, int tokenIndex = -1, int errorIndex = -1) { var buffer = Encoding.UTF8.GetBytes (text); var options = ParserOptions.Default; ContentDisposition disposition; Assert.AreEqual (result, ContentDisposition.TryParse (text, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (options, text, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (buffer, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (options, buffer, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (buffer, 0, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (options, buffer, 0, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (buffer, 0, buffer.Length, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); Assert.AreEqual (result, ContentDisposition.TryParse (options, buffer, 0, buffer.Length, out disposition), "Unexpected result for TryParse: {0}", text); AssertParseResults (disposition, expected); try { disposition = ContentDisposition.Parse (text); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (options, text); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (buffer); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (options, buffer); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (buffer, 0); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (options, buffer, 0); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (buffer, 0, buffer.Length); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } try { disposition = ContentDisposition.Parse (options, buffer, 0, buffer.Length); if (tokenIndex != -1 && errorIndex != -1) Assert.Fail ("Parsing \"{0}\" should have failed.", text); AssertParseResults (disposition, expected); } catch (ParseException ex) { Assert.AreEqual (tokenIndex, ex.TokenIndex, "Unexpected token index"); Assert.AreEqual (errorIndex, ex.ErrorIndex, "Unexpected error index"); } catch (Exception e) { Assert.Fail ("Unexpected exception: {0}", e); } }
public void TestChineseFilename () { const string expected = " attachment;\n\tfilename*=gb18030''%B2%E2%CA%D4%CE%C4%B1%BE.txt\n"; var disposition = new ContentDisposition (ContentDisposition.Attachment); disposition.Parameters.Add ("GB18030", "filename", "测试文本.txt"); var format = FormatOptions.Default.Clone (); format.NewLineFormat = NewLineFormat.Unix; var encoded = disposition.Encode (format, Encoding.UTF8); Parameter param; Assert.AreEqual (expected, encoded, "The encoded Chinese filename parameter does not match the expected value."); Assert.IsTrue (ContentDisposition.TryParse (encoded, out disposition), "Failed to parse Content-Disposition"); Assert.AreEqual ("测试文本.txt", disposition.FileName, "The decoded Chinese filename does not match."); Assert.IsTrue (disposition.Parameters.TryGetValue ("filename", out param), "Failed to locate filename parameter."); Assert.AreEqual ("GB18030", param.Encoding.HeaderName, "The filename encoding did not match."); }
static ContentDisposition ParseContentDisposition (ImapEngine engine, CancellationToken cancellationToken) { var token = engine.ReadToken (cancellationToken); if (token.Type == ImapTokenType.Nil) return null; if (token.Type != ImapTokenType.OpenParen) throw ImapEngine.UnexpectedToken (token, false); var dsp = ReadStringToken (engine, cancellationToken); var builder = new StringBuilder (dsp); ContentDisposition disposition; token = engine.ReadToken (cancellationToken); if (token.Type == ImapTokenType.OpenParen) ParseParameterList (builder, engine, cancellationToken); else if (token.Type != ImapTokenType.Nil) throw ImapEngine.UnexpectedToken (token, false); token = engine.ReadToken (cancellationToken); if (token.Type != ImapTokenType.CloseParen) throw ImapEngine.UnexpectedToken (token, false); if (!ContentDisposition.TryParse (builder.ToString (), out disposition)) disposition = new ContentDisposition (dsp); return disposition; }
public void TestIssue239 () { const string text = " attachment; size=1049971;\n\tfilename*=\"utf-8''SBD%20%C5%A0kodov%C3%A1k%2Ejpg\""; const string filename = "SBD Škodovák.jpg"; var expected = new ContentDisposition ("attachment"); expected.Parameters.Add ("size", "1049971"); expected.Parameters.Add ("filename", filename); AssertParse (text, expected); }
internal static void Encode (StringBuilder builder, ContentDisposition disposition) { if (disposition == null) { builder.Append ("NIL"); return; } builder.Append ('('); Encode (builder, disposition.Disposition); builder.Append (' '); Encode (builder, disposition.Parameters); builder.Append (')'); }
/// <summary> /// Called when the headers change in some way. /// </summary> /// <param name="action">The type of change.</param> /// <param name="header">The header being added, changed or removed.</param> protected virtual void OnHeadersChanged(HeaderListChangedAction action, Header header) { switch (action) { case HeaderListChangedAction.Added: case HeaderListChangedAction.Changed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; if (ContentDisposition.TryParse (Headers.Options, header.RawValue, out disposition)) disposition.Changed += ContentDispositionChanged; break; case HeaderId.ContentId: contentId = MimeUtils.EnumerateReferences (header.RawValue, 0, header.RawValue.Length).FirstOrDefault (); break; } break; case HeaderListChangedAction.Removed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; break; case HeaderId.ContentId: contentId = null; break; } break; case HeaderListChangedAction.Cleared: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; contentId = null; break; default: throw new ArgumentOutOfRangeException (); } }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// </remarks> /// <returns><c>true</c>, if the disposition was successfully parsed, <c>false</c> otherwise.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> is out of range. /// </exception> public static bool TryParse (ParserOptions options, byte[] buffer, int startIndex, out ContentDisposition disposition) { if (options == null) throw new ArgumentNullException ("options"); if (buffer == null) throw new ArgumentNullException ("buffer"); if (startIndex < 0 || startIndex >= buffer.Length) throw new ArgumentOutOfRangeException ("startIndex"); int index = startIndex; return TryParse (options, buffer, ref index, buffer.Length, false, out disposition); }
/// <summary> /// Called when the headers change in some way. /// </summary> /// <remarks> /// <para>Whenever a header is added, changed, or removed, this method will /// be called in order to allow custom <see cref="MimeEntity"/> subclasses /// to update their state.</para> /// <para>Overrides of this method should call the base method so that their /// superclass may also update its own state.</para> /// </remarks> /// <param name="action">The type of change.</param> /// <param name="header">The header being added, changed or removed.</param> protected virtual void OnHeadersChanged (HeaderListChangedAction action, Header header) { string text; switch (action) { case HeaderListChangedAction.Added: case HeaderListChangedAction.Changed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; if (ContentDisposition.TryParse (Headers.Options, header.RawValue, out disposition)) disposition.Changed += ContentDispositionChanged; break; case HeaderId.ContentLocation: text = header.Value.Trim (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) location = new Uri (text, UriKind.Absolute); else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) location = new Uri (text, UriKind.Relative); else location = null; break; case HeaderId.ContentBase: text = header.Value.Trim (); if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) baseUri = new Uri (text, UriKind.Absolute); else baseUri = null; break; case HeaderId.ContentId: contentId = MimeUtils.EnumerateReferences (header.RawValue, 0, header.RawValue.Length).FirstOrDefault (); break; } break; case HeaderListChangedAction.Removed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; break; case HeaderId.ContentLocation: location = null; break; case HeaderId.ContentBase: baseUri = null; break; case HeaderId.ContentId: contentId = null; break; } break; case HeaderListChangedAction.Cleared: if (disposition != null) disposition.Changed -= ContentDispositionChanged; disposition = null; contentId = null; location = null; baseUri = null; break; default: throw new ArgumentOutOfRangeException ("action"); } }
internal static bool TryParse(ParserOptions options, byte[] text, ref int index, int endIndex, bool throwOnError, out ContentDisposition disposition) { string type; int atom; disposition = null; if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } if (index >= endIndex) { if (throwOnError) { throw new ParseException(string.Format("Expected atom token at position {0}", index), index, index); } return(false); } atom = index; if (text[index] == '"') { if (throwOnError) { throw new ParseException(string.Format("Unxpected qstring token at position {0}", atom), atom, index); } // Note: This is a work-around for broken mailers that quote the disposition value... // // See https://github.com/jstedfast/MailKit/issues/486 for details. if (!ParseUtils.SkipQuoted(text, ref index, endIndex, throwOnError)) { return(false); } type = CharsetUtils.ConvertToUnicode(options, text, atom, index - atom); type = MimeUtils.Unquote(type); if (string.IsNullOrEmpty(type)) { type = Attachment; } } else { if (!ParseUtils.SkipAtom(text, ref index, endIndex)) { if (throwOnError) { throw new ParseException(string.Format("Invalid atom token at position {0}", atom), atom, index); } // Note: this is a work-around for broken mailers that do not specify a disposition value... // // See https://github.com/jstedfast/MailKit/issues/486 for details. if (index > atom || text[index] != (byte)';') { return(false); } type = Attachment; } else { type = Encoding.ASCII.GetString(text, atom, index - atom); } } disposition = new ContentDisposition(); disposition.disposition = type; if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } if (index >= endIndex) { return(true); } if (text[index] != (byte)';') { if (throwOnError) { throw new ParseException(string.Format("Expected ';' at position {0}", index), index, index); } return(false); } index++; if (!ParseUtils.SkipCommentsAndWhiteSpace(text, ref index, endIndex, throwOnError)) { return(false); } if (index >= endIndex) { return(true); } ParameterList parameters; if (!ParameterList.TryParse(options, text, ref index, endIndex, throwOnError, out parameters)) { return(false); } disposition.Parameters = parameters; return(true); }
/// <summary> /// Tries to parse the given input buffer into a new <see cref="MimeKit.ContentDisposition"/> instance. /// </summary> /// <remarks> /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// </remarks> /// <returns><c>true</c> if the disposition was successfully parsed; otherwise, <c>false</c>.</returns> /// <param name="options">The parser options.</param> /// <param name="buffer">The input buffer.</param> /// <param name="startIndex">The starting index of the input buffer.</param> /// <param name="disposition">The parsed disposition.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="options"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="buffer"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="startIndex"/> is out of range. /// </exception> public static bool TryParse(ParserOptions options, byte[] buffer, int startIndex, out ContentDisposition disposition) { ParseUtils.ValidateArguments(options, buffer, startIndex); int index = startIndex; return(TryParse(options, buffer, ref index, buffer.Length, false, out disposition)); }
/// <summary> /// Called when the headers change in some way. /// </summary> /// <remarks> /// <para>Whenever a header is added, changed, or removed, this method will /// be called in order to allow custom <see cref="MimeEntity"/> subclasses /// to update their state.</para> /// <para>Overrides of this method should call the base method so that their /// superclass may also update its own state.</para> /// </remarks> /// <param name="action">The type of change.</param> /// <param name="header">The header being added, changed or removed.</param> protected virtual void OnHeadersChanged(HeaderListChangedAction action, Header header) { string text; switch (action) { case HeaderListChangedAction.Added: case HeaderListChangedAction.Changed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) { disposition.Changed -= ContentDispositionChanged; } if (ContentDisposition.TryParse(Headers.Options, header.RawValue, out disposition)) { disposition.Changed += ContentDispositionChanged; } break; case HeaderId.ContentLocation: text = header.Value.Trim(); if (Uri.IsWellFormedUriString(text, UriKind.Absolute)) { location = new Uri(text, UriKind.Absolute); } else if (Uri.IsWellFormedUriString(text, UriKind.Relative)) { location = new Uri(text, UriKind.Relative); } else { location = null; } break; case HeaderId.ContentBase: text = header.Value.Trim(); if (Uri.IsWellFormedUriString(text, UriKind.Absolute)) { baseUri = new Uri(text, UriKind.Absolute); } else { baseUri = null; } break; case HeaderId.ContentId: contentId = MimeUtils.EnumerateReferences(header.RawValue, 0, header.RawValue.Length).FirstOrDefault(); break; } break; case HeaderListChangedAction.Removed: switch (header.Id) { case HeaderId.ContentDisposition: if (disposition != null) { disposition.Changed -= ContentDispositionChanged; } disposition = null; break; case HeaderId.ContentLocation: location = null; break; case HeaderId.ContentBase: baseUri = null; break; case HeaderId.ContentId: contentId = null; break; } break; case HeaderListChangedAction.Cleared: if (disposition != null) { disposition.Changed -= ContentDispositionChanged; } disposition = null; contentId = null; location = null; baseUri = null; break; default: throw new ArgumentOutOfRangeException("action"); } }