Skip to content

Commit

Permalink
Additional updates for proper encoding (#54); also respects name he…
Browse files Browse the repository at this point in the history
…ader value when reading in attachments (closes #63)
  • Loading branch information
andyedinborough committed Apr 9, 2012
1 parent 43508f8 commit a049cf5
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 25 deletions.
9 changes: 4 additions & 5 deletions Attachment.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using System;
using System.ComponentModel;

namespace AE.Net.Mail {
public class Attachment : ObjectWHeaders {
public string Filename {
get { return Headers["Content-Disposition"]["filename"]; }
get { return Headers["Content-Disposition"]["filename"].NotEmpty(Headers["Content-Disposition"]["name"]); }
}

private string _ContentDisposition;
private string ContentDisposition {
get { return _ContentDisposition ?? (_ContentDisposition = Headers["Content-Disposition"].Value.ToLower()); }
Expand Down Expand Up @@ -36,10 +35,10 @@ public byte[] GetData() {
try {
data = Convert.FromBase64String(Body);
} catch (Exception) {
data = System.Text.Encoding.UTF8.GetBytes(Body);
data = Encoding.GetBytes(Body);
}
} else {
data = System.Text.Encoding.UTF8.GetBytes(Body);
data = Encoding.GetBytes(Body);
}
return data;
}
Expand Down
4 changes: 2 additions & 2 deletions HeaderCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ public MailAddress[] GetAddresses(string header) {
}


public static HeaderDictionary Parse(string headers) {
headers = Utilities.DecodeWords(headers);
public static HeaderDictionary Parse(string headers, System.Text.Encoding encoding) {
headers = Utilities.DecodeWords(headers, encoding);
var temp = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var lines = headers.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int i;
Expand Down
20 changes: 16 additions & 4 deletions HeaderObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public abstract class ObjectWHeaders {
private HeaderDictionary _Headers;
public HeaderDictionary Headers {
get {
return _Headers ?? (_Headers = HeaderDictionary.Parse(RawHeaders));
return _Headers ?? (_Headers = HeaderDictionary.Parse(RawHeaders, Encoding));
}
internal set {
_Headers = value;
Expand Down Expand Up @@ -35,20 +35,32 @@ public string Charset {
}
}

System.Text.Encoding _DefaultEncoding;
System.Text.Encoding _Encoding;
public System.Text.Encoding Encoding {
get {
return _Encoding ?? (_Encoding = Utilities.ParseCharsetToEncoding(Charset, _DefaultEncoding));
}
set {
_DefaultEncoding = value;
if (_Encoding != null) //Encoding has been initialized from the specified Charset
_Encoding = value;
}
}

public string Body { get; set; }

internal void SetBody(string value) {
var encoding = Utilities.ParseCharsetToEncoding(Charset);
if (ContentTransferEncoding.Is("quoted-printable")) {
value = Utilities.DecodeQuotedPrintable(value, encoding);
value = Utilities.DecodeQuotedPrintable(value, Encoding);

} else if (ContentTransferEncoding.Is("base64")
//only decode the content if it is a text document
&& ContentType.StartsWith("text/", StringComparison.OrdinalIgnoreCase)
&& Utilities.IsValidBase64String(value)) {
var data = Convert.FromBase64String(value);
using (var mem = new System.IO.MemoryStream(data))
using (var str = new System.IO.StreamReader(mem, encoding))
using (var str = new System.IO.StreamReader(mem, Encoding))
value = str.ReadToEnd();

ContentTransferEncoding = string.Empty;
Expand Down
2 changes: 1 addition & 1 deletion ImapClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ public MailMessage[] GetMessages(string start, string end, bool uid, bool header
if (response[0] != '*' || !response.Contains("FETCH ("))
continue;

var mail = new MailMessage();
var mail = new MailMessage { Encoding = Encoding };
var imapHeaders = ParseImapHeader(response.Substring(response.IndexOf('(') + 1));
mail.Size = (imapHeaders["BODY[HEADER]"] ?? imapHeaders["BODY[]"]).Trim('{', '}').ToInt();

Expand Down
7 changes: 2 additions & 5 deletions MailMessage.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net.Mail;
Expand Down Expand Up @@ -78,7 +76,6 @@ public MailMessage() {
public string Raw { get; private set; }
public MailPriority Importance { get; set; }


public void Load(string message, bool headersOnly = false) {
Raw = message;
using (var reader = new StringReader(message)) {
Expand Down Expand Up @@ -141,7 +138,7 @@ public void Load(TextReader reader, bool headersOnly = false) {
Importance = Headers.GetEnum<MailPriority>("Importance");
Subject = Headers["Subject"].RawValue;
}

private void ParseMime(TextReader reader, string boundary) {
string data,
bounderInner = "--" + boundary,
Expand All @@ -153,7 +150,7 @@ private void ParseMime(TextReader reader, string boundary) {

while (data != null && !data.StartsWith(bounderOuter)) {
data = reader.ReadLine();
var a = new Attachment();
var a = new Attachment { Encoding = Encoding };

var part = new StringBuilder();
// read part header
Expand Down
16 changes: 8 additions & 8 deletions Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ internal static bool StartsWithWhiteSpace(this string line) {

internal static string DecodeQuotedPrintable(string value, Encoding encoding = null) {
if (encoding == null) {
encoding = System.Text.Encoding.UTF8;
encoding = System.Text.Encoding.Default;
}

if (value.IndexOf('_') > -1 && value.IndexOf(' ') == -1)
Expand Down Expand Up @@ -125,11 +125,11 @@ internal static string DecodeBase64(string data, Encoding encoding = null) {
return data;
}
var bytes = Convert.FromBase64String(data);
return (encoding ?? System.Text.Encoding.UTF8).GetString(bytes);
return (encoding ?? System.Text.Encoding.Default).GetString(bytes);
}

#region OpenPOP.NET
internal static string DecodeWords(string encodedWords) {
internal static string DecodeWords(string encodedWords, Encoding @default) {
if (string.IsNullOrEmpty(encodedWords))
return string.Empty;

Expand Down Expand Up @@ -162,7 +162,7 @@ internal static string DecodeWords(string encodedWords) {
string charset = match.Groups["Charset"].Value;

// Get the encoding which corrosponds to the character set
Encoding charsetEncoding = ParseCharsetToEncoding(charset);
Encoding charsetEncoding = ParseCharsetToEncoding(charset, @default);

// Store decoded text here when done
string decodedText;
Expand Down Expand Up @@ -204,9 +204,9 @@ internal static string DecodeWords(string encodedWords) {
/// <param name="characterSet">The character set to parse</param>
/// <returns>An encoding which corresponds to the character set</returns>
/// <exception cref="ArgumentNullException">If <paramref name="characterSet"/> is <see langword="null"/></exception>
public static Encoding ParseCharsetToEncoding(string characterSet) {
public static Encoding ParseCharsetToEncoding(string characterSet, Encoding @default) {
if (string.IsNullOrEmpty(characterSet))
return Encoding.Default;
return @default ?? Encoding.Default;

string charSetUpper = characterSet.ToUpperInvariant();
if (charSetUpper.Contains("WINDOWS") || charSetUpper.Contains("CP")) {
Expand All @@ -219,12 +219,12 @@ public static Encoding ParseCharsetToEncoding(string characterSet) {
int codepageNumber = int.Parse(charSetUpper, System.Globalization.CultureInfo.InvariantCulture);

return Encoding.GetEncodings().Where(x => x.CodePage == codepageNumber)
.Select(x => x.GetEncoding()).FirstOrDefault() ?? Encoding.Default;
.Select(x => x.GetEncoding()).FirstOrDefault() ?? @default ?? Encoding.Default;
}

// It seems there is no codepage value in the characterSet. It must be a named encoding
return Encoding.GetEncodings().Where(x => x.Name.Is(characterSet))
.Select(x => x.GetEncoding()).FirstOrDefault() ?? Encoding.Default;
.Select(x => x.GetEncoding()).FirstOrDefault() ?? @default ?? System.Text.Encoding.Default;
}
#endregion

Expand Down

0 comments on commit a049cf5

Please sign in to comment.