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.
This commit is contained in:
Axel Dörfler 2013-04-17 22:25:33 +02:00
parent 229c777323
commit 9234fd439e
4 changed files with 105 additions and 4 deletions

View File

@ -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 <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 -

View File

@ -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;
};

View File

@ -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 ] ;

View File

@ -0,0 +1,39 @@
/*
* Copyright 2013, Axel Dörfler, axeld@pinc-software.de.
* 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);
}
}