diff --git a/ActiveUp.Net.sln b/ActiveUp.Net.sln
index 533b108..35225b8 100644
--- a/ActiveUp.Net.sln
+++ b/ActiveUp.Net.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.26020.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Class Library", "Class Library", "{629D406B-F46A-4A9D-A31F-C5956E0AB157}"
EndProject
diff --git a/Class Library/ActiveUp.Net.Common/ActiveUp.Net.Common.csproj b/Class Library/ActiveUp.Net.Common/ActiveUp.Net.Common.csproj
index 3646690..d68f9ce 100644
--- a/Class Library/ActiveUp.Net.Common/ActiveUp.Net.Common.csproj
+++ b/Class Library/ActiveUp.Net.Common/ActiveUp.Net.Common.csproj
@@ -119,6 +119,7 @@
+
diff --git a/Class Library/ActiveUp.Net.Common/Extensions.cs b/Class Library/ActiveUp.Net.Common/Extensions.cs
new file mode 100644
index 0000000..29e8ee0
--- /dev/null
+++ b/Class Library/ActiveUp.Net.Common/Extensions.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ActiveUp.Net.Common
+{
+ ///
+ /// Some general extension methodes
+ ///
+ public static class Extensions
+ {
+ ///
+ /// Searches a array for the occurance of another array
+ ///
+ ///
+ /// the array to search in
+ /// the array which should be found in the
+ ///
+ public static IEnumerable IndexOf(this T[] haystack, T[] needle)
+ {
+ if ((needle != null) && (haystack.Length >= needle.Length))
+ {
+ for (int l = 0; l < haystack.Length - needle.Length + 1; l++)
+ {
+ if (!needle.Where((data, index) => !haystack[l + index].Equals(data)).Any())
+ yield return l;
+ }
+ }
+ }
+
+ ///
+ /// Converts the byte array to an ASCII encoded string.
+ ///
+ /// The byte array to convert
+ public static string ToASCII(this byte[] data)
+ {
+ const int BUFFER_SIZE = 2048;
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < data.Length; i += BUFFER_SIZE)
+ sb.Append(ConvertByteBlock(data, i, Math.Min(BUFFER_SIZE, data.Length - i)));
+
+ return sb.ToString();
+ }
+
+ private static string ConvertByteBlock(byte[] data, int start, int length)
+ {
+ return Encoding.ASCII.GetString(data, start, length);
+ }
+ }
+}
diff --git a/Class Library/ActiveUp.Net.Common/MimePart.cs b/Class Library/ActiveUp.Net.Common/MimePart.cs
index 5ac8f98..827469d 100644
--- a/Class Library/ActiveUp.Net.Common/MimePart.cs
+++ b/Class Library/ActiveUp.Net.Common/MimePart.cs
@@ -21,6 +21,7 @@
using System.Linq;
using System.Collections.Generic;
using ActiveUp.Net.Common.Rfc2047;
+using ActiveUp.Net.Common;
#if !PocketPC
using System.Security.Cryptography.Pkcs;
#endif
@@ -356,6 +357,14 @@ private string Base64EncodeAndWrap()
///
public string OriginalContent { get; set; }
+ ///
+ /// Decodes the again to
+ ///
+ public void DecodeOriginalContent()
+ {
+ OriginalContent = BinaryContent.ToASCII();
+ }
+
///
/// The Content-Type of the MimePart.
///
diff --git a/Class Library/ActiveUp.Net.Common/Parser.cs b/Class Library/ActiveUp.Net.Common/Parser.cs
index 79b31a8..024bc7e 100644
--- a/Class Library/ActiveUp.Net.Common/Parser.cs
+++ b/Class Library/ActiveUp.Net.Common/Parser.cs
@@ -23,6 +23,8 @@
using System.Text;
using ActiveUp.Net.Security;
using System.IO;
+using ActiveUp.Net.Common;
+using System.Linq;
namespace ActiveUp.Net.Mail
{
@@ -133,55 +135,36 @@ private static int GetASCIIByteCountOfPart(string part)
/// Parses the sub parts.
///
/// The part.
- private static void ParseSubParts(ref MimePart part, Message message)
+ /// The message to add the data
+ /// removes the original content string from mime parts. To get the string later, use
+ private static void ParseSubParts(ref MimePart part, Message message, bool compact)
{
- string boundary = part.ContentType.Parameters["boundary"];
- string parentPartAsciiBody = ToASCII(part.BinaryContent);
byte[] parentPartBinary = part.BinaryContent;
+ byte[] boundary = Encoding.ASCII.GetBytes("--" + part.ContentType.Parameters["boundary"]);
+ int[] boundaryPositions = parentPartBinary.IndexOf(boundary).ToArray();
+ int last = 0;
- Logger.AddEntry(typeof(Parser), "boundary : " + boundary);
- string[] arrpart = Regex.Split(parentPartAsciiBody, @"\r?\n?" + Regex.Escape("--" + boundary));
-
- foreach (var strpart in arrpart)
+ foreach (int pos in boundaryPositions)
{
- if (string.IsNullOrWhiteSpace(strpart))
+ if (pos == 0)
continue;
-
- int bounaryByteLen = GetASCIIByteCountOfPart(parentPartAsciiBody.Substring(0, parentPartAsciiBody.IndexOf(strpart)));
- int binaryPartLen = bounaryByteLen + GetASCIIByteCountOfPart(strpart);
- parentPartAsciiBody = null;
-
//complete Part (incl. boundary)
- byte[] binaryPart = new byte[binaryPartLen];
- Array.Copy(parentPartBinary, binaryPart, binaryPart.Length);
+ byte[] binaryPart = new byte[pos - last];
+ Array.Copy(parentPartBinary, last, binaryPart, 0, binaryPart.Length);
//Body only (without Boundary)
- byte[] binaryBody = new byte[GetASCIIByteCountOfPart(strpart)];
- Array.Copy(binaryPart, bounaryByteLen, binaryBody, 0, binaryBody.Length);
-
- //Remove Subpart from ParentPart
- byte[] tmp = new byte[parentPartBinary.Length - binaryPart.Length];
- Array.Copy(parentPartBinary, binaryPart.Length, tmp, 0, (parentPartBinary.Length - binaryPart.Length));
+ int bodyLength = pos - last - (boundary.Length + 2);
+ if (bodyLength <= 0)
+ continue;
+ byte[] binaryBody = new byte[bodyLength];
+ Array.Copy(binaryPart, (boundary.Length + 2), binaryBody, 0, binaryBody.Length);
- parentPartBinary = null;
binaryPart = null;
- GC.Collect(GC.MaxGeneration);
- GC.WaitForPendingFinalizers();
-
- parentPartBinary = tmp;
- parentPartAsciiBody = ToASCII(parentPartBinary);
- tmp = null;
- if (!strpart.StartsWith("--") && !string.IsNullOrEmpty(strpart))
- {
- MimePart newpart = ParseMimePart(binaryBody, message);
- newpart.Container = part;
- part.SubParts.Add(newpart);
- }
-
- binaryBody = null;
- GC.Collect(GC.MaxGeneration);
- GC.WaitForPendingFinalizers();
+ MimePart newpart = ParseMimePart(binaryBody, message, compact);
+ newpart.Container = part;
+ part.SubParts.Add(newpart);
+ last = pos;
}
}
@@ -192,8 +175,8 @@ private static void ParseSubParts(ref MimePart part, Message message)
/// The message.
private static void DispatchParts(MimePart root, ref Message message)
{
- foreach (MimePart entity in root.SubParts)
- DispatchPart(entity, ref message);
+ foreach (MimePart part in root.SubParts)
+ DispatchPart(part, ref message);
}
///
@@ -314,7 +297,7 @@ private static void DecodePartBody(ref MimePart part)
}
else if (part.ContentTransferEncoding.Equals(ContentTransferEncoding.QuotedPrintable))
{
- part.TextContent = Codec.FromQuotedPrintable(ToASCII(part.BinaryContent), charset);
+ part.TextContent = Codec.FromQuotedPrintable(part.BinaryContent.ToASCII(), charset);
part.BinaryContent = Codec.GetEncoding(charset).GetBytes(part.TextContent);
}
else
@@ -330,7 +313,7 @@ private static void DecodePartBody(ref MimePart part)
private static void DecodeBase64Part(MimePart part, string charset)
{
- string text = ToASCII(part.BinaryContent);
+ string text = part.BinaryContent.ToASCII();
byte[] binary = null;
#if !PocketPC
try
@@ -345,7 +328,7 @@ private static void DecodeBase64Part(MimePart part, string charset)
binary = Convert.FromBase64String(text);
}
#endif
- text = ToASCII(binary);
+ text = binary.ToASCII();
if (part.ContentDisposition != ContentDisposition.Attachment)
text = Codec.GetEncoding(charset).GetString(binary, 0, binary.Length);
@@ -451,7 +434,7 @@ public static string Unfold(string input)
/// Delegate for body parsed event.
///
/// The sender object.
- /// The header object.
+ /// The message object.
public delegate void OnBodyParsedEvent(object sender, Message message);
///
@@ -459,21 +442,6 @@ public static string Unfold(string input)
///
public static event OnBodyParsedEvent BodyParsed;
- private static string ToASCII(byte[] data)
- {
- const int BUFFER_SIZE = 2048;
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < data.Length; i += BUFFER_SIZE)
- sb.Append(ConvertByteBlock(data, i, Math.Min(BUFFER_SIZE, data.Length - i)));
-
- return sb.ToString();
- }
-
- private static string ConvertByteBlock(byte[] data, int start, int length)
- {
- return Encoding.ASCII.GetString(data, start, length);
- }
-
private static void ParseHeaderFields(MimePart part, int headerEnd)
{
string header = Unfold(part.OriginalContent.Substring(0, headerEnd));
@@ -504,12 +472,14 @@ private static void ParseBody(byte[] binaryData, MimePart part, int bodyStart)
/// Parses the MIME part.
///
/// The data.
+ /// The message to add the data
+ /// removes the original content string from mime parts. To get the string later, use
///
- public static MimePart ParseMimePart(byte[] binaryData, Message message)
+ public static MimePart ParseMimePart(byte[] binaryData, Message message, bool compact)
{
MimePart part = new MimePart();
part.ParentMessage = message;
- part.OriginalContent = ToASCII(binaryData); //ASCII content for header parsing
+ part.OriginalContent = binaryData.ToASCII(); //ASCII content for header parsing
try
{
@@ -532,9 +502,7 @@ public static MimePart ParseMimePart(byte[] binaryData, Message message)
// Build the part tree.
// This is a container part.
if (part.ContentType.Type.ToLower().Equals("multipart"))
- {
- ParseSubParts(ref part, message);
- }
+ ParseSubParts(ref part, message, compact);
// This is a nested message.
else if (part.ContentType.Type.ToLower().Equals("message"))
{
@@ -542,11 +510,11 @@ public static MimePart ParseMimePart(byte[] binaryData, Message message)
}
// Other types.
else
- {
DecodePartBody(ref part);
- }
- // Call event id BodyParsed is not null.
+ if (compact)
+ part.OriginalContent = null;
+
BodyParsed?.Invoke(null, message);
}
}
@@ -779,7 +747,7 @@ public static Header ParseHeaderString(string data)
/// Delegate for OnErrorParsingEvent.
///
/// The sender object.
- /// The exception object.
+ /// The exception object.
public delegate void OnErrorParsingEvent(object sender, Exception ex);
///
@@ -791,15 +759,16 @@ public static Header ParseHeaderString(string data)
/// Parses the message.
///
/// The data.
+ /// removes the original content string from mime parts. To get the string later, use
///
- public static Message ParseMessage(byte[] data)
+ public static Message ParseMessage(byte[] data, bool compact = false)
{
Message message = new Message();
try
{
// Build a part tree and get all headers.
- MimePart part = ParseMimePart(data, message);
+ MimePart part = ParseMimePart(data, message, compact);
// Fill a new message object with the new information.
message.OriginalData = data;
@@ -861,8 +830,7 @@ public static Message ParseMessage(byte[] data)
}
catch (Exception ex)
{
- if (ErrorParsing != null)
- ErrorParsing(null, ex);
+ ErrorParsing?.Invoke(null, ex);
}
return message;
@@ -872,6 +840,7 @@ public static Message ParseMessage(byte[] data)
/// Parses a MemoryStream's content to a Message object.
///
/// The MemoryStream containing the Header data to be parsed.
+ /// removes the original content string from mime parts. To get the string later, use
/// The parsed Header as a Message object.
///
///
@@ -894,13 +863,13 @@ public static Message ParseMessage(byte[] data)
/// var subject:string = message.Subject;
///
///
- public static Message ParseMessage(MemoryStream inputStream)
+ public static Message ParseMessage(MemoryStream inputStream, bool compact = false)
{
byte[] buf = new byte[inputStream.Length];
inputStream.Read(buf, 0, buf.Length);
Message msg = new Message();
msg.OriginalData = buf;
- ParseMessage(buf);
+ ParseMessage(buf, compact);
return msg;
}
@@ -908,6 +877,7 @@ public static Message ParseMessage(MemoryStream inputStream)
/// Parses a Message from a string formatted accordingly to the RFC822.
///
/// The string containing the message data to be parsed.
+ /// removes the original content string from mime parts. To get the string later, use
/// The parsed message as a Message object.
///
///
@@ -930,10 +900,10 @@ public static Message ParseMessage(MemoryStream inputStream)
/// var subject:string = message.Subject;
///
///
- public static Message ParseMessage(string data)
+ public static Message ParseMessage(string data, bool compact = false)
{
#if !PocketPC
- return ParseMessage(Encoding.GetEncoding("iso-8859-1").GetBytes(data));
+ return ParseMessage(Encoding.GetEncoding("iso-8859-1").GetBytes(data), compact);
#else
return Parser.ParseMessage(Pop3Client.PPCEncode.GetBytes(data));
#endif
@@ -943,6 +913,7 @@ public static Message ParseMessage(string data)
/// Parses a message from a file to a Message object.
///
/// The path of the file to be parsed.
+ /// removes the original content string from mime parts. To get the string later, use
/// The parsed message as a Message object.
///
///
@@ -965,7 +936,7 @@ public static Message ParseMessage(string data)
/// var subject:string = message.Subject;
///
///
- public static Message ParseMessageFromFile(string filePath)
+ public static Message ParseMessageFromFile(string filePath, bool compact = false)
{
byte[] data = null;
@@ -974,7 +945,7 @@ public static Message ParseMessageFromFile(string filePath)
data = new byte[fs.Length];
ReadStream(fs, data);
}
- return ParseMessage(data);
+ return ParseMessage(data, compact);
}
private static void ReadStream(Stream stream, byte[] data)
diff --git a/Class Library/ActiveUp.Net.Imap4/Imap4Client.cs b/Class Library/ActiveUp.Net.Imap4/Imap4Client.cs
index 407f536..7656b40 100644
--- a/Class Library/ActiveUp.Net.Imap4/Imap4Client.cs
+++ b/Class Library/ActiveUp.Net.Imap4/Imap4Client.cs
@@ -1160,19 +1160,20 @@ public byte[] CommandBinary(string command, string stamp, CommandOptions options
}
}
- var bufferString = buffer.ToString();
byte[] bufferBytes = new byte[sr.BaseStream.Length];
sr.BaseStream.Seek(0, SeekOrigin.Begin);
sr.BaseStream.Read(bufferBytes, 0, bufferBytes.Length);
- if (!sr.CurrentEncoding.Equals(Encoding.UTF8))
- {
- var utf8Bytes = Encoding.Convert(sr.CurrentEncoding, Encoding.UTF8, sr.CurrentEncoding.GetBytes(bufferString));
- bufferString = Encoding.UTF8.GetString(utf8Bytes);
- }
-
if (buffer.Length < 200)
+ {
+ var bufferString = buffer.ToString();
+ if (!sr.CurrentEncoding.Equals(Encoding.UTF8))
+ {
+ var utf8Bytes = Encoding.Convert(sr.CurrentEncoding, Encoding.UTF8, sr.CurrentEncoding.GetBytes(bufferString));
+ bufferString = Encoding.UTF8.GetString(utf8Bytes);
+ }
OnTcpRead(new TcpReadEventArgs(bufferString));
+ }
else
OnTcpRead(new TcpReadEventArgs("long data"));
if (lastLine.StartsWith(stamp + " OK") || lastLine.ToLower().StartsWith("* " + command.Split(' ')[0].ToLower()) || lastLine.StartsWith("+ "))
@@ -1185,13 +1186,13 @@ public byte[] CommandBinary(string command, string stamp, CommandOptions options
private bool CheckResponse(StringBuilder buffer, string command, string lastLineOfPartResponse, ref string lastLine, string stamp)
{
if (buffer.Length > 100)
- lastLineOfPartResponse = buffer.ToString().Substring(buffer.Length - 100).Replace("\r\n", "");
+ lastLineOfPartResponse = buffer.ToString(buffer.Length - 100, 100).Replace("\r\n", "");
else
lastLineOfPartResponse = buffer.ToString().Replace("\r\n", "");
int stampPos = lastLineOfPartResponse.IndexOf(stamp + " OK");
if (stampPos >= 0)
{
- if (buffer.ToString().EndsWith("\n") || buffer.ToString().EndsWith("\r"))
+ if (buffer.ToString(buffer.Length - 100, 100).EndsWith("\n") || buffer.ToString(buffer.Length - 100, 100).EndsWith("\r"))
{
lastLine = lastLineOfPartResponse.Substring(stampPos);
return true;
@@ -1200,7 +1201,7 @@ private bool CheckResponse(StringBuilder buffer, string command, string lastLine
stampPos = lastLineOfPartResponse.IndexOf(stamp + " NO");
if (stampPos >= 0)
{
- if (buffer.ToString().EndsWith("\n") || buffer.ToString().EndsWith("\r"))
+ if (buffer.ToString(buffer.Length - 100, 100).EndsWith("\n") || buffer.ToString(buffer.Length - 100, 100).EndsWith("\r"))
{
lastLine = lastLineOfPartResponse.Replace(stamp, "");
throw new Imap4Exception("Command \"" + command + "\" failed\r\nServer replied:" + lastLine);
@@ -1209,7 +1210,7 @@ private bool CheckResponse(StringBuilder buffer, string command, string lastLine
stampPos = lastLineOfPartResponse.IndexOf(stamp + " BAD");
if (stampPos >= 0)
{
- if (buffer.ToString().EndsWith("\n") || buffer.ToString().EndsWith("\r"))
+ if (buffer.ToString(buffer.Length - 100, 100).EndsWith("\n") || buffer.ToString(buffer.Length - 100, 100).EndsWith("\r"))
{
lastLine = lastLineOfPartResponse.Replace(stamp, "");
throw new Imap4Exception("Command \"" + command + "\" failed\r\nServer replied:" + lastLine);