diff --git a/email.d b/email.d index 6c704ca..a665650 100644 --- a/email.d +++ b/email.d @@ -9,6 +9,9 @@ pragma(lib, "curl"); import std.base64; import std.string; import std.range; +import std.utf; +import std.array; +import std.algorithm.iteration; import arsd.characterencodings; @@ -866,18 +869,10 @@ class IncomingEmailMessage { break; case "base64": if(textMessageBody.length) { - // alas, phobos' base64 decoder cannot accept ranges, so we have to allocate here - char[] mmb; - mmb.reserve(textMessageBody.length); - foreach (char ch; textMessageBody) if (ch > ' ' && ch < 127) mmb ~= ch; - textMessageBody = convertToUtf8Lossy(Base64.decode(mmb), charset); + textMessageBody = textMessageBody.decodeBase64Mime.convertToUtf8Lossy(charset); } if(htmlMessageBody.length) { - // alas, phobos' base64 decoder cannot accept ranges, so we have to allocate here - char[] mmb; - mmb.reserve(htmlMessageBody.length); - foreach (char ch; htmlMessageBody) if (ch > ' ' && ch < 127) mmb ~= ch; - htmlMessageBody = convertToUtf8Lossy(Base64.decode(mmb), charset); + htmlMessageBody = htmlMessageBody.decodeBase64Mime.convertToUtf8Lossy(charset); } break; @@ -1172,6 +1167,20 @@ string encodeBase64Mime(const(ubyte[]) content, string LINESEP = "\r\n") { return cast(immutable(char[]))content.chunks(SOURCE_CHUNK_LENGTH).base64encode.join(LINESEP); } +/// Base64 range decoder UFCS helper. +alias base64decode = Base64.decoder; + +/// Base64 decoder, ignoring linebreaks which are mandated by RFC2045 +immutable(ubyte[]) decodeBase64Mime(string encodedPart) { + return cast(immutable(ubyte[])) encodedPart + .byChar // prevent Autodecoding, which will break Base64 decoder. Since its base64, it's guarenteed to be 7bit ascii + .filter!((c) => c != '\r') + .splitter!((c) => c == '\n') + .joiner + .base64decode + .array; +} + /+ void main() { import std.file;