diff options
author | Mark Brand <mabrand@mabrand.nl> | 2012-11-12 20:56:00 (GMT) |
---|---|---|
committer | Mark Brand <mabrand@mabrand.nl> | 2012-11-12 20:59:08 (GMT) |
commit | 34dee5aa6389a7ff82a4c9e633d066c614e2f42b (patch) | |
tree | 60272521d9af416f22138b630c9ee25a108cfffa | |
parent | 3f212f54367eb8b1a0908743957273c436f739ad (diff) | |
download | mxe-34dee5aa6389a7ff82a4c9e633d066c614e2f42b.zip mxe-34dee5aa6389a7ff82a4c9e633d066c614e2f42b.tar.gz mxe-34dee5aa6389a7ff82a4c9e633d066c614e2f42b.tar.bz2 |
package vmime: use github tarball
This seems like a much better idea than applying our own copy
of the patches to the 0.9.1 tarball.
-rw-r--r-- | index.html | 4 | ||||
-rw-r--r-- | src/vmime-1-fixes.patch | 10488 | ||||
-rw-r--r-- | src/vmime.mk | 14 |
3 files changed, 9 insertions, 10497 deletions
@@ -1920,8 +1920,8 @@ USE_OSGPLUGIN(<plugin2>) </tr> <tr> <td id="vmime-package">vmime</td> - <td id="vmime-version">0.9.1</td> - <td id="vmime-website"><a href="http://vmime.sourceforge.net/">VMime</a></td> + <td id="vmime-version">794afe9</td> + <td id="vmime-website"><a href="http://www.vmime.org/">VMime</a></td> </tr> <tr> <td id="vorbis-package">vorbis</td> diff --git a/src/vmime-1-fixes.patch b/src/vmime-1-fixes.patch deleted file mode 100644 index 69a5df4..0000000 --- a/src/vmime-1-fixes.patch +++ /dev/null @@ -1,10488 +0,0 @@ -This file is part of MXE. -See index.html for further information. - -Commits from master branch of git://github.com/kisli/vmime -rebased onto version 0.9.1 tarball files. - -From 17ff5157ffdc749f60b8285f84e64ac5e06d4283 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Tue, 16 Nov 2010 13:28:05 +0000 -Subject: [PATCH 01/47] Started version 0.9.2. - - -diff --git a/ChangeLog b/ChangeLog -index 871d055..8fdcdb0 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,4 +1,12 @@ - -+VERSION 0.9.2svn -+================ -+ -+2010-11-16 Vincent Richard <vincent@vincent-richard.net> -+ -+ * Started version 0.9.2. -+ -+ - VERSION 0.9.1 - ============= - -diff --git a/SConstruct b/SConstruct -index fb01edf..55f9223 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -29,7 +29,7 @@ import string - # Package version number - packageVersionMajor = 0 - packageVersionMinor = 9 --packageVersionMicro = 1 -+packageVersionMicro = 2 - - # API version number (libtool) - # --- -1.7.10.4 - - -From c12ee2b267b9dcfd092a298dfd9a8eec81ab3a0b Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Tue, 30 Nov 2010 14:57:03 +0000 -Subject: [PATCH 02/47] Initialize and delete object. - - -diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp -index 0f3e9ec..d71c3ca 100644 ---- a/vmime/net/imap/IMAPParser.hpp -+++ b/vmime/net/imap/IMAPParser.hpp -@@ -3823,7 +3823,9 @@ public: - - msg_att_item() - : m_date_time(NULL), m_number(NULL), m_envelope(NULL), -- m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL) -+ m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL), -+ m_section(NULL) -+ - { - } - -@@ -3836,6 +3838,7 @@ public: - delete (m_nstring); - delete (m_body); - delete (m_flag_list); -+ delete (m_section); - } - - void go(IMAPParser& parser, string& line, string::size_type* currentPos) --- -1.7.10.4 - - -From fd277afe87485c9d3377964794b76006c6d36a56 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Wed, 8 Dec 2010 08:52:54 +0000 -Subject: [PATCH 03/47] No extra space between ':' and '<' in MAIL FROM and - RCPT TO. Wait for server response after QUIT and - before closing connection. - - -diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp -index 204daae..d9fb7b8 100644 ---- a/src/net/smtp/SMTPTransport.cpp -+++ b/src/net/smtp/SMTPTransport.cpp -@@ -516,6 +516,7 @@ void SMTPTransport::internalDisconnect() - try - { - sendRequest("QUIT"); -+ readResponse(); - } - catch (exception&) - { -@@ -565,7 +566,7 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients - // Emit the "MAIL" command - ref <SMTPResponse> resp; - -- sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">"); -+ sendRequest("MAIL FROM:<" + expeditor.getEmail() + ">"); - - if ((resp = readResponse())->getCode() != 250) - { -@@ -578,7 +579,7 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients - { - const mailbox& mbox = *recipients.getMailboxAt(i); - -- sendRequest("RCPT TO: <" + mbox.getEmail() + ">"); -+ sendRequest("RCPT TO:<" + mbox.getEmail() + ">"); - - if ((resp = readResponse())->getCode() != 250) - { --- -1.7.10.4 - - -From d64da50e879c0e480d2e65c43e3b903c3e80101f Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 10 Dec 2010 16:24:06 +0000 -Subject: [PATCH 04/47] Fixed unit test after bug fix. - - -diff --git a/tests/net/smtp/SMTPTransportTest.cpp b/tests/net/smtp/SMTPTransportTest.cpp -index 5015552..6552f9e 100644 ---- a/tests/net/smtp/SMTPTransportTest.cpp -+++ b/tests/net/smtp/SMTPTransportTest.cpp -@@ -165,7 +165,7 @@ public: - } - else if (cmd == "MAIL") - { -- VASSERT_EQ("MAIL", std::string("MAIL FROM: <expeditor@test.vmime.org>"), line); -+ VASSERT_EQ("MAIL", std::string("MAIL FROM:<expeditor@test.vmime.org>"), line); - - localSend("250 OK\r\n"); - } --- -1.7.10.4 - - -From 130d0aabda2a9988913ad201390796775dc16a65 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 10 Dec 2010 16:54:38 +0000 -Subject: [PATCH 05/47] Fixed boundary parsing (thanks to John van der Kamp, - Zarafa). - - -diff --git a/src/body.cpp b/src/body.cpp -index 13dff6b..738d3e7 100644 ---- a/src/body.cpp -+++ b/src/body.cpp -@@ -127,10 +127,30 @@ void body::parse(const string& buffer, const string::size_type position, - const string boundarySep("--" + boundary); - - string::size_type partStart = position; -- string::size_type pos = buffer.find(boundarySep, position); -+ string::size_type pos = position; - - bool lastPart = false; - -+ while (pos != string::npos && pos < end) -+ { -+ pos = buffer.find(boundarySep, pos); -+ -+ if (pos == string::npos || -+ ((pos == 0 || buffer[pos - 1] == '\n') && -+ (buffer[pos + boundarySep.length()] == '\r' || -+ buffer[pos + boundarySep.length()] == '\n' || -+ buffer[pos + boundarySep.length()] == '-' -+ ) -+ ) -+ ) -+ { -+ break; -+ } -+ -+ // boundary not a beginning of line, or just a prefix of another, continue the search. -+ pos++; -+ } -+ - if (pos != string::npos && pos < end) - { - m_prologText = string(buffer.begin() + position, buffer.begin() + pos); -@@ -181,7 +201,26 @@ void body::parse(const string& buffer, const string::size_type position, - } - - partStart = pos; -- pos = buffer.find(boundarySep, partStart); -+ -+ while (pos != string::npos && pos < end) -+ { -+ pos = buffer.find(boundarySep, pos); -+ -+ if (pos == string::npos || -+ ((pos == 0 || buffer[pos - 1] == '\n') && -+ (buffer[pos + boundarySep.length()] == '\r' || -+ buffer[pos + boundarySep.length()] == '\n' || -+ buffer[pos + boundarySep.length()] == '-' -+ ) -+ ) -+ ) -+ { -+ break; -+ } -+ -+ // boundary not a beginning of line, or just a prefix of another, continue the search. -+ pos++; -+ } - } - - m_contents = vmime::create <emptyContentHandler>(); -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index 12c4f74..df2bf85 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -84,7 +84,7 @@ VMIME_TEST_SUITE_BEGIN - vmime::string str = - "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" - "\r\n\r\n" -- "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1" -+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" - "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2"; - - vmime::bodyPart p; --- -1.7.10.4 - - -From c63f37c888798f0e7e99aa03afda16445a72b7b2 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 21 Jan 2011 15:28:06 +0000 -Subject: [PATCH 06/47] Fixed possible infinite loop (thanks to John van der - Kamp, Zarafa). - - -diff --git a/src/word.cpp b/src/word.cpp -index db720dc..1c1c1a6 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -386,7 +386,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe - - maxRunLength = std::max(maxRunLength, curRunLength); - -- if (maxRunLength >= maxLineLength - 3) -+ if (((flags & text::FORCE_NO_ENCODING) == 0) && maxRunLength >= maxLineLength - 3) - { - // Generate with encoding forced - generate(os, maxLineLength, curLinePos, newLinePos, flags | text::FORCE_ENCODING, state); -diff --git a/tests/parser/textTest.cpp b/tests/parser/textTest.cpp -index b84f376..746ac94 100644 ---- a/tests/parser/textTest.cpp -+++ b/tests/parser/textTest.cpp -@@ -52,6 +52,7 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testWhitespaceMBox) - - VMIME_TEST(testFoldingAscii) -+ VMIME_TEST(testForcedNonEncoding) - VMIME_TEST_LIST_END - - -@@ -442,5 +443,15 @@ VMIME_TEST_SUITE_BEGIN - " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)); - } - -+ void testForcedNonEncoding() -+ { -+ // Testing long unbreakable and unencodable header -+ vmime::relay r; -+ r.parse(" from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t" -+ "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"); -+ -+ VASSERT_EQ("received.long", "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100", r.generate(78)); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From 1fafad8f913e700b350e6915de8be710fc2d1ced Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 28 Jan 2011 12:11:08 +0000 -Subject: [PATCH 07/47] Fixed possible read to invalid memory location (thanks - to Alexander Konovalov). - - -diff --git a/src/word.cpp b/src/word.cpp -index 1c1c1a6..fa08d33 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -460,7 +460,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe - - os << string(curLineStart, p); - -- if (parserHelpers::isSpace(*(p - 1))) -+ if (p != m_buffer.begin() && parserHelpers::isSpace(*(p - 1))) - state->lastCharIsSpace = true; - else - state->lastCharIsSpace = false; --- -1.7.10.4 - - -From 73298423f695d7c4441d44619e4b7f9de75f566e Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Wed, 9 Mar 2011 18:03:31 +0000 -Subject: [PATCH 08/47] Fixed bug #3174903. Fixed word parsing when buffer - does not end with NL. Fixed 'no encoding' when - forced. - - -diff --git a/src/body.cpp b/src/body.cpp -index 738d3e7..8596833 100644 ---- a/src/body.cpp -+++ b/src/body.cpp -@@ -153,7 +153,10 @@ void body::parse(const string& buffer, const string::size_type position, - - if (pos != string::npos && pos < end) - { -- m_prologText = string(buffer.begin() + position, buffer.begin() + pos); -+ vmime::text text; -+ text.parse(buffer, position, pos); -+ -+ m_prologText = text.getWholeBuffer(); - } - - for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index) -@@ -246,7 +249,10 @@ void body::parse(const string& buffer, const string::size_type position, - // Treat remaining text as epilog - else if (partStart < end) - { -- m_epilogText = string(buffer.begin() + partStart, buffer.begin() + end); -+ vmime::text text; -+ text.parse(buffer, partStart, end); -+ -+ m_epilogText = text.getWholeBuffer(); - } - } - // Treat the contents as 'simple' data -@@ -333,7 +339,7 @@ void body::generate(utility::outputStream& os, const string::size_type maxLineLe - - if (!prologText.empty()) - { -- text prolog(word(prologText, getCharset())); -+ text prolog(prologText, vmime::charset("us-ascii")); - - prolog.encodeAndFold(os, maxLineLength, 0, - NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); -@@ -356,7 +362,7 @@ void body::generate(utility::outputStream& os, const string::size_type maxLineLe - - if (!epilogText.empty()) - { -- text epilog(word(epilogText, getCharset())); -+ text epilog(epilogText, vmime::charset("us-ascii")); - - epilog.encodeAndFold(os, maxLineLength, 0, - NULL, text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE); -diff --git a/src/word.cpp b/src/word.cpp -index fa08d33..aeaa737 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -102,7 +102,9 @@ ref <word> word::parseNext(const string& buffer, const string::size_type positio - ++pos; - - unencoded += buffer.substr(startPos, endPos - startPos); -- unencoded += ' '; -+ -+ if (pos != end) // ignore white-spaces at end -+ unencoded += ' '; - - startPos = pos; - continue; -@@ -191,14 +193,15 @@ ref <word> word::parseNext(const string& buffer, const string::size_type positio - ++pos; - } - -- // Treat unencoded text at the end of the buffer -- if (end != startPos) -- { -- if (startPos != pos && !isFirst && prevIsEncoded) -- unencoded += whiteSpaces; -+ if (startPos != end && !isFirst && prevIsEncoded) -+ unencoded += whiteSpaces; - -+ if (startPos != end) - unencoded += buffer.substr(startPos, end - startPos); - -+ // Treat unencoded text at the end of the buffer -+ if (!unencoded.empty()) -+ { - ref <word> w = vmime::create <word>(unencoded, charset(charsets::US_ASCII)); - w->setParsedBounds(position, end); - -@@ -337,12 +340,14 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe - state = &defaultGeneratorState; - - // Find out if encoding is forced or required by contents + charset -- bool encodingNeeded = (flags & text::FORCE_ENCODING) != 0; -+ bool encodingNeeded = false; - -- if (encodingNeeded == false) -- encodingNeeded = wordEncoder::isEncodingNeeded(m_buffer, m_charset); -- else if ((flags & text::FORCE_NO_ENCODING) != 0) -+ if ((flags & text::FORCE_NO_ENCODING) != 0) - encodingNeeded = false; -+ else if ((flags & text::FORCE_ENCODING) != 0) -+ encodingNeeded = true; -+ else // auto-detect -+ encodingNeeded = wordEncoder::isEncodingNeeded(m_buffer, m_charset); - - // If possible and requested (with flag), quote the buffer (no folding is performed). - // Quoting is possible if and only if: -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index df2bf85..b129913 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -34,6 +34,8 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testParse) - VMIME_TEST(testGenerate) - VMIME_TEST(testParseMissingLastBoundary) -+ VMIME_TEST(testPrologEpilog) -+ VMIME_TEST(testPrologEncoding) - VMIME_TEST_LIST_END - - -@@ -105,5 +107,79 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate()); - } - -+ void testPrologEpilog() -+ { -+ const char testMail[] = -+ "To: test@vmime.org\r\n" -+ "From: test@vmime.org\r\n" -+ "Subject: Prolog and epilog test\r\n" -+ "Content-Type: multipart/mixed; \r\n" -+ " boundary=\"=_boundary\"\r\n" -+ "\r\n" -+ "Prolog text\r\n" -+ "--=_boundary\r\n" -+ "Content-Type: text/plain\r\n" -+ "\r\n" -+ "Part1\r\n" -+ "--=_boundary--\r\n" -+ "Epilog text"; -+ -+ vmime::bodyPart part; -+ part.parse(testMail); -+ -+ VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText()); -+ VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText()); -+ } -+ -+ // Test for bug fix: prolog should not be encoded -+ // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724 -+ void testPrologEncoding() -+ { -+ const char testmail[] = -+ "To: test@vmime.org\r\n" -+ "From: test@vmime.org\r\n" -+ "Subject: Prolog encoding test\r\n" -+ "Content-Type: multipart/mixed; \r\n" -+ " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n" -+ "\r\n" -+ "This is a multi-part message in MIME format. Your mail reader does not\r\n" -+ "understand MIME message format.\r\n" -+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" -+ "Content-Type: text/html; charset=windows-1251\r\n" -+ "Content-Transfer-Encoding: quoted-printable\r\n" -+ "\r\n" -+ "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n" -+ "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n" -+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n" -+ "Content-Type: application/octet-stream; charset=windows-1251\r\n" -+ "Content-Disposition: attachment; filename=FNS.zip\r\n" -+ "Content-Transfer-Encoding: base64\r\n" -+ "\r\n" -+ "UEsDBB...snap...EEAAAAAA==\r\n" -+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n" -+ "Epilog text"; -+ -+ vmime::ref<vmime::message> msg = vmime::create<vmime::message>(); -+ -+ std::string istr(testmail); -+ -+ std::string ostr; -+ vmime::utility::outputStreamStringAdapter out(ostr); -+ -+ for (int i = 0 ; i < 10 ; ++i) -+ { -+ ostr.clear(); -+ -+ msg->parse(istr); -+ msg->generate(out); -+ -+ istr = ostr; -+ } -+ -+ VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader" -+ " does not understand MIME message format.", msg->getBody()->getPrologText()); -+ VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText()); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From 5f5757b9d4bb0febb1e2183578eb91e801a08038 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 27 Mar 2011 11:26:55 +0000 -Subject: [PATCH 09/47] Allow static linking in mingw-cross-env. Added 'iconv' - and uses 'ws2_32' instead of 'winsock32' (#3213487). - - -diff --git a/SConstruct b/SConstruct -index 55f9223..177f5b4 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -1089,7 +1089,7 @@ def generateAutotools(target, source, env): - vmime_pc_in.write("Description: " + packageDescription + "\n") - vmime_pc_in.write("Version: @VERSION@\n") - vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n") -- vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") -+ vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") - #vmime_pc_in.write("Cflags: -I${includedir}/@GENERIC_VERSIONED_LIBRARY_NAME@\n") - vmime_pc_in.write("Cflags: -I${includedir}/ @LIBGNUTLS_CFLAGS@\n") - vmime_pc_in.close() -@@ -1709,7 +1709,7 @@ fi - - # -- Link with Winsock (Windows) - if test "x$VMIME_DETECT_PLATFORM" = "xwindows"; then -- VMIME_ADDITIONAL_PC_LIBS="$VMIME_ADDITIONAL_PC_LIBS -lwsock32" -+ VMIME_ADDITIONAL_PC_LIBS="$VMIME_ADDITIONAL_PC_LIBS -lws2_32" - fi - - # -- getaddrinfo (POSIX) --- -1.7.10.4 - - -From 2b48b4a68ce3e9b9b1a3f485123af5938a568324 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 31 Mar 2011 19:13:03 +0000 -Subject: [PATCH 10/47] Flush stateful data from iconv (thanks to John van der - Kamp, Zarafa). - - -diff --git a/src/charsetConverter.cpp b/src/charsetConverter.cpp -index 38b9e5e..2135788 100644 ---- a/src/charsetConverter.cpp -+++ b/src/charsetConverter.cpp -@@ -119,6 +119,7 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& - size_t inPos = 0; - - bool prevIsInvalid = false; -+ bool breakAfterNext = false; - - while (true) - { -@@ -126,11 +127,12 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& - size_t inLength = static_cast <size_t>(in.read(inBuffer + inPos, sizeof(inBuffer) - inPos) + inPos); - size_t outLength = sizeof(outBuffer); - -- const char* inPtr = inBuffer; -+ const char* inPtr = breakAfterNext ? NULL : inBuffer; -+ size_t *ptrLength = breakAfterNext ? NULL : &inLength; - char* outPtr = outBuffer; - - // Convert input bytes -- if (iconv(cd, ICONV_HACK(&inPtr), &inLength, -+ if (iconv(cd, ICONV_HACK(&inPtr), ptrLength, - &outPtr, &outLength) == static_cast <size_t>(-1)) - { - // Illegal input sequence or input sequence has no equivalent -@@ -170,9 +172,12 @@ void charsetConverter::convert(utility::inputStream& in, utility::outputStream& - prevIsInvalid = false; - } - -- // Check for end of data -- if (in.eof() && inPos == 0) -+ if (breakAfterNext) - break; -+ -+ // Check for end of data, loop again to flush stateful data from iconv -+ if (in.eof() && inPos == 0) -+ breakAfterNext = true; - } - } - -diff --git a/tests/parser/charsetTest.cpp b/tests/parser/charsetTest.cpp -index 8ad71d7..54a09a7 100644 ---- a/tests/parser/charsetTest.cpp -+++ b/tests/parser/charsetTest.cpp -@@ -100,6 +100,7 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testFilterValid1) - VMIME_TEST(testFilterValid2) - VMIME_TEST(testFilterValid3) -+ VMIME_TEST(testEncodingHebrew1255) - - // Test invalid input - VMIME_TEST(testFilterInvalid1) -@@ -227,6 +228,15 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("1", toHex(expectedOut), toHex(actualOut)); - } - -+ void testEncodingHebrew1255() -+ { -+ // hewbrew string in windows-1255 charset -+ const char data[] = "\xe9\xf9\xf7\xf8\xe9\xf9\xf8\xf7\xe9\xe9\xf9"; -+ vmime::word w = vmime::word(data, "windows-1255"); -+ vmime::string encoded = w.generate(); -+ // less than 60% ascii, base64 received -+ VASSERT_EQ("1", "=?windows-1255?B?6fn3+On5+Pfp6fk=?=", encoded); -+ } - - // Conversion to hexadecimal for easier debugging - static const vmime::string toHex(const vmime::string str) --- -1.7.10.4 - - -From 8d2e039c5201e144ff08e2ff7cf9efe77fe4b3d0 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 10 Jun 2011 19:39:09 +0000 -Subject: [PATCH 11/47] Requested email change. - - -diff --git a/AUTHORS b/AUTHORS -index 20a0181..bbddb30 100644 ---- a/AUTHORS -+++ b/AUTHORS -@@ -21,7 +21,7 @@ AUTHORS file. - - Rafael Fernandez <prf@adinet.com.uy> - - Xin Li <lixin3@staff.sina.com.cn> - - Benjamin Biron <benbiron@gmail.com> -- - Bertrand Benoit <bsquare@bsquare.levillage.org> -+ - Bertrand Benoit <projettwk@users.sourceforge.net> - - Tim Teulings <rael@edge.ping.de> - - Georg Sauthoff <gsauthof@techfak.uni-bielefeld.de> - - Pierre Thierry <nowhere.man@levallois.eu.org> (patches for STL algorithms) --- -1.7.10.4 - - -From cc6317f28ae0b61fea36e1bc78b09dc8300579f8 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Tue, 14 Jun 2011 18:37:54 +0000 -Subject: [PATCH 12/47] Fixed compilation issue following namespace change. - - -diff --git a/examples/example7.cpp b/examples/example7.cpp -index 1ddb3d0..243b1da 100644 ---- a/examples/example7.cpp -+++ b/examples/example7.cpp -@@ -43,18 +43,18 @@ int main() - vmime::platform::setHandler<vmime::platforms::posix::posixHandler>(); - - // Enumerate encoders -- vmime::encoderFactory* ef = vmime::encoderFactory::getInstance(); -+ vmime::utility::encoder::encoderFactory* ef = vmime::utility::encoder::encoderFactory::getInstance(); - - std::cout << "Available encoders:" << std::endl; - - for (int i = 0 ; i < ef->getEncoderCount() ; ++i) - { -- vmime::ref <const vmime::encoderFactory::registeredEncoder> -+ vmime::ref <const vmime::utility::encoder::encoderFactory::registeredEncoder> - enc = ef->getEncoderAt(i); - - std::cout << " * " << enc->getName() << std::endl; - -- vmime::ref <vmime::encoder> e = enc->create(); -+ vmime::ref <vmime::utility::encoder::encoder> e = enc->create(); - - std::vector <vmime::string> props = e->getAvailableProperties(); - --- -1.7.10.4 - - -From a916d12d44ac43fc8e4729e0a91f4d6243f29a11 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 19 Jun 2011 17:51:33 +0000 -Subject: [PATCH 13/47] Fixed parsing of an attachment filename that is - between 66 and 76 characters long (Zarafa). - - -diff --git a/src/parameter.cpp b/src/parameter.cpp -index 91a7e5c..f59d5ab 100644 ---- a/src/parameter.cpp -+++ b/src/parameter.cpp -@@ -281,7 +281,8 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - bool needQuoting = false; - string::size_type valueLength = 0; - -- for (string::size_type i = 0 ; (i < value.length()) && (pos + valueLength < maxLineLength - 4) ; ++i, ++valueLength) -+ // Use worst-case length name.length()+2 for 'name=' part of line -+ for (string::size_type i = 0 ; (i < value.length()) && (pos + name.length() + 2 + valueLength < maxLineLength - 4) ; ++i, ++valueLength) - { - switch (value[i]) - { --- -1.7.10.4 - - -From 9735165c57000a6368e91ce8852206a20930c1ca Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 19 Jun 2011 18:08:12 +0000 -Subject: [PATCH 14/47] Correctly generate attachment names which are long and - have high characters for Outlook Express (Zarafa). - - -diff --git a/src/parameter.cpp b/src/parameter.cpp -index f59d5ab..d757e1b 100644 ---- a/src/parameter.cpp -+++ b/src/parameter.cpp -@@ -268,17 +268,19 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - // value is to be generated. - - // A stream for a temporary storage -- std::ostringstream sevenBitBuffer; -+ std::string sevenBitBuffer; -+ utility::outputStreamStringAdapter sevenBitStream(sevenBitBuffer); - - string::size_type pos = curLinePos; - - if (pos + name.length() + 10 + value.length() > maxLineLength) - { -- sevenBitBuffer << NEW_LINE_SEQUENCE; -+ sevenBitStream << NEW_LINE_SEQUENCE; - pos = NEW_LINE_SEQUENCE_LENGTH; - } - - bool needQuoting = false; -+ bool needQuotedPrintable = false; - string::size_type valueLength = 0; - - // Use worst-case length name.length()+2 for 'name=' part of line -@@ -308,6 +310,16 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - - needQuoting = true; - break; -+ -+ default: -+ -+ if (!parserHelpers::isAscii(value[i])) -+ { -+ needQuotedPrintable = true; -+ needQuoting = true; -+ } -+ -+ break; - } - } - -@@ -315,12 +327,12 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - - if (needQuoting) - { -- sevenBitBuffer << name << "=\""; -+ sevenBitStream << name << "=\""; - pos += name.length() + 2; - } - else - { -- sevenBitBuffer << name << "="; -+ sevenBitStream << name << "="; - pos += name.length() + 1; - } - -@@ -332,29 +344,43 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - const bool alwaysEncode = m_value.getCharset().getRecommendedEncoding(recommendedEnc); - bool extended = alwaysEncode; - -- for (string::size_type i = 0 ; (i < value.length()) && (pos < maxLineLength - 4) ; ++i) -+ if (needQuotedPrintable) - { -- const char_t c = value[i]; -- -- if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit -- { -- sevenBitBuffer << '\\' << value[i]; // escape 'x' with '\x' -- pos += 2; -- } -- else if (parserHelpers::isAscii(c)) -- { -- sevenBitBuffer << value[i]; -- ++pos; -- } -- else -+ // Send the name in quoted-printable, so outlook express et.al. -+ // will understand the real filename -+ size_t oldLen = sevenBitBuffer.length(); -+ m_value.generate(sevenBitStream); -+ pos += sevenBitBuffer.length() - oldLen; -+ extended = true; // also send with RFC-2231 encoding -+ } -+ else -+ { -+ // Do not chop off this value, but just add the complete name as one header line. -+ for (string::size_type i = 0 ; i < value.length() ; ++i) - { -- extended = true; -+ const char_t c = value[i]; -+ -+ if (/* needQuoting && */ (c == '"' || c == '\\')) // 'needQuoting' is implicit -+ { -+ sevenBitStream << '\\' << value[i]; // escape 'x' with '\x' -+ pos += 2; -+ } -+ else if (parserHelpers::isAscii(c)) -+ { -+ sevenBitStream << value[i]; -+ ++pos; -+ } -+ else -+ { -+ extended = true; -+ } - } -- } -+ -+ } // !needQuotedPrintable - - if (needQuoting) - { -- sevenBitBuffer << '"'; -+ sevenBitStream << '"'; - ++pos; - } - -@@ -532,7 +558,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - // "7bit/us-ascii" will suffice in this case. - - // Output what has been stored in temporary buffer so far -- os << sevenBitBuffer.str(); -+ os << sevenBitBuffer; - } - #endif // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER - --- -1.7.10.4 - - -From 8d69ad6849d8d6b211674942157f2af8bcd51c26 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 19 Jun 2011 18:16:49 +0000 -Subject: [PATCH 15/47] Alias for UTF-7 charset. - - -diff --git a/src/charset.cpp b/src/charset.cpp -index e043186..0fda450 100644 ---- a/src/charset.cpp -+++ b/src/charset.cpp -@@ -45,6 +45,9 @@ charset::charset() - charset::charset(const string& name) - : m_name(name) - { -+ // If we receive this rfc-1642 valid MIME charset, convert it to something usefull for iconv -+ if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) -+ m_name = "utf-7"; - } - - -@@ -60,6 +63,10 @@ void charset::parse(const string& buffer, const string::size_type position, - m_name = utility::stringUtils::trim - (string(buffer.begin() + position, buffer.begin() + end)); - -+ // If we parsed this rfc-1642 valid MIME charset, convert it to something usefull for iconv -+ if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) -+ m_name = "utf-7"; -+ - setParsedBounds(position, end); - - if (newPosition) --- -1.7.10.4 - - -From ccd95daf9cdd7171fc2027afa5d0ad80b0475ded Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 19 Jun 2011 18:39:35 +0000 -Subject: [PATCH 16/47] Fixed messageBuilder to accept an empty mailbox group - in 'To:' field, to allow for undisclosed-recipients - (Zarafa). - - -diff --git a/src/messageBuilder.cpp b/src/messageBuilder.cpp -index 870d59e..3597b3a 100644 ---- a/src/messageBuilder.cpp -+++ b/src/messageBuilder.cpp -@@ -51,17 +51,15 @@ ref <message> messageBuilder::construct() const - // Generate the header fields - msg->getHeader()->Subject()->setValue(m_subject); - -- if (m_from.isEmpty()) -- throw exceptions::no_expeditor(); -- -- if ((m_to.isEmpty() || m_to.getAddressAt(0)->isEmpty()) && -+ if (((m_to.isEmpty()) || (m_to.getAddressAt(0)->isEmpty() && !m_to.getAddressAt(0)->isGroup())) && - (m_cc.isEmpty() || m_cc.getAddressAt(0)->isEmpty()) && - (m_bcc.isEmpty() || m_bcc.getAddressAt(0)->isEmpty())) - { - throw exceptions::no_recipient(); - } - -- msg->getHeader()->From()->setValue(m_from); -+ if (!m_from.isEmpty()) -+ msg->getHeader()->From()->setValue(m_from); - - if (!m_to.isEmpty()) - msg->getHeader()->To()->setValue(m_to); --- -1.7.10.4 - - -From 583e25bcdee132e53e0792cd8f0d8e535cabb743 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 19 Jun 2011 18:49:55 +0000 -Subject: [PATCH 17/47] Added support for mailboxes that specify an (encoded) - full name with an empty email address, set by a <> - marker (Zarafa). - - -diff --git a/src/mailbox.cpp b/src/mailbox.cpp -index 5cb0139..fea7479 100644 ---- a/src/mailbox.cpp -+++ b/src/mailbox.cpp -@@ -88,6 +88,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, - // Temporary buffers for extracted name and address - string name; - string address; -+ bool hadBrackets = false; - - while (p < pend) - { -@@ -283,6 +284,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, - } - else if (*p == '>') - { -+ hadBrackets = true; - break; - } - else if (!parserHelpers::isSpace(*p)) -@@ -309,7 +311,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, - - // Swap name and address when no address was found - // (email address is mandatory, whereas name is optional). -- if (address.empty() && !name.empty()) -+ if (address.empty() && !name.empty() && !hadBrackets) - { - m_email.clear(); - m_email.reserve(name.size()); -diff --git a/tests/parser/mailboxTest.cpp b/tests/parser/mailboxTest.cpp -index 8411daa..9ebadca 100644 ---- a/tests/parser/mailboxTest.cpp -+++ b/tests/parser/mailboxTest.cpp -@@ -32,6 +32,7 @@ VMIME_TEST_SUITE_BEGIN - - VMIME_TEST_LIST_BEGIN - VMIME_TEST(testParse) -+ VMIME_TEST(testEmptyEmailAddress) - VMIME_TEST_LIST_END - - -@@ -113,5 +114,19 @@ VMIME_TEST_SUITE_BEGIN - } - } - -+ void testEmptyEmailAddress() -+ { -+ vmime::addressList addrList; -+ addrList.parse("\"Full Name\" <>"); -+ -+ VASSERT_EQ("count", 1, addrList.getAddressCount()); -+ VASSERT_EQ("!group", false, addrList.getAddressAt(0)->isGroup()); -+ -+ vmime::ref <vmime::mailbox> mbox = addrList.getAddressAt(0).dynamicCast <vmime::mailbox>(); -+ -+ VASSERT_EQ("name", "Full Name", mbox->getName()); -+ VASSERT_EQ("email", "", mbox->getEmail()); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From 461b92f84d5c16b297d33610fcd89fc7ca5a161a Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 24 Jun 2011 15:46:23 +0000 -Subject: [PATCH 18/47] Added missing libs in pkg-config file. - - -diff --git a/SConstruct b/SConstruct -index 177f5b4..37c0ac6 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -1089,7 +1089,7 @@ def generateAutotools(target, source, env): - vmime_pc_in.write("Description: " + packageDescription + "\n") - vmime_pc_in.write("Version: @VERSION@\n") - vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n") -- vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") -+ vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @LIBICONV@ @PTHREAD_LIBS@ @VMIME_ADDITIONAL_PC_LIBS@\n") - #vmime_pc_in.write("Cflags: -I${includedir}/@GENERIC_VERSIONED_LIBRARY_NAME@\n") - vmime_pc_in.write("Cflags: -I${includedir}/ @LIBGNUTLS_CFLAGS@\n") - vmime_pc_in.close() --- -1.7.10.4 - - -From 2b2c0abd02a17ccff7d49e266b9854f4ea47f8e4 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sat, 25 Jun 2011 17:07:53 +0000 -Subject: [PATCH 19/47] Fixed parsing of empty body parts (thanks to John van - der Kamp, from Zarafa). - - -diff --git a/src/body.cpp b/src/body.cpp -index 8596833..9d7d57f 100644 ---- a/src/body.cpp -+++ b/src/body.cpp -@@ -197,6 +197,11 @@ void body::parse(const string& buffer, const string::size_type position, - { - ref <bodyPart> part = vmime::create <bodyPart>(); - -+ // End before start may happen on empty bodyparts (directly -+ // successive boundaries without even a line-break) -+ if (partEnd < partStart) -+ std::swap(partStart, partEnd); -+ - part->parse(buffer, partStart, partEnd, NULL); - part->m_parent = m_part; - -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index b129913..075b8f9 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -36,6 +36,7 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testParseMissingLastBoundary) - VMIME_TEST(testPrologEpilog) - VMIME_TEST(testPrologEncoding) -+ VMIME_TEST(testSuccessiveBoundaries) - VMIME_TEST_LIST_END - - -@@ -181,5 +182,23 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText()); - } - -+ void testSuccessiveBoundaries() -+ { -+ vmime::string str = -+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" -+ "\r\n\r\n" -+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" -+ "--MY-BOUNDARY\r\n" -+ "--MY-BOUNDARY--\r\n"; -+ -+ vmime::bodyPart p; -+ p.parse(str); -+ -+ VASSERT_EQ("count", 2, p.getBody()->getPartCount()); -+ -+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); -+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From 2648d744da0e2e744c7959999ac513c3016072b4 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 26 Jun 2011 08:19:11 +0000 -Subject: [PATCH 20/47] Use gnutls_priority_set_direct() instead of GNUTLS - deprecated functions. - - -diff --git a/SConstruct b/SConstruct -index 37c0ac6..01ad3f3 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -816,6 +816,7 @@ else: - config_hpp.write('// -- TLS/SSL support\n') - if env['with_tls'] == 'yes': - config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 1\n') -+ config_hpp.write('#define HAVE_GNUTLS_PRIORITY_FUNCS 1\n') - else: - config_hpp.write('#define VMIME_HAVE_TLS_SUPPORT 0\n') - -@@ -1626,11 +1627,42 @@ if test "x$conf_tls" = "xyes"; then - else - AC_MSG_ERROR(can't find an usable version of GNU TLS library) - fi -+ -+ # -- check for gnutls_priority_set_direct() function -+ if test "x$have_gnutls" = "xyes"; then -+ AC_MSG_CHECKING(for gnutls_priority_set_direct) -+ -+ LIBS_save="$LIBS" -+ LIBS="$LIBS $LIBGNUTLS_LIBS" -+ CPPFLAGS_save="$CPPFLAGS" -+ CPPFLAGS="$CPPFLAGS $LIBGNUTLS_CFLAGS" -+ -+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <gnutls/gnutls.h>], -+ [gnutls_session s; gnutls_priority_set_direct(s, NULL, NULL);])], -+ [have_gnutls_priority_funcs=yes], -+ [have_gnutls_priority_funcs=no]) -+ -+ CPPFLAGS="$CPPFLAGS_save" -+ LIBS="$LIBS_save" -+ -+ AC_MSG_RESULT([$have_gnutls_priority_funcs]) -+ -+ if test "x$have_gnutls_priority_funcs" = "xyes"; then -+ AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, true) -+ HAVE_GNUTLS_PRIORITY_FUNCS=1 -+ else -+ AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) -+ HAVE_GNUTLS_PRIORITY_FUNCS=0 -+ fi -+ fi - else - AM_CONDITIONAL(VMIME_HAVE_TLS_SUPPORT, false) - VMIME_HAVE_TLS_SUPPORT=0 - fi - -+AC_SUBST(LIBGNUTLS_CFLAGS) -+AC_SUBST(LIBGNUTLS_LIBS) -+ - # ** platform handlers - - VMIME_BUILTIN_PLATFORMS='' -@@ -1919,6 +1951,7 @@ typedef unsigned ${VMIME_TYPE_INT32} vmime_uint32; - #define VMIME_HAVE_SASL_SUPPORT ${VMIME_HAVE_SASL_SUPPORT} - // -- TLS support - #define VMIME_HAVE_TLS_SUPPORT ${VMIME_HAVE_TLS_SUPPORT} -+#define HAVE_GNUTLS_PRIORITY_FUNCS ${HAVE_GNUTLS_PRIORITY_FUNCS} - // -- Messaging support - #define VMIME_HAVE_MESSAGING_FEATURES ${VMIME_HAVE_MESSAGING_FEATURES} - """) -diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp -index 010c007..af73a05 100644 ---- a/src/net/tls/TLSSession.cpp -+++ b/src/net/tls/TLSSession.cpp -@@ -123,6 +123,21 @@ TLSSession::TLSSession(ref <security::cert::certificateVerifier> cv) - - // Sets some default priority on the ciphers, key exchange methods, - // macs and compression methods. -+#if HAVE_GNUTLS_PRIORITY_FUNCS -+ -+ if ((res = gnutls_priority_set_direct -+ (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0) -+ { -+ if ((res = gnutls_priority_set_direct -+ (*m_gnutlsSession, "NORMAL", NULL)) != 0) -+ { -+ throwTLSException -+ ("gnutls_priority_set_direct", res); -+ } -+ } -+ -+#else // !HAVE_GNUTLS_PRIORITY_FUNCS -+ - gnutls_set_default_priority(*m_gnutlsSession); - - // Sets the priority on the certificate types supported by gnutls. -@@ -197,6 +212,8 @@ TLSSession::TLSSession(ref <security::cert::certificateVerifier> cv) - - gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority); - -+#endif // !HAVE_GNUTLS_PRIORITY_FUNCS -+ - // Initialize credentials - gnutls_credentials_set(*m_gnutlsSession, - GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred); --- -1.7.10.4 - - -From 1060121ffd4315c3158ffc001040f4f705514e7a Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 26 Jun 2011 12:47:25 +0000 -Subject: [PATCH 21/47] Fixed encoding of whitespace. Fixed old test case. - - -diff --git a/src/text.cpp b/src/text.cpp -index 2454456..66c3b35 100644 ---- a/src/text.cpp -+++ b/src/text.cpp -@@ -320,12 +320,6 @@ void text::createFromString(const string& in, const charset& ch) - } - else - { -- if (count) -- { -- ref <word> w = getWordAt(getWordCount() - 1); -- w->getBuffer() += ' '; -- } -- - appendWord(vmime::create <word> - (chunk, charset(charsets::US_ASCII))); - -diff --git a/tests/parser/textTest.cpp b/tests/parser/textTest.cpp -index 746ac94..43ec836 100644 ---- a/tests/parser/textTest.cpp -+++ b/tests/parser/textTest.cpp -@@ -53,6 +53,8 @@ VMIME_TEST_SUITE_BEGIN - - VMIME_TEST(testFoldingAscii) - VMIME_TEST(testForcedNonEncoding) -+ -+ VMIME_TEST(testBugFix20110511) - VMIME_TEST_LIST_END - - -@@ -149,7 +151,7 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("2.1", 3, t2.getWordCount()); - VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer()); - VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset()); -- VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4 ", t2.getWordAt(1)->getBuffer()); -+ VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer()); - VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset()); - VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer()); - VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset()); -@@ -453,5 +455,43 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("received.long", "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100", r.generate(78)); - } - -+ void testBugFix20110511() -+ { -+ /* -+ -+ Using the latest version of vmime (0.9.1), encoding the following string: Jean -+ Gwenaël Dutourd will result in: -+ Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd -+ However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces -+ between the last 2 words). The encoder adds a _ after the second word, but -+ since the last word is not encoded, the space between them is not ignored, and -+ is decoded into an additional space. -+ -+ See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365 -+ -+ */ -+ -+ const std::string DECODED_TEXT = "Jean Gwenaël Dutourd"; -+ const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd"; -+ -+ // Encode -+ VASSERT_EQ("encode", ENCODED_TEXT, -+ vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()); -+ -+ // Decode -+ vmime::text t; -+ t.parse(ENCODED_TEXT); -+ -+ // -- words -+ std::ostringstream oss; oss << t; -+ VASSERT_EQ("decode1", -+ "[text: [[word: charset=us-ascii, buffer=Jean ]," -+ "[word: charset=utf-8, buffer=Gwenaël]," -+ "[word: charset=us-ascii, buffer= Dutourd]]]", oss.str()); -+ -+ // -- getWholeBuffer -+ VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer()); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From dc6dc039fc0edccf4630894fa6ed8cd4bf3bb3ce Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sat, 20 Aug 2011 06:35:06 +0000 -Subject: [PATCH 22/47] Use gnutls_strerror() for reporting errors. - - -diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp -index af73a05..7426a73 100644 ---- a/src/net/tls/TLSSession.cpp -+++ b/src/net/tls/TLSSession.cpp -@@ -41,6 +41,9 @@ - //#define GNUTLS_DEBUG 1 - - -+#include <sstream> -+#include <iomanip> -+ - #if VMIME_DEBUG && GNUTLS_DEBUG - #include <iostream> - #endif // VMIME_DEBUG && GNUTLS_DEBUG -@@ -257,119 +260,14 @@ ref <security::cert::certificateVerifier> TLSSession::getCertificateVerifier() - - void TLSSession::throwTLSException(const string& fname, const int code) - { -- string msg = fname + "() returned "; -- --#define ERROR(x) \ -- case x: msg += #x; break; -- -- switch (code) -- { -- ERROR(GNUTLS_E_SUCCESS) -- ERROR(GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM) -- ERROR(GNUTLS_E_UNKNOWN_CIPHER_TYPE) -- ERROR(GNUTLS_E_LARGE_PACKET) -- ERROR(GNUTLS_E_UNSUPPORTED_VERSION_PACKET) -- ERROR(GNUTLS_E_UNEXPECTED_PACKET_LENGTH) -- ERROR(GNUTLS_E_INVALID_SESSION) -- ERROR(GNUTLS_E_FATAL_ALERT_RECEIVED) -- ERROR(GNUTLS_E_UNEXPECTED_PACKET) -- ERROR(GNUTLS_E_WARNING_ALERT_RECEIVED) -- ERROR(GNUTLS_E_ERROR_IN_FINISHED_PACKET) -- ERROR(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) -- ERROR(GNUTLS_E_UNKNOWN_CIPHER_SUITE) -- ERROR(GNUTLS_E_UNWANTED_ALGORITHM) -- ERROR(GNUTLS_E_MPI_SCAN_FAILED) -- ERROR(GNUTLS_E_DECRYPTION_FAILED) -- ERROR(GNUTLS_E_MEMORY_ERROR) -- ERROR(GNUTLS_E_DECOMPRESSION_FAILED) -- ERROR(GNUTLS_E_COMPRESSION_FAILED) -- ERROR(GNUTLS_E_AGAIN) -- ERROR(GNUTLS_E_EXPIRED) -- ERROR(GNUTLS_E_DB_ERROR) -- ERROR(GNUTLS_E_SRP_PWD_ERROR) -- ERROR(GNUTLS_E_INSUFFICIENT_CREDENTIALS) -- ERROR(GNUTLS_E_HASH_FAILED) -- ERROR(GNUTLS_E_BASE64_DECODING_ERROR) -- ERROR(GNUTLS_E_MPI_PRINT_FAILED) -- ERROR(GNUTLS_E_REHANDSHAKE) -- ERROR(GNUTLS_E_GOT_APPLICATION_DATA) -- ERROR(GNUTLS_E_RECORD_LIMIT_REACHED) -- ERROR(GNUTLS_E_ENCRYPTION_FAILED) -- ERROR(GNUTLS_E_PK_ENCRYPTION_FAILED) -- ERROR(GNUTLS_E_PK_DECRYPTION_FAILED) -- ERROR(GNUTLS_E_PK_SIGN_FAILED) -- ERROR(GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION) -- ERROR(GNUTLS_E_KEY_USAGE_VIOLATION) -- ERROR(GNUTLS_E_NO_CERTIFICATE_FOUND) -- ERROR(GNUTLS_E_INVALID_REQUEST) -- ERROR(GNUTLS_E_SHORT_MEMORY_BUFFER) -- ERROR(GNUTLS_E_INTERRUPTED) -- ERROR(GNUTLS_E_PUSH_ERROR) -- ERROR(GNUTLS_E_PULL_ERROR) -- ERROR(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER) -- ERROR(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) -- ERROR(GNUTLS_E_PKCS1_WRONG_PAD) -- ERROR(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION) -- ERROR(GNUTLS_E_INTERNAL_ERROR) -- ERROR(GNUTLS_E_DH_PRIME_UNACCEPTABLE) -- ERROR(GNUTLS_E_FILE_ERROR) -- ERROR(GNUTLS_E_TOO_MANY_EMPTY_PACKETS) -- ERROR(GNUTLS_E_UNKNOWN_PK_ALGORITHM) -- ERROR(GNUTLS_E_INIT_LIBEXTRA) -- ERROR(GNUTLS_E_LIBRARY_VERSION_MISMATCH) -- ERROR(GNUTLS_E_NO_TEMPORARY_RSA_PARAMS) -- ERROR(GNUTLS_E_LZO_INIT_FAILED) -- ERROR(GNUTLS_E_NO_COMPRESSION_ALGORITHMS) -- ERROR(GNUTLS_E_NO_CIPHER_SUITES) -- ERROR(GNUTLS_E_OPENPGP_GETKEY_FAILED) -- ERROR(GNUTLS_E_PK_SIG_VERIFY_FAILED) -- ERROR(GNUTLS_E_ILLEGAL_SRP_USERNAME) -- ERROR(GNUTLS_E_SRP_PWD_PARSING_ERROR) -- ERROR(GNUTLS_E_NO_TEMPORARY_DH_PARAMS) -- ERROR(GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) -- ERROR(GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND) -- ERROR(GNUTLS_E_ASN1_DER_ERROR) -- ERROR(GNUTLS_E_ASN1_VALUE_NOT_FOUND) -- ERROR(GNUTLS_E_ASN1_GENERIC_ERROR) -- ERROR(GNUTLS_E_ASN1_VALUE_NOT_VALID) -- ERROR(GNUTLS_E_ASN1_TAG_ERROR) -- ERROR(GNUTLS_E_ASN1_TAG_IMPLICIT) -- ERROR(GNUTLS_E_ASN1_TYPE_ANY_ERROR) -- ERROR(GNUTLS_E_ASN1_SYNTAX_ERROR) -- ERROR(GNUTLS_E_ASN1_DER_OVERFLOW) -- //ERROR(GNUTLS_E_OPENPGP_TRUSTDB_VERSION_UNSUPPORTED) -- ERROR(GNUTLS_E_OPENPGP_UID_REVOKED) -- ERROR(GNUTLS_E_CERTIFICATE_ERROR) -- //ERROR(GNUTLS_E_X509_CERTIFICATE_ERROR) -- ERROR(GNUTLS_E_CERTIFICATE_KEY_MISMATCH) -- ERROR(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE) -- ERROR(GNUTLS_E_X509_UNKNOWN_SAN) -- ERROR(GNUTLS_E_OPENPGP_FINGERPRINT_UNSUPPORTED) -- ERROR(GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE) -- ERROR(GNUTLS_E_UNKNOWN_HASH_ALGORITHM) -- ERROR(GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE) -- ERROR(GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE) -- ERROR(GNUTLS_E_INVALID_PASSWORD) -- ERROR(GNUTLS_E_MAC_VERIFY_FAILED) -- ERROR(GNUTLS_E_CONSTRAINT_ERROR) -- ERROR(GNUTLS_E_BASE64_ENCODING_ERROR) -- ERROR(GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY) -- //ERROR(GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY) -- ERROR(GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY) -- ERROR(GNUTLS_E_OPENPGP_KEYRING_ERROR) -- ERROR(GNUTLS_E_X509_UNSUPPORTED_OID) -- //ERROR(GNUTLS_E_RANDOM_FAILED) -- ERROR(GNUTLS_E_UNIMPLEMENTED_FEATURE) -- -- default: -- -- msg += "unknown error"; -- break; -- } -+ std::ostringstream msg; - --#undef ERROR -+ msg << fname + "() returned code "; -+ msg << std::hex << code; -+ msg << ": "; -+ msg << gnutls_strerror(code); - -- throw exceptions::tls_exception(msg); -+ throw exceptions::tls_exception(msg.str()); - } - - --- -1.7.10.4 - - -From 7ea6fc3737ef36407e1c90f3aa05f89a39bdefb7 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 21 Aug 2011 08:55:46 +0000 -Subject: [PATCH 23/47] Removed dependency on gcrypt for gnutls version >= - 2.12. - - -diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp -index 7426a73..d3f6d49 100644 ---- a/src/net/tls/TLSSession.cpp -+++ b/src/net/tls/TLSSession.cpp -@@ -26,9 +26,17 @@ - - #include "vmime/config.hpp" - -+// Dependency on gcrypt is not needed since GNU TLS version 2.12. -+// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651 -+#if GNUTLS_VERSION_NUMBER <= 0x020b00 -+# define VMIME_GNUTLS_NEEDS_GCRYPT 1 -+#endif -+ - #if VMIME_HAVE_PTHREAD - # include <pthread.h> --# include <gcrypt.h> -+# if VMIME_GNUTLS_NEEDS_GCRYPT -+# include <gcrypt.h> -+# endif - # include <errno.h> - #endif // VMIME_HAVE_PTHREAD - -@@ -49,7 +57,7 @@ - #endif // VMIME_DEBUG && GNUTLS_DEBUG - - --#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) -+#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) - extern "C" - { - GCRY_THREAD_OPTION_PTHREAD_IMPL; -@@ -70,7 +78,9 @@ struct TLSGlobal - TLSGlobal() - { - #if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) -+ #if VMIME_GNUTLS_NEEDS_GCRYPT - gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); -+ #endif // VMIME_GNUTLS_NEEDS_GCRYPT - #endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL - - gnutls_global_init(); --- -1.7.10.4 - - -From f21c55be642b166a2f0518ace2b179bed3916b23 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sun, 21 Aug 2011 09:04:46 +0000 -Subject: [PATCH 24/47] Fixed HAVE_GNUTLS_PRIORITY_FUNCS never defined when - configured with no TLS support. - - -diff --git a/SConstruct b/SConstruct -index 01ad3f3..11e884b 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -1654,10 +1654,16 @@ if test "x$conf_tls" = "xyes"; then - AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) - HAVE_GNUTLS_PRIORITY_FUNCS=0 - fi -+ else -+ AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) -+ HAVE_GNUTLS_PRIORITY_FUNCS=0 - fi - else - AM_CONDITIONAL(VMIME_HAVE_TLS_SUPPORT, false) - VMIME_HAVE_TLS_SUPPORT=0 -+ -+ AM_CONDITIONAL(HAVE_GNUTLS_PRIORITY_FUNCS, false) -+ HAVE_GNUTLS_PRIORITY_FUNCS=0 - fi - - AC_SUBST(LIBGNUTLS_CFLAGS) --- -1.7.10.4 - - -From d4e66226a696745adafa1767210580f8fbb7ae00 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Tue, 15 Nov 2011 11:40:42 +0000 -Subject: [PATCH 25/47] GNU TLS 3 has no 'extra' (thanks to mabrand). - - -diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp -index d3f6d49..cb50acc 100644 ---- a/src/net/tls/TLSSession.cpp -+++ b/src/net/tls/TLSSession.cpp -@@ -22,7 +22,9 @@ - // - - #include <gnutls/gnutls.h> -+#if GNUTLS_VERSION_NUMBER < 0x030000 - #include <gnutls/extra.h> -+#endif - - #include "vmime/config.hpp" - --- -1.7.10.4 - - -From bacbe512e406d22f6acc83597fcdfc2d624cf82b Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Tue, 15 Nov 2011 11:46:07 +0000 -Subject: [PATCH 26/47] Set Diffie-Hellman prime size (bug SF#3434852). - - -diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp -index cb50acc..0606808 100644 ---- a/src/net/tls/TLSSession.cpp -+++ b/src/net/tls/TLSSession.cpp -@@ -139,6 +139,7 @@ TLSSession::TLSSession(ref <security::cert::certificateVerifier> cv) - // Sets some default priority on the ciphers, key exchange methods, - // macs and compression methods. - #if HAVE_GNUTLS_PRIORITY_FUNCS -+ gnutls_dh_set_prime_bits(*m_gnutlsSession, 128); - - if ((res = gnutls_priority_set_direct - (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0) --- -1.7.10.4 - - -From 6574b60a303c5d864e840aa23959656bb2803485 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 22 Dec 2011 08:51:28 +0000 -Subject: [PATCH 27/47] Updated coding conventions. - - -diff --git a/HACKING b/HACKING -index 4f35a53..f51d738 100644 ---- a/HACKING -+++ b/HACKING -@@ -1,10 +1,10 @@ - --This file contains coding guidelines for VMime. You should follow these --guidelines if you want to contribute to VMime. It guarantees some minimal --quality of the code. -+This file contains coding guidelines for VMime. You should follow them -+if you want to contribute to VMime. The rules below are not guidelines -+or recommendations, but strict rules. - - --1. General guidelines -+1. General rules - 1.1. Language - 1.2. Unit tests - 1.3. CVS -@@ -18,19 +18,22 @@ quality of the code. - 2.5. Line length - 2.6. Spaces and parentheses - 2.7. End-of-line character -+ 2.8. Short functions -+ 2.9. Limit Variable Scope - 3. Naming conventions - 3.1. Classes - 3.2. Variables/parameters/member variables - 3.3. Member variables - 3.4. Files - 3.5. Namespaces -+ 3.6. Constants - 4. Comments - 5. Miscellaneous - - - --1. General guidelines --===================== -+1. General rules -+================ - - 1.1. Language - ------------- -@@ -50,7 +53,7 @@ When you fix a bug, also add a new test case to ensure the bug will not - happen anymore. - - --1.3. CVS -+1.3. SVN - -------- - - Each commit MUST be done with a message ('-m' flag) that briefly describes what -@@ -154,7 +157,11 @@ Except when body spans over multiple lines: - 2.5. Line length - ---------------- - --Line length should not exceed 80 characters. -+Each line of text should not exceed 80 characters. -+ -+Exception: if a comment line contains an example command or a literal URL -+longer than 100 characters, that line may be longer than 100 characters -+for ease of cut and paste. - - - 2.6. Spaces and parentheses -@@ -193,6 +200,30 @@ Configure your editor to use "\n" (UNIX convention) for end-of-line sequence, - and not "\r\n" (Windows), nor "\n\r", nor any other combination. - - -+2.8. Short functions -+-------------------- -+ -+To the extent that it is feasible, functions should be kept small and focused. -+It is, however, recognized that long functions are sometimes appropriate, so no -+hard limit is placed on method length. If a function exceeds 40 lines or so, -+think about whether it can be broken up without harming the structure of the -+program. -+ -+ -+2.9. Limit Variable Scope -+------------------------- -+ -+The scope of local variables should be kept to a minimum. By doing so, you -+increase the readability and maintainability of your code and reduce the -+likelihood of error. Each variable should be declared in the innermost block -+that encloses all uses of the variable. -+ -+Local variables should be declared at the point they are first used. Nearly -+every local variable declaration should contain an initializer. If you don't -+yet have enough information to initialize a variable sensibly, you should -+postpone the declaration until you do. -+ -+ - - 3. Naming conventions - ===================== -@@ -255,6 +286,12 @@ Implementation files must be placed in 'src/' directory. - Namespaces are named exactly like variables. - - -+3.6. Constants -+-------------- -+ -+Constants are ALL_CAPS_WITH_UNDERSCORES. -+ -+ - - 4. Comments - =========== --- -1.7.10.4 - - -From 130e5223dea0af2f8d9d01cca7845be4e1a08d13 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 11:46:39 +0200 -Subject: [PATCH 28/47] Added function to retrieve sequence numbers of - messages whose UID is greater or equal than a - specified UID (thanks to Zahi Mashael). - - -diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp -index 0122d21..50a2f2b 100644 ---- a/src/net/imap/IMAPFolder.cpp -+++ b/src/net/imap/IMAPFolder.cpp -@@ -1772,6 +1772,62 @@ void IMAPFolder::status(int& count, int& unseen) - } - - -+std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) -+{ -+ std::vector<int> v; -+ -+ std::ostringstream command; -+ command.imbue(std::locale::classic()); -+ -+ command << "SEARCH UID " << uid; -+ -+ // Send the request -+ m_connection->send(true, command.str(), true); -+ -+ // Get the response -+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); -+ -+ if (resp->isBad() || -+ resp->response_done()->response_tagged()->resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) -+ { -+ throw exceptions::command_error("SEARCH", -+ m_connection->getParser()->lastLine(), "bad response"); -+ } -+ -+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data(); -+ -+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator -+ it = respDataList.begin() ; it != respDataList.end() ; ++it) -+ { -+ if ((*it)->response_data() == NULL) -+ { -+ throw exceptions::command_error("SEARCH", -+ m_connection->getParser()->lastLine(), "invalid response"); -+ } -+ -+ const IMAPParser::mailbox_data* mailboxData = -+ (*it)->response_data()->mailbox_data(); -+ -+ // We are only interested in responses of type "SEARCH" -+ if (mailboxData == NULL || -+ mailboxData->type() != IMAPParser::mailbox_data::SEARCH) -+ { -+ continue; -+ } -+ -+ for (std::vector <IMAPParser::nz_number*>::const_iterator -+ it = mailboxData->search_nz_number_list().begin() ; -+ it != mailboxData->search_nz_number_list().end(); -+ ++it) -+ { -+ v.push_back((*it)->value()); -+ } -+ } -+ -+ return v; -+} -+ -+ - } // imap - } // net - } // vmime -diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp -index dd680c9..d11ae3b 100644 ---- a/src/net/maildir/maildirFolder.cpp -+++ b/src/net/maildir/maildirFolder.cpp -@@ -1363,6 +1363,12 @@ const utility::file::path maildirFolder::getMessageFSPath(const int number) cons - } - - -+std::vector <int> maildirFolder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ - } // maildir - } // net - } // vmime -diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp -index d5fc687..e085609 100644 ---- a/src/net/pop3/POP3Folder.cpp -+++ b/src/net/pop3/POP3Folder.cpp -@@ -843,6 +843,12 @@ void POP3Folder::expunge() - } - - -+std::vector <int> POP3Folder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ - } // pop3 - } // net - } // vmime -diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp -index b20e9c9..df9cbaf 100644 ---- a/vmime/net/folder.hpp -+++ b/vmime/net/folder.hpp -@@ -383,6 +383,13 @@ public: - */ - virtual int getFetchCapabilities() const = 0; - -+ /** Return the sequence numbers of messages whose UID equal or greater than uid -+ * -+ * @param uid the uid of the first message -+ * @throw net_exception if an error occurs -+ */ -+ virtual std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid) = 0; -+ - // Event listeners - void addMessageChangedListener(events::messageChangedListener* l); - void removeMessageChangedListener(events::messageChangedListener* l); -diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp -index dec3878..cc52596 100644 ---- a/vmime/net/imap/IMAPFolder.hpp -+++ b/vmime/net/imap/IMAPFolder.hpp -@@ -120,6 +120,8 @@ public: - - int getFetchCapabilities() const; - -+ std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid); -+ - private: - - void registerMessage(IMAPMessage* msg); -diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp -index 7474b1a..68b5b89 100644 ---- a/vmime/net/maildir/maildirFolder.hpp -+++ b/vmime/net/maildir/maildirFolder.hpp -@@ -121,6 +121,8 @@ public: - - int getFetchCapabilities() const; - -+ std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid); -+ - private: - - void scanFolder(); -diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp -index abaa8eb..c482908 100644 ---- a/vmime/net/pop3/POP3Folder.hpp -+++ b/vmime/net/pop3/POP3Folder.hpp -@@ -119,6 +119,8 @@ public: - - int getFetchCapabilities() const; - -+ std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid); -+ - private: - - void registerMessage(POP3Message* msg); --- -1.7.10.4 - - -From 3f1a565b8b532f0d11a13d3f6d763b00c8ce625b Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 11:55:07 +0200 -Subject: [PATCH 29/47] Added .gitignore. - - -diff --git a/.gitignore b/.gitignore -new file mode 100644 -index 0000000..44e03a8 ---- /dev/null -+++ b/.gitignore -@@ -0,0 +1,11 @@ -+*.o -+*.swp -+build/ -+ -+/libvmime.a -+/vmime.pc -+/vmime/config.hpp -+ -+# SConstruct -+.sconsign.dblite -+/options.cache --- -1.7.10.4 - - -From 5937bcda0fac9cb80d0cecbaa663ecdfe2839c09 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 12:08:01 +0200 -Subject: [PATCH 30/47] Added check before dereferencing. - - -diff --git a/vmime/utility/smartPtr.hpp b/vmime/utility/smartPtr.hpp -index c448632..df63685 100644 ---- a/vmime/utility/smartPtr.hpp -+++ b/vmime/utility/smartPtr.hpp -@@ -338,7 +338,9 @@ protected: - { - if (m_ptr) - { -- m_ptr->getRefManager()->releaseStrong(); -+ if (m_ptr->getRefManager()) -+ m_ptr->getRefManager()->releaseStrong(); -+ - m_ptr = 0; - } - } --- -1.7.10.4 - - -From b0d74ce63ea9563ef4b218bce2497bd668dfad29 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 12:34:51 +0200 -Subject: [PATCH 31/47] Updated README. - - -diff --git a/README b/README -index 6921cea..7db9175 100644 ---- a/README -+++ b/README -@@ -1,2 +1,30 @@ - --TODO -+VMime is a powerful C++ class library for working with RFC-822 and MIME messages -+and Internet messaging services like IMAP, POP or SMTP. -+ -+With VMime you can parse, generate and modify messages, and also connect to store -+and transport services to receive or send messages over the Internet. The library -+offers all the features to build a complete mail client. -+ -+Key Features -+------------ -+ -+* it is free software! GNU GPL license (Commercial licenses available!) -+* fully RFC-compliant implementation -+* object-oriented and modular design -+* very easy-to-use (intuitive design) -+* well documented code -+* very high reliability -+* maximum portability -+ -+Features Overview -+----------------- -+ -+* RFC-2822 and multipart messages -+* aggregate documents and embedded objects -+* 8-bit MIME and encoded word extensions -+* full support for attachments -+* POP3, IMAP, SMTP, maildir and sendmail -+* SSL/TLS security layer and X.509 certificates (using GNU TLS) -+* SASL authentication (using GNU SASL) -+ --- -1.7.10.4 - - -From 350fada21a4f11c2f633a3cde1f2195efefe7e32 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 22:10:54 +0200 -Subject: [PATCH 32/47] Added test: Ensure '7bit' encoding is used when body - is 7-bit only. - - -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index 075b8f9..e1d47a3 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -37,6 +37,7 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testPrologEpilog) - VMIME_TEST(testPrologEncoding) - VMIME_TEST(testSuccessiveBoundaries) -+ VMIME_TEST(testGenerate7bit) - VMIME_TEST_LIST_END - - -@@ -200,5 +201,18 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); - } - -+ /** Ensure '7bit' encoding is used when body is 7-bit only. */ -+ void testGenerate7bit() -+ { -+ vmime::ref <vmime::plainTextPart> p1 = vmime::create <vmime::plainTextPart>(); -+ p1->setText(vmime::create <vmime::stringContentHandler>("Part1 is US-ASCII only.")); -+ -+ vmime::ref <vmime::message> msg = vmime::create <vmime::message>(); -+ p1->generateIn(msg, msg); -+ -+ vmime::ref <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader(); -+ VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); -+ } -+ - VMIME_TEST_SUITE_END - --- -1.7.10.4 - - -From 6c877ea41a2e408df61ac6f988c3bae7e0821141 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 22:29:32 +0200 -Subject: [PATCH 33/47] Added tests for Quoted-Printable encoding. - - -diff --git a/tests/utility/encoderTest.cpp b/tests/utility/encoderTest.cpp -index f2d42b6..b2d6bc8 100644 ---- a/tests/utility/encoderTest.cpp -+++ b/tests/utility/encoderTest.cpp -@@ -33,6 +33,8 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST_LIST_BEGIN - VMIME_TEST(testBase64) - VMIME_TEST(testQuotedPrintable) -+ VMIME_TEST(testQuotedPrintable_SoftLineBreaks) -+ VMIME_TEST(testQuotedPrintable_CRLF) - VMIME_TEST(testQuotedPrintable_RFC2047) - VMIME_TEST_LIST_END - -@@ -288,6 +290,35 @@ VMIME_TEST_SUITE_BEGIN - } - } - -+ /** Tests Soft Line Breaks (RFC-2047/6.7(5). */ -+ void testQuotedPrintable_SoftLineBreaks() -+ { -+ VASSERT_EQ("1", "Now's the time=\r\n" -+ " for all folk =\r\n" -+ "to come to the=\r\n" -+ " aid of their =\r\n" -+ "country.", -+ encode("quoted-printable", "Now's the time for all folk " -+ "to come to the aid of their country.", 15)); -+ } -+ -+ /** In text mode, ensure line breaks in QP-encoded text are represented -+ * by a CRLF sequence, as per RFC-2047/6.7(4). */ -+ void testQuotedPrintable_CRLF() -+ { -+ vmime::propertySet encProps; -+ -+ // in "text" mode -+ encProps["text"] = true; -+ VASSERT_EQ("text", "line1\r\nline2", -+ encode("quoted-printable", "line1\r\nline2", 80, encProps)); -+ -+ // in "binary" mode -+ encProps["text"] = false; -+ VASSERT_EQ("binary", "line1=0D=0Aline2", -+ encode("quoted-printable", "line1\r\nline2", 80, encProps)); -+ } -+ - void testQuotedPrintable_RFC2047() - { - /* --- -1.7.10.4 - - -From e88f062ab58654aee3cf45f94e8a5dd6c1256279 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Thu, 5 Apr 2012 23:15:04 +0200 -Subject: [PATCH 34/47] Fixed wrong encoding of line breaks in QP-encoded text - (issue #7). - - -diff --git a/src/encoding.cpp b/src/encoding.cpp -index 0919d44..b4e79db 100644 ---- a/src/encoding.cpp -+++ b/src/encoding.cpp -@@ -34,19 +34,28 @@ namespace vmime - - - encoding::encoding() -- : m_name(encodingTypes::SEVEN_BIT) -+ : m_name(encodingTypes::SEVEN_BIT), -+ m_usage(USAGE_UNKNOWN) - { - } - - - encoding::encoding(const string& name) -- : m_name(utility::stringUtils::toLower(name)) -+ : m_name(utility::stringUtils::toLower(name)), -+ m_usage(USAGE_UNKNOWN) -+{ -+} -+ -+ -+encoding::encoding(const string& name, const EncodingUsage usage) -+ : m_name(utility::stringUtils::toLower(name)), -+ m_usage(usage) - { - } - - - encoding::encoding(const encoding& enc) -- : headerFieldValue(), m_name(enc.m_name) -+ : headerFieldValue(), m_name(enc.m_name), m_usage(enc.m_usage) - { - } - -@@ -54,6 +63,8 @@ encoding::encoding(const encoding& enc) - void encoding::parse(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { -+ m_usage = USAGE_UNKNOWN; -+ - m_name = utility::stringUtils::toLower(utility::stringUtils::trim - (utility::stringUtils::unquote(utility::stringUtils::trim - (string(buffer.begin() + position, buffer.begin() + end))))); -@@ -80,7 +91,14 @@ void encoding::generate(utility::outputStream& os, const string::size_type /* ma - - ref <utility::encoder::encoder> encoding::getEncoder() const - { -- return (utility::encoder::encoderFactory::getInstance()->create(generate())); -+ ref <utility::encoder::encoder> encoder = -+ utility::encoder::encoderFactory::getInstance()->create(generate()); -+ -+ // FIXME: this should not be here (move me into QP encoder instead?) -+ if (m_usage == USAGE_TEXT && m_name == encodingTypes::QUOTED_PRINTABLE) -+ encoder->getProperties()["text"] = true; -+ -+ return encoder; - } - - -@@ -94,6 +112,7 @@ encoding& encoding::operator=(const encoding& other) - encoding& encoding::operator=(const string& name) - { - m_name = utility::stringUtils::toLower(name); -+ m_usage = USAGE_UNKNOWN; - return (*this); - } - -@@ -167,6 +186,8 @@ const encoding encoding::decideImpl - const encoding encoding::decide - (ref <const contentHandler> data, const EncodingUsage usage) - { -+ encoding enc; -+ - if (usage == USAGE_TEXT && data->isBuffered() && - data->getLength() > 0 && data->getLength() < 32768) - { -@@ -177,12 +198,16 @@ const encoding encoding::decide - data->extract(os); - os.flush(); - -- return decideImpl(buffer.begin(), buffer.end()); -+ enc = decideImpl(buffer.begin(), buffer.end()); - } - else - { -- return encoding(encodingTypes::BASE64); -+ enc = encoding(encodingTypes::BASE64); - } -+ -+ enc.setUsage(usage); -+ -+ return enc; - } - - -@@ -194,7 +219,10 @@ const encoding encoding::decide(ref <const contentHandler> data, - encoding recEncoding; - - if (chset.getRecommendedEncoding(recEncoding)) -+ { -+ recEncoding.setUsage(usage); - return recEncoding; -+ } - } - - return decide(data, usage); -@@ -227,6 +255,18 @@ void encoding::setName(const string& name) - } - - -+encoding::EncodingUsage encoding::getUsage() const -+{ -+ return m_usage; -+} -+ -+ -+void encoding::setUsage(const EncodingUsage usage) -+{ -+ m_usage = usage; -+} -+ -+ - const std::vector <ref <const component> > encoding::getChildComponents() const - { - return std::vector <ref <const component> >(); -diff --git a/src/utility/encoder/qpEncoder.cpp b/src/utility/encoder/qpEncoder.cpp -index aa95022..ab8db2e 100644 ---- a/src/utility/encoder/qpEncoder.cpp -+++ b/src/utility/encoder/qpEncoder.cpp -@@ -292,14 +292,15 @@ utility::stream::size_type qpEncoder::encode(utility::inputStream& in, - case 13: // CR - case 10: // LF - { -- // Text mode (where using CRLF or LF or ... does not -- // care for a new line...) -- if (text) -+ // RFC-2045/6.7(4) -+ -+ // Text data -+ if (text && !rfc2047) - { - outBuffer[outBufferPos++] = c; - ++curCol; - } -- // Binary mode (where CR and LF bytes are important!) -+ // Binary data - else - { - QP_ENCODE_HEX(c); -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index e1d47a3..9d51262 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -38,6 +38,7 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST(testPrologEncoding) - VMIME_TEST(testSuccessiveBoundaries) - VMIME_TEST(testGenerate7bit) -+ VMIME_TEST(testTextUsageForQPEncoding) - VMIME_TEST_LIST_END - - -@@ -214,5 +215,28 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); - } - -+ void testTextUsageForQPEncoding() -+ { -+ vmime::ref <vmime::plainTextPart> part = vmime::create <vmime::plainTextPart>(); -+ part->setText(vmime::create <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89")); -+ -+ vmime::ref <vmime::message> msg = vmime::create <vmime::message>(); -+ part->generateIn(msg, msg); -+ -+ vmime::ref <vmime::body> body = msg->getBody()->getPartAt(0)->getBody(); -+ vmime::ref <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader(); -+ -+ std::ostringstream oss; -+ vmime::utility::outputStreamAdapter os(oss); -+ body->generate(os, 80); -+ -+ VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate()); -+ -+ // This should *NOT* be: -+ // Part1-line1=0D=0APart1-line2=0D=0A=89 -+ VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str()); -+ } -+ -+ - VMIME_TEST_SUITE_END - -diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp -index ba78081..42f5246 100644 ---- a/vmime/encoding.hpp -+++ b/vmime/encoding.hpp -@@ -47,6 +47,7 @@ public: - - enum EncodingUsage - { -+ USAGE_UNKNOWN, - USAGE_TEXT, /**< Use for body text. */ - USAGE_BINARY_DATA /**< Use for attachment, image... */ - }; -@@ -54,6 +55,7 @@ public: - - encoding(); - explicit encoding(const string& name); -+ encoding(const string& name, const EncodingUsage usage); - encoding(const encoding& enc); - - public: -@@ -72,6 +74,19 @@ public: - */ - void setName(const string& name); - -+ /** Return the type of contents this encoding is used for. -+ * See the EncodingUsage enum. -+ */ -+ EncodingUsage getUsage() const; -+ -+ /** Set the type of contents this encoding is used for. -+ * See the EncodingUsage enum. -+ * -+ * @param usage type of contents -+ */ -+ void setUsage(const EncodingUsage usage); -+ -+ - encoding& operator=(const encoding& other); - encoding& operator=(const string& name); - -@@ -113,6 +128,7 @@ public: - private: - - string m_name; -+ EncodingUsage m_usage; - - /** Decide which encoding to use based on the specified data. - * --- -1.7.10.4 - - -From ea77bdba96588345090e3de81d9d6af116edeeb5 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 6 Apr 2012 22:26:18 +0200 -Subject: [PATCH 35/47] Fixed memory leak. - - -diff --git a/src/net/tls/TLSSocket.cpp b/src/net/tls/TLSSocket.cpp -index dab0338..3cccc1e 100644 ---- a/src/net/tls/TLSSocket.cpp -+++ b/src/net/tls/TLSSocket.cpp -@@ -50,6 +50,12 @@ TLSSocket::TLSSocket(ref <TLSSession> session, ref <socket> sok) - - TLSSocket::~TLSSocket() - { -+ if (m_ex) -+ { -+ delete m_ex; -+ m_ex = NULL; -+ } -+ - try - { - disconnect(); --- -1.7.10.4 - - -From 440d491fd6da134fcb5f19416743e8f2044556bf Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sat, 14 Apr 2012 13:46:05 +0200 -Subject: [PATCH 36/47] Split stream.hpp/.cpp into multiple source files. - - -diff --git a/SConstruct b/SConstruct -index 11e884b..ea5c4eb 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -144,6 +144,20 @@ libvmime_sources = [ - 'utility/smartPtr.cpp', 'utility/smartPtr.hpp', - 'utility/smartPtrInt.cpp', 'utility/smartPtrInt.hpp', - 'utility/stream.cpp', 'utility/stream.hpp', -+ 'utility/streamUtils.cpp', 'utility/streamUtils.hpp', -+ 'utility/filteredStream.cpp', 'utility/filteredStream.hpp', -+ 'utility/inputStream.cpp', 'utility/inputStream.hpp', -+ 'utility/inputStreamAdapter.cpp', 'utility/inputStreamAdapter.hpp', -+ 'utility/inputStreamByteBufferAdapter.cpp', 'utility/inputStreamByteBufferAdapter.hpp', -+ 'utility/inputStreamPointerAdapter.cpp', 'utility/inputStreamPointerAdapter.hpp', -+ 'utility/inputStreamSocketAdapter.cpp', 'utility/inputStreamSocketAdapter.hpp', -+ 'utility/inputStreamStringAdapter.cpp', 'utility/inputStreamStringAdapter.hpp', -+ 'utility/inputStreamStringProxyAdapter.cpp', 'utility/inputStreamStringProxyAdapter.hpp', -+ 'utility/outputStream.cpp', 'utility/outputStream.hpp', -+ 'utility/outputStreamAdapter.cpp', 'utility/outputStreamAdapter.hpp', -+ 'utility/outputStreamByteArrayAdapter.cpp', 'utility/outputStreamByteArrayAdapter.hpp', -+ 'utility/outputStreamSocketAdapter.cpp', 'utility/outputStreamSocketAdapter.hpp', -+ 'utility/outputStreamStringAdapter.cpp', 'utility/outputStreamStringAdapter.hpp', - 'utility/stringProxy.cpp', 'utility/stringProxy.hpp', - 'utility/stringUtils.cpp', 'utility/stringUtils.hpp', - 'utility/url.cpp', 'utility/url.hpp', -diff --git a/src/charsetConverter.cpp b/src/charsetConverter.cpp -index 2135788..cf75bdd 100644 ---- a/src/charsetConverter.cpp -+++ b/src/charsetConverter.cpp -@@ -23,6 +23,8 @@ - - #include "vmime/charsetConverter.hpp" - #include "vmime/exception.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/outputStreamStringAdapter.hpp" - - - extern "C" -diff --git a/src/component.cpp b/src/component.cpp -index fbf677b..139cf66 100644 ---- a/src/component.cpp -+++ b/src/component.cpp -@@ -23,6 +23,7 @@ - - #include "vmime/component.hpp" - #include "vmime/base.hpp" -+#include "vmime/utility/outputStreamAdapter.hpp" - - #include <sstream> - -diff --git a/src/encoding.cpp b/src/encoding.cpp -index b4e79db..5d99ab6 100644 ---- a/src/encoding.cpp -+++ b/src/encoding.cpp -@@ -24,6 +24,7 @@ - #include "vmime/encoding.hpp" - #include "vmime/contentHandler.hpp" - -+#include "vmime/utility/outputStreamStringAdapter.hpp" - #include "vmime/utility/encoder/encoderFactory.hpp" - - #include <algorithm> -diff --git a/src/fileAttachment.cpp b/src/fileAttachment.cpp -index da7c4b7..cb23cd0 100644 ---- a/src/fileAttachment.cpp -+++ b/src/fileAttachment.cpp -@@ -28,6 +28,7 @@ - #include "vmime/exception.hpp" - - #include "vmime/streamContentHandler.hpp" -+#include "vmime/utility/inputStreamPointerAdapter.hpp" - - #include "vmime/contentDispositionField.hpp" - -diff --git a/src/generatedMessageAttachment.cpp b/src/generatedMessageAttachment.cpp -index e9bd1a6..443a9d3 100644 ---- a/src/generatedMessageAttachment.cpp -+++ b/src/generatedMessageAttachment.cpp -@@ -23,6 +23,8 @@ - - #include "vmime/generatedMessageAttachment.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime - { -diff --git a/src/htmlTextPart.cpp b/src/htmlTextPart.cpp -index c845b57..98524af 100644 ---- a/src/htmlTextPart.cpp -+++ b/src/htmlTextPart.cpp -@@ -31,6 +31,8 @@ - #include "vmime/emptyContentHandler.hpp" - #include "vmime/stringContentHandler.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime - { -diff --git a/src/mdn/MDNHelper.cpp b/src/mdn/MDNHelper.cpp -index b419b85..1dd7ff3 100644 ---- a/src/mdn/MDNHelper.cpp -+++ b/src/mdn/MDNHelper.cpp -@@ -31,6 +31,8 @@ - #include "vmime/path.hpp" - #include "vmime/dateTime.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime { - namespace mdn { -diff --git a/src/mdn/receivedMDNInfos.cpp b/src/mdn/receivedMDNInfos.cpp -index cff211c..f97a58d 100644 ---- a/src/mdn/receivedMDNInfos.cpp -+++ b/src/mdn/receivedMDNInfos.cpp -@@ -23,6 +23,8 @@ - - #include "vmime/mdn/receivedMDNInfos.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime { - namespace mdn { -diff --git a/src/message.cpp b/src/message.cpp -index 6f4b046..1b4f086 100644 ---- a/src/message.cpp -+++ b/src/message.cpp -@@ -24,6 +24,8 @@ - #include "vmime/message.hpp" - #include "vmime/options.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - #include <sstream> - - -diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp -index 50a2f2b..81bf386 100644 ---- a/src/net/imap/IMAPFolder.cpp -+++ b/src/net/imap/IMAPFolder.cpp -@@ -34,6 +34,8 @@ - #include "vmime/exception.hpp" - #include "vmime/utility/smartPtr.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - #include <algorithm> - #include <sstream> - -diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp -index bc661ed..702d5f2 100644 ---- a/src/net/imap/IMAPMessage.cpp -+++ b/src/net/imap/IMAPMessage.cpp -@@ -31,6 +31,8 @@ - #include "vmime/net/imap/IMAPPart.hpp" - #include "vmime/net/imap/IMAPMessagePartContentHandler.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - #include <sstream> - #include <iterator> - #include <typeinfo> -diff --git a/src/net/imap/IMAPMessagePartContentHandler.cpp b/src/net/imap/IMAPMessagePartContentHandler.cpp -index 4e6ba97..85c6ec2 100644 ---- a/src/net/imap/IMAPMessagePartContentHandler.cpp -+++ b/src/net/imap/IMAPMessagePartContentHandler.cpp -@@ -23,6 +23,9 @@ - - #include "vmime/net/imap/IMAPMessagePartContentHandler.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/inputStreamStringProxyAdapter.hpp" -+ - - namespace vmime { - namespace net { -diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp -index d11ae3b..8c4b275 100644 ---- a/src/net/maildir/maildirFolder.cpp -+++ b/src/net/maildir/maildirFolder.cpp -@@ -35,6 +35,9 @@ - #include "vmime/exception.hpp" - #include "vmime/platform.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+ - - namespace vmime { - namespace net { -diff --git a/src/net/maildir/maildirMessage.cpp b/src/net/maildir/maildirMessage.cpp -index 51cd1ba..4ab75e7 100644 ---- a/src/net/maildir/maildirMessage.cpp -+++ b/src/net/maildir/maildirMessage.cpp -@@ -31,6 +31,8 @@ - #include "vmime/exception.hpp" - #include "vmime/platform.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime { - namespace net { -diff --git a/src/net/pop3/POP3Message.cpp b/src/net/pop3/POP3Message.cpp -index 50f4f87..69ef004 100644 ---- a/src/net/pop3/POP3Message.cpp -+++ b/src/net/pop3/POP3Message.cpp -@@ -25,6 +25,8 @@ - #include "vmime/net/pop3/POP3Folder.hpp" - #include "vmime/net/pop3/POP3Store.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - #include <sstream> - - -diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp -index 9d554c6..793112a 100644 ---- a/src/net/pop3/POP3Store.cpp -+++ b/src/net/pop3/POP3Store.cpp -@@ -30,6 +30,7 @@ - #include "vmime/security/digest/messageDigestFactory.hpp" - #include "vmime/utility/filteredStream.hpp" - #include "vmime/utility/stringUtils.hpp" -+#include "vmime/utility/inputStreamSocketAdapter.hpp" - - #include "vmime/net/defaultConnectionInfos.hpp" - -diff --git a/src/net/sendmail/sendmailTransport.cpp b/src/net/sendmail/sendmailTransport.cpp -index 53ff0d1..e7762cc 100644 ---- a/src/net/sendmail/sendmailTransport.cpp -+++ b/src/net/sendmail/sendmailTransport.cpp -@@ -32,6 +32,8 @@ - #include "vmime/utility/childProcess.hpp" - #include "vmime/utility/smartPtr.hpp" - -+#include "vmime/utility/streamUtils.hpp" -+ - #include "vmime/net/defaultConnectionInfos.hpp" - - #include "vmime/config.hpp" -diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp -index d9fb7b8..bbbea75 100644 ---- a/src/net/smtp/SMTPTransport.cpp -+++ b/src/net/smtp/SMTPTransport.cpp -@@ -30,6 +30,8 @@ - - #include "vmime/utility/filteredStream.hpp" - #include "vmime/utility/stringUtils.hpp" -+#include "vmime/utility/outputStreamSocketAdapter.hpp" -+#include "vmime/utility/streamUtils.hpp" - - #include "vmime/net/defaultConnectionInfos.hpp" - -diff --git a/src/net/transport.cpp b/src/net/transport.cpp -index dd4663d..f8ca7b7 100644 ---- a/src/net/transport.cpp -+++ b/src/net/transport.cpp -@@ -27,6 +27,9 @@ - #include "vmime/mailboxList.hpp" - #include "vmime/message.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+ - - namespace vmime { - namespace net { -diff --git a/src/parameter.cpp b/src/parameter.cpp -index d757e1b..ccbe1a5 100644 ---- a/src/parameter.cpp -+++ b/src/parameter.cpp -@@ -27,6 +27,9 @@ - #include "vmime/text.hpp" - #include "vmime/encoding.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+ - - namespace vmime - { -diff --git a/src/parsedMessageAttachment.cpp b/src/parsedMessageAttachment.cpp -index bde56aa..cb7d71d 100644 ---- a/src/parsedMessageAttachment.cpp -+++ b/src/parsedMessageAttachment.cpp -@@ -26,6 +26,8 @@ - #include "vmime/stringContentHandler.hpp" - #include "vmime/contentDisposition.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime - { -diff --git a/src/security/cert/X509Certificate.cpp b/src/security/cert/X509Certificate.cpp -index 1cd079c..8df4e5e 100644 ---- a/src/security/cert/X509Certificate.cpp -+++ b/src/security/cert/X509Certificate.cpp -@@ -28,6 +28,8 @@ - - #include "vmime/security/cert/X509Certificate.hpp" - -+#include "vmime/utility/outputStreamByteArrayAdapter.hpp" -+ - - namespace vmime { - namespace security { -diff --git a/src/security/sasl/SASLContext.cpp b/src/security/sasl/SASLContext.cpp -index 51c2bed..4bb33c1 100644 ---- a/src/security/sasl/SASLContext.cpp -+++ b/src/security/sasl/SASLContext.cpp -@@ -33,6 +33,9 @@ - #include "vmime/utility/encoder/encoderFactory.hpp" - - #include "vmime/utility/stream.hpp" -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamByteBufferAdapter.hpp" - - - namespace vmime { -diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp -index 2ebd073..89a36b4 100644 ---- a/src/streamContentHandler.cpp -+++ b/src/streamContentHandler.cpp -@@ -23,6 +23,10 @@ - - #include "vmime/streamContentHandler.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/streamUtils.hpp" -+ - - namespace vmime - { -diff --git a/src/stringContentHandler.cpp b/src/stringContentHandler.cpp -index 4e85a6c..5a1e72c 100644 ---- a/src/stringContentHandler.cpp -+++ b/src/stringContentHandler.cpp -@@ -23,6 +23,10 @@ - - #include "vmime/stringContentHandler.hpp" - -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamStringProxyAdapter.hpp" -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - - namespace vmime - { -diff --git a/src/utility/encoder/defaultEncoder.cpp b/src/utility/encoder/defaultEncoder.cpp -index 4d0ffb5..e2d226e 100644 ---- a/src/utility/encoder/defaultEncoder.cpp -+++ b/src/utility/encoder/defaultEncoder.cpp -@@ -23,6 +23,8 @@ - - #include "vmime/utility/encoder/defaultEncoder.hpp" - -+#include "vmime/utility/streamUtils.hpp" -+ - - namespace vmime { - namespace utility { -diff --git a/src/utility/inputStream.cpp b/src/utility/inputStream.cpp -new file mode 100644 -index 0000000..dd0adf4 ---- /dev/null -+++ b/src/utility/inputStream.cpp -@@ -0,0 +1,33 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/inputStreamAdapter.cpp b/src/utility/inputStreamAdapter.cpp -new file mode 100644 -index 0000000..b44b084 ---- /dev/null -+++ b/src/utility/inputStreamAdapter.cpp -@@ -0,0 +1,70 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamAdapter::inputStreamAdapter(std::istream& is) -+ : m_stream(is) -+{ -+} -+ -+ -+bool inputStreamAdapter::eof() const -+{ -+ return (m_stream.eof()); -+} -+ -+ -+void inputStreamAdapter::reset() -+{ -+ m_stream.exceptions(std::ios_base::badbit); -+ m_stream.seekg(0, std::ios::beg); -+ m_stream.clear(); -+} -+ -+ -+stream::size_type inputStreamAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ m_stream.exceptions(std::ios_base::badbit); -+ m_stream.read(data, count); -+ return (m_stream.gcount()); -+} -+ -+ -+stream::size_type inputStreamAdapter::skip(const size_type count) -+{ -+ m_stream.exceptions(std::ios_base::badbit); -+ m_stream.ignore(count); -+ return (m_stream.gcount()); -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/inputStreamByteBufferAdapter.cpp b/src/utility/inputStreamByteBufferAdapter.cpp -new file mode 100644 -index 0000000..92e779f ---- /dev/null -+++ b/src/utility/inputStreamByteBufferAdapter.cpp -@@ -0,0 +1,90 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamByteBufferAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte_t* buffer, const size_type length) -+ : m_buffer(buffer), m_length(length), m_pos(0) -+{ -+} -+ -+ -+bool inputStreamByteBufferAdapter::eof() const -+{ -+ return m_pos >= m_length; -+} -+ -+ -+void inputStreamByteBufferAdapter::reset() -+{ -+ m_pos = 0; -+} -+ -+ -+stream::size_type inputStreamByteBufferAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ const size_type remaining = m_length - m_pos; -+ -+ if (remaining < count) -+ { -+ std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data); -+ m_pos += remaining; -+ -+ return remaining; -+ } -+ else -+ { -+ std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data); -+ m_pos += count; -+ -+ return count; -+ } -+} -+ -+ -+stream::size_type inputStreamByteBufferAdapter::skip(const size_type count) -+{ -+ const size_type remaining = m_length - m_pos; -+ -+ if (remaining < count) -+ { -+ m_pos += remaining; -+ return remaining; -+ } -+ else -+ { -+ m_pos += count; -+ return count; -+ } -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/inputStreamPointerAdapter.cpp b/src/utility/inputStreamPointerAdapter.cpp -new file mode 100644 -index 0000000..4d03e30 ---- /dev/null -+++ b/src/utility/inputStreamPointerAdapter.cpp -@@ -0,0 +1,46 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamPointerAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own) -+ : inputStreamAdapter(*is), m_stream(is), m_own(own) -+{ -+} -+ -+ -+inputStreamPointerAdapter::~inputStreamPointerAdapter() -+{ -+ if (m_own) -+ delete (m_stream); -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/inputStreamSocketAdapter.cpp b/src/utility/inputStreamSocketAdapter.cpp -new file mode 100644 -index 0000000..b93cc3c ---- /dev/null -+++ b/src/utility/inputStreamSocketAdapter.cpp -@@ -0,0 +1,82 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamSocketAdapter.hpp" -+ -+ -+#if VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+#include "vmime/net/socket.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok) -+ : m_socket(sok) -+{ -+} -+ -+ -+bool inputStreamSocketAdapter::eof() const -+{ -+ // Can't know... -+ return false; -+} -+ -+ -+void inputStreamSocketAdapter::reset() -+{ -+ // Not supported -+} -+ -+ -+stream::size_type inputStreamSocketAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ return m_socket.receiveRaw(data, count); -+} -+ -+ -+stream::size_type inputStreamSocketAdapter::skip -+ (const size_type /* count */) -+{ -+ // Not supported -+ return 0; -+} -+ -+ -+stream::size_type inputStreamSocketAdapter::getBlockSize() -+{ -+ return m_socket.getBlockSize(); -+} -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_HAVE_MESSAGING_FEATURES -+ -diff --git a/src/utility/inputStreamStringAdapter.cpp b/src/utility/inputStreamStringAdapter.cpp -new file mode 100644 -index 0000000..31c9fda ---- /dev/null -+++ b/src/utility/inputStreamStringAdapter.cpp -@@ -0,0 +1,94 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer) -+ : m_buffer(buffer), m_begin(0), m_end(buffer.length()), m_pos(0) -+{ -+} -+ -+ -+inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer, -+ const string::size_type begin, const string::size_type end) -+ : m_buffer(buffer), m_begin(begin), m_end(end), m_pos(begin) -+{ -+} -+ -+ -+bool inputStreamStringAdapter::eof() const -+{ -+ return (m_pos >= m_end); -+} -+ -+ -+void inputStreamStringAdapter::reset() -+{ -+ m_pos = m_begin; -+} -+ -+ -+stream::size_type inputStreamStringAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ if (m_pos + count >= m_end) -+ { -+ const size_type remaining = m_end - m_pos; -+ -+ std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data); -+ m_pos = m_end; -+ return (remaining); -+ } -+ else -+ { -+ std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data); -+ m_pos += count; -+ return (count); -+ } -+} -+ -+ -+stream::size_type inputStreamStringAdapter::skip(const size_type count) -+{ -+ if (m_pos + count >= m_end) -+ { -+ const size_type remaining = m_end - m_pos; -+ m_pos = m_end; -+ return (remaining); -+ } -+ else -+ { -+ m_pos += count; -+ return (count); -+ } -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/inputStreamStringProxyAdapter.cpp b/src/utility/inputStreamStringProxyAdapter.cpp -new file mode 100644 -index 0000000..5e4b60b ---- /dev/null -+++ b/src/utility/inputStreamStringProxyAdapter.cpp -@@ -0,0 +1,89 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/inputStreamStringProxyAdapter.hpp" -+#include "vmime/utility/stringProxy.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+inputStreamStringProxyAdapter::inputStreamStringProxyAdapter(const stringProxy& buffer) -+ : m_buffer(buffer), m_pos(0) -+{ -+} -+ -+ -+bool inputStreamStringProxyAdapter::eof() const -+{ -+ return (m_pos >= m_buffer.length()); -+} -+ -+ -+void inputStreamStringProxyAdapter::reset() -+{ -+ m_pos = 0; -+} -+ -+ -+stream::size_type inputStreamStringProxyAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ const size_type remaining = m_buffer.length() - m_pos; -+ -+ if (count > remaining) -+ { -+ std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_end(), data); -+ m_pos = m_buffer.length(); -+ return (remaining); -+ } -+ else -+ { -+ std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_begin() + m_pos + count, data); -+ m_pos += count; -+ return (count); -+ } -+} -+ -+ -+stream::size_type inputStreamStringProxyAdapter::skip(const size_type count) -+{ -+ const size_type remaining = m_buffer.length() - m_pos; -+ -+ if (count > remaining) -+ { -+ m_pos = m_buffer.length(); -+ return (remaining); -+ } -+ else -+ { -+ m_pos += count; -+ return (count); -+ } -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/outputStream.cpp b/src/utility/outputStream.cpp -new file mode 100644 -index 0000000..8a65db5 ---- /dev/null -+++ b/src/utility/outputStream.cpp -@@ -0,0 +1,33 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/outputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/outputStreamAdapter.cpp b/src/utility/outputStreamAdapter.cpp -new file mode 100644 -index 0000000..2da94f1 ---- /dev/null -+++ b/src/utility/outputStreamAdapter.cpp -@@ -0,0 +1,54 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/outputStreamAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+outputStreamAdapter::outputStreamAdapter(std::ostream& os) -+ : m_stream(os) -+{ -+} -+ -+ -+void outputStreamAdapter::write -+ (const value_type* const data, const size_type count) -+{ -+ m_stream.exceptions(std::ios_base::badbit); -+ m_stream.write(data, count); -+} -+ -+ -+void outputStreamAdapter::flush() -+{ -+ m_stream.exceptions(std::ios_base::badbit); -+ m_stream.flush(); -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/outputStreamByteArrayAdapter.cpp b/src/utility/outputStreamByteArrayAdapter.cpp -new file mode 100644 -index 0000000..97b27d2 ---- /dev/null -+++ b/src/utility/outputStreamByteArrayAdapter.cpp -@@ -0,0 +1,51 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/outputStreamByteArrayAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array) -+ : m_array(array) -+{ -+} -+ -+ -+void outputStreamByteArrayAdapter::write(const value_type* const data, const size_type count) -+{ -+ m_array.insert(m_array.end(), data, data + count); -+} -+ -+ -+void outputStreamByteArrayAdapter::flush() -+{ -+ // Do nothing -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/outputStreamSocketAdapter.cpp b/src/utility/outputStreamSocketAdapter.cpp -new file mode 100644 -index 0000000..d933e73 ---- /dev/null -+++ b/src/utility/outputStreamSocketAdapter.cpp -@@ -0,0 +1,68 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/outputStreamSocketAdapter.hpp" -+ -+ -+#if VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+#include "vmime/net/socket.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok) -+ : m_socket(sok) -+{ -+} -+ -+ -+void outputStreamSocketAdapter::write -+ (const value_type* const data, const size_type count) -+{ -+ m_socket.sendRaw(data, count); -+} -+ -+ -+void outputStreamSocketAdapter::flush() -+{ -+ // Do nothing -+} -+ -+ -+stream::size_type outputStreamSocketAdapter::getBlockSize() -+{ -+ return m_socket.getBlockSize(); -+} -+ -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_HAVE_MESSAGING_FEATURES -+ -diff --git a/src/utility/outputStreamStringAdapter.cpp b/src/utility/outputStreamStringAdapter.cpp -new file mode 100644 -index 0000000..62b2a72 ---- /dev/null -+++ b/src/utility/outputStreamStringAdapter.cpp -@@ -0,0 +1,51 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+outputStreamStringAdapter::outputStreamStringAdapter(string& buffer) -+ : m_buffer(buffer) -+{ -+} -+ -+ -+void outputStreamStringAdapter::write(const value_type* const data, const size_type count) -+{ -+ m_buffer.append(data, count); -+} -+ -+ -+void outputStreamStringAdapter::flush() -+{ -+ // Do nothing -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp -index ec30b7d..1c940c2 100644 ---- a/src/utility/stream.cpp -+++ b/src/utility/stream.cpp -@@ -22,503 +22,18 @@ - // - - #include "vmime/utility/stream.hpp" --#include "vmime/utility/stringProxy.hpp" - --#include <algorithm> // for std::copy --#include <iterator> // for std::back_inserter -- --#if VMIME_HAVE_MESSAGING_FEATURES -- #include "vmime/net/socket.hpp" --#endif - - - namespace vmime { - namespace utility { - - --// stream -- - stream::size_type stream::getBlockSize() - { - return 32768; // 32 KB - } - - --// Helpers -- --outputStream& operator<<(outputStream& os, const stream::value_type c) --{ -- os.write(&c, 1); -- return (os); --} -- -- --outputStream& operator<<(outputStream& os, const string& str) --{ -- os.write(str.data(), str.length()); -- return (os); --} -- -- --stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os) --{ -- return bufferedStreamCopy(is, os, 0, NULL); --} -- -- --stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os, -- const stream::size_type length, progressListener* progress) --{ -- const stream::size_type blockSize = -- std::min(is.getBlockSize(), os.getBlockSize()); -- -- std::vector <stream::value_type> vbuffer(blockSize); -- -- stream::value_type* buffer = &vbuffer.front(); -- stream::size_type total = 0; -- -- if (progress != NULL) -- progress->start(length); -- -- while (!is.eof()) -- { -- const stream::size_type read = is.read(buffer, blockSize); -- -- if (read != 0) -- { -- os.write(buffer, read); -- total += read; -- -- if (progress != NULL) -- progress->progress(total, std::max(total, length)); -- } -- } -- -- if (progress != NULL) -- progress->stop(total); -- -- return (total); --} -- -- -- --// outputStreamAdapter -- --outputStreamAdapter::outputStreamAdapter(std::ostream& os) -- : m_stream(os) --{ --} -- -- --void outputStreamAdapter::write -- (const value_type* const data, const size_type count) --{ -- m_stream.exceptions(std::ios_base::badbit); -- m_stream.write(data, count); --} -- -- --void outputStreamAdapter::flush() --{ -- m_stream.exceptions(std::ios_base::badbit); -- m_stream.flush(); --} -- -- -- --// outputStreamStringAdapter -- --outputStreamStringAdapter::outputStreamStringAdapter(string& buffer) -- : m_buffer(buffer) --{ --} -- -- --void outputStreamStringAdapter::write(const value_type* const data, const size_type count) --{ -- m_buffer.append(data, count); --} -- -- --void outputStreamStringAdapter::flush() --{ -- // Do nothing --} -- -- -- --// outputStreamByteArrayAdapter -- --outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array) -- : m_array(array) --{ --} -- -- --void outputStreamByteArrayAdapter::write(const value_type* const data, const size_type count) --{ -- m_array.insert(m_array.end(), data, data + count); --} -- -- --void outputStreamByteArrayAdapter::flush() --{ -- // Do nothing --} -- -- -- --// inputStreamAdapter -- --inputStreamAdapter::inputStreamAdapter(std::istream& is) -- : m_stream(is) --{ --} -- -- --bool inputStreamAdapter::eof() const --{ -- return (m_stream.eof()); --} -- -- --void inputStreamAdapter::reset() --{ -- m_stream.exceptions(std::ios_base::badbit); -- m_stream.seekg(0, std::ios::beg); -- m_stream.clear(); --} -- -- --stream::size_type inputStreamAdapter::read -- (value_type* const data, const size_type count) --{ -- m_stream.exceptions(std::ios_base::badbit); -- m_stream.read(data, count); -- return (m_stream.gcount()); --} -- -- --stream::size_type inputStreamAdapter::skip(const size_type count) --{ -- m_stream.exceptions(std::ios_base::badbit); -- m_stream.ignore(count); -- return (m_stream.gcount()); --} -- -- -- --// inputStreamStringAdapter -- --inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer) -- : m_buffer(buffer), m_begin(0), m_end(buffer.length()), m_pos(0) --{ --} -- -- --inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer, -- const string::size_type begin, const string::size_type end) -- : m_buffer(buffer), m_begin(begin), m_end(end), m_pos(begin) --{ --} -- -- --bool inputStreamStringAdapter::eof() const --{ -- return (m_pos >= m_end); --} -- -- --void inputStreamStringAdapter::reset() --{ -- m_pos = m_begin; --} -- -- --stream::size_type inputStreamStringAdapter::read -- (value_type* const data, const size_type count) --{ -- if (m_pos + count >= m_end) -- { -- const size_type remaining = m_end - m_pos; -- -- std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data); -- m_pos = m_end; -- return (remaining); -- } -- else -- { -- std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data); -- m_pos += count; -- return (count); -- } --} -- -- --stream::size_type inputStreamStringAdapter::skip(const size_type count) --{ -- if (m_pos + count >= m_end) -- { -- const size_type remaining = m_end - m_pos; -- m_pos = m_end; -- return (remaining); -- } -- else -- { -- m_pos += count; -- return (count); -- } --} -- -- -- --// inputStreamStringProxyAdapter -- --inputStreamStringProxyAdapter::inputStreamStringProxyAdapter(const stringProxy& buffer) -- : m_buffer(buffer), m_pos(0) --{ --} -- -- --bool inputStreamStringProxyAdapter::eof() const --{ -- return (m_pos >= m_buffer.length()); --} -- -- --void inputStreamStringProxyAdapter::reset() --{ -- m_pos = 0; --} -- -- --stream::size_type inputStreamStringProxyAdapter::read -- (value_type* const data, const size_type count) --{ -- const size_type remaining = m_buffer.length() - m_pos; -- -- if (count > remaining) -- { -- std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_end(), data); -- m_pos = m_buffer.length(); -- return (remaining); -- } -- else -- { -- std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_begin() + m_pos + count, data); -- m_pos += count; -- return (count); -- } --} -- -- --stream::size_type inputStreamStringProxyAdapter::skip(const size_type count) --{ -- const size_type remaining = m_buffer.length() - m_pos; -- -- if (count > remaining) -- { -- m_pos = m_buffer.length(); -- return (remaining); -- } -- else -- { -- m_pos += count; -- return (count); -- } --} -- -- -- --// inputStreamPointerAdapter -- --inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own) -- : m_stream(is), m_own(own) --{ --} -- -- --inputStreamPointerAdapter::inputStreamPointerAdapter(const inputStreamPointerAdapter&) -- : inputStream(), m_stream(NULL), m_own(false) --{ -- // Not copiable --} -- -- --inputStreamPointerAdapter::~inputStreamPointerAdapter() --{ -- if (m_own) -- delete (m_stream); --} -- -- --bool inputStreamPointerAdapter::eof() const --{ -- return (m_stream->eof()); --} -- -- --void inputStreamPointerAdapter::reset() --{ -- m_stream->exceptions(std::ios_base::badbit); -- m_stream->seekg(0, std::ios::beg); -- m_stream->clear(); --} -- -- --stream::size_type inputStreamPointerAdapter::read -- (value_type* const data, const size_type count) --{ -- m_stream->exceptions(std::ios_base::badbit); -- m_stream->read(data, count); -- return (m_stream->gcount()); --} -- -- --stream::size_type inputStreamPointerAdapter::skip(const size_type count) --{ -- m_stream->exceptions(std::ios_base::badbit); -- m_stream->ignore(count); -- return (m_stream->gcount()); --} -- -- -- --// inputStreamByteBufferAdapter -- --inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte_t* buffer, const size_type length) -- : m_buffer(buffer), m_length(length), m_pos(0) --{ --} -- -- --bool inputStreamByteBufferAdapter::eof() const --{ -- return m_pos >= m_length; --} -- -- --void inputStreamByteBufferAdapter::reset() --{ -- m_pos = 0; --} -- -- --stream::size_type inputStreamByteBufferAdapter::read -- (value_type* const data, const size_type count) --{ -- const size_type remaining = m_length - m_pos; -- -- if (remaining < count) -- { -- std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data); -- m_pos += remaining; -- -- return remaining; -- } -- else -- { -- std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data); -- m_pos += count; -- -- return count; -- } --} -- -- --stream::size_type inputStreamByteBufferAdapter::skip(const size_type count) --{ -- const size_type remaining = m_length - m_pos; -- -- if (remaining < count) -- { -- m_pos += remaining; -- return remaining; -- } -- else -- { -- m_pos += count; -- return count; -- } --} -- -- -- --#ifdef VMIME_HAVE_MESSAGING_FEATURES -- -- --// outputStreamSocketAdapter -- --outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok) -- : m_socket(sok) --{ --} -- -- --void outputStreamSocketAdapter::write -- (const value_type* const data, const size_type count) --{ -- m_socket.sendRaw(data, count); --} -- -- --void outputStreamSocketAdapter::flush() --{ -- // Do nothing --} -- -- --stream::size_type outputStreamSocketAdapter::getBlockSize() --{ -- return m_socket.getBlockSize(); --} -- -- -- --// inputStreamSocketAdapter -- --inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok) -- : m_socket(sok) --{ --} -- -- --bool inputStreamSocketAdapter::eof() const --{ -- // Can't know... -- return false; --} -- -- --void inputStreamSocketAdapter::reset() --{ -- // Not supported --} -- -- --stream::size_type inputStreamSocketAdapter::read -- (value_type* const data, const size_type count) --{ -- return m_socket.receiveRaw(data, count); --} -- -- --stream::size_type inputStreamSocketAdapter::skip -- (const size_type /* count */) --{ -- // Not supported -- return 0; --} -- -- --stream::size_type inputStreamSocketAdapter::getBlockSize() --{ -- return m_socket.getBlockSize(); --} -- -- --#endif // VMIME_HAVE_MESSAGING_FEATURES -- -- - } // utility - } // vmime -diff --git a/src/utility/streamUtils.cpp b/src/utility/streamUtils.cpp -new file mode 100644 -index 0000000..f1d3b9d ---- /dev/null -+++ b/src/utility/streamUtils.cpp -@@ -0,0 +1,92 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/streamUtils.hpp" -+ -+#include <algorithm> // for std::copy -+#include <iterator> // for std::back_inserter -+ -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+outputStream& operator<<(outputStream& os, const stream::value_type c) -+{ -+ os.write(&c, 1); -+ return (os); -+} -+ -+ -+outputStream& operator<<(outputStream& os, const string& str) -+{ -+ os.write(str.data(), str.length()); -+ return (os); -+} -+ -+ -+stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os) -+{ -+ return bufferedStreamCopy(is, os, 0, NULL); -+} -+ -+ -+stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os, -+ const stream::size_type length, progressListener* progress) -+{ -+ const stream::size_type blockSize = -+ std::min(is.getBlockSize(), os.getBlockSize()); -+ -+ std::vector <stream::value_type> vbuffer(blockSize); -+ -+ stream::value_type* buffer = &vbuffer.front(); -+ stream::size_type total = 0; -+ -+ if (progress != NULL) -+ progress->start(length); -+ -+ while (!is.eof()) -+ { -+ const stream::size_type read = is.read(buffer, blockSize); -+ -+ if (read != 0) -+ { -+ os.write(buffer, read); -+ total += read; -+ -+ if (progress != NULL) -+ progress->progress(total, std::max(total, length)); -+ } -+ } -+ -+ if (progress != NULL) -+ progress->stop(total); -+ -+ return (total); -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/stringProxy.cpp b/src/utility/stringProxy.cpp -index a4ba6d2..74344b5 100644 ---- a/src/utility/stringProxy.cpp -+++ b/src/utility/stringProxy.cpp -@@ -23,6 +23,8 @@ - - #include "vmime/utility/stringProxy.hpp" - -+#include "vmime/utility/outputStreamAdapter.hpp" -+ - #include <iterator> - #include <algorithm> - -diff --git a/src/word.cpp b/src/word.cpp -index aeaa737..79060a1 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -28,6 +28,9 @@ - #include "vmime/utility/smartPtr.hpp" - #include "vmime/parserHelpers.hpp" - -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+ - #include "vmime/utility/encoder/encoder.hpp" - #include "vmime/utility/encoder/b64Encoder.hpp" - #include "vmime/utility/encoder/qpEncoder.hpp" -diff --git a/src/wordEncoder.cpp b/src/wordEncoder.cpp -index 67bd7a1..194a189 100644 ---- a/src/wordEncoder.cpp -+++ b/src/wordEncoder.cpp -@@ -33,6 +33,9 @@ - - #include "vmime/utility/stringUtils.hpp" - -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+ - - namespace vmime - { -diff --git a/vmime/base.hpp b/vmime/base.hpp -index 60e637d..b794031 100644 ---- a/vmime/base.hpp -+++ b/vmime/base.hpp -@@ -35,7 +35,6 @@ - #include "vmime/config.hpp" - #include "vmime/types.hpp" - #include "vmime/constants.hpp" --#include "vmime/utility/stream.hpp" - #include "vmime/utility/smartPtr.hpp" - - -@@ -255,7 +254,26 @@ namespace vmime - return y.dynamicCast <X>(); - } - -+ /** Inherit from this class to indicate the subclass is not copyable, -+ * ie. you want to prohibit copy construction and copy assignment. -+ */ -+ class noncopyable -+ { -+ protected: -+ -+ noncopyable() { } -+ virtual ~noncopyable() { } -+ -+ private: -+ -+ noncopyable(const noncopyable&); -+ void operator=(const noncopyable&); -+ }; -+ - } // vmime - - -+#include "vmime/utility/stream.hpp" -+ -+ - #endif // VMIME_BASE_HPP_INCLUDED -diff --git a/vmime/charset.hpp b/vmime/charset.hpp -index b2e241c..5f5e8e5 100644 ---- a/vmime/charset.hpp -+++ b/vmime/charset.hpp -@@ -26,6 +26,8 @@ - - - #include "vmime/base.hpp" -+#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/outputStream.hpp" - #include "vmime/component.hpp" - - -diff --git a/vmime/component.hpp b/vmime/component.hpp -index b38127f..12b0406 100644 ---- a/vmime/component.hpp -+++ b/vmime/component.hpp -@@ -26,6 +26,8 @@ - - - #include "vmime/base.hpp" -+#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/outputStream.hpp" - - - namespace vmime -diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp -index d71c3ca..f430510 100644 ---- a/vmime/net/imap/IMAPParser.hpp -+++ b/vmime/net/imap/IMAPParser.hpp -@@ -37,6 +37,9 @@ - #include "vmime/utility/encoder/b64Encoder.hpp" - #include "vmime/utility/encoder/qpEncoder.hpp" - -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+ - #include "vmime/platform.hpp" - - #include "vmime/net/timeoutHandler.hpp" -@@ -3825,7 +3828,7 @@ public: - : m_date_time(NULL), m_number(NULL), m_envelope(NULL), - m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL), - m_section(NULL) -- -+ - { - } - -diff --git a/vmime/utility/filteredStream.hpp b/vmime/utility/filteredStream.hpp -index 00be785..2a55edd 100644 ---- a/vmime/utility/filteredStream.hpp -+++ b/vmime/utility/filteredStream.hpp -@@ -27,7 +27,8 @@ - - #include <algorithm> - --#include "vmime/utility/stream.hpp" -+#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/outputStream.hpp" - - - namespace vmime { -diff --git a/vmime/utility/inputStream.hpp b/vmime/utility/inputStream.hpp -new file mode 100644 -index 0000000..4a76a7d ---- /dev/null -+++ b/vmime/utility/inputStream.hpp -@@ -0,0 +1,76 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED -+ -+ -+#include "vmime/utility/stream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** Simple input stream. -+ */ -+ -+class inputStream : public stream -+{ -+public: -+ -+ /** Test for end of stream (no more data to read). -+ * -+ * @return true if we have reached the end of stream, false otherwise -+ */ -+ virtual bool eof() const = 0; -+ -+ /** Set the read pointer to the beginning of the stream. -+ * -+ * @warning WARNING: this may not work for all stream types. -+ */ -+ virtual void reset() = 0; -+ -+ /** Read data from the stream. -+ * -+ * @param data will receive the data read -+ * @param count maximum number of bytes to read -+ * @return number of bytes read -+ */ -+ virtual size_type read(value_type* const data, const size_type count) = 0; -+ -+ /** Skip a number of bytes. -+ * -+ * @param count maximum number of bytes to ignore -+ * @return number of bytes skipped -+ */ -+ virtual size_type skip(const size_type count) = 0; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamAdapter.hpp b/vmime/utility/inputStreamAdapter.hpp -new file mode 100644 -index 0000000..278ab52 ---- /dev/null -+++ b/vmime/utility/inputStreamAdapter.hpp -@@ -0,0 +1,64 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+#include <istream> -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for C++ standard input streams. -+ */ -+ -+class inputStreamAdapter : public inputStream -+{ -+public: -+ -+ /** @param is input stream to wrap -+ */ -+ inputStreamAdapter(std::istream& is); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ -+private: -+ -+ std::istream& m_stream; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime/utility/inputStreamByteBufferAdapter.hpp -new file mode 100644 -index 0000000..0f6a442 ---- /dev/null -+++ b/vmime/utility/inputStreamByteBufferAdapter.hpp -@@ -0,0 +1,63 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for reading from an array of bytes. -+ */ -+ -+class inputStreamByteBufferAdapter : public inputStream -+{ -+public: -+ -+ inputStreamByteBufferAdapter(const byte_t* buffer, size_type length); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ -+private: -+ -+ const byte_t* m_buffer; -+ const size_type m_length; -+ -+ size_type m_pos; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamPointerAdapter.hpp b/vmime/utility/inputStreamPointerAdapter.hpp -new file mode 100644 -index 0000000..44e9bad ---- /dev/null -+++ b/vmime/utility/inputStreamPointerAdapter.hpp -@@ -0,0 +1,63 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStreamAdapter.hpp" -+ -+#include <istream> -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for pointer to C++ standard input stream. -+ */ -+ -+class inputStreamPointerAdapter : public inputStreamAdapter -+{ -+public: -+ -+ /** @param is input stream to wrap -+ * @param own if set to 'true', the pointer will be deleted when -+ * this object is destroyed -+ */ -+ inputStreamPointerAdapter(std::istream* is, const bool own = true); -+ ~inputStreamPointerAdapter(); -+ -+private: -+ -+ std::istream* m_stream; -+ const bool m_own; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamSocketAdapter.hpp b/vmime/utility/inputStreamSocketAdapter.hpp -new file mode 100644 -index 0000000..0f99c21 ---- /dev/null -+++ b/vmime/utility/inputStreamSocketAdapter.hpp -@@ -0,0 +1,77 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+#if VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+namespace vmime { -+namespace net { -+ class socket; // forward reference -+} // net -+} // vmime -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An input stream that is connected to a socket. -+ */ -+ -+class inputStreamSocketAdapter : public inputStream -+{ -+public: -+ -+ inputStreamSocketAdapter(net::socket& sok); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ -+ size_type getBlockSize(); -+ -+private: -+ -+ inputStreamSocketAdapter(const inputStreamSocketAdapter&); -+ -+ net::socket& m_socket; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamStringAdapter.hpp b/vmime/utility/inputStreamStringAdapter.hpp -new file mode 100644 -index 0000000..a7d986f ---- /dev/null -+++ b/vmime/utility/inputStreamStringAdapter.hpp -@@ -0,0 +1,66 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for string input. -+ */ -+ -+class inputStreamStringAdapter : public inputStream -+{ -+public: -+ -+ inputStreamStringAdapter(const string& buffer); -+ inputStreamStringAdapter(const string& buffer, const string::size_type begin, const string::size_type end); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ -+private: -+ -+ inputStreamStringAdapter(const inputStreamStringAdapter&); -+ -+ const string m_buffer; // do _NOT_ keep a reference... -+ const string::size_type m_begin; -+ const string::size_type m_end; -+ string::size_type m_pos; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/inputStreamStringProxyAdapter.hpp b/vmime/utility/inputStreamStringProxyAdapter.hpp -new file mode 100644 -index 0000000..74b3f60 ---- /dev/null -+++ b/vmime/utility/inputStreamStringProxyAdapter.hpp -@@ -0,0 +1,68 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+class stringProxy; -+ -+ -+/** An adapter class for stringProxy input. -+ */ -+ -+class inputStreamStringProxyAdapter : public inputStream -+{ -+public: -+ -+ /** @param buffer stringProxy object to wrap -+ */ -+ inputStreamStringProxyAdapter(const stringProxy& buffer); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ -+private: -+ -+ inputStreamStringProxyAdapter(const inputStreamStringProxyAdapter&); -+ -+ const stringProxy& m_buffer; -+ string::size_type m_pos; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/outputStream.hpp b/vmime/utility/outputStream.hpp -new file mode 100644 -index 0000000..7372d20 ---- /dev/null -+++ b/vmime/utility/outputStream.hpp -@@ -0,0 +1,107 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED -+#define VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED -+ -+ -+#include "vmime/utility/stream.hpp" -+ -+ -+#if defined(_MSC_VER) && (_MSC_VER <= 1200) // VC++6 -+# include <cstring> -+#endif -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** Simple output stream. -+ */ -+ -+class outputStream : public stream -+{ -+public: -+ -+ /** Write data to the stream. -+ * -+ * @param data buffer containing data to write -+ * @param count number of bytes to write -+ */ -+ virtual void write(const value_type* const data, const size_type count) = 0; -+ -+ /** Flush this output stream and forces any buffered output -+ * bytes to be written out to the stream. -+ */ -+ virtual void flush() = 0; -+}; -+ -+ -+// Helpers functions -+ -+outputStream& operator<<(outputStream& os, const string& str); -+outputStream& operator<<(outputStream& os, const stream::value_type c); -+ -+ -+#if defined(_MSC_VER) && (_MSC_VER <= 1200) // Internal compiler error with VC++6 -+ -+inline outputStream& operator<<(outputStream& os, const char* str) -+{ -+ os.write(str, ::strlen(str)); -+ return (os); -+} -+ -+#else -+ -+template <int N> -+outputStream& operator<<(outputStream& os, const char (&str)[N]) -+{ -+ os.write(str, N - 1); -+ return (os); -+} -+ -+#endif // defined(_MSC_VER) && (_MSC_VER <= 1200) -+ -+ -+template <typename T> -+outputStream& operator<<(outputStream& os, const T& t) -+{ -+ std::ostringstream oss; -+ oss.imbue(std::locale::classic()); // no formatting -+ -+ oss << t; -+ -+ os << oss.str(); -+ -+ return (os); -+} -+ -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED -+ -diff --git a/vmime/utility/outputStreamAdapter.hpp b/vmime/utility/outputStreamAdapter.hpp -new file mode 100644 -index 0000000..be55d8d ---- /dev/null -+++ b/vmime/utility/outputStreamAdapter.hpp -@@ -0,0 +1,62 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/outputStream.hpp" -+ -+#include <ostream> -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for C++ standard output streams. -+ */ -+ -+class outputStreamAdapter : public outputStream -+{ -+public: -+ -+ /** @param os output stream to wrap -+ */ -+ outputStreamAdapter(std::ostream& os); -+ -+ void write(const value_type* const data, const size_type count); -+ void flush(); -+ -+private: -+ -+ std::ostream& m_stream; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/outputStreamByteArrayAdapter.hpp b/vmime/utility/outputStreamByteArrayAdapter.hpp -new file mode 100644 -index 0000000..bf7d839 ---- /dev/null -+++ b/vmime/utility/outputStreamByteArrayAdapter.hpp -@@ -0,0 +1,58 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/outputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for byte array output. -+ */ -+ -+class outputStreamByteArrayAdapter : public outputStream -+{ -+public: -+ -+ outputStreamByteArrayAdapter(byteArray& array); -+ -+ void write(const value_type* const data, const size_type count); -+ void flush(); -+ -+private: -+ -+ byteArray& m_array; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/outputStreamSocketAdapter.hpp b/vmime/utility/outputStreamSocketAdapter.hpp -new file mode 100644 -index 0000000..e3d3eb0 ---- /dev/null -+++ b/vmime/utility/outputStreamSocketAdapter.hpp -@@ -0,0 +1,75 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/outputStream.hpp" -+ -+ -+#if VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+namespace vmime { -+namespace net { -+ class socket; // forward reference -+} // net -+} // vmime -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An output stream that is connected to a socket. -+ */ -+ -+class outputStreamSocketAdapter : public outputStream -+{ -+public: -+ -+ outputStreamSocketAdapter(net::socket& sok); -+ -+ void write(const value_type* const data, const size_type count); -+ void flush(); -+ -+ size_type getBlockSize(); -+ -+private: -+ -+ outputStreamSocketAdapter(const outputStreamSocketAdapter&); -+ -+ net::socket& m_socket; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_HAVE_MESSAGING_FEATURES -+ -+ -+#endif // VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/outputStreamStringAdapter.hpp b/vmime/utility/outputStreamStringAdapter.hpp -new file mode 100644 -index 0000000..8c8b304 ---- /dev/null -+++ b/vmime/utility/outputStreamStringAdapter.hpp -@@ -0,0 +1,59 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/outputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class for string output. -+ */ -+ -+class outputStreamStringAdapter : public outputStream -+{ -+public: -+ -+ outputStreamStringAdapter(string& buffer); -+ -+ void write(const value_type* const data, const size_type count); -+ void flush(); -+ -+size_type getBlockSize(){return 8192;} -+private: -+ -+ string& m_buffer; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/stream.hpp b/vmime/utility/stream.hpp -index 1faab55..566ab9d 100644 ---- a/vmime/utility/stream.hpp -+++ b/vmime/utility/stream.hpp -@@ -25,40 +25,22 @@ - #define VMIME_UTILITY_STREAM_HPP_INCLUDED - - --#include <istream> --#include <ostream> - #include <sstream> - - #include "vmime/config.hpp" - #include "vmime/types.hpp" -- --#include "vmime/utility/progressListener.hpp" -- -- --#if VMIME_HAVE_MESSAGING_FEATURES -- namespace vmime { -- namespace net { -- class socket; // forward reference -- } // net -- } // vmime --#endif -- --#if defined(_MSC_VER) && (_MSC_VER <= 1200) // VC++6 --# include <cstring> --#endif -+#include "vmime/base.hpp" - - - namespace vmime { - namespace utility { - - --class stringProxy; -- - - /** Base class for input/output stream. - */ - --class stream : public object -+class stream : public object, private noncopyable - { - public: - -@@ -81,365 +63,6 @@ public: - }; - - -- --/** Simple output stream. -- */ -- --class outputStream : public stream --{ --public: -- -- /** Write data to the stream. -- * -- * @param data buffer containing data to write -- * @param count number of bytes to write -- */ -- virtual void write(const value_type* const data, const size_type count) = 0; -- -- /** Flush this output stream and forces any buffered output -- * bytes to be written out to the stream. -- */ -- virtual void flush() = 0; --}; -- -- -- --/** Simple input stream. -- */ -- --class inputStream : public stream --{ --public: -- -- /** Test for end of stream (no more data to read). -- * -- * @return true if we have reached the end of stream, false otherwise -- */ -- virtual bool eof() const = 0; -- -- /** Set the read pointer to the beginning of the stream. -- * -- * @warning WARNING: this may not work for all stream types. -- */ -- virtual void reset() = 0; -- -- /** Read data from the stream. -- * -- * @param data will receive the data read -- * @param count maximum number of bytes to read -- * @return number of bytes read -- */ -- virtual size_type read(value_type* const data, const size_type count) = 0; -- -- /** Skip a number of bytes. -- * -- * @param count maximum number of bytes to ignore -- * @return number of bytes skipped -- */ -- virtual size_type skip(const size_type count) = 0; --}; -- -- -- --// Helpers functions -- --outputStream& operator<<(outputStream& os, const string& str); --outputStream& operator<<(outputStream& os, const stream::value_type c); -- -- --#if defined(_MSC_VER) && (_MSC_VER <= 1200) // Internal compiler error with VC++6 -- --inline outputStream& operator<<(outputStream& os, const char* str) --{ -- os.write(str, ::strlen(str)); -- return (os); --} -- --#else -- --template <int N> --outputStream& operator<<(outputStream& os, const char (&str)[N]) --{ -- os.write(str, N - 1); -- return (os); --} -- --#endif // defined(_MSC_VER) && (_MSC_VER <= 1200) -- -- --template <typename T> --outputStream& operator<<(outputStream& os, const T& t) --{ -- std::ostringstream oss; -- oss.imbue(std::locale::classic()); // no formatting -- -- oss << t; -- -- os << oss.str(); -- -- return (os); --} -- -- --/** Copy data from one stream into another stream using a buffered method. -- * -- * @param is input stream (source data) -- * @param os output stream (destination for data) -- * @return number of bytes copied -- */ -- --stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os); -- --/** Copy data from one stream into another stream using a buffered method -- * and notify progress state of the operation. -- * -- * @param is input stream (source data) -- * @param os output stream (destination for data) -- * @param length predicted number of bytes to copy -- * @param progress listener to notify -- * @return number of bytes copied -- */ -- --stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os, -- const stream::size_type length, progressListener* progress); -- -- --// Adapters -- -- --/** An adapter class for C++ standard output streams. -- */ -- --class outputStreamAdapter : public outputStream --{ --public: -- -- /** @param os output stream to wrap -- */ -- outputStreamAdapter(std::ostream& os); -- -- void write(const value_type* const data, const size_type count); -- void flush(); -- --private: -- -- std::ostream& m_stream; --}; -- -- --/** An adapter class for string output. -- */ -- --class outputStreamStringAdapter : public outputStream --{ --public: -- -- outputStreamStringAdapter(string& buffer); -- -- void write(const value_type* const data, const size_type count); -- void flush(); -- --size_type getBlockSize(){return 8192;} --private: -- -- string& m_buffer; --}; -- -- --/** An adapter class for byte array output. -- */ -- --class outputStreamByteArrayAdapter : public outputStream --{ --public: -- -- outputStreamByteArrayAdapter(byteArray& array); -- -- void write(const value_type* const data, const size_type count); -- void flush(); -- --private: -- -- byteArray& m_array; --}; -- -- --/** An adapter class for C++ standard input streams. -- */ -- --class inputStreamAdapter : public inputStream --{ --public: -- -- /** @param is input stream to wrap -- */ -- inputStreamAdapter(std::istream& is); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- --private: -- -- std::istream& m_stream; --}; -- -- --/** An adapter class for string input. -- */ -- --class inputStreamStringAdapter : public inputStream --{ --public: -- -- inputStreamStringAdapter(const string& buffer); -- inputStreamStringAdapter(const string& buffer, const string::size_type begin, const string::size_type end); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- --private: -- -- inputStreamStringAdapter(const inputStreamStringAdapter&); -- -- const string m_buffer; // do _NOT_ keep a reference... -- const string::size_type m_begin; -- const string::size_type m_end; -- string::size_type m_pos; --}; -- -- --/** An adapter class for stringProxy input. -- */ -- --class inputStreamStringProxyAdapter : public inputStream --{ --public: -- -- /** @param buffer stringProxy object to wrap -- */ -- inputStreamStringProxyAdapter(const stringProxy& buffer); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- --private: -- -- inputStreamStringProxyAdapter(const inputStreamStringProxyAdapter&); -- -- const stringProxy& m_buffer; -- string::size_type m_pos; --}; -- -- --/** An adapter class for pointer to C++ standard input stream. -- */ -- --class inputStreamPointerAdapter : public inputStream --{ --public: -- -- /** @param is input stream to wrap -- * @param own if set to 'true', the pointer will be deleted when -- * this object is destroyed -- */ -- inputStreamPointerAdapter(std::istream* is, const bool own = true); -- ~inputStreamPointerAdapter(); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- --private: -- -- inputStreamPointerAdapter(const inputStreamPointerAdapter&); -- -- std::istream* m_stream; -- const bool m_own; --}; -- -- --/** An adapter class for reading from an array of bytes. -- */ -- --class inputStreamByteBufferAdapter : public inputStream --{ --public: -- -- inputStreamByteBufferAdapter(const byte_t* buffer, size_type length); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- --private: -- -- const byte_t* m_buffer; -- const size_type m_length; -- -- size_type m_pos; --}; -- -- --#if VMIME_HAVE_MESSAGING_FEATURES -- -- --/** An output stream that is connected to a socket. -- */ -- --class outputStreamSocketAdapter : public outputStream --{ --public: -- -- outputStreamSocketAdapter(net::socket& sok); -- -- void write(const value_type* const data, const size_type count); -- void flush(); -- -- size_type getBlockSize(); -- --private: -- -- outputStreamSocketAdapter(const outputStreamSocketAdapter&); -- -- net::socket& m_socket; --}; -- -- --/** An input stream that is connected to a socket. -- */ -- --class inputStreamSocketAdapter : public inputStream --{ --public: -- -- inputStreamSocketAdapter(net::socket& sok); -- -- bool eof() const; -- void reset(); -- size_type read(value_type* const data, const size_type count); -- size_type skip(const size_type count); -- -- size_type getBlockSize(); -- --private: -- -- inputStreamSocketAdapter(const inputStreamSocketAdapter&); -- -- net::socket& m_socket; --}; -- -- --#endif // VMIME_HAVE_MESSAGING_FEATURES -- -- - } // utility - } // vmime - -diff --git a/vmime/utility/streamUtils.hpp b/vmime/utility/streamUtils.hpp -new file mode 100644 -index 0000000..cdf70aa ---- /dev/null -+++ b/vmime/utility/streamUtils.hpp -@@ -0,0 +1,66 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED -+#define VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/outputStream.hpp" -+ -+#include "vmime/utility/progressListener.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** Copy data from one stream into another stream using a buffered method. -+ * -+ * @param is input stream (source data) -+ * @param os output stream (destination for data) -+ * @return number of bytes copied -+ */ -+ -+stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os); -+ -+/** Copy data from one stream into another stream using a buffered method -+ * and notify progress state of the operation. -+ * -+ * @param is input stream (source data) -+ * @param os output stream (destination for data) -+ * @param length predicted number of bytes to copy -+ * @param progress listener to notify -+ * @return number of bytes copied -+ */ -+ -+stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os, -+ const stream::size_type length, progressListener* progress); -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED -+ -diff --git a/vmime/utility/stringProxy.hpp b/vmime/utility/stringProxy.hpp -index 21c65ea..66a6dfd 100644 ---- a/vmime/utility/stringProxy.hpp -+++ b/vmime/utility/stringProxy.hpp -@@ -29,6 +29,7 @@ - - #include "vmime/types.hpp" - #include "vmime/utility/stream.hpp" -+#include "vmime/utility/outputStream.hpp" - #include "vmime/utility/progressListener.hpp" - - -diff --git a/vmime/vmime.hpp b/vmime/vmime.hpp -index f187b9e..fd04853 100644 ---- a/vmime/vmime.hpp -+++ b/vmime/vmime.hpp -@@ -68,6 +68,22 @@ - // Encoders - #include "vmime/utility/encoder/encoderFactory.hpp" - -+// Streams -+#include "vmime/utility/filteredStream.hpp" -+#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/inputStreamAdapter.hpp" -+#include "vmime/utility/inputStreamByteBufferAdapter.hpp" -+#include "vmime/utility/inputStreamPointerAdapter.hpp" -+#include "vmime/utility/inputStreamSocketAdapter.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/inputStreamStringProxyAdapter.hpp" -+#include "vmime/utility/outputStream.hpp" -+#include "vmime/utility/outputStreamAdapter.hpp" -+#include "vmime/utility/outputStreamByteArrayAdapter.hpp" -+#include "vmime/utility/outputStreamSocketAdapter.hpp" -+#include "vmime/utility/outputStreamStringAdapter.hpp" -+#include "vmime/utility/streamUtils.hpp" -+ - // Message builder/parser - #include "vmime/messageBuilder.hpp" - #include "vmime/messageParser.hpp" --- -1.7.10.4 - - -From be30b47f09c5358db2ac8e42fa2bb4a14ec24c51 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 16 Apr 2012 22:32:33 +0200 -Subject: [PATCH 37/47] Added ability to parse directly from an input stream - (eg. file). This allows very big messages to be - parsed without loading the whole message data into - memory. - - -diff --git a/ChangeLog b/ChangeLog -index 8fdcdb0..1b5b2cf 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -2,6 +2,12 @@ - VERSION 0.9.2svn - ================ - -+2012-04-16 Vincent Richard <vincent@vincent-richard.net> -+ -+ * MIME Parser can now operate directly on an input stream (eg. file). -+ This allows very big messages to be parsed without loading the whole -+ message data into memory. -+ - 2010-11-16 Vincent Richard <vincent@vincent-richard.net> - - * Started version 0.9.2. -diff --git a/SConstruct b/SConstruct -index ea5c4eb..2690172 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -153,11 +153,14 @@ libvmime_sources = [ - 'utility/inputStreamSocketAdapter.cpp', 'utility/inputStreamSocketAdapter.hpp', - 'utility/inputStreamStringAdapter.cpp', 'utility/inputStreamStringAdapter.hpp', - 'utility/inputStreamStringProxyAdapter.cpp', 'utility/inputStreamStringProxyAdapter.hpp', -+ 'utility/seekableInputStream.hpp', -+ 'utility/seekableInputStreamRegionAdapter.cpp', 'utility/seekableInputStreamRegionAdapter.hpp', - 'utility/outputStream.cpp', 'utility/outputStream.hpp', - 'utility/outputStreamAdapter.cpp', 'utility/outputStreamAdapter.hpp', - 'utility/outputStreamByteArrayAdapter.cpp', 'utility/outputStreamByteArrayAdapter.hpp', - 'utility/outputStreamSocketAdapter.cpp', 'utility/outputStreamSocketAdapter.hpp', - 'utility/outputStreamStringAdapter.cpp', 'utility/outputStreamStringAdapter.hpp', -+ 'utility/parserInputStreamAdapter.cpp', 'utility/parserInputStreamAdapter.hpp', - 'utility/stringProxy.cpp', 'utility/stringProxy.hpp', - 'utility/stringUtils.cpp', 'utility/stringUtils.hpp', - 'utility/url.cpp', 'utility/url.hpp', -diff --git a/src/addressList.cpp b/src/addressList.cpp -index 31a2a3d..f06460d 100644 ---- a/src/addressList.cpp -+++ b/src/addressList.cpp -@@ -50,7 +50,7 @@ addressList::~addressList() - } - - --void addressList::parse(const string& buffer, const string::size_type position, -+void addressList::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - removeAllAddresses(); -@@ -72,7 +72,7 @@ void addressList::parse(const string& buffer, const string::size_type position, - } - - --void addressList::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void addressList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - string::size_type pos = curLinePos; -@@ -248,9 +248,9 @@ const std::vector <ref <address> > addressList::getAddressList() - } - - --const std::vector <ref <const component> > addressList::getChildComponents() const -+const std::vector <ref <component> > addressList::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - copy_vector(m_list, list); - -diff --git a/src/body.cpp b/src/body.cpp -index 9d7d57f..732fa8b 100644 ---- a/src/body.cpp -+++ b/src/body.cpp -@@ -31,10 +31,13 @@ - - #include "vmime/utility/random.hpp" - -+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp" -+ - #include "vmime/parserHelpers.hpp" - - #include "vmime/emptyContentHandler.hpp" - #include "vmime/stringContentHandler.hpp" -+#include "vmime/streamContentHandler.hpp" - - - namespace vmime -@@ -52,11 +55,28 @@ body::~body() - } - - --void body::parse(const string& buffer, const string::size_type position, -- const string::size_type end, string::size_type* newPosition) -+void body::parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition) - { - removeAllParts(); - -+ m_prologText.clear(); -+ m_epilogText.clear(); -+ -+ if (end == position) -+ { -+ -+ setParsedBounds(position, end); -+ -+ if (newPosition) -+ *newPosition = end; -+ -+ return; -+ } -+ - // Check whether the body is a MIME-multipart - bool isMultipart = false; - string boundary; -@@ -80,37 +100,61 @@ void body::parse(const string& buffer, const string::size_type position, - { - // No "boundary" parameter specified: we can try to - // guess it by scanning the body contents... -- string::size_type pos = buffer.find("\n--", position); -+ utility::stream::size_type pos = position; -+ -+ parser->seek(pos); -+ -+ if (pos + 2 < end && parser->matchBytes("--", 2)) -+ { -+ pos += 2; -+ } -+ else -+ { -+ pos = parser->findNext("\n--", position); - -- if ((pos != string::npos) && (pos < end)) -+ if ((pos != utility::stream::npos) && (pos + 3 < end)) -+ pos += 3; // skip \n-- -+ } -+ -+ if ((pos != utility::stream::npos) && (pos < end)) - { -- pos += 3; -+ parser->seek(pos); - -- const string::size_type start = pos; -+ // Read some bytes after boundary separator -+ utility::stream::value_type buffer[256]; -+ const utility::stream::size_type bufferLen = -+ parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0]))); - -- char_t c = buffer[pos]; -- string::size_type length = 0; -+ buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0'; - -+ // Extract boundary from buffer (stop at first CR or LF). - // We have to stop after a reasonnably long boundary length (100) - // not to take the whole body contents for a boundary... -- while (pos < end && length < 100 && !(c == '\r' || c == '\n')) -+ string::value_type boundaryBytes[100]; -+ string::size_type boundaryLen = 0; -+ -+ for (string::value_type c = buffer[0] ; -+ boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ; -+ c = buffer[++boundaryLen]) - { -- ++length; -- c = buffer[pos++]; -+ boundaryBytes[boundaryLen] = buffer[boundaryLen]; - } - -- if (pos < end && length < 100) -+ if (boundaryLen >= 1 && boundaryLen < 100) - { - // RFC #1521, Page 31: - // "...the boundary parameter, which consists of 1 to 70 - // characters from a set of characters known to be very - // robust through email gateways, and NOT ending with - // white space..." -- while (pos != start && parserHelpers::isSpace(buffer[pos - 1])) -- --pos; -- -- boundary = string(buffer.begin() + start, -- buffer.begin() + pos); -+ while (boundaryLen != 0 && -+ parserHelpers::isSpace(boundaryBytes[boundaryLen - 1])) -+ { -+ boundaryLen--; -+ } -+ -+ if (boundaryLen >= 1) -+ boundary = string(boundaryBytes, boundaryBytes + boundaryLen); - } - } - } -@@ -126,51 +170,79 @@ void body::parse(const string& buffer, const string::size_type position, - { - const string boundarySep("--" + boundary); - -- string::size_type partStart = position; -- string::size_type pos = position; -+ utility::stream::size_type partStart = position; -+ utility::stream::size_type pos = position; - - bool lastPart = false; - -- while (pos != string::npos && pos < end) -+ while (pos != utility::stream::npos && pos < end) - { -- pos = buffer.find(boundarySep, pos); -- -- if (pos == string::npos || -- ((pos == 0 || buffer[pos - 1] == '\n') && -- (buffer[pos + boundarySep.length()] == '\r' || -- buffer[pos + boundarySep.length()] == '\n' || -- buffer[pos + boundarySep.length()] == '-' -- ) -- ) -- ) -+ pos = parser->findNext(boundarySep, pos); -+ -+ if (pos == utility::stream::npos) -+ break; // not found -+ -+ if (pos != 0) - { -- break; -+ parser->seek(pos - 1); -+ -+ if (parser->peekByte() != '\n') -+ { -+ // Boundary is not at a beginning of a line -+ pos++; -+ continue; -+ } -+ -+ parser->skip(1 + boundarySep.length()); -+ } -+ else -+ { -+ parser->seek(pos + boundarySep.length()); - } - -- // boundary not a beginning of line, or just a prefix of another, continue the search. -+ const utility::stream::value_type next = parser->peekByte(); -+ -+ if (next == '\r' || next == '\n' || next == '-') -+ break; -+ -+ // Boundary is a prefix of another, continue the search - pos++; - } - -- if (pos != string::npos && pos < end) -+ if (pos != utility::stream::npos && pos < end) - { - vmime::text text; -- text.parse(buffer, position, pos); -+ text.parse(parser, position, pos); - - m_prologText = text.getWholeBuffer(); - } - -- for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index) -+ for (int index = 0 ; !lastPart && (pos != utility::stream::npos) && (pos < end) ; ++index) - { -- string::size_type partEnd = pos; -+ utility::stream::size_type partEnd = pos; - - // Get rid of the [CR]LF just before the boundary string -- if (pos >= (position + 1) && buffer[pos - 1] == '\n') --partEnd; -- if (pos >= (position + 2) && buffer[pos - 2] == '\r') --partEnd; -+ if (pos >= (position + 1)) -+ { -+ parser->seek(pos - 1); -+ -+ if (parser->peekByte() == '\n') -+ --partEnd; -+ } -+ -+ if (pos >= (position + 2)) -+ { -+ parser->seek(pos - 2); -+ -+ if (parser->peekByte() == '\r') -+ --partEnd; -+ } - - // Check whether it is the last part (boundary terminated by "--") - pos += boundarySep.length(); -+ parser->seek(pos); - -- if (pos + 1 < end && buffer[pos] == '-' && buffer[pos + 1] == '-') -+ if (pos + 1 < end && parser->matchBytes("--", 2)) - { - lastPart = true; - pos += 2; -@@ -180,15 +252,15 @@ void body::parse(const string& buffer, const string::size_type position, - // "...(If a boundary appears to end with white space, the - // white space must be presumed to have been added by a - // gateway, and must be deleted.)..." -- while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) -- ++pos; -+ parser->seek(pos); -+ pos += parser->skipIf(parserHelpers::isSpaceOrTab, end); - - // End of boundary line -- if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] =='\n') -+ if (pos + 1 < end && parser->matchBytes("\r\n", 2)) - { - pos += 2; - } -- else if (pos < end && buffer[pos] == '\n') -+ else if (pos < end && parser->peekByte() == '\n') - { - ++pos; - } -@@ -202,7 +274,7 @@ void body::parse(const string& buffer, const string::size_type position, - if (partEnd < partStart) - std::swap(partStart, partEnd); - -- part->parse(buffer, partStart, partEnd, NULL); -+ part->parse(parser, partStart, partEnd, NULL); - part->m_parent = m_part; - - m_parts.push_back(part); -@@ -210,23 +282,37 @@ void body::parse(const string& buffer, const string::size_type position, - - partStart = pos; - -- while (pos != string::npos && pos < end) -+ while (pos != utility::stream::npos && pos < end) - { -- pos = buffer.find(boundarySep, pos); -- -- if (pos == string::npos || -- ((pos == 0 || buffer[pos - 1] == '\n') && -- (buffer[pos + boundarySep.length()] == '\r' || -- buffer[pos + boundarySep.length()] == '\n' || -- buffer[pos + boundarySep.length()] == '-' -- ) -- ) -- ) -+ pos = parser->findNext(boundarySep, pos); -+ -+ if (pos == utility::stream::npos) -+ break; // not found -+ -+ if (pos != 0) - { -- break; -+ parser->seek(pos - 1); -+ -+ if (parser->peekByte() != '\n') -+ { -+ // Boundary is not at a beginning of a line -+ pos++; -+ continue; -+ } -+ -+ parser->skip(1 + boundarySep.length()); -+ } -+ else -+ { -+ parser->seek(pos + boundarySep.length()); - } - -- // boundary not a beginning of line, or just a prefix of another, continue the search. -+ const utility::stream::value_type next = parser->peekByte(); -+ -+ if (next == '\r' || next == '\n' || next == '-') -+ break; -+ -+ // Boundary is a prefix of another, continue the search - pos++; - } - } -@@ -234,13 +320,13 @@ void body::parse(const string& buffer, const string::size_type position, - m_contents = vmime::create <emptyContentHandler>(); - - // Last part was not found: recover from missing boundary -- if (!lastPart && pos == string::npos) -+ if (!lastPart && pos == utility::stream::npos) - { - ref <bodyPart> part = vmime::create <bodyPart>(); - - try - { -- part->parse(buffer, partStart, end); -+ part->parse(parser, partStart, end); - } - catch (std::exception&) - { -@@ -255,7 +341,7 @@ void body::parse(const string& buffer, const string::size_type position, - else if (partStart < end) - { - vmime::text text; -- text.parse(buffer, partStart, end); -+ text.parse(parser, partStart, end); - - m_epilogText = text.getWholeBuffer(); - } -@@ -282,7 +368,13 @@ void body::parse(const string& buffer, const string::size_type position, - } - - // Extract the (encoded) contents -- m_contents = vmime::create <stringContentHandler>(buffer, position, end, enc); -+ const utility::stream::size_type length = end - position; -+ -+ ref <utility::inputStream> contentStream = -+ vmime::create <utility::seekableInputStreamRegionAdapter> -+ (parser->getUnderlyingStream(), position, length); -+ -+ m_contents = vmime::create <streamContentHandler>(contentStream, length, enc); - } - - setParsedBounds(position, end); -@@ -292,7 +384,7 @@ void body::parse(const string& buffer, const string::size_type position, - } - - --void body::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void body::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type /* curLinePos */, string::size_type* newLinePos) const - { - // MIME-Multipart -@@ -862,9 +954,9 @@ const std::vector <ref <bodyPart> > body::getPartList() - } - - --const std::vector <ref <const component> > body::getChildComponents() const -+const std::vector <ref <component> > body::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - copy_vector(m_parts, list); - -diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp -index 7d60461..522cbb2 100644 ---- a/src/bodyPart.cpp -+++ b/src/bodyPart.cpp -@@ -46,15 +46,18 @@ bodyPart::bodyPart(weak_ref <vmime::bodyPart> parentPart) - } - - --void bodyPart::parse(const string& buffer, const string::size_type position, -- const string::size_type end, string::size_type* newPosition) -+void bodyPart::parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition) - { - // Parse the headers - string::size_type pos = position; -- m_header->parse(buffer, pos, end, &pos); -+ m_header->parse(parser, pos, end, &pos); - - // Parse the body contents -- m_body->parse(buffer, pos, end, NULL); -+ m_body->parse(parser, pos, end, NULL); - - setParsedBounds(position, end); - -@@ -63,7 +66,7 @@ void bodyPart::parse(const string& buffer, const string::size_type position, - } - - --void bodyPart::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void bodyPart::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type /* curLinePos */, string::size_type* newLinePos) const - { - m_header->generate(os, maxLineLength); -@@ -142,9 +145,9 @@ ref <const bodyPart> bodyPart::getParentPart() const - } - - --const std::vector <ref <const component> > bodyPart::getChildComponents() const -+const std::vector <ref <component> > bodyPart::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - list.push_back(m_header); - list.push_back(m_body); -diff --git a/src/charset.cpp b/src/charset.cpp -index 0fda450..705664f 100644 ---- a/src/charset.cpp -+++ b/src/charset.cpp -@@ -57,7 +57,7 @@ charset::charset(const char* name) - } - - --void charset::parse(const string& buffer, const string::size_type position, -+void charset::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - m_name = utility::stringUtils::trim -@@ -74,7 +74,7 @@ void charset::parse(const string& buffer, const string::size_type position, - } - - --void charset::generate(utility::outputStream& os, const string::size_type /* maxLineLength */, -+void charset::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - os << m_name; -@@ -142,9 +142,9 @@ void charset::copyFrom(const component& other) - } - - --const std::vector <ref <const component> > charset::getChildComponents() const -+const std::vector <ref <component> > charset::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/component.cpp b/src/component.cpp -index 139cf66..e93aacf 100644 ---- a/src/component.cpp -+++ b/src/component.cpp -@@ -23,6 +23,9 @@ - - #include "vmime/component.hpp" - #include "vmime/base.hpp" -+ -+#include "vmime/utility/streamUtils.hpp" -+#include "vmime/utility/inputStreamStringAdapter.hpp" - #include "vmime/utility/outputStreamAdapter.hpp" - - #include <sstream> -@@ -43,9 +46,102 @@ component::~component() - } - - -+void component::parse -+ (ref <utility::inputStream> inputStream, const utility::stream::size_type length) -+{ -+ parse(inputStream, 0, length, NULL); -+} -+ -+ -+void component::parse -+ (ref <utility::inputStream> inputStream, const utility::stream::size_type position, -+ const utility::stream::size_type end, utility::stream::size_type* newPosition) -+{ -+ m_parsedOffset = m_parsedLength = 0; -+ -+ ref <utility::seekableInputStream> seekableStream = -+ inputStream.dynamicCast <utility::seekableInputStream>(); -+ -+ if (seekableStream == NULL || end == 0) -+ { -+ // Read the whole stream into a buffer -+ std::ostringstream oss; -+ utility::outputStreamAdapter ossAdapter(oss); -+ -+ utility::bufferedStreamCopyRange(*inputStream, ossAdapter, position, end - position); -+ -+ const string buffer = oss.str(); -+ parseImpl(buffer, 0, buffer.length(), NULL); -+ } -+ else -+ { -+ ref <utility::parserInputStreamAdapter> parser = -+ vmime::create <utility::parserInputStreamAdapter>(seekableStream); -+ -+ parseImpl(parser, position, end, newPosition); -+ } -+} -+ -+ - void component::parse(const string& buffer) - { -- parse(buffer, 0, buffer.length(), NULL); -+ m_parsedOffset = m_parsedLength = 0; -+ -+ parseImpl(buffer, 0, buffer.length(), NULL); -+} -+ -+ -+void component::parse -+ (const string& buffer, const string::size_type position, -+ const string::size_type end, string::size_type* newPosition) -+{ -+ m_parsedOffset = m_parsedLength = 0; -+ -+ parseImpl(buffer, position, end, newPosition); -+} -+ -+ -+void component::offsetParsedBounds(const utility::stream::size_type offset) -+{ -+ // Offset parsed bounds of this component -+ if (m_parsedLength != 0) -+ m_parsedOffset += offset; -+ -+ // Offset parsed bounds of our children -+ std::vector <ref <component> > children = getChildComponents(); -+ -+ for (unsigned int i = 0, n = children.size() ; i < n ; ++i) -+ children[i]->offsetParsedBounds(offset); -+} -+ -+ -+void component::parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, const utility::stream::size_type position, -+ const utility::stream::size_type end, utility::stream::size_type* newPosition) -+{ -+ const std::string buffer = parser->extract(position, end); -+ parseImpl(buffer, 0, buffer.length(), newPosition); -+ -+ // Recursivey offset parsed bounds on children -+ if (position != 0) -+ offsetParsedBounds(position); -+ -+ if (newPosition != NULL) -+ *newPosition += position; -+} -+ -+ -+void component::parseImpl -+ (const string& buffer, const string::size_type position, -+ const string::size_type end, string::size_type* newPosition) -+{ -+ ref <utility::seekableInputStream> stream = -+ vmime::create <utility::inputStreamStringAdapter>(buffer); -+ -+ ref <utility::parserInputStreamAdapter> parser = -+ vmime::create <utility::parserInputStreamAdapter>(stream); -+ -+ parseImpl(parser, position, end, newPosition); - } - - -@@ -61,6 +157,26 @@ const string component::generate(const string::size_type maxLineLength, - } - - -+void component::generate -+ (utility::outputStream& os, -+ const string::size_type maxLineLength, -+ const string::size_type curLinePos, -+ string::size_type* newLinePos) const -+{ -+ generateImpl(os, maxLineLength, curLinePos, newLinePos); -+} -+ -+ -+void component::generate -+ (ref <utility::outputStream> os, -+ const string::size_type maxLineLength, -+ const string::size_type curLinePos, -+ string::size_type* newLinePos) const -+{ -+ generateImpl(*os, maxLineLength, curLinePos, newLinePos); -+} -+ -+ - string::size_type component::getParsedOffset() const - { - return (m_parsedOffset); -@@ -80,22 +196,5 @@ void component::setParsedBounds(const string::size_type start, const string::siz - } - - --const std::vector <ref <component> > component::getChildComponents() --{ -- const std::vector <ref <const component> > constList = -- const_cast <const component*>(this)->getChildComponents(); -- -- std::vector <ref <component> > list; -- -- const std::vector <ref <const component> >::size_type count = constList.size(); -+} // vmime - -- list.resize(count); -- -- for (std::vector <ref <const component> >::size_type i = 0 ; i < count ; ++i) -- list[i] = constList[i].constCast <component>(); -- -- return (list); --} -- -- --} -diff --git a/src/contentDisposition.cpp b/src/contentDisposition.cpp -index 0ab7c45..253dbba 100644 ---- a/src/contentDisposition.cpp -+++ b/src/contentDisposition.cpp -@@ -47,7 +47,7 @@ contentDisposition::contentDisposition(const contentDisposition& type) - } - - --void contentDisposition::parse(const string& buffer, const string::size_type position, -+void contentDisposition::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - m_name = utility::stringUtils::trim(utility::stringUtils::toLower -@@ -60,7 +60,7 @@ void contentDisposition::parse(const string& buffer, const string::size_type pos - } - - --void contentDisposition::generate(utility::outputStream& os, const string::size_type /* maxLineLength */, -+void contentDisposition::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - os << m_name; -@@ -122,9 +122,9 @@ void contentDisposition::setName(const string& name) - } - - --const std::vector <ref <const component> > contentDisposition::getChildComponents() const -+const std::vector <ref <component> > contentDisposition::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/dateTime.cpp b/src/dateTime.cpp -index 089a900..0d97b2f 100644 ---- a/src/dateTime.cpp -+++ b/src/dateTime.cpp -@@ -67,7 +67,7 @@ zone = "UT" / "GMT" ; Universal Time - */ - - --void datetime::parse(const string& buffer, const string::size_type position, -+void datetime::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -588,7 +588,7 @@ void datetime::parse(const string& buffer, const string::size_type position, - } - - --void datetime::generate(utility::outputStream& os, const string::size_type /* maxLineLength */, -+void datetime::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - static const string::value_type* dayNames[] = -@@ -784,9 +784,9 @@ ref <component> datetime::clone() const - } - - --const std::vector <ref <const component> > datetime::getChildComponents() const -+const std::vector <ref <component> > datetime::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/disposition.cpp b/src/disposition.cpp -index b8059a7..24a4579 100644 ---- a/src/disposition.cpp -+++ b/src/disposition.cpp -@@ -79,9 +79,9 @@ disposition& disposition::operator=(const disposition& other) - } - - --const std::vector <ref <const component> > disposition::getChildComponents() const -+const std::vector <ref <component> > disposition::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -@@ -171,7 +171,7 @@ const std::vector <string> disposition::getModifierList() const - } - - --void disposition::parse(const string& buffer, const string::size_type position, -+void disposition::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - // disposition-mode ";" disposition-type -@@ -276,7 +276,7 @@ void disposition::parse(const string& buffer, const string::size_type position, - } - - --void disposition::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void disposition::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - string::size_type pos = curLinePos; -diff --git a/src/encoding.cpp b/src/encoding.cpp -index 5d99ab6..343a822 100644 ---- a/src/encoding.cpp -+++ b/src/encoding.cpp -@@ -61,7 +61,7 @@ encoding::encoding(const encoding& enc) - } - - --void encoding::parse(const string& buffer, const string::size_type position, -+void encoding::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - m_usage = USAGE_UNKNOWN; -@@ -80,7 +80,7 @@ void encoding::parse(const string& buffer, const string::size_type position, - } - - --void encoding::generate(utility::outputStream& os, const string::size_type /* maxLineLength */, -+void encoding::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - os << m_name; -@@ -268,9 +268,9 @@ void encoding::setUsage(const EncodingUsage usage) - } - - --const std::vector <ref <const component> > encoding::getChildComponents() const -+const std::vector <ref <component> > encoding::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/header.cpp b/src/header.cpp -index 443aab8..fcdca2c 100644 ---- a/src/header.cpp -+++ b/src/header.cpp -@@ -61,7 +61,7 @@ field-body-contents = - specials tokens, or else consisting of texts> - */ - --void header::parse(const string& buffer, const string::size_type position, -+void header::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - string::size_type pos = position; -@@ -83,7 +83,7 @@ void header::parse(const string& buffer, const string::size_type position, - } - - --void header::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void header::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type /* curLinePos */, string::size_type* newLinePos) const - { - // Generate the fields -@@ -337,9 +337,9 @@ const std::vector <ref <headerField> > header::getFieldList() - } - - --const std::vector <ref <const component> > header::getChildComponents() const -+const std::vector <ref <component> > header::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - copy_vector(m_fields, list); - -diff --git a/src/headerField.cpp b/src/headerField.cpp -index d1d4236..a8460aa 100644 ---- a/src/headerField.cpp -+++ b/src/headerField.cpp -@@ -262,14 +262,14 @@ ref <headerField> headerField::parseNext(const string& buffer, const string::siz - } - - --void headerField::parse(const string& buffer, const string::size_type position, const string::size_type end, -+void headerField::parseImpl(const string& buffer, const string::size_type position, const string::size_type end, - string::size_type* newPosition) - { - m_value->parse(buffer, position, end, newPosition); - } - - --void headerField::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void headerField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - os << m_name + ": "; -@@ -296,9 +296,9 @@ bool headerField::isCustom() const - } - - --const std::vector <ref <const component> > headerField::getChildComponents() const -+const std::vector <ref <component> > headerField::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - if (m_value) - list.push_back(m_value); -diff --git a/src/mailbox.cpp b/src/mailbox.cpp -index fea7479..dfdccad 100644 ---- a/src/mailbox.cpp -+++ b/src/mailbox.cpp -@@ -65,7 +65,7 @@ angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr - - */ - --void mailbox::parse(const string& buffer, const string::size_type position, -+void mailbox::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -343,7 +343,7 @@ void mailbox::parse(const string& buffer, const string::size_type position, - } - - --void mailbox::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void mailbox::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - if (m_name.isEmpty()) -@@ -514,9 +514,9 @@ void mailbox::setEmail(const string& email) - } - - --const std::vector <ref <const component> > mailbox::getChildComponents() const -+const std::vector <ref <component> > mailbox::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/mailboxGroup.cpp b/src/mailboxGroup.cpp -index 94f7ba6..c37444a 100644 ---- a/src/mailboxGroup.cpp -+++ b/src/mailboxGroup.cpp -@@ -54,7 +54,7 @@ mailboxGroup::~mailboxGroup() - } - - --void mailboxGroup::parse(const string& buffer, const string::size_type position, -+void mailboxGroup::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -111,7 +111,7 @@ void mailboxGroup::parse(const string& buffer, const string::size_type position, - } - - --void mailboxGroup::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void mailboxGroup::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - // We have to encode the name: -@@ -348,9 +348,9 @@ const std::vector <ref <mailbox> > mailboxGroup::getMailboxList() - } - - --const std::vector <ref <const component> > mailboxGroup::getChildComponents() const -+const std::vector <ref <component> > mailboxGroup::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - copy_vector(m_list, list); - -diff --git a/src/mailboxList.cpp b/src/mailboxList.cpp -index 0023d9d..f87fb48 100644 ---- a/src/mailboxList.cpp -+++ b/src/mailboxList.cpp -@@ -190,20 +190,20 @@ mailboxList& mailboxList::operator=(const mailboxList& other) - } - - --const std::vector <ref <const component> > mailboxList::getChildComponents() const -+const std::vector <ref <component> > mailboxList::getChildComponents() - { - return (m_list.getChildComponents()); - } - - --void mailboxList::parse(const string& buffer, const string::size_type position, -+void mailboxList::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - m_list.parse(buffer, position, end, newPosition); - } - - --void mailboxList::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void mailboxList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - m_list.generate(os, maxLineLength, curLinePos, newLinePos); -diff --git a/src/mediaType.cpp b/src/mediaType.cpp -index 725f933..627b276 100644 ---- a/src/mediaType.cpp -+++ b/src/mediaType.cpp -@@ -48,7 +48,7 @@ mediaType::mediaType(const string& type, const string& subType) - } - - --void mediaType::parse(const string& buffer, const string::size_type position, -+void mediaType::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -82,7 +82,7 @@ void mediaType::parse(const string& buffer, const string::size_type position, - } - - --void mediaType::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void mediaType::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - const string value = m_type + "/" + m_subType; -@@ -176,9 +176,9 @@ void mediaType::setFromString(const string& type) - } - - --const std::vector <ref <const component> > mediaType::getChildComponents() const -+const std::vector <ref <component> > mediaType::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/message.cpp b/src/message.cpp -index 1b4f086..3fa9b6a 100644 ---- a/src/message.cpp -+++ b/src/message.cpp -@@ -61,9 +61,14 @@ const string message::generate(const string::size_type maxLineLength, - } - - --void message::parse(const string& buffer) -+ -+void message::generate -+ (ref <utility::outputStream> os, -+ const string::size_type maxLineLength, -+ const string::size_type curLinePos, -+ string::size_type* newLinePos) const - { -- bodyPart::parse(buffer); -+ bodyPart::generate(os, maxLineLength, curLinePos, newLinePos); - } - - -diff --git a/src/messageId.cpp b/src/messageId.cpp -index 961fb63..1f4b186 100644 ---- a/src/messageId.cpp -+++ b/src/messageId.cpp -@@ -61,7 +61,7 @@ messageId::messageId(const string& left, const string& right) - msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] - */ - --void messageId::parse(const string& buffer, const string::size_type position, -+void messageId::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -185,7 +185,7 @@ const string messageId::getId() const - } - - --void messageId::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void messageId::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - string::size_type pos = curLinePos; -@@ -288,9 +288,9 @@ void messageId::setRight(const string& right) - } - - --const std::vector <ref <const component> > messageId::getChildComponents() const -+const std::vector <ref <component> > messageId::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/messageIdSequence.cpp b/src/messageIdSequence.cpp -index 08103d0..0a5c9a0 100644 ---- a/src/messageIdSequence.cpp -+++ b/src/messageIdSequence.cpp -@@ -74,9 +74,9 @@ messageIdSequence& messageIdSequence::operator=(const messageIdSequence& other) - } - - --const std::vector <ref <const component> > messageIdSequence::getChildComponents() const -+const std::vector <ref <component> > messageIdSequence::getChildComponents() - { -- std::vector <ref <const component> > res; -+ std::vector <ref <component> > res; - - copy_vector(m_list, res); - -@@ -84,7 +84,7 @@ const std::vector <ref <const component> > messageIdSequence::getChildComponents - } - - --void messageIdSequence::parse(const string& buffer, const string::size_type position, -+void messageIdSequence::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - removeAllMessageIds(); -@@ -106,7 +106,7 @@ void messageIdSequence::parse(const string& buffer, const string::size_type posi - } - - --void messageIdSequence::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void messageIdSequence::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - string::size_type pos = curLinePos; -diff --git a/src/parameter.cpp b/src/parameter.cpp -index ccbe1a5..58d9a3e 100644 ---- a/src/parameter.cpp -+++ b/src/parameter.cpp -@@ -36,19 +36,19 @@ namespace vmime - - - parameter::parameter(const string& name) -- : m_name(name) -+ : m_name(name), m_value(vmime::create <word>()) - { - } - - - parameter::parameter(const string& name, const word& value) -- : m_name(name), m_value(value) -+ : m_name(name), m_value(vmime::create <word>(value)) - { - } - - - parameter::parameter(const string& name, const string& value) -- : m_name(name), m_value(value) -+ : m_name(name), m_value(vmime::create <word>(value)) - { - } - -@@ -73,7 +73,7 @@ void parameter::copyFrom(const component& other) - const parameter& param = dynamic_cast <const parameter&>(other); - - m_name = param.m_name; -- m_value.copyFrom(param.m_value); -+ m_value->copyFrom(*param.m_value); - } - - -@@ -92,7 +92,7 @@ const string& parameter::getName() const - - const word& parameter::getValue() const - { -- return m_value; -+ return *m_value; - } - - -@@ -109,15 +109,15 @@ void parameter::setValue(const component& value) - - void parameter::setValue(const word& value) - { -- m_value = value; -+ *m_value = value; - } - - --void parameter::parse(const string& buffer, const string::size_type position, -+void parameter::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { -- m_value.setBuffer(string(buffer.begin() + position, buffer.begin() + end)); -- m_value.setCharset(charset(charsets::US_ASCII)); -+ m_value->setBuffer(string(buffer.begin() + position, buffer.begin() + end)); -+ m_value->setCharset(charset(charsets::US_ASCII)); - - if (newPosition) - *newPosition = end; -@@ -248,16 +248,16 @@ void parameter::parse(const std::vector <valueChunk>& chunks) - } - } - -- m_value.setBuffer(value.str()); -- m_value.setCharset(ch); -+ m_value->setBuffer(value.str()); -+ m_value->setCharset(ch); - } - - --void parameter::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void parameter::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - const string& name = m_name; -- const string& value = m_value.getBuffer(); -+ const string& value = m_value->getBuffer(); - - // For compatibility with implementations that do not understand RFC-2231, - // also generate a normal "7bit/us-ascii" parameter -@@ -344,7 +344,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - // 7-bit (ASCII) bytes in the input will be used to determine if - // we need to encode the whole buffer. - encoding recommendedEnc; -- const bool alwaysEncode = m_value.getCharset().getRecommendedEncoding(recommendedEnc); -+ const bool alwaysEncode = m_value->getCharset().getRecommendedEncoding(recommendedEnc); - bool extended = alwaysEncode; - - if (needQuotedPrintable) -@@ -352,7 +352,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - // Send the name in quoted-printable, so outlook express et.al. - // will understand the real filename - size_t oldLen = sevenBitBuffer.length(); -- m_value.generate(sevenBitStream); -+ m_value->generate(sevenBitStream); - pos += sevenBitBuffer.length() - oldLen; - extended = true; // also send with RFC-2231 encoding - } -@@ -429,7 +429,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - // + at least 5 characters for the value - const string::size_type firstSectionLength = - name.length() + 4 /* *0*= */ + 2 /* '' */ -- + m_value.getCharset().getName().length(); -+ + m_value->getCharset().getName().length(); - - if (pos + firstSectionLength + 5 >= maxLineLength) - { -@@ -539,7 +539,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - - if (sectionNumber == 0) - { -- os << m_value.getCharset().getName(); -+ os << m_value->getCharset().getName(); - os << '\'' << /* No language */ '\''; - } - -@@ -570,11 +570,11 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL - } - - --const std::vector <ref <const component> > parameter::getChildComponents() const -+const std::vector <ref <component> > parameter::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - -- list.push_back(ref <const component>::fromPtr(&m_value)); -+ list.push_back(m_value); - - return list; - } -diff --git a/src/parameterizedHeaderField.cpp b/src/parameterizedHeaderField.cpp -index 464990e..756d02f 100644 ---- a/src/parameterizedHeaderField.cpp -+++ b/src/parameterizedHeaderField.cpp -@@ -78,7 +78,7 @@ struct paramInfo - #endif // VMIME_BUILDING_DOC - - --void parameterizedHeaderField::parse(const string& buffer, const string::size_type position, -+void parameterizedHeaderField::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -328,13 +328,13 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty - } - - --void parameterizedHeaderField::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void parameterizedHeaderField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - string::size_type pos = curLinePos; - - // Parent header field -- headerField::generate(os, maxLineLength, pos, &pos); -+ headerField::generateImpl(os, maxLineLength, pos, &pos); - - // Parameters - for (std::vector <ref <parameter> >::const_iterator -@@ -552,11 +552,11 @@ const std::vector <ref <parameter> > parameterizedHeaderField::getParameterList( - } - - --const std::vector <ref <const component> > parameterizedHeaderField::getChildComponents() const -+const std::vector <ref <component> > parameterizedHeaderField::getChildComponents() - { -- std::vector <ref <const component> > list = headerField::getChildComponents(); -+ std::vector <ref <component> > list = headerField::getChildComponents(); - -- for (std::vector <ref <parameter> >::const_iterator it = m_params.begin() ; -+ for (std::vector <ref <parameter> >::iterator it = m_params.begin() ; - it != m_params.end() ; ++it) - { - list.push_back(*it); -diff --git a/src/path.cpp b/src/path.cpp -index 37a4090..d92bb0a 100644 ---- a/src/path.cpp -+++ b/src/path.cpp -@@ -106,14 +106,14 @@ path& path::operator=(const path& other) - } - - --const std::vector <ref <const component> > path::getChildComponents() const -+const std::vector <ref <component> > path::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - --void path::parse(const string& buffer, const string::size_type position, -- const string::size_type end, string::size_type* newPosition) -+void path::parseImpl(const string& buffer, const string::size_type position, -+ const string::size_type end, string::size_type* newPosition) - { - string::size_type pos = position; - -@@ -165,8 +165,8 @@ void path::parse(const string& buffer, const string::size_type position, - } - - --void path::generate(utility::outputStream& os, const string::size_type /* maxLineLength */, -- const string::size_type curLinePos, string::size_type* newLinePos) const -+void path::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */, -+ const string::size_type curLinePos, string::size_type* newLinePos) const - { - if (m_localPart.empty() && m_domain.empty()) - { -diff --git a/src/platforms/posix/posixFile.cpp b/src/platforms/posix/posixFile.cpp -index ec529eb..4087a21 100644 ---- a/src/platforms/posix/posixFile.cpp -+++ b/src/platforms/posix/posixFile.cpp -@@ -224,6 +224,26 @@ vmime::utility::stream::size_type posixFileReaderInputStream::skip(const size_ty - } - - -+vmime::utility::stream::size_type posixFileReaderInputStream::getPosition() const -+{ -+ const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR); -+ -+ if (curPos == off_t(-1)) -+ posixFileSystemFactory::reportError(m_path, errno); -+ -+ return static_cast <size_type>(curPos); -+} -+ -+ -+void posixFileReaderInputStream::seek(const size_type pos) -+{ -+ const off_t newPos = ::lseek(m_fd, pos, SEEK_SET); -+ -+ if (newPos == off_t(-1)) -+ posixFileSystemFactory::reportError(m_path, errno); -+} -+ -+ - - // - // posixFileWriter -diff --git a/src/platforms/windows/windowsFile.cpp b/src/platforms/windows/windowsFile.cpp -index 624612a..5da786e 100644 ---- a/src/platforms/windows/windowsFile.cpp -+++ b/src/platforms/windows/windowsFile.cpp -@@ -479,6 +479,24 @@ vmime::utility::stream::size_type windowsFileReaderInputStream::skip(const size_ - return (dwNewPos - dwCurPos); - } - -+vmime::utility::stream::size_type windowsFileReaderInputStream::getPosition() const -+{ -+ DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT); -+ -+ if (dwCurPos == INVALID_SET_FILE_POINTER) -+ windowsFileSystemFactory::reportError(m_path, GetLastError()); -+ -+ return static_cast <size_type>(dwCurPos); -+} -+ -+void windowsFileReaderInputStream::seek(const size_type pos) -+{ -+ DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)pos, NULL, FILE_BEGIN); -+ -+ if (dwNewPos == INVALID_SET_FILE_POINTER) -+ windowsFileSystemFactory::reportError(m_path, GetLastError()); -+} -+ - windowsFileWriter::windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath) - : m_path(path), m_nativePath(nativePath) - { -diff --git a/src/relay.cpp b/src/relay.cpp -index 5cd454f..97f793d 100644 ---- a/src/relay.cpp -+++ b/src/relay.cpp -@@ -57,7 +57,7 @@ relay::relay(const relay& r) - ["for" addr-spec] ; initial form - */ - --void relay::parse(const string& buffer, const string::size_type position, -+void relay::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - const string::value_type* const pend = buffer.data() + end; -@@ -198,7 +198,7 @@ void relay::parse(const string& buffer, const string::size_type position, - } - - --void relay::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void relay::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - std::ostringstream oss; -@@ -338,10 +338,10 @@ std::vector <string>& relay::getWithList() - } - - --const std::vector <ref <const component> > relay::getChildComponents() const -+const std::vector <ref <component> > relay::getChildComponents() - { - // TODO: should fields inherit from 'component'? (using typeAdapter) -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp -index 89a36b4..14837d2 100644 ---- a/src/streamContentHandler.cpp -+++ b/src/streamContentHandler.cpp -@@ -25,6 +25,7 @@ - - #include "vmime/utility/outputStreamAdapter.hpp" - #include "vmime/utility/inputStreamStringAdapter.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - #include "vmime/utility/streamUtils.hpp" - - -@@ -207,6 +208,9 @@ const vmime::encoding& streamContentHandler::getEncoding() const - - bool streamContentHandler::isBuffered() const - { -+ if (m_stream.dynamicCast <utility::seekableInputStream>() != NULL) -+ return true; -+ - // FIXME: some streams can be resetted - return false; - } -diff --git a/src/text.cpp b/src/text.cpp -index 66c3b35..91b81e1 100644 ---- a/src/text.cpp -+++ b/src/text.cpp -@@ -67,7 +67,7 @@ text::~text() - } - - --void text::parse(const string& buffer, const string::size_type position, -+void text::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - removeAllWords(); -@@ -85,7 +85,7 @@ void text::parse(const string& buffer, const string::size_type position, - } - - --void text::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void text::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - encodeAndFold(os, maxLineLength, curLinePos, newLinePos, 0); -@@ -389,9 +389,9 @@ text* text::decodeAndUnfold(const string& in, text* generateInExisting) - } - - --const std::vector <ref <const component> > text::getChildComponents() const -+const std::vector <ref <component> > text::getChildComponents() - { -- std::vector <ref <const component> > list; -+ std::vector <ref <component> > list; - - copy_vector(m_words, list); - -diff --git a/src/utility/inputStreamAdapter.cpp b/src/utility/inputStreamAdapter.cpp -index b44b084..441307b 100644 ---- a/src/utility/inputStreamAdapter.cpp -+++ b/src/utility/inputStreamAdapter.cpp -@@ -65,6 +65,18 @@ stream::size_type inputStreamAdapter::skip(const size_type count) - } - - -+stream::size_type inputStreamAdapter::getPosition() const -+{ -+ return m_stream.tellg(); -+} -+ -+ -+void inputStreamAdapter::seek(const size_type pos) -+{ -+ m_stream.seekg(pos, std::ios_base::beg); -+} -+ -+ - } // utility - } // vmime - -diff --git a/src/utility/inputStreamByteBufferAdapter.cpp b/src/utility/inputStreamByteBufferAdapter.cpp -index 92e779f..907f1ee 100644 ---- a/src/utility/inputStreamByteBufferAdapter.cpp -+++ b/src/utility/inputStreamByteBufferAdapter.cpp -@@ -85,6 +85,19 @@ stream::size_type inputStreamByteBufferAdapter::skip(const size_type count) - } - - -+stream::size_type inputStreamByteBufferAdapter::getPosition() const -+{ -+ return m_pos; -+} -+ -+ -+void inputStreamByteBufferAdapter::seek(const size_type pos) -+{ -+ if (pos <= m_length) -+ m_pos = pos; -+} -+ -+ - } // utility - } // vmime - -diff --git a/src/utility/inputStreamStringAdapter.cpp b/src/utility/inputStreamStringAdapter.cpp -index 31c9fda..9b8fb0c 100644 ---- a/src/utility/inputStreamStringAdapter.cpp -+++ b/src/utility/inputStreamStringAdapter.cpp -@@ -89,6 +89,19 @@ stream::size_type inputStreamStringAdapter::skip(const size_type count) - } - - -+stream::size_type inputStreamStringAdapter::getPosition() const -+{ -+ return m_pos - m_begin; -+} -+ -+ -+void inputStreamStringAdapter::seek(const size_type pos) -+{ -+ if (m_begin + pos <= m_end) -+ m_pos = m_begin + pos; -+} -+ -+ - } // utility - } // vmime - -diff --git a/src/utility/inputStreamStringProxyAdapter.cpp b/src/utility/inputStreamStringProxyAdapter.cpp -index 5e4b60b..feecddd 100644 ---- a/src/utility/inputStreamStringProxyAdapter.cpp -+++ b/src/utility/inputStreamStringProxyAdapter.cpp -@@ -84,6 +84,19 @@ stream::size_type inputStreamStringProxyAdapter::skip(const size_type count) - } - - -+stream::size_type inputStreamStringProxyAdapter::getPosition() const -+{ -+ return m_pos; -+} -+ -+ -+void inputStreamStringProxyAdapter::seek(const size_type pos) -+{ -+ if (pos <= m_buffer.length()) -+ m_pos = pos; -+} -+ -+ - } // utility - } // vmime - -diff --git a/src/utility/parserInputStreamAdapter.cpp b/src/utility/parserInputStreamAdapter.cpp -new file mode 100644 -index 0000000..7a38ef1 ---- /dev/null -+++ b/src/utility/parserInputStreamAdapter.cpp -@@ -0,0 +1,162 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/parserInputStreamAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+parserInputStreamAdapter::parserInputStreamAdapter(ref <seekableInputStream> stream) -+ : m_stream(stream) -+{ -+} -+ -+ -+bool parserInputStreamAdapter::eof() const -+{ -+ return m_stream->eof(); -+} -+ -+ -+void parserInputStreamAdapter::reset() -+{ -+ m_stream->reset(); -+} -+ -+ -+stream::size_type parserInputStreamAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ return m_stream->read(data, count); -+} -+ -+ -+ref <seekableInputStream> parserInputStreamAdapter::getUnderlyingStream() -+{ -+ return m_stream; -+} -+ -+ -+const string parserInputStreamAdapter::extract(const size_type begin, const size_type end) const -+{ -+ const size_type initialPos = m_stream->getPosition(); -+ -+ try -+ { -+ value_type *buffer = new value_type[end - begin + 1]; -+ -+ m_stream->seek(begin); -+ -+ const size_type readBytes = m_stream->read(buffer, end - begin); -+ buffer[readBytes] = '\0'; -+ -+ m_stream->seek(initialPos); -+ -+ string str(buffer, buffer + readBytes); -+ delete [] buffer; -+ -+ return str; -+ } -+ catch (...) -+ { -+ m_stream->seek(initialPos); -+ throw; -+ } -+} -+ -+ -+stream::size_type parserInputStreamAdapter::findNext -+ (const std::string& token, const size_type startPosition) -+{ -+ static const unsigned int BUFFER_SIZE = 4096; -+ -+ // Token must not be longer than BUFFER_SIZE/2 -+ if (token.empty() || token.length() > BUFFER_SIZE / 2) -+ return npos; -+ -+ const size_type initialPos = getPosition(); -+ -+ seek(startPosition); -+ -+ try -+ { -+ value_type findBuffer[BUFFER_SIZE]; -+ value_type* findBuffer1 = findBuffer; -+ value_type* findBuffer2 = findBuffer + (BUFFER_SIZE / 2) * sizeof(value_type); -+ -+ size_type findBufferLen = 0; -+ size_type findBufferOffset = 0; -+ -+ // Fill in initial buffer -+ findBufferLen = read(findBuffer, BUFFER_SIZE * sizeof(value_type)); -+ -+ for (;;) -+ { -+ // Find token -+ for (value_type *begin = findBuffer, *end = findBuffer + findBufferLen - token.length() ; -+ begin <= end ; ++begin) -+ { -+ if (begin[0] == token[0] && -+ (token.length() == 1 || -+ memcmp(static_cast <const void *>(&begin[1]), -+ static_cast <const void *>(token.data() + 1), -+ token.length() - 1) == 0)) -+ { -+ seek(initialPos); -+ return startPosition + findBufferOffset + (begin - findBuffer); -+ } -+ } -+ -+ // Rotate buffer -+ memcpy(findBuffer1, findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type)); -+ -+ // Read more bytes -+ if (findBufferLen < BUFFER_SIZE && eof()) -+ { -+ break; -+ } -+ else -+ { -+ const size_type bytesRead = read(findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type)); -+ findBufferLen = (BUFFER_SIZE / 2) + bytesRead; -+ findBufferOffset += (BUFFER_SIZE / 2); -+ } -+ } -+ -+ seek(initialPos); -+ } -+ catch (...) -+ { -+ seek(initialPos); -+ throw; -+ } -+ -+ return npos; -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/seekableInputStreamRegionAdapter.cpp b/src/utility/seekableInputStreamRegionAdapter.cpp -new file mode 100644 -index 0000000..348618c ---- /dev/null -+++ b/src/utility/seekableInputStreamRegionAdapter.cpp -@@ -0,0 +1,95 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+seekableInputStreamRegionAdapter::seekableInputStreamRegionAdapter -+ (ref <seekableInputStream> stream, const size_type begin, const size_type length) -+ : m_stream(stream), m_begin(begin), m_length(length) -+{ -+} -+ -+ -+bool seekableInputStreamRegionAdapter::eof() const -+{ -+ return getPosition() >= m_length; -+} -+ -+ -+void seekableInputStreamRegionAdapter::reset() -+{ -+ m_stream->seek(m_begin); -+} -+ -+ -+stream::size_type seekableInputStreamRegionAdapter::read -+ (value_type* const data, const size_type count) -+{ -+ if (getPosition() + count >= m_length) -+ { -+ const size_type remaining = m_length - getPosition(); -+ return m_stream->read(data, remaining); -+ } -+ else -+ { -+ return m_stream->read(data, count); -+ } -+} -+ -+ -+stream::size_type seekableInputStreamRegionAdapter::skip(const size_type count) -+{ -+ if (getPosition() + count >= m_length) -+ { -+ const size_type remaining = m_length - getPosition(); -+ m_stream->skip(remaining); -+ return remaining; -+ } -+ else -+ { -+ m_stream->skip(count); -+ return count; -+ } -+} -+ -+ -+stream::size_type seekableInputStreamRegionAdapter::getPosition() const -+{ -+ return m_stream->getPosition() - m_begin; -+} -+ -+ -+void seekableInputStreamRegionAdapter::seek(const size_type pos) -+{ -+ m_stream->seek(m_begin + pos); -+} -+ -+ -+} // utility -+} // vmime -+ -diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp -index 1c940c2..67c1f33 100644 ---- a/src/utility/stream.cpp -+++ b/src/utility/stream.cpp -@@ -29,6 +29,9 @@ namespace vmime { - namespace utility { - - -+const stream::size_type stream::npos = static_cast <size_type>(vmime::string::npos); -+ -+ - stream::size_type stream::getBlockSize() - { - return 32768; // 32 KB -@@ -37,3 +40,4 @@ stream::size_type stream::getBlockSize() - - } // utility - } // vmime -+ -diff --git a/src/utility/streamUtils.cpp b/src/utility/streamUtils.cpp -index f1d3b9d..f7ea62f 100644 ---- a/src/utility/streamUtils.cpp -+++ b/src/utility/streamUtils.cpp -@@ -52,6 +52,35 @@ stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os) - } - - -+stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os, -+ const stream::size_type start, const stream::size_type length) -+{ -+ const stream::size_type blockSize = -+ std::min(is.getBlockSize(), os.getBlockSize()); -+ -+ is.skip(start); -+ -+ std::vector <stream::value_type> vbuffer(blockSize); -+ -+ stream::value_type* buffer = &vbuffer.front(); -+ stream::size_type total = 0; -+ -+ while (!is.eof() && total < length) -+ { -+ const stream::size_type remaining = std::min(length - total, blockSize); -+ const stream::size_type read = is.read(buffer, blockSize); -+ -+ if (read != 0) -+ { -+ os.write(buffer, read); -+ total += read; -+ } -+ } -+ -+ return total; -+} -+ -+ - stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os, - const stream::size_type length, progressListener* progress) - { -diff --git a/src/word.cpp b/src/word.cpp -index 79060a1..2876ddf 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -241,7 +241,7 @@ const std::vector <ref <word> > word::parseMultiple(const string& buffer, const - } - - --void word::parse(const string& buffer, const string::size_type position, -+void word::parseImpl(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition) - { - if (position + 6 < end && // 6 = "=?(.+)?(.*)?=" -@@ -324,7 +324,7 @@ void word::parse(const string& buffer, const string::size_type position, - } - - --void word::generate(utility::outputStream& os, const string::size_type maxLineLength, -+void word::generateImpl(utility::outputStream& os, const string::size_type maxLineLength, - const string::size_type curLinePos, string::size_type* newLinePos) const - { - generate(os, maxLineLength, curLinePos, newLinePos, 0, NULL); -@@ -743,9 +743,9 @@ void word::setBuffer(const string& buffer) - } - - --const std::vector <ref <const component> > word::getChildComponents() const -+const std::vector <ref <component> > word::getChildComponents() - { -- return std::vector <ref <const component> >(); -+ return std::vector <ref <component> >(); - } - - -diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp -index 9d51262..deb4b9c 100644 ---- a/tests/parser/bodyPartTest.cpp -+++ b/tests/parser/bodyPartTest.cpp -@@ -33,12 +33,14 @@ VMIME_TEST_SUITE_BEGIN - VMIME_TEST_LIST_BEGIN - VMIME_TEST(testParse) - VMIME_TEST(testGenerate) -+ VMIME_TEST(testParseGuessBoundary) - VMIME_TEST(testParseMissingLastBoundary) - VMIME_TEST(testPrologEpilog) - VMIME_TEST(testPrologEncoding) - VMIME_TEST(testSuccessiveBoundaries) - VMIME_TEST(testGenerate7bit) - VMIME_TEST(testTextUsageForQPEncoding) -+ VMIME_TEST(testParseVeryBigMessage) - VMIME_TEST_LIST_END - - -@@ -237,6 +239,93 @@ VMIME_TEST_SUITE_BEGIN - VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str()); - } - -+ void testParseGuessBoundary() -+ { -+ // Boundary is not specified in "Content-Type" field -+ // Parser will try to guess it from message contents. -+ -+ vmime::string str = -+ "Content-Type: multipart/mixed" -+ "\r\n\r\n" -+ "--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n" -+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n" -+ "--UNKNOWN-BOUNDARY--"; -+ -+ vmime::bodyPart p; -+ p.parse(str); -+ -+ VASSERT_EQ("count", 2, p.getBody()->getPartCount()); -+ -+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents())); -+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents())); -+ } -+ -+ void testParseVeryBigMessage() -+ { -+ // When parsing from a seekable input stream, body contents should not -+ // be kept in memory in a "stringContentHandler" object. Instead, content -+ // should be accessible via a "streamContentHandler" object. -+ -+ static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1"; -+ static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1"; -+ static const std::string BODY1_END = "END1END1"; -+ static const unsigned int BODY1_REPEAT = 35000; -+ static const unsigned int BODY1_LENGTH = -+ BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length(); -+ -+ static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2"; -+ static const unsigned int BODY2_REPEAT = 20000; -+ -+ std::ostringstream oss; -+ oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\"" -+ << "\r\n\r\n" -+ << "--MY-BOUNDARY\r\n" -+ << "HEADER1\r\n" -+ << "\r\n"; -+ -+ oss << BODY1_BEGIN; -+ -+ for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i) -+ oss << BODY1_LINE; -+ -+ oss << BODY1_END; -+ -+ oss << "\r\n" -+ << "--MY-BOUNDARY\r\n" -+ << "HEADER2\r\n" -+ << "\r\n"; -+ -+ for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i) -+ oss << BODY2_LINE; -+ -+ oss << "\r\n" -+ << "--MY-BOUNDARY--\r\n"; -+ -+ vmime::ref <vmime::utility::inputStreamStringAdapter> is = -+ vmime::create <vmime::utility::inputStreamStringAdapter>(oss.str()); -+ -+ vmime::ref <vmime::message> msg = vmime::create <vmime::message>(); -+ msg->parse(is, oss.str().length()); -+ -+ vmime::ref <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody(); -+ vmime::ref <const vmime::contentHandler> body1Cts = body1->getContents(); -+ -+ vmime::ref <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody(); -+ vmime::ref <const vmime::contentHandler> body2Cts = body2->getContents(); -+ -+ vmime::string body1CtsExtracted; -+ vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted); -+ body1Cts->extract(body1CtsExtractStream); -+ -+ VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength()); -+ VASSERT("1.2", body1Cts.dynamicCast <const vmime::streamContentHandler>() != NULL); -+ VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length()); -+ VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length())); -+ VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length())); -+ -+ VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength()); -+ VASSERT("2.2", body2Cts.dynamicCast <const vmime::streamContentHandler>() != NULL); -+ } - - VMIME_TEST_SUITE_END - -diff --git a/vmime/addressList.hpp b/vmime/addressList.hpp -index 2e537c0..9dc283c 100644 ---- a/vmime/addressList.hpp -+++ b/vmime/addressList.hpp -@@ -56,7 +56,7 @@ public: - addressList& operator=(const addressList& other); - addressList& operator=(const mailboxList& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - - /** Add a address at the end of the list. -@@ -163,14 +163,20 @@ private: - - std::vector <ref <address> > m_list; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/body.hpp b/vmime/body.hpp -index 9e83d6b..bd5bbb9 100644 ---- a/vmime/body.hpp -+++ b/vmime/body.hpp -@@ -278,7 +278,7 @@ public: - void copyFrom(const component& other); - body& operator=(const body& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - private: - -@@ -299,14 +299,20 @@ private: - - void initNewPart(ref <bodyPart> part); - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/bodyPart.hpp b/vmime/bodyPart.hpp -index aa0f040..5f36d90 100644 ---- a/vmime/bodyPart.hpp -+++ b/vmime/bodyPart.hpp -@@ -89,7 +89,7 @@ public: - void copyFrom(const component& other); - bodyPart& operator=(const bodyPart& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - private: - -@@ -98,14 +98,20 @@ private: - - weak_ref <bodyPart> m_parent; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/charset.hpp b/vmime/charset.hpp -index 5f5e8e5..26abb4f 100644 ---- a/vmime/charset.hpp -+++ b/vmime/charset.hpp -@@ -62,7 +62,7 @@ public: - bool operator==(const charset& value) const; - bool operator!=(const charset& value) const; - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Gets the recommended encoding for this charset. - * Note: there may be no recommended encoding. -@@ -117,14 +117,20 @@ private: - - string m_name; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/component.hpp b/vmime/component.hpp -index 12b0406..5e6f393 100644 ---- a/vmime/component.hpp -+++ b/vmime/component.hpp -@@ -27,6 +27,8 @@ - - #include "vmime/base.hpp" - #include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/seekableInputStream.hpp" -+#include "vmime/utility/parserInputStreamAdapter.hpp" - #include "vmime/utility/outputStream.hpp" - - -@@ -51,6 +53,12 @@ public: - */ - void parse(const string& buffer); - -+ /** Parse RFC-822/MIME data for this component. If stream is not seekable, -+ * or if length is not specified, entire contents of the stream will -+ * be loaded into memory before parsing. -+ */ -+ void parse(ref <utility::inputStream> inputStream, const utility::stream::size_type length); -+ - /** Parse RFC-822/MIME data for this component. - * - * @param buffer input buffer -@@ -58,7 +66,26 @@ public: - * @param end end position in the input buffer - * @param newPosition will receive the new position in the input buffer - */ -- virtual void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL) = 0; -+ void parse -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ /** Parse RFC-822/MIME data for this component. If stream is not seekable, -+ * or if end position is not specified, entire contents of the stream will -+ * be loaded into memory before parsing. -+ * -+ * @param inputStream stream from which to read data -+ * @param position current position in the input stream -+ * @param end end position in the input stream -+ * @param newPosition will receive the new position in the input stream -+ */ -+ void parse -+ (ref <utility::inputStream> inputStream, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition = NULL); - - /** Generate RFC-2822/MIME data for this component. - * -@@ -68,16 +95,35 @@ public: - * @param curLinePos length of the current line in the output buffer - * @return generated data - */ -- const string generate(const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0) const; -+ virtual const string generate -+ (const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0) const; - - /** Generate RFC-2822/MIME data for this component. - * -- * @param os output stream -+ * @param outputStream output stream - * @param maxLineLength maximum line length for output - * @param curLinePos length of the current line in the output buffer - * @param newLinePos will receive the new line position (length of the last line written) - */ -- virtual void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const = 0; -+ virtual void generate -+ (utility::outputStream& outputStream, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; -+ -+ /** Generate RFC-2822/MIME data for this component. -+ * -+ * @param outputStream output stream -+ * @param maxLineLength maximum line length for output -+ * @param curLinePos length of the current line in the output buffer -+ * @param newLinePos will receive the new line position (length of the last line written) -+ */ -+ virtual void generate -+ (ref <utility::outputStream> outputStream, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - - /** Clone this component. - * -@@ -95,41 +141,56 @@ public: - virtual void copyFrom(const component& other) = 0; - - /** Return the start position of this component in the -- * parsed message contents. -+ * parsed message contents. Use for debugging only. - * - * @return start position in parsed buffer - * or 0 if this component has not been parsed - */ -- string::size_type getParsedOffset() const; -+ utility::stream::size_type getParsedOffset() const; - - /** Return the length of this component in the -- * parsed message contents. -+ * parsed message contents. Use for debugging only. - * - * @return length of the component in parsed buffer - * or 0 if this component has not been parsed - */ -- string::size_type getParsedLength() const; -+ utility::stream::size_type getParsedLength() const; - - /** Return the list of children of this component. - * - * @return list of child components - */ -- const std::vector <ref <component> > getChildComponents(); -- -- /** Return the list of children of this component (const version). -- * -- * @return list of child components -- */ -- virtual const std::vector <ref <const component> > getChildComponents() const = 0; -+ virtual const std::vector <ref <component> > getChildComponents() = 0; - - protected: - -- void setParsedBounds(const string::size_type start, const string::size_type end); -+ void setParsedBounds(const utility::stream::size_type start, const utility::stream::size_type end); -+ -+ // AT LEAST ONE of these parseImpl() functions MUST be implemented in derived class -+ virtual void parseImpl -+ (ref <utility::parserInputStreamAdapter> parser, -+ const utility::stream::size_type position, -+ const utility::stream::size_type end, -+ utility::stream::size_type* newPosition = NULL); -+ -+ virtual void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ virtual void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const = 0; - - private: - -- string::size_type m_parsedOffset; -- string::size_type m_parsedLength; -+ void offsetParsedBounds(const utility::stream::size_type offset); -+ -+ utility::stream::size_type m_parsedOffset; -+ utility::stream::size_type m_parsedLength; - }; - - -diff --git a/vmime/contentDisposition.hpp b/vmime/contentDisposition.hpp -index 9d1749b..abd2e1a 100644 ---- a/vmime/contentDisposition.hpp -+++ b/vmime/contentDisposition.hpp -@@ -63,7 +63,7 @@ public: - void copyFrom(const component& other); - contentDisposition& operator=(const contentDisposition& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - - contentDisposition& operator=(const string& name); -@@ -75,14 +75,20 @@ private: - - string m_name; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/dateTime.hpp b/vmime/dateTime.hpp -index 8e99640..053f4a6 100644 ---- a/vmime/dateTime.hpp -+++ b/vmime/dateTime.hpp -@@ -237,16 +237,22 @@ public: - // Current date and time - static const datetime now(); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/disposition.hpp b/vmime/disposition.hpp -index 05bfca2..7bdc832 100644 ---- a/vmime/disposition.hpp -+++ b/vmime/disposition.hpp -@@ -50,7 +50,7 @@ public: - void copyFrom(const component& other); - disposition& operator=(const disposition& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - - /** Set the disposition action mode. -@@ -134,14 +134,20 @@ private: - - std::vector <string> m_modifiers; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp -index 42f5246..4322b29 100644 ---- a/vmime/encoding.hpp -+++ b/vmime/encoding.hpp -@@ -93,7 +93,7 @@ public: - bool operator==(const encoding& value) const; - bool operator!=(const encoding& value) const; - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Decide which encoding to use based on the specified data. - * -@@ -141,14 +141,20 @@ private: - */ - static const encoding decideImpl(const string::const_iterator begin, const string::const_iterator end); - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/header.hpp b/vmime/header.hpp -index 95a9326..ed555b0 100644 ---- a/vmime/header.hpp -+++ b/vmime/header.hpp -@@ -220,7 +220,7 @@ public: - void copyFrom(const component& other); - header& operator=(const header& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - private: - -@@ -251,14 +251,20 @@ private: - string m_name; - }; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/headerField.hpp b/vmime/headerField.hpp -index 50494c9..61e01ee 100644 ---- a/vmime/headerField.hpp -+++ b/vmime/headerField.hpp -@@ -59,7 +59,7 @@ public: - void copyFrom(const component& other); - headerField& operator=(const headerField& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Sets the name of this field. - * -@@ -118,15 +118,26 @@ public: - void setValue(const string& value); - - -- using component::parse; -- using component::generate; -+protected: - -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - --protected: - -- static ref <headerField> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -+ static ref <headerField> parseNext -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); - - - string m_name; -diff --git a/vmime/mailbox.hpp b/vmime/mailbox.hpp -index 2072be8..2099355 100644 ---- a/vmime/mailbox.hpp -+++ b/vmime/mailbox.hpp -@@ -85,7 +85,7 @@ public: - - void clear(); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - - bool isGroup() const; -@@ -101,8 +101,17 @@ public: - using address::generate; - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/mailboxGroup.hpp b/vmime/mailboxGroup.hpp -index 0061d5b..1433141 100644 ---- a/vmime/mailboxGroup.hpp -+++ b/vmime/mailboxGroup.hpp -@@ -52,7 +52,7 @@ public: - ref <component> clone() const; - mailboxGroup& operator=(const component& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Return the name of the group. - * -@@ -165,14 +165,20 @@ private: - text m_name; - std::vector <ref <mailbox> > m_list; - --public: -- -- using address::parse; -- using address::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/mailboxList.hpp b/vmime/mailboxList.hpp -index 11e4e79..1b480c1 100644 ---- a/vmime/mailboxList.hpp -+++ b/vmime/mailboxList.hpp -@@ -51,7 +51,7 @@ public: - void copyFrom(const component& other); - mailboxList& operator=(const mailboxList& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Add a mailbox at the end of the list. - * -@@ -155,14 +155,20 @@ private: - - addressList m_list; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/mediaType.hpp b/vmime/mediaType.hpp -index 658b21f..18182f0 100644 ---- a/vmime/mediaType.hpp -+++ b/vmime/mediaType.hpp -@@ -55,7 +55,7 @@ public: - void copyFrom(const component& other); - mediaType& operator=(const mediaType& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Return the media type. - * See the constants in vmime::mediaTypes. -@@ -97,14 +97,18 @@ protected: - string m_type; - string m_subType; - --public: -- -- using component::parse; -- using component::generate; -- - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/message.hpp b/vmime/message.hpp -index f3be229..9767564 100644 ---- a/vmime/message.hpp -+++ b/vmime/message.hpp -@@ -43,12 +43,25 @@ public: - message(); - - -- // Component parsing & assembling -- void generate(utility::outputStream& os, const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -- -- const string generate(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0) const; -+public: - -- void parse(const string& buffer); -+ // Override default generate() functions so that we can change -+ // the default 'maxLineLength' value -+ void generate -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; -+ -+ const string generate -+ (const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), -+ const string::size_type curLinePos = 0) const; -+ -+ void generate -+ (ref <utility::outputStream> os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/messageId.hpp b/vmime/messageId.hpp -index 3686b11..ac408e6 100644 ---- a/vmime/messageId.hpp -+++ b/vmime/messageId.hpp -@@ -97,23 +97,27 @@ public: - void copyFrom(const component& other); - messageId& operator=(const messageId& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - private: - - string m_left; - string m_right; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -- --protected: -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - - /** Parse a message-id from an input buffer. - * -@@ -123,7 +127,11 @@ protected: - * @param newPosition will receive the new position in the input buffer - * @return a new message-id object, or null if no more message-id can be parsed from the input buffer - */ -- static ref <messageId> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition); -+ static ref <messageId> parseNext -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition); - }; - - -diff --git a/vmime/messageIdSequence.hpp b/vmime/messageIdSequence.hpp -index 5dfb840..6736d0a 100644 ---- a/vmime/messageIdSequence.hpp -+++ b/vmime/messageIdSequence.hpp -@@ -49,7 +49,7 @@ public: - void copyFrom(const component& other); - messageIdSequence& operator=(const messageIdSequence& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - - /** Add a message-id at the end of the list. -@@ -148,14 +148,20 @@ private: - - std::vector <ref <messageId> > m_list; - --public: -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/parameter.hpp b/vmime/parameter.hpp -index e1b13a1..0773ea6 100644 ---- a/vmime/parameter.hpp -+++ b/vmime/parameter.hpp -@@ -67,7 +67,7 @@ public: - void copyFrom(const component& other); - parameter& operator=(const parameter& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Return the name of this parameter. - * -@@ -104,7 +104,7 @@ public: - const T getValueAs() const - { - T ret; -- ret.parse(m_value.getBuffer()); -+ ret.parse(m_value->getBuffer()); - - return ret; - } -@@ -122,11 +122,19 @@ public: - void setValue(const word& value); - - -- using component::parse; -- using component::generate; -+protected: - -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - - private: - -@@ -134,7 +142,7 @@ private: - - - string m_name; -- word m_value; -+ ref <word> m_value; - }; - - -diff --git a/vmime/parameterizedHeaderField.hpp b/vmime/parameterizedHeaderField.hpp -index 2940ca3..d2c934f 100644 ---- a/vmime/parameterizedHeaderField.hpp -+++ b/vmime/parameterizedHeaderField.hpp -@@ -172,19 +172,25 @@ public: - */ - const std::vector <ref <parameter> > getParameterList(); - -+ const std::vector <ref <component> > getChildComponents(); -+ - private: - - std::vector <ref <parameter> > m_params; - --public: -- -- using headerField::parse; -- using headerField::generate; -- -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+protected: - -- const std::vector <ref <const component> > getChildComponents() const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/parserHelpers.hpp b/vmime/parserHelpers.hpp -index 9b075f7..d4f1246 100644 ---- a/vmime/parserHelpers.hpp -+++ b/vmime/parserHelpers.hpp -@@ -45,6 +45,10 @@ public: - return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); - } - -+ static bool isSpaceOrTab(const char_t c) -+ { -+ return (c == ' ' || c == '\t'); -+ } - - static bool isDigit(const char_t c) - { -diff --git a/vmime/path.hpp b/vmime/path.hpp -index beaa72b..eec8dfc 100644 ---- a/vmime/path.hpp -+++ b/vmime/path.hpp -@@ -76,21 +76,26 @@ public: - ref <component> clone() const; - path& operator=(const path& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - protected: - - string m_localPart; - string m_domain; - --public: -- -- using component::parse; -- using component::generate; - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/platforms/posix/posixFile.hpp b/vmime/platforms/posix/posixFile.hpp -index 70986df..704b7b0 100644 ---- a/vmime/platforms/posix/posixFile.hpp -+++ b/vmime/platforms/posix/posixFile.hpp -@@ -26,6 +26,7 @@ - - - #include "vmime/utility/file.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - - #if VMIME_HAVE_FILESYSTEM_FEATURES -@@ -57,7 +58,7 @@ private: - - - --class posixFileReaderInputStream : public vmime::utility::inputStream -+class posixFileReaderInputStream : public vmime::utility::seekableInputStream - { - public: - -@@ -72,6 +73,9 @@ public: - - size_type skip(const size_type count); - -+ size_type getPosition() const; -+ void seek(const size_type pos); -+ - private: - - const vmime::utility::file::path m_path; -diff --git a/vmime/platforms/windows/windowsFile.hpp b/vmime/platforms/windows/windowsFile.hpp -index 6e1c8fb..f417032 100644 ---- a/vmime/platforms/windows/windowsFile.hpp -+++ b/vmime/platforms/windows/windowsFile.hpp -@@ -26,6 +26,7 @@ - - - #include "vmime/utility/file.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - #include <windows.h> - -@@ -157,6 +158,8 @@ public: - void reset(); - size_type read(value_type* const data, const size_type count); - size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); - - private: - -diff --git a/vmime/relay.hpp b/vmime/relay.hpp -index 583ad80..dbaedf2 100644 ---- a/vmime/relay.hpp -+++ b/vmime/relay.hpp -@@ -51,7 +51,7 @@ public: - void copyFrom(const component& other); - relay& operator=(const relay& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - const string& getFrom() const; - void setFrom(const string& from); -@@ -85,13 +85,19 @@ private: - - datetime m_date; - --public: -+protected: - -- using component::parse; -- using component::generate; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); - -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - }; - - -diff --git a/vmime/text.hpp b/vmime/text.hpp -index 15e11ae..778ce86 100644 ---- a/vmime/text.hpp -+++ b/vmime/text.hpp -@@ -58,7 +58,7 @@ public: - text& operator=(const component& other); - text& operator=(const text& other); - -- const std::vector <ref <const component> > getChildComponents() const; -+ const std::vector <ref <component> > getChildComponents(); - - /** Add a word at the end of the list. - * -@@ -226,13 +226,20 @@ public: - */ - static text* decodeAndUnfold(const string& in, text* generateInExisting); - -- -- using component::parse; -- using component::generate; -+protected: - - // Component parsing & assembling -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); -+ -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - - private: - -diff --git a/vmime/utility/inputStreamAdapter.hpp b/vmime/utility/inputStreamAdapter.hpp -index 278ab52..bd4d21e 100644 ---- a/vmime/utility/inputStreamAdapter.hpp -+++ b/vmime/utility/inputStreamAdapter.hpp -@@ -25,7 +25,7 @@ - #define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED - - --#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - #include <istream> - -@@ -37,7 +37,7 @@ namespace utility { - /** An adapter class for C++ standard input streams. - */ - --class inputStreamAdapter : public inputStream -+class inputStreamAdapter : public seekableInputStream - { - public: - -@@ -49,6 +49,8 @@ public: - void reset(); - size_type read(value_type* const data, const size_type count); - size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); - - private: - -diff --git a/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime/utility/inputStreamByteBufferAdapter.hpp -index 0f6a442..b3dafd9 100644 ---- a/vmime/utility/inputStreamByteBufferAdapter.hpp -+++ b/vmime/utility/inputStreamByteBufferAdapter.hpp -@@ -25,7 +25,7 @@ - #define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED - - --#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - - namespace vmime { -@@ -35,7 +35,7 @@ namespace utility { - /** An adapter class for reading from an array of bytes. - */ - --class inputStreamByteBufferAdapter : public inputStream -+class inputStreamByteBufferAdapter : public seekableInputStream - { - public: - -@@ -45,6 +45,8 @@ public: - void reset(); - size_type read(value_type* const data, const size_type count); - size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); - - private: - -diff --git a/vmime/utility/inputStreamStringAdapter.hpp b/vmime/utility/inputStreamStringAdapter.hpp -index a7d986f..18a9083 100644 ---- a/vmime/utility/inputStreamStringAdapter.hpp -+++ b/vmime/utility/inputStreamStringAdapter.hpp -@@ -25,7 +25,7 @@ - #define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED - - --#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - - namespace vmime { -@@ -35,7 +35,7 @@ namespace utility { - /** An adapter class for string input. - */ - --class inputStreamStringAdapter : public inputStream -+class inputStreamStringAdapter : public seekableInputStream - { - public: - -@@ -46,6 +46,8 @@ public: - void reset(); - size_type read(value_type* const data, const size_type count); - size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); - - private: - -diff --git a/vmime/utility/inputStreamStringProxyAdapter.hpp b/vmime/utility/inputStreamStringProxyAdapter.hpp -index 74b3f60..dc52637 100644 ---- a/vmime/utility/inputStreamStringProxyAdapter.hpp -+++ b/vmime/utility/inputStreamStringProxyAdapter.hpp -@@ -25,7 +25,7 @@ - #define VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED - - --#include "vmime/utility/inputStream.hpp" -+#include "vmime/utility/seekableInputStream.hpp" - - - namespace vmime { -@@ -38,7 +38,7 @@ class stringProxy; - /** An adapter class for stringProxy input. - */ - --class inputStreamStringProxyAdapter : public inputStream -+class inputStreamStringProxyAdapter : public seekableInputStream - { - public: - -@@ -50,6 +50,8 @@ public: - void reset(); - size_type read(value_type* const data, const size_type count); - size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); - - private: - -diff --git a/vmime/utility/parserInputStreamAdapter.hpp b/vmime/utility/parserInputStreamAdapter.hpp -new file mode 100644 -index 0000000..c24fa44 ---- /dev/null -+++ b/vmime/utility/parserInputStreamAdapter.hpp -@@ -0,0 +1,173 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/seekableInputStream.hpp" -+ -+#include <cstring> -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter class used for parsing from an input stream. -+ */ -+ -+class parserInputStreamAdapter : public seekableInputStream -+{ -+public: -+ -+ /** @param is input stream to wrap -+ */ -+ parserInputStreamAdapter(ref <seekableInputStream> inputStream); -+ -+ ref <seekableInputStream> getUnderlyingStream(); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ -+ void seek(const size_type pos) -+ { -+ m_stream->seek(pos); -+ } -+ -+ size_type skip(const size_type count) -+ { -+ return m_stream->skip(count); -+ } -+ -+ size_type getPosition() const -+ { -+ return m_stream->getPosition(); -+ } -+ -+ /** Get the byte at the current position without updating the -+ * current position. -+ * -+ * @return byte at the current position -+ */ -+ value_type peekByte() const -+ { -+ const size_type initialPos = m_stream->getPosition(); -+ -+ try -+ { -+ value_type buffer[1]; -+ const size_type readBytes = m_stream->read(buffer, 1); -+ -+ m_stream->seek(initialPos); -+ -+ return (readBytes == 1 ? buffer[0] : 0); -+ } -+ catch (...) -+ { -+ m_stream->seek(initialPos); -+ throw; -+ } -+ } -+ -+ /** Get the byte at the current position and advance current -+ * position by one byte. -+ * -+ * @return byte at the current position -+ */ -+ value_type getByte() -+ { -+ value_type buffer[1]; -+ const size_type readBytes = m_stream->read(buffer, 1); -+ -+ return (readBytes == 1 ? buffer[0] : 0); -+ } -+ -+ /** Check whether the bytes following the current position match -+ * the specified bytes. Position is not updated. -+ * -+ * @param bytes bytes to compare -+ * @param length number of bytes -+ * @return true if the next bytes match the pattern, false otherwise -+ */ -+ bool matchBytes(const value_type* bytes, const size_type length) const -+ { -+ const size_type initialPos = m_stream->getPosition(); -+ -+ try -+ { -+ value_type buffer[32]; -+ const size_type readBytes = m_stream->read(buffer, length); -+ -+ m_stream->seek(initialPos); -+ -+ return readBytes == length && -+ ::memcmp(bytes, buffer, length) == 0; -+ } -+ catch (...) -+ { -+ m_stream->seek(initialPos); -+ throw; -+ } -+ } -+ -+ const string extract(const size_type begin, const size_type end) const; -+ -+ /** Skips bytes matching a predicate from the current position. -+ * The current position is updated to the next following byte -+ * which does not match the predicate. -+ * -+ * @param pred predicate -+ * @param endPosition stop at this position (or at end of the stream, -+ * whichever comes first) -+ * @return number of bytes skipped -+ */ -+ template <typename PREDICATE> -+ size_type skipIf(PREDICATE pred, const size_type endPosition) -+ { -+ const size_type initialPos = getPosition(); -+ size_type pos = initialPos; -+ -+ while (!m_stream->eof() && pos < endPosition && pred(getByte())) -+ ++pos; -+ -+ m_stream->seek(pos); -+ -+ return pos - initialPos; -+ } -+ -+ size_type findNext(const std::string& token, const size_type startPosition = 0); -+ -+private: -+ -+ mutable ref <seekableInputStream> m_stream; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/seekableInputStream.hpp b/vmime/utility/seekableInputStream.hpp -new file mode 100644 -index 0000000..c2ab1bb ---- /dev/null -+++ b/vmime/utility/seekableInputStream.hpp -@@ -0,0 +1,64 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED -+#define VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED -+ -+ -+#include "vmime/utility/inputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An input stream that allows seeking within the input. -+ */ -+ -+class seekableInputStream : public inputStream -+{ -+public: -+ -+ /** Returns the current position in this stream. -+ * -+ * @return the offset from the beginning of the stream, in bytes, -+ * at which the next read occurs -+ */ -+ virtual size_type getPosition() const = 0; -+ -+ /** Sets the position, measured from the beginning of this stream, -+ * at which the next read occurs. -+ * -+ * @param pos the offset position, measured in bytes from the -+ * beginning of the stream, at which to set the stream pointer. -+ */ -+ virtual void seek(const size_type pos) = 0; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED -+ -diff --git a/vmime/utility/seekableInputStreamRegionAdapter.hpp b/vmime/utility/seekableInputStreamRegionAdapter.hpp -new file mode 100644 -index 0000000..5ebccc6 ---- /dev/null -+++ b/vmime/utility/seekableInputStreamRegionAdapter.hpp -@@ -0,0 +1,71 @@ -+// -+// VMime library (http://www.vmime.org) -+// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net> -+// -+// This program is free software; you can redistribute it and/or -+// modify it under the terms of the GNU General Public License as -+// published by the Free Software Foundation; either version 3 of -+// the License, or (at your option) any later version. -+// -+// This program is distributed in the hope that it will be useful, -+// but WITHOUT ANY WARRANTY; without even the implied warranty of -+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+// General Public License for more details. -+// -+// You should have received a copy of the GNU General Public License along -+// with this program; if not, write to the Free Software Foundation, Inc., -+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+// -+// Linking this library statically or dynamically with other modules is making -+// a combined work based on this library. Thus, the terms and conditions of -+// the GNU General Public License cover the whole combination. -+// -+ -+#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED -+#define VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED -+ -+ -+#include "vmime/utility/seekableInputStream.hpp" -+ -+ -+namespace vmime { -+namespace utility { -+ -+ -+/** An adapter for reading a limited region of a seekable input stream. -+ */ -+ -+class seekableInputStreamRegionAdapter : public seekableInputStream -+{ -+public: -+ -+ /** Creates a new adapter for a seekableInputStream. -+ * -+ * @param stream source stream -+ * @param begin start position in source stream -+ * @param length region length in source stream -+ */ -+ seekableInputStreamRegionAdapter(ref <seekableInputStream> stream, -+ const size_type begin, const size_type length); -+ -+ bool eof() const; -+ void reset(); -+ size_type read(value_type* const data, const size_type count); -+ size_type skip(const size_type count); -+ size_type getPosition() const; -+ void seek(const size_type pos); -+ -+private: -+ -+ ref <seekableInputStream> m_stream; -+ size_type m_begin; -+ size_type m_length; -+}; -+ -+ -+} // utility -+} // vmime -+ -+ -+#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED -+ -diff --git a/vmime/utility/stream.hpp b/vmime/utility/stream.hpp -index 566ab9d..78be827 100644 ---- a/vmime/utility/stream.hpp -+++ b/vmime/utility/stream.hpp -@@ -54,6 +54,10 @@ public: - */ - typedef string::size_type size_type; - -+ /** Constant value with the greatest possible value for an element of type size_type. -+ */ -+ static const size_type npos; -+ - /** Return the preferred maximum block size when reading - * from or writing to this stream. - * -diff --git a/vmime/utility/streamUtils.hpp b/vmime/utility/streamUtils.hpp -index cdf70aa..87c8fc5 100644 ---- a/vmime/utility/streamUtils.hpp -+++ b/vmime/utility/streamUtils.hpp -@@ -45,6 +45,19 @@ namespace utility { - stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os); - - /** Copy data from one stream into another stream using a buffered method -+ * and copying only a specified range of data. -+ * -+ * @param is input stream (source data) -+ * @param os output stream (destination for data) -+ * @param start number of bytes to ignore before starting copying -+ * @param length maximum number of bytes to copy -+ * @return number of bytes copied -+ */ -+ -+stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os, -+ const stream::size_type start, const stream::size_type length); -+ -+/** Copy data from one stream into another stream using a buffered method - * and notify progress state of the operation. - * - * @param is input stream (source data) -diff --git a/vmime/word.hpp b/vmime/word.hpp -index ad848ec..492aab5 100644 ---- a/vmime/word.hpp -+++ b/vmime/word.hpp -@@ -128,21 +128,52 @@ public: - #endif - - -- using component::parse; -- using component::generate; -+protected: - -- void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); -- void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; -+ void parseImpl -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition = NULL); - -- void generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, generatorState* state) const; -+ void generateImpl -+ (utility::outputStream& os, -+ const string::size_type maxLineLength = lineLengthLimits::infinite, -+ const string::size_type curLinePos = 0, -+ string::size_type* newLinePos = NULL) const; - -- const std::vector <ref <const component> > getChildComponents() const; -+public: - --private: -+ using component::generate; - -- static ref <word> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, bool prevIsEncoded, bool* isEncoded, bool isFirst); -+#ifndef VMIME_BUILDING_DOC -+ void generate -+ (utility::outputStream& os, -+ const string::size_type maxLineLength, -+ const string::size_type curLinePos, -+ string::size_type* newLinePos, -+ const int flags, -+ generatorState* state) const; -+#endif -+ -+ const std::vector <ref <component> > getChildComponents(); -+ -+private: - -- static const std::vector <ref <word> > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition); -+ static ref <word> parseNext -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition, -+ bool prevIsEncoded, -+ bool* isEncoded, -+ bool isFirst); -+ -+ static const std::vector <ref <word> > parseMultiple -+ (const string& buffer, -+ const string::size_type position, -+ const string::size_type end, -+ string::size_type* newPosition); - - - // The "m_buffer" of this word holds the data, and this data is encoded --- -1.7.10.4 - - -From 2e05e574fde890c7ec6dd9f3930d06b1b492ea80 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 27 Apr 2012 08:34:26 +0200 -Subject: [PATCH 38/47] Fixed duplicate file reference (thanks to Enes Albay). - - -diff --git a/SConstruct b/SConstruct -index 2690172..1f3c7c9 100644 ---- a/SConstruct -+++ b/SConstruct -@@ -137,7 +137,6 @@ libvmime_sources = [ - 'utility/childProcess.hpp', - 'utility/file.hpp', - 'utility/datetimeUtils.cpp', 'utility/datetimeUtils.hpp', -- 'utility/filteredStream.cpp', 'utility/filteredStream.hpp', - 'utility/path.cpp', 'utility/path.hpp', - 'utility/progressListener.cpp', 'utility/progressListener.hpp', - 'utility/random.cpp', 'utility/random.hpp', --- -1.7.10.4 - - -From 799629fd8b21a716f3e3abc6e6a5264555470d85 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Fri, 6 Jul 2012 18:45:02 +0200 -Subject: [PATCH 39/47] Fixed issue #10. - - -diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp -index 702d5f2..8006920 100644 ---- a/src/net/imap/IMAPMessage.cpp -+++ b/src/net/imap/IMAPMessage.cpp -@@ -279,8 +279,6 @@ void IMAPMessage::extract(ref <const part> p, utility::outputStream& os, - { - if (headerOnly) - command << "HEADER"; -- else -- command << "TEXT"; - } - else - { --- -1.7.10.4 - - -From 72cf7a025f7764998609683904eea1046a766d97 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Sat, 28 Jul 2012 13:01:48 +0200 -Subject: [PATCH 40/47] Added functions to get messages by UID (IMAP only for - now). - - -diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp -index 81bf386..3d8c17e 100644 ---- a/src/net/imap/IMAPFolder.cpp -+++ b/src/net/imap/IMAPFolder.cpp -@@ -208,7 +208,7 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) - { - case IMAPParser::resp_text_code::UIDVALIDITY: - -- m_uidValidity = code->nz_number()->value(); -+ m_uidValidity = static_cast <unsigned int>(code->nz_number()->value()); - break; - - default: -@@ -550,6 +550,109 @@ std::vector <ref <message> > IMAPFolder::getMessages(const std::vector <int>& nu - } - - -+ref <message> IMAPFolder::getMessageByUID(const message::uid& uid) -+{ -+ std::vector <message::uid> uids; -+ uids.push_back(uid); -+ -+ std::vector <ref <message> > msgs = getMessagesByUID(uids); -+ -+ if (msgs.size() == 0) -+ throw exceptions::message_not_found(); -+ -+ return msgs[0]; -+} -+ -+ -+std::vector <ref <message> > IMAPFolder::getMessagesByUID(const std::vector <message::uid>& uids) -+{ -+ if (!isOpen()) -+ throw exceptions::illegal_state("Folder not open"); -+ -+ if (uids.size() == 0) -+ return std::vector <ref <message> >(); -+ -+ // C: . UID FETCH uuuu1,uuuu2,uuuu3 UID -+ // S: * nnnn1 FETCH (UID uuuu1) -+ // S: * nnnn2 FETCH (UID uuuu2) -+ // S: * nnnn3 FETCH (UID uuuu3) -+ // S: . OK UID FETCH completed -+ -+ // Prepare command and arguments -+ std::ostringstream cmd; -+ cmd.imbue(std::locale::classic()); -+ -+ cmd << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(uids[0]); -+ -+ for (unsigned int i = 1, n = uids.size() ; i < n ; ++i) -+ cmd << "," << IMAPUtils::extractUIDFromGlobalUID(uids[i]); -+ -+ cmd << " UID"; -+ -+ // Send the request -+ m_connection->send(true, cmd.str(), true); -+ -+ // Get the response -+ utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse()); -+ -+ if (resp->isBad() || resp->response_done()->response_tagged()-> -+ resp_cond_state()->status() != IMAPParser::resp_cond_state::OK) -+ { -+ throw exceptions::command_error("UID FETCH ... UID", m_connection->getParser()->lastLine(), "bad response"); -+ } -+ -+ // Process the response -+ const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = -+ resp->continue_req_or_response_data(); -+ -+ std::vector <ref <message> > messages; -+ -+ for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator -+ it = respDataList.begin() ; it != respDataList.end() ; ++it) -+ { -+ if ((*it)->response_data() == NULL) -+ { -+ throw exceptions::command_error("UID FETCH ... UID", -+ m_connection->getParser()->lastLine(), "invalid response"); -+ } -+ -+ const IMAPParser::message_data* messageData = -+ (*it)->response_data()->message_data(); -+ -+ // We are only interested in responses of type "FETCH" -+ if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH) -+ continue; -+ -+ // Get Process fetch response for this message -+ const int msgNum = static_cast <int>(messageData->number()); -+ message::uid msgUID, msgFullUID; -+ -+ // Find UID in message attributes -+ const std::vector <IMAPParser::msg_att_item*> atts = messageData->msg_att()->items(); -+ -+ for (std::vector <IMAPParser::msg_att_item*>::const_iterator -+ it = atts.begin() ; it != atts.end() ; ++it) -+ { -+ if ((*it)->type() == IMAPParser::msg_att_item::UID) -+ { -+ msgFullUID = IMAPUtils::makeGlobalUID(m_uidValidity, (*it)->unique_id()->value()); -+ msgUID = (*it)->unique_id()->value(); -+ -+ break; -+ } -+ } -+ -+ if (!msgUID.empty()) -+ { -+ ref <IMAPFolder> thisFolder = thisRef().dynamicCast <IMAPFolder>(); -+ messages.push_back(vmime::create <IMAPMessage>(thisFolder, msgNum, msgFullUID)); -+ } -+ } -+ -+ return messages; -+} -+ -+ - int IMAPFolder::getMessageCount() - { - if (!isOpen()) -@@ -730,7 +833,7 @@ void IMAPFolder::fetchMessages(std::vector <ref <message> >& msg, const int opti - - if (msg != numberToMsg.end()) - { -- (*msg).second->processFetchResponse(options, messageData->msg_att()); -+ (*msg).second->processFetchResponse(options, messageData); - - if (progress) - progress->progress(++current, total); -@@ -1781,7 +1884,7 @@ std::vector <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& - std::ostringstream command; - command.imbue(std::locale::classic()); - -- command << "SEARCH UID " << uid; -+ command << "SEARCH UID " << uid << ":*"; - - // Send the request - m_connection->send(true, command.str(), true); -diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp -index 8006920..7202a7d 100644 ---- a/src/net/imap/IMAPMessage.cpp -+++ b/src/net/imap/IMAPMessage.cpp -@@ -98,6 +98,14 @@ IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num) - } - - -+IMAPMessage::IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId) -+ : m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED), -+ m_expunged(false), m_uid(uniqueId), m_structure(NULL) -+{ -+ folder->registerMessage(this); -+} -+ -+ - IMAPMessage::~IMAPMessage() - { - ref <IMAPFolder> folder = m_folder.acquire(); -@@ -271,7 +279,11 @@ void IMAPMessage::extract(ref <const part> p, utility::outputStream& os, - std::ostringstream command; - command.imbue(std::locale::classic()); - -- command << "FETCH " << m_num << " BODY"; -+ if (m_uid.empty()) -+ command << "FETCH " << m_num << " BODY"; -+ else -+ command << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(m_uid) << " BODY"; -+ - if (peek) command << ".PEEK"; - command << "["; - -@@ -361,19 +373,18 @@ void IMAPMessage::fetch(ref <IMAPFolder> msgFolder, const int options) - continue; - - // Process fetch response for this message -- processFetchResponse(options, messageData->msg_att()); -+ processFetchResponse(options, messageData); - } - } - - - void IMAPMessage::processFetchResponse -- (const int options, const IMAPParser::msg_att* msgAtt) -+ (const int options, const IMAPParser::message_data* msgData) - { - ref <IMAPFolder> folder = m_folder.acquire(); - - // Get message attributes -- const std::vector <IMAPParser::msg_att_item*> atts = -- msgAtt->items(); -+ const std::vector <IMAPParser::msg_att_item*> atts = msgData->msg_att()->items(); - - int flags = 0; - -@@ -389,12 +400,7 @@ void IMAPMessage::processFetchResponse - } - case IMAPParser::msg_att_item::UID: - { -- std::ostringstream oss; -- oss.imbue(std::locale::classic()); -- -- oss << folder->m_uidValidity << ":" << (*it)->unique_id()->value(); -- -- m_uid = oss.str(); -+ m_uid = IMAPUtils::makeGlobalUID(folder->m_uidValidity, (*it)->unique_id()->value()); - break; - } - case IMAPParser::msg_att_item::ENVELOPE: -diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp -index 0d6fc47..eceac16 100644 ---- a/src/net/imap/IMAPUtils.cpp -+++ b/src/net/imap/IMAPUtils.cpp -@@ -540,6 +540,24 @@ const string IMAPUtils::listToSet(const std::vector <int>& list, const int max, - - - // static -+const string IMAPUtils::listToSet(const std::vector <message::uid>& list) -+{ -+ if (list.size() == 0) -+ return ""; -+ -+ std::ostringstream res; -+ res.imbue(std::locale::classic()); -+ -+ res << extractUIDFromGlobalUID(list[0]); -+ -+ for (unsigned int i = 1, n = list.size() ; i < n ; ++i) -+ res << "," << extractUIDFromGlobalUID(list[i]); -+ -+ return res.str(); -+} -+ -+ -+// static - const string IMAPUtils::dateTime(const vmime::datetime& date) - { - std::ostringstream res; -@@ -609,7 +627,8 @@ const string IMAPUtils::dateTime(const vmime::datetime& date) - - - // static --const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options) -+const string IMAPUtils::buildFetchRequestImpl -+ (const std::string& mode, const std::string& set, const int options) - { - // Example: - // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)]) -@@ -671,7 +690,10 @@ const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const i - std::ostringstream command; - command.imbue(std::locale::classic()); - -- command << "FETCH " << listToSet(list, -1, false) << " ("; -+ if (mode == "uid") -+ command << "UID FETCH " << set << " ("; -+ else -+ command << "FETCH " << set << " ("; - - for (std::vector <string>::const_iterator it = items.begin() ; - it != items.end() ; ++it) -@@ -687,6 +709,20 @@ const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const i - - - // static -+const string IMAPUtils::buildFetchRequest(const std::vector <int>& list, const int options) -+{ -+ return buildFetchRequestImpl("number", listToSet(list, -1, false), options); -+} -+ -+ -+// static -+const string IMAPUtils::buildFetchRequest(const std::vector <message::uid>& list, const int options) -+{ -+ return buildFetchRequestImpl("uid", listToSet(list), options); -+} -+ -+ -+// static - void IMAPUtils::convertAddressList - (const IMAPParser::address_list& src, mailboxList& dest) - { -@@ -706,6 +742,46 @@ void IMAPUtils::convertAddressList - } - - -+// static -+unsigned int IMAPUtils::extractUIDFromGlobalUID(const message::uid& uid) -+{ -+ message::uid::size_type colonPos = uid.find(':'); -+ -+ if (colonPos == message::uid::npos) -+ { -+ std::istringstream iss(uid); -+ iss.imbue(std::locale::classic()); -+ -+ unsigned int n = 0; -+ iss >> n; -+ -+ return n; -+ } -+ else -+ { -+ std::istringstream iss(uid.substr(colonPos + 1)); -+ iss.imbue(std::locale::classic()); -+ -+ unsigned int n = 0; -+ iss >> n; -+ -+ return n; -+ } -+} -+ -+ -+// static -+const message::uid IMAPUtils::makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID) -+{ -+ std::ostringstream oss; -+ oss.imbue(std::locale::classic()); -+ -+ oss << UIDValidity << ":" << messageUID; -+ -+ return message::uid(oss.str()); -+} -+ -+ - } // imap - } // net - } // vmime -diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp -index 8c4b275..b606cda 100644 ---- a/src/net/maildir/maildirFolder.cpp -+++ b/src/net/maildir/maildirFolder.cpp -@@ -444,6 +444,18 @@ std::vector <ref <message> > maildirFolder::getMessages(const std::vector <int>& - } - - -+ref <message> maildirFolder::getMessageByUID(const message::uid& /* uid */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ -+std::vector <ref <message> > maildirFolder::getMessagesByUID(const std::vector <message::uid>& /* uids */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ - int maildirFolder::getMessageCount() - { - return (m_messageCount); -diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp -index e085609..21e7a8b 100644 ---- a/src/net/pop3/POP3Folder.cpp -+++ b/src/net/pop3/POP3Folder.cpp -@@ -249,6 +249,18 @@ std::vector <ref <message> > POP3Folder::getMessages(const int from, const int t - } - - -+ref <message> POP3Folder::getMessageByUID(const message::uid& /* uid */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ -+std::vector <ref <message> > POP3Folder::getMessagesByUID(const std::vector <message::uid>& /* uids */) -+{ -+ throw exceptions::operation_not_supported(); -+} -+ -+ - std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nums) - { - ref <POP3Store> store = m_store.acquire(); -diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp -index df9cbaf..a50ee0e 100644 ---- a/vmime/net/folder.hpp -+++ b/vmime/net/folder.hpp -@@ -169,7 +169,7 @@ public: - */ - virtual bool isOpen() const = 0; - -- /** Get a new reference to a message in this folder. -+ /** Get a new reference to a message in this folder, given its number. - * - * @param num message sequence number - * @return a new object referencing the specified message -@@ -177,7 +177,7 @@ public: - */ - virtual ref <message> getMessage(const int num) = 0; - -- /** Get new references to messages in this folder. -+ /** Get new references to messages in this folder, given their numbers. - * - * @param from sequence number of the first message to get - * @param to sequence number of the last message to get -@@ -186,14 +186,30 @@ public: - */ - virtual std::vector <ref <message> > getMessages(const int from = 1, const int to = -1) = 0; - -- /** Get new references to messages in this folder. -+ /** Get new references to messages in this folder, given their numbers. - * -- * @param nums sequence numbers of the messages to delete -+ * @param nums sequence numbers of the messages to retrieve - * @return new objects referencing the specified messages - * @throw net_exception if an error occurs - */ - virtual std::vector <ref <message> > getMessages(const std::vector <int>& nums) = 0; - -+ /** Get message in this folder, given its UID. -+ * -+ * @param uid UID of message to retrieve -+ * @return a new object referencing the specified message -+ * @throw net_exception if an error occurs -+ */ -+ virtual ref <message> getMessageByUID(const message::uid& uid) = 0; -+ -+ /** Get messages in this folder, given their UIDs. -+ * -+ * @param uids UIDs of messages to retrieve -+ * @return new objects referencing the specified messages -+ * @throw net_exception if an error occurs -+ */ -+ virtual std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids) = 0; -+ - /** Return the number of messages in this folder. - * - * @return number of messages in the folder -diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp -index cc52596..3337858 100644 ---- a/vmime/net/imap/IMAPFolder.hpp -+++ b/vmime/net/imap/IMAPFolder.hpp -@@ -84,6 +84,12 @@ public: - ref <message> getMessage(const int num); - std::vector <ref <message> > getMessages(const int from = 1, const int to = -1); - std::vector <ref <message> > getMessages(const std::vector <int>& nums); -+ -+ ref <message> getMessageByUID(const message::uid& uid); -+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids); -+ -+ std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid); -+ - int getMessageCount(); - - ref <folder> getFolder(const folder::path::component& name); -@@ -120,8 +126,6 @@ public: - - int getFetchCapabilities() const; - -- std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid); -- - private: - - void registerMessage(IMAPMessage* msg); -@@ -152,7 +156,7 @@ private: - - int m_messageCount; - -- int m_uidValidity; -+ unsigned int m_uidValidity; - - std::vector <IMAPMessage*> m_messages; - }; -diff --git a/vmime/net/imap/IMAPMessage.hpp b/vmime/net/imap/IMAPMessage.hpp -index edbf69f..fbba6e7 100644 ---- a/vmime/net/imap/IMAPMessage.hpp -+++ b/vmime/net/imap/IMAPMessage.hpp -@@ -50,6 +50,7 @@ private: - friend class vmime::creator; // vmime::create <IMAPMessage> - - IMAPMessage(ref <IMAPFolder> folder, const int num); -+ IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId); - IMAPMessage(const IMAPMessage&) : message() { } - - ~IMAPMessage(); -@@ -83,7 +84,7 @@ private: - - void fetch(ref <IMAPFolder> folder, const int options); - -- void processFetchResponse(const int options, const IMAPParser::msg_att* msgAtt); -+ void processFetchResponse(const int options, const IMAPParser::message_data* msgData); - - /** Recursively fetch part header for all parts in the structure. - * -diff --git a/vmime/net/imap/IMAPUtils.hpp b/vmime/net/imap/IMAPUtils.hpp -index d1ed5c8..9c9c420 100644 ---- a/vmime/net/imap/IMAPUtils.hpp -+++ b/vmime/net/imap/IMAPUtils.hpp -@@ -29,6 +29,7 @@ - #include "vmime/dateTime.hpp" - - #include "vmime/net/folder.hpp" -+#include "vmime/net/message.hpp" - #include "vmime/net/imap/IMAPParser.hpp" - - #include "vmime/mailboxList.hpp" -@@ -65,8 +66,8 @@ public: - - static const string messageFlagList(const int flags); - -- /** Build an "IMAP set" given a list. The function tries to group -- * consecutive message numbers to reduce the list. -+ /** Build an "IMAP set" given a list of message numbers. The function tries -+ * to group consecutive message numbers to reduce the list. - * - * Example: - * IN = "1,2,3,4,5,7,8,13,15,16,17" -@@ -81,6 +82,13 @@ public: - static const string listToSet(const std::vector <int>& list, - const int max = -1, const bool alreadySorted = false); - -+ /** Build an "IMAP set" set given a list of message UIDs. -+ * -+ * @param list list of message UIDs -+ * @return a set corresponding to the list -+ */ -+ static const string listToSet(const std::vector <message::uid>& list); -+ - /** Format a date/time to IMAP date/time format. - * - * @param date date/time to format -@@ -88,7 +96,7 @@ public: - */ - static const string dateTime(const vmime::datetime& date); - -- /** Construct a fetch request for the specified messages. -+ /** Construct a fetch request for the specified messages, designated by their sequence numbers. - * - * @param list list of message numbers - * @param options fetch options -@@ -96,12 +104,40 @@ public: - */ - static const string buildFetchRequest(const std::vector <int>& list, const int options); - -+ /** Construct a fetch request for the specified messages, designated by their UIDs. -+ * -+ * @param list list of message UIDs -+ * @param options fetch options -+ * @return fetch request -+ */ -+ static const string buildFetchRequest(const std::vector <message::uid>& list, const int options); -+ - /** Convert a parser-style address list to a mailbox list. - * - * @param src input address list - * @param dest output mailbox list - */ - static void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest); -+ -+ /** Extract the message UID from a globally unique UID. -+ * -+ * @param uid globally unique UID (as returned by makeGlobalUID(), for example) -+ * @return message UID -+ */ -+ static unsigned int extractUIDFromGlobalUID(const message::uid& uid); -+ -+ /** Construct a globally unique UID from UID Validity and a message UID. -+ * -+ * @param UIDValidity UID Validity of the folder -+ * @param messageUID UID of the message -+ * @return global UID -+ */ -+ static const message::uid makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID); -+ -+private: -+ -+ static const string buildFetchRequestImpl -+ (const std::string& mode, const std::string& set, const int options); - }; - - -diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp -index 68b5b89..c9ba899 100644 ---- a/vmime/net/maildir/maildirFolder.hpp -+++ b/vmime/net/maildir/maildirFolder.hpp -@@ -85,6 +85,10 @@ public: - ref <message> getMessage(const int num); - std::vector <ref <message> > getMessages(const int from = 1, const int to = -1); - std::vector <ref <message> > getMessages(const std::vector <int>& nums); -+ -+ ref <message> getMessageByUID(const message::uid& uid); -+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids); -+ - int getMessageCount(); - - ref <folder> getFolder(const folder::path::component& name); -diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp -index c482908..090f948 100644 ---- a/vmime/net/pop3/POP3Folder.hpp -+++ b/vmime/net/pop3/POP3Folder.hpp -@@ -83,6 +83,10 @@ public: - ref <message> getMessage(const int num); - std::vector <ref <message> > getMessages(const int from = 1, const int to = -1); - std::vector <ref <message> > getMessages(const std::vector <int>& nums); -+ -+ ref <message> getMessageByUID(const message::uid& uid); -+ std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids); -+ - int getMessageCount(); - - ref <folder> getFolder(const folder::path::component& name); --- -1.7.10.4 - - -From 7501f61214b06a35c8fce7772fd48dded2cad335 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 30 Jul 2012 11:23:23 +0200 -Subject: [PATCH 41/47] Fixed compilation warning. - - -diff --git a/vmime/utility/parserInputStreamAdapter.hpp b/vmime/utility/parserInputStreamAdapter.hpp -index c24fa44..861e75b 100644 ---- a/vmime/utility/parserInputStreamAdapter.hpp -+++ b/vmime/utility/parserInputStreamAdapter.hpp -@@ -82,7 +82,7 @@ public: - - m_stream->seek(initialPos); - -- return (readBytes == 1 ? buffer[0] : 0); -+ return (readBytes == 1 ? buffer[0] : static_cast <value_type>(0)); - } - catch (...) - { -@@ -101,7 +101,7 @@ public: - value_type buffer[1]; - const size_type readBytes = m_stream->read(buffer, 1); - -- return (readBytes == 1 ? buffer[0] : 0); -+ return (readBytes == 1 ? buffer[0] : static_cast <value_type>(0)); - } - - /** Check whether the bytes following the current position match --- -1.7.10.4 - - -From f9f9b3bf52c76e1803855d1c44147f68ec9f62f2 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 30 Jul 2012 20:45:17 +0200 -Subject: [PATCH 42/47] Fixed body part extraction (only body should be - extracted). - - -diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp -index 7202a7d..808f7d1 100644 ---- a/src/net/imap/IMAPMessage.cpp -+++ b/src/net/imap/IMAPMessage.cpp -@@ -192,7 +192,7 @@ void IMAPMessage::extract(utility::outputStream& os, utility::progressListener* - if (!folder) - throw exceptions::folder_not_found(); - -- extract(NULL, os, progress, start, length, false, peek); -+ extractImpl(NULL, os, progress, start, length, EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)); - } - - -@@ -205,7 +205,7 @@ void IMAPMessage::extractPart - if (!folder) - throw exceptions::folder_not_found(); - -- extract(p, os, progress, start, length, false, peek); -+ extractImpl(p, os, progress, start, length, EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)); - } - - -@@ -219,7 +219,7 @@ void IMAPMessage::fetchPartHeader(ref <part> p) - std::ostringstream oss; - utility::outputStreamAdapter ossAdapter(oss); - -- extract(p, ossAdapter, NULL, 0, -1, true, true); -+ extractImpl(p, ossAdapter, NULL, 0, -1, EXTRACT_HEADER | EXTRACT_PEEK); - - p.dynamicCast <IMAPPart>()->getOrCreateHeader().parse(oss.str()); - } -@@ -240,9 +240,9 @@ void IMAPMessage::fetchPartHeaderForStructure(ref <structure> str) - } - - --void IMAPMessage::extract(ref <const part> p, utility::outputStream& os, -+void IMAPMessage::extractImpl(ref <const part> p, utility::outputStream& os, - utility::progressListener* progress, const int start, -- const int length, const bool headerOnly, const bool peek) const -+ const int length, const int extractFlags) const - { - ref <const IMAPFolder> folder = m_folder.acquire(); - -@@ -284,18 +284,45 @@ void IMAPMessage::extract(ref <const part> p, utility::outputStream& os, - else - command << "UID FETCH " << IMAPUtils::extractUIDFromGlobalUID(m_uid) << " BODY"; - -- if (peek) command << ".PEEK"; -+ /* -+ BODY[] header + body -+ BODY.PEEK[] header + body (peek) -+ BODY[HEADER] header -+ BODY.PEEK[HEADER] header (peek) -+ BODY[TEXT] body -+ BODY.PEEK[TEXT] body (peek) -+ */ -+ -+ if (extractFlags & EXTRACT_PEEK) -+ command << ".PEEK"; -+ - command << "["; - - if (section.str().empty()) - { -- if (headerOnly) -+ // header + body -+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) -+ command << ""; -+ // body only -+ else if (extractFlags & EXTRACT_BODY) -+ command << "TEXT"; -+ // header only -+ else if (extractFlags & EXTRACT_HEADER) - command << "HEADER"; - } - else - { - command << section.str(); -- if (headerOnly) command << ".MIME"; // "MIME" not "HEADER" for parts -+ -+ // header + body -+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) -+ *((int *) 0)=42;//throw exceptions::operation_not_supported(); -+ // body only -+ else if (extractFlags & EXTRACT_BODY) -+ command << ".TEXT"; -+ // header only -+ else if (extractFlags & EXTRACT_HEADER) -+ command << ".MIME"; // "MIME" not "HEADER" for parts - } - - command << "]"; -@@ -318,7 +345,7 @@ void IMAPMessage::extract(ref <const part> p, utility::outputStream& os, - } - - -- if (!headerOnly) -+ if (extractFlags & EXTRACT_BODY) - { - // TODO: update the flags (eg. flag "\Seen" may have been set) - } -diff --git a/src/net/imap/IMAPMessagePartContentHandler.cpp b/src/net/imap/IMAPMessagePartContentHandler.cpp -index 85c6ec2..c2cd647 100644 ---- a/src/net/imap/IMAPMessagePartContentHandler.cpp -+++ b/src/net/imap/IMAPMessagePartContentHandler.cpp -@@ -121,7 +121,7 @@ void IMAPMessagePartContentHandler::extract - // No decoding to perform - if (!isEncoded()) - { -- msg->extractPart(part, os, progress); -+ msg->extractImpl(part, os, progress, 0, -1, IMAPMessage::EXTRACT_BODY); - } - // Need to decode data - else -@@ -130,7 +130,7 @@ void IMAPMessagePartContentHandler::extract - std::ostringstream oss; - utility::outputStreamAdapter tmp(oss); - -- msg->extractPart(part, tmp, NULL); -+ msg->extractImpl(part, tmp, NULL, 0, -1, IMAPMessage::EXTRACT_BODY); - - // Encode temporary buffer to output stream - utility::inputStreamStringAdapter is(oss.str()); -diff --git a/vmime/net/imap/IMAPMessage.hpp b/vmime/net/imap/IMAPMessage.hpp -index fbba6e7..06f8091 100644 ---- a/vmime/net/imap/IMAPMessage.hpp -+++ b/vmime/net/imap/IMAPMessage.hpp -@@ -47,6 +47,7 @@ class IMAPMessage : public message - private: - - friend class IMAPFolder; -+ friend class IMAPMessagePartContentHandler; - friend class vmime::creator; // vmime::create <IMAPMessage> - - IMAPMessage(ref <IMAPFolder> folder, const int num); -@@ -101,7 +102,16 @@ private: - */ - void constructParsedMessage(ref <bodyPart> parentPart, ref <structure> str, int level = 0); - -- void extract(ref <const part> p, utility::outputStream& os, utility::progressListener* progress, const int start, const int length, const bool headerOnly, const bool peek) const; -+ -+ enum ExtractFlags -+ { -+ EXTRACT_HEADER = 0x1, -+ EXTRACT_BODY = 0x2, -+ EXTRACT_PEEK = 0x10 -+ }; -+ -+ void extractImpl(ref <const part> p, utility::outputStream& os, utility::progressListener* progress, -+ const int start, const int length, const int extractFlags) const; - - - ref <header> getOrCreateHeader(); --- -1.7.10.4 - - -From 1c58fc9735c9832c8e849d4f37f4f502b1fc895c Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 30 Jul 2012 21:28:59 +0200 -Subject: [PATCH 43/47] Added README about autotools scripts. (cherry picked - from commit 99908ce889eaa7ea6ba917255f11bf9969515793) - - -diff --git a/README.autotools b/README.autotools -new file mode 100644 -index 0000000..4b83a22 ---- /dev/null -+++ b/README.autotools -@@ -0,0 +1,8 @@ -+Where are the ./configure script and the Makefile's? -+ -+Configure and Make scripts are not included in the git source tree. They are -+automatically generated by the SConstruct script. -+ -+Just type "scons autotools" to generate everything needed for the traditional -+./configure, make, make install build process. -+ --- -1.7.10.4 - - -From 1e3ba8c5d520a4b6ab85478672e96f219b9f6135 Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 15 Oct 2012 11:19:53 +0200 -Subject: [PATCH 45/47] Do not fail if charset is not recognized. (cherry - picked from commit - e4102b4374e3acde31c9d320166ef37855834c72) - - -diff --git a/src/word.cpp b/src/word.cpp -index 2876ddf..1ea2293 100644 ---- a/src/word.cpp -+++ b/src/word.cpp -@@ -695,7 +695,16 @@ const string word::getConvertedText(const charset& dest) const - { - string out; - -- charset::convert(m_buffer, out, m_charset, dest); -+ try -+ { -+ charset::convert(m_buffer, out, m_charset, dest); -+ } -+ catch (vmime::exceptions::charset_conv_error& e) -+ { -+ // Do not fail if charset is not recognized: -+ // copy 'word' as raw text -+ out = m_buffer; -+ } - - return (out); - } --- -1.7.10.4 - - -From 927c052cafd65b14036834e9cb91a4b453aa2c5c Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 15 Oct 2012 11:23:22 +0200 -Subject: [PATCH 46/47] Support for bogus encoding name 'bmoted-printable' - (Zarafa). (cherry picked from commit - 2b09c6ea6cfad29682976ea7748721551dd3db64) - - -diff --git a/src/utility/encoder/encoderFactory.cpp b/src/utility/encoder/encoderFactory.cpp -index 2237178..1798ffa 100644 ---- a/src/utility/encoder/encoderFactory.cpp -+++ b/src/utility/encoder/encoderFactory.cpp -@@ -50,6 +50,9 @@ encoderFactory::encoderFactory() - // Also register some non-standard encoding names - registerName <sevenBitEncoder>("7-bit"); - registerName <eightBitEncoder>("8-bit"); -+ -+ // Finally, register some bogus encoding names, for compatibility -+ registerName <qpEncoder>("bmoted-printable"); - } - - --- -1.7.10.4 - - -From fe3114a41e2803b2a6993e8dd03e1ed685e4570c Mon Sep 17 00:00:00 2001 -From: Vincent Richard <vincent@vincent-richard.net> -Date: Mon, 15 Oct 2012 11:48:14 +0200 -Subject: [PATCH 47/47] Added support for timeout when receiving data from a - socket (POSIX platform). (cherry picked from commit - 794afe9a1b5ee36a5de8f90f3d789ca46f393bb7) - - -diff --git a/src/platforms/posix/posixSocket.cpp b/src/platforms/posix/posixSocket.cpp -index b8bb8b1..f280dad 100644 ---- a/src/platforms/posix/posixSocket.cpp -+++ b/src/platforms/posix/posixSocket.cpp -@@ -336,7 +336,45 @@ void posixSocket::receive(vmime::string& buffer) - - posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type count) - { -- const int ret = ::recv(m_desc, buffer, count, 0); -+ // Check whether data is available -+ fd_set fds; -+ FD_ZERO(&fds); -+ FD_SET(m_desc, &fds); -+ -+ struct timeval tv; -+ tv.tv_sec = 1; -+ tv.tv_usec = 0; -+ -+ int ret = ::select(m_desc + 1, &fds, NULL, NULL, &tv); -+ -+ if (ret < 0) -+ { -+ if (errno != EAGAIN) -+ throwSocketError(errno); -+ -+ // No data available at this time -+ // Check if we are timed out -+ if (m_timeoutHandler && -+ m_timeoutHandler->isTimeOut()) -+ { -+ if (!m_timeoutHandler->handleTimeOut()) -+ { -+ // Server did not react within timeout delay -+ throwSocketError(errno); -+ } -+ else -+ { -+ // Reset timeout -+ m_timeoutHandler->resetTimeOut(); -+ } -+ } -+ -+ // Continue waiting for data -+ return 0; -+ } -+ -+ // Read available data -+ ret = ::recv(m_desc, buffer, count, 0); - - if (ret < 0) - { -@@ -351,6 +389,12 @@ posixSocket::size_type posixSocket::receiveRaw(char* buffer, const size_type cou - // Host shutdown - throwSocketError(ENOTCONN); - } -+ else -+ { -+ // Data received, reset timeout -+ if (m_timeoutHandler) -+ m_timeoutHandler->resetTimeOut(); -+ } - - return ret; - } -@@ -383,6 +427,10 @@ void posixSocket::sendRaw(const char* buffer, const size_type count) - size -= ret; - } - } -+ -+ // Reset timeout -+ if (m_timeoutHandler) -+ m_timeoutHandler->resetTimeOut(); - } - - --- -1.7.10.4 - diff --git a/src/vmime.mk b/src/vmime.mk index 25e485a..eb01456 100644 --- a/src/vmime.mk +++ b/src/vmime.mk @@ -3,16 +3,16 @@ PKG := vmime $(PKG)_IGNORE := -$(PKG)_CHECKSUM := 3e8dd8855e423db438d465777efeb523c4abb5f3 -$(PKG)_SUBDIR := lib$(PKG)-$($(PKG)_VERSION) -$(PKG)_FILE := lib$(PKG)-$($(PKG)_VERSION).tar.bz2 -$(PKG)_URL := http://$(SOURCEFORGE_MIRROR)/project/$(PKG)/$(PKG)/$(call SHORT_PKG_VERSION,$(PKG))/$($(PKG)_FILE) +$(PKG)_CHECKSUM := 24a32dcc2eaf78d4a53541936ef72e4cf4f0a6ff +$(PKG)_SUBDIR := kisli-vmime-$($(PKG)_VERSION) +$(PKG)_FILE := $(PKG)-$($(PKG)_VERSION).tar.gz +$(PKG)_URL := https://github.com/kisli/vmime/tarball/$($(PKG)_VERSION)/$(PKG)_FILE $(PKG)_DEPS := gcc libiconv gnutls libgsasl pthreads zlib define $(PKG)_UPDATE - $(WGET) -q -O- 'http://sourceforge.net/projects/vmime/files/vmime/' | \ - $(SED) -n 's,.*libvmime-\([0-9][^>]*\)\.tar.*,\1,p' | \ - tail -1 + $(WGET) -q -O- 'https://github.com/kisli/vmime/commits/master' | \ + $(SED) -n 's#.*<span class="sha">\([^<]\{7\}\)[^<]\{3\}<.*#\1#p' | \ + head -1 endef define $(PKG)_BUILD |