From 9234fd439edf8e9047e7eceb9ad34ee39b192edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 17 Apr 2013 22:25:33 +0200 Subject: [PATCH] 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. --- .../imap/imap_lib/Response.cpp | 59 ++++++++++++++++++- .../imap/imap_lib/Response.h | 4 +- src/tests/add-ons/mail/imap/Jamfile | 7 +++ .../mail/imap/rfc3501_encoding_test.cpp | 39 ++++++++++++ 4 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/tests/add-ons/mail/imap/rfc3501_encoding_test.cpp 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 101e6ff011..d27b4c4976 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@pinc-software.de. + * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -8,6 +8,8 @@ #include +#include + #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 87c00591df..7460cf421a 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@pinc-software.de. + * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. * 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 da961518f7..847fd8c00f 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 [ TargetLibstdc++ ] [ TargetLibsupc++ ] 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 0000000000..cf5f0859af --- /dev/null +++ b/src/tests/add-ons/mail/imap/rfc3501_encoding_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#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); + } +}