added 1 changeset to branch 'refs/remotes/axeld-github/imap' old head: ce277462a563387065533e5ce790b4a1a32a04dd new head: 94631a592c79e8c1ad3cec6a94500544fb6834da overview: https://github.com/axeld/haiku/compare/ce27746...94631a5 ---------------------------------------------------------------------------- 94631a5: imap: Implemented encoding RFC3501 strings. * Was completely missing so far. * Fixed bug in decoding that handled the "&-" sequence incorrectly. * Added small test application that should easily be convertible to a unit test. [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: 94631a592c79e8c1ad3cec6a94500544fb6834da Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> Date: Wed Apr 17 20:25:33 2013 UTC ---------------------------------------------------------------------------- 4 files changed, 105 insertions(+), 4 deletions(-) .../inbound_protocols/imap/imap_lib/Response.cpp | 59 +++++++++++++++++++- .../inbound_protocols/imap/imap_lib/Response.h | 4 +- src/tests/add-ons/mail/imap/Jamfile | 7 +++ .../add-ons/mail/imap/rfc3501_encoding_test.cpp | 39 +++++++++++++ ---------------------------------------------------------------------------- diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp index 101e6ff..d27b4c4 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2011-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * Distributed under the terms of the MIT License. */ @@ -8,6 +8,8 @@ #include <stdlib.h> +#include <UnicodeChar.h> + #define TRACE_IMAP #ifdef TRACE_IMAP @@ -53,8 +55,41 @@ RFC3501Encoding::~RFC3501Encoding() BString RFC3501Encoding::Encode(const BString& clearText) const { - // TODO! - return clearText; + const char* clear = clearText.String(); + bool shifted = false; + int32 bitsToWrite = 0; + int32 sextet = 0; + BString buffer; + + while (true) { + uint32 c = BUnicodeChar::FromUTF8(&clear); + if (c == 0) + break; + + if (!shifted && c == '&') + buffer += "&-"; + else if (c >= 0x20 && c <= 0x7e) { + _Unshift(buffer, bitsToWrite, sextet, shifted); + buffer += c; + } else { + // Enter shifted mode, encode in base64 + if (!shifted) { + buffer += '&'; + shifted = true; + } + + bitsToWrite += 16; + while (bitsToWrite >= 6) { + bitsToWrite -= 6; + buffer += kBase64Alphabet[(sextet + (c >> bitsToWrite)) & 0x3f]; + sextet = 0; + } + sextet = (c << (6 - bitsToWrite)) & 0x3f; + } + } + + _Unshift(buffer, bitsToWrite, sextet, shifted); + return buffer; } @@ -69,6 +104,7 @@ RFC3501Encoding::Decode(const BString& encodedText) const if (i < end - 1 && encodedText.ByteAt(i + 1) == '-') { // just add an ampersand buffer += '&'; + i++; } else { // base64 encoded chunk uint32 value = 0; @@ -134,6 +170,23 @@ RFC3501Encoding::_ToUTF8(BString& string, uint32 c) const } +//! Exit base64, or "shifted" mode. +void +RFC3501Encoding::_Unshift(BString& buffer, int32& bitsToWrite, int32& sextet, + bool& shifted) const +{ + if (!shifted) + return; + + if (bitsToWrite != 0) + buffer += kBase64Alphabet[sextet]; + buffer += '-'; + sextet = 0; + bitsToWrite = 0; + shifted = false; +} + + // #pragma mark - diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h index 87c0059..7460cf4 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Copyright 2011-2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * Distributed under the terms of the MIT License. */ #ifndef RESPONSE_H @@ -30,6 +30,8 @@ public: private: void _ToUTF8(BString& string, uint32 c) const; + void _Unshift(BString& string, int32& bitsToWrite, + int32& sextet, bool& shifted) const; }; diff --git a/src/tests/add-ons/mail/imap/Jamfile b/src/tests/add-ons/mail/imap/Jamfile index 7eecdc8..75a0916 100644 --- a/src/tests/add-ons/mail/imap/Jamfile +++ b/src/tests/add-ons/mail/imap/Jamfile @@ -33,6 +33,13 @@ SimpleTest imap_tester : : be $(TARGET_LIBSTDC++) $(TARGET_LIBSUPC++) bnetapi mail ; +SimpleTest rfc3501_encoding_test : + rfc3501_encoding_test.cpp + $(libSources) + + : be $(TARGET_LIBSTDC++) $(TARGET_LIBSUPC++) bnetapi +; + SEARCH on [ FGristFiles $(libSources) ] = [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap imap_lib ] ; diff --git a/src/tests/add-ons/mail/imap/rfc3501_encoding_test.cpp b/src/tests/add-ons/mail/imap/rfc3501_encoding_test.cpp new file mode 100644 index 0000000..cf5f085 --- /dev/null +++ b/src/tests/add-ons/mail/imap/rfc3501_encoding_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include "Response.h" + + +void +assertEquals(const char* expected, const char* result) +{ + if (strcmp(expected, result) != 0) { + printf("Expected \"%s\", got \"%s\"\n", expected, result); + exit(EXIT_FAILURE); + } +} + + +int +main() +{ + const char* samples[] = { + "Gelöscht", "Gel&APY-scht", + "&äöß", "&-&AOQA9gDf-" + }; + + IMAP::RFC3501Encoding encoding; + + for (size_t i = 0; i < sizeof(samples) / sizeof(samples[0]); i += 2) { + BString encoded = encoding.Encode(samples[i]); + assertEquals(samples[i + 1], encoded); + BString decoded = encoding.Decode(encoded); + assertEquals(samples[i], decoded); + } +}