Permalink
Browse files

Added support for decoding RFC-3501 mailbox names.

* Added new RFC3501Encoding class that implements modified UTF-7 as specified
  in RFC-3501; only decoding is implemented right now.
* ListCommand now uses this new class to encode, and decode the folder names.
  • Loading branch information...
1 parent 59c9129 commit 6a9f445993788f8841b6c66f3cdf88f86b8074e2 @axeld committed Dec 18, 2011
View
12 src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp
@@ -642,7 +642,7 @@ ListCommand::CommandString()
BString command = _Command();
command += " \"\" \"";
if (fPrefix != NULL)
- command << fPrefix << "%";
+ command << fEncoding.Encode(fPrefix) << "%";
else
command += "*";
command += "\"";
@@ -655,7 +655,15 @@ bool
ListCommand::HandleUntagged(Response& response)
{
if (response.IsCommand(_Command()) && response.IsStringAt(3)) {
- fFolders.push_back(response.StringAt(3));
+ BString folder = response.StringAt(3);
+ try {
+ fFolders.push_back(fEncoding.Decode(folder));
+ } catch (ParseException& exception) {
+ // Decoding failed, just add the plain text
+ fprintf(stderr, "Decoding \"%s\" failed: %s\n", folder.String(),
+ exception.Message());
+ fFolders.push_back(folder);
+ }
return true;
}
View
1 src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h
@@ -258,6 +258,7 @@ class ListCommand : public Command, public Handler {
const char* _Command() const;
private:
+ RFC3501Encoding fEncoding;
const char* fPrefix;
StringList fFolders;
bool fSubscribedOnly;
View
117 src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.cpp
@@ -20,6 +20,123 @@
namespace IMAP {
+// Note, the following alphabet is a modified base64; the '/' is replaced by
+// a ',' here.
+static const char kBase64Alphabet[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ '+', ','
+};
+static char kInverseBase64Alphabet[128];
+static bool kInverseBase64Initialized = false;
+
+
+RFC3501Encoding::RFC3501Encoding()
+{
+ if (!kInverseBase64Initialized) {
+ // This is not thread safe, but it's not harmful
+ for (size_t i = 0; i < sizeof(kBase64Alphabet); i++)
+ kInverseBase64Alphabet[kBase64Alphabet[i]] = i + 1;
+ kInverseBase64Initialized = true;
+ }
+}
+
+
+RFC3501Encoding::~RFC3501Encoding()
+{
+}
+
+
+BString
+RFC3501Encoding::Encode(const BString& clearText) const
+{
+ // TODO!
+ return clearText;
+}
+
+
+BString
+RFC3501Encoding::Decode(const BString& encodedText) const
+{
+ int32 end = encodedText.Length();
+ BString buffer;
+ for (int32 i = 0; i < end; i++) {
+ uint8 c = (uint8)encodedText.ByteAt(i);
+ if (c == '&') {
+ if (i < end - 1 && encodedText.ByteAt(i + 1) == '-') {
+ // just add an ampersand
+ buffer += '&';
+ } else {
+ // base64 encoded chunk
+ uint32 value = 0;
+ int32 bitsRead = 0;
+ while (true) {
+ if (++i >= end)
+ throw ParseException("Malformed base64!");
+
+ c = encodedText.ByteAt(i);
+ if (c == '-') {
+ if (value != 0 || bitsRead >= 6)
+ throw ParseException("Base64 encoding ends early!");
+ break;
+ }
+ if (c >= 128)
+ throw ParseException("Malformed base64!");
+ int32 sextet = kInverseBase64Alphabet[c] - 1;
+ if (sextet >= 0) {
+ bitsRead += 6;
+ if (bitsRead < 16) {
+ value += sextet << (16 - bitsRead);
+ } else {
+ bitsRead -= 16;
+ value += sextet >> bitsRead;
+ _ToUTF8(buffer, value);
+
+ // Move on to next character
+ value = (sextet << (16 - bitsRead)) & 0xffff;
+ }
+ } else {
+ buffer += c;
+ if (value != 0 || bitsRead >= 6)
+ throw ParseException("Malformed base64!");
+ break;
+ }
+ }
+ }
+ } else
+ buffer += c;
+ }
+ return buffer;
+}
+
+
+void
+RFC3501Encoding::_ToUTF8(BString& string, uint32 c) const
+{
+ if (c < 0x80)
+ string += (char)c;
+ else if (c < 0x800) {
+ string += 0xc0 | (c >> 6);
+ string += 0x80 | (c & 0x3f);
+ } else if (c < 0x10000) {
+ string += 0xe0 | (c >> 12);
+ string += 0x80 | ((c >> 6) & 0x3f);
+ string += 0x80 | (c & 0x3f);
+ } else if (c <= 0x10ffff) {
+ string += 0xf0 | (c >> 18);
+ string += 0x80 | ((c >> 12) & 0x3f);
+ string += 0x80 | ((c >> 6) & 0x3f);
+ string += 0x80 | (c & 0x3f);
+ }
+}
+
+
+// #pragma mark -
+
+
ArgumentList::ArgumentList()
:
BObjectList<Argument>(5, true)
View
13 src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Response.h
@@ -20,6 +20,19 @@ class Argument;
class Response;
+class RFC3501Encoding {
+public:
+ RFC3501Encoding();
+ ~RFC3501Encoding();
+
+ BString Encode(const BString& clearText) const;
+ BString Decode(const BString& encodedText) const;
+
+private:
+ void _ToUTF8(BString& string, uint32 c) const;
+};
+
+
class ArgumentList : public BObjectList<Argument> {
public:
ArgumentList();

0 comments on commit 6a9f445

Please sign in to comment.