# HG changeset patch # User Mark Brand # Date 1339320410 -7200 # Node ID ebe77bc7e002037d2788344a75c69f9fe44323fc # Parent 88eccc6528bad23fb48705b801491f41c55dfb7c package vmime: take upstream fixes diff -r 88eccc6528ba -r ebe77bc7e002 src/vmime-1-fixes.patch --- a/src/vmime-1-fixes.patch Sat Jun 09 22:18:13 2012 +0200 +++ b/src/vmime-1-fixes.patch Sun Jun 10 11:26:50 2012 +0200 @@ -1,49 +1,18 @@ This file is part of MXE. See index.html for further information. -Cherry picked fixes from svn -http://sourceforge.net/projects/vmime/develop - -Produced with this script: -#--------------------------------------------------------------------# -#!/usr/bin/env bash - -( - echo "This file is part of MXE." - echo "See index.html for further information." - echo - echo "Cherry picked fixes from svn" - echo "http://sourceforge.net/projects/vmime/develop" - echo - echo "Produced with this script:" - echo "#--------------------------------------------------------------------#" - cat "$0" - echo "#--------------------------------------------------------------------#" -) > src/vmime-1-fixes.patch - -# setup git svn clone -#cd ~/projects/vmime/git -#git svn clone -s https://vmime.svn.sourceforge.net/svnroot/vmime -#git reset --hard -# get updates -#git svn fetch -#git svn rebase - -GITDIR=~/projects/vmime/git/vmime - -( - cd $GITDIR - echo - git format-patch -p --relative=vmime --stdout ":/Version 0.9.1"..master-fixed -) >> src/vmime-1-fixes.patch -#--------------------------------------------------------------------# - -From ed4451fd3c86faf9ecc03a59ba9f1ad78417a9f9 Mon Sep 17 00:00:00 2001 -From: vincent-richard +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 Date: Tue, 16 Nov 2010 13:28:05 +0000 -Subject: [PATCH 01/27] Started version 0.9.2. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@576 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 01/38] Started version 0.9.2. + +--- + ChangeLog | 8 ++++++++ + SConstruct | 2 +- + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 871d055..8fdcdb0 100644 @@ -76,15 +45,17 @@ # API version number (libtool) # -- -1.7.7.3 - - -From bf282a05cdbbb538a1cafbd7305cece14f5b1571 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From c12ee2b267b9dcfd092a298dfd9a8eec81ab3a0b Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Tue, 30 Nov 2010 14:57:03 +0000 -Subject: [PATCH 02/27] Initialize and delete object. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@577 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 02/38] Initialize and delete object. + +--- + vmime/net/imap/IMAPParser.hpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp index 0f3e9ec..d71c3ca 100644 @@ -110,29 +81,19 @@ void go(IMAPParser& parser, string& line, string::size_type* currentPos) -- -1.7.7.3 - - -From 941b10bca8e89ca61eebee1345ee3e5cbebd7530 Mon Sep 17 00:00:00 2001 -From: vincent-richard -Date: Mon, 6 Dec 2010 11:57:44 +0000 -Subject: [PATCH 03/27] Updated deprecated function. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@578 5301114d-f842-0410-bbdd-996ee0417009 - -SKIPPED --- -1.7.7.3 - - -From 4a4c3a94db671ff7750b32ebf2c998a914717367 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From fd277afe87485c9d3377964794b76006c6d36a56 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Wed, 8 Dec 2010 08:52:54 +0000 -Subject: [PATCH 04/27] No extra space between ':' and '<' in MAIL FROM and +Subject: [PATCH 03/38] No extra space between ':' and '<' in MAIL FROM and RCPT TO. Wait for server response after QUIT and before closing connection. -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@579 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/net/smtp/SMTPTransport.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp index 204daae..d9fb7b8 100644 @@ -165,15 +126,17 @@ if ((resp = readResponse())->getCode() != 250) { -- -1.7.7.3 - - -From 4ea325c953f0cdc669b932aa4961a434656f3ecf Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From d64da50e879c0e480d2e65c43e3b903c3e80101f Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 10 Dec 2010 16:24:06 +0000 -Subject: [PATCH 05/27] Fixed unit test after bug fix. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@580 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 04/38] Fixed unit test after bug fix. + +--- + tests/net/smtp/SMTPTransportTest.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/smtp/SMTPTransportTest.cpp b/tests/net/smtp/SMTPTransportTest.cpp index 5015552..6552f9e 100644 @@ -189,16 +152,19 @@ localSend("250 OK\r\n"); } -- -1.7.7.3 - - -From ff207927a5aab002f38af0224133b345ab458144 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 130d0aabda2a9988913ad201390796775dc16a65 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 10 Dec 2010 16:54:38 +0000 -Subject: [PATCH 06/27] Fixed boundary parsing (thanks to John van der Kamp, +Subject: [PATCH 05/38] Fixed boundary parsing (thanks to John van der Kamp, Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@581 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/body.cpp | 43 +++++++++++++++++++++++++++++++++++++++-- + tests/parser/bodyPartTest.cpp | 2 +- + 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/body.cpp b/src/body.cpp index 13dff6b..738d3e7 100644 @@ -278,16 +244,19 @@ vmime::bodyPart p; -- -1.7.7.3 - - -From 3f5172e47f75f64952adef349bec875416ae9b89 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From c63f37c888798f0e7e99aa03afda16445a72b7b2 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 21 Jan 2011 15:28:06 +0000 -Subject: [PATCH 07/27] Fixed possible infinite loop (thanks to John van der +Subject: [PATCH 06/38] Fixed possible infinite loop (thanks to John van der Kamp, Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@582 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/word.cpp | 2 +- + tests/parser/textTest.cpp | 11 +++++++++++ + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/word.cpp b/src/word.cpp index db720dc..1c1c1a6 100644 @@ -331,16 +300,18 @@ VMIME_TEST_SUITE_END -- -1.7.7.3 - - -From 4e9eb3191066dec7f17592c2ce099b16e6329941 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 1fafad8f913e700b350e6915de8be710fc2d1ced Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 28 Jan 2011 12:11:08 +0000 -Subject: [PATCH 08/27] Fixed possible read to invalid memory location (thanks +Subject: [PATCH 07/38] Fixed possible read to invalid memory location (thanks to Alexander Konovalov). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@583 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/word.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/word.cpp b/src/word.cpp index 1c1c1a6..fa08d33 100644 @@ -356,17 +327,21 @@ else state->lastCharIsSpace = false; -- -1.7.7.3 - - -From 07ebf241115eba44675223e307d212c772e1cc08 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 73298423f695d7c4441d44619e4b7f9de75f566e Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Wed, 9 Mar 2011 18:03:31 +0000 -Subject: [PATCH 09/27] Fixed bug #3174903. Fixed word parsing when buffer +Subject: [PATCH 08/38] Fixed bug #3174903. Fixed word parsing when buffer does not end with NL. Fixed 'no encoding' when forced. -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@584 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/body.cpp | 14 +++++--- + src/word.cpp | 25 ++++++++------ + tests/parser/bodyPartTest.cpp | 76 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 101 insertions(+), 14 deletions(-) diff --git a/src/body.cpp b/src/body.cpp index 738d3e7..8596833 100644 @@ -563,16 +538,18 @@ VMIME_TEST_SUITE_END -- -1.7.7.3 - - -From 22ca7dc23b6bbbc8cc6aedd569ec938ecae96e92 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 5f5757b9d4bb0febb1e2183578eb91e801a08038 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 27 Mar 2011 11:26:55 +0000 -Subject: [PATCH 10/27] Allow static linking in MXE. Added 'iconv' +Subject: [PATCH 09/38] Allow static linking in mingw-cross-env. Added 'iconv' and uses 'ws2_32' instead of 'winsock32' (#3213487). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@585 5301114d-f842-0410-bbdd-996ee0417009 +--- + SConstruct | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SConstruct b/SConstruct index 55f9223..177f5b4 100644 @@ -597,16 +574,19 @@ # -- getaddrinfo (POSIX) -- -1.7.7.3 - - -From 9e06cc39d47e2eba8f554b337d472cc995be0d9d Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 2b48b4a68ce3e9b9b1a3f485123af5938a568324 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Thu, 31 Mar 2011 19:13:03 +0000 -Subject: [PATCH 11/27] Flush stateful data from iconv (thanks to John van der +Subject: [PATCH 10/38] Flush stateful data from iconv (thanks to John van der Kamp, Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@586 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/charsetConverter.cpp | 13 +++++++++---- + tests/parser/charsetTest.cpp | 10 ++++++++++ + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/charsetConverter.cpp b/src/charsetConverter.cpp index 38b9e5e..2135788 100644 @@ -679,15 +659,17 @@ // Conversion to hexadecimal for easier debugging static const vmime::string toHex(const vmime::string str) -- -1.7.7.3 - - -From 418a39a7d33921672bd1c4beb31c8a31bc87d8dd Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 8d2e039c5201e144ff08e2ff7cf9efe77fe4b3d0 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 10 Jun 2011 19:39:09 +0000 -Subject: [PATCH 12/27] Requested email change. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@587 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 11/38] Requested email change. + +--- + AUTHORS | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 20a0181..bbddb30 100644 @@ -703,15 +685,17 @@ - Georg Sauthoff - Pierre Thierry (patches for STL algorithms) -- -1.7.7.3 - - -From 4008955783ef566b98b16762c7bfa28df26e9198 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From cc6317f28ae0b61fea36e1bc78b09dc8300579f8 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Tue, 14 Jun 2011 18:37:54 +0000 -Subject: [PATCH 13/27] Fixed compilation issue following namespace change. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@588 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 12/38] Fixed compilation issue following namespace change. + +--- + examples/example7.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/example7.cpp b/examples/example7.cpp index 1ddb3d0..243b1da 100644 @@ -740,16 +724,18 @@ std::vector props = e->getAvailableProperties(); -- -1.7.7.3 - - -From e80db1ce802a45b71659d16d77ea47368beeabc1 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From a916d12d44ac43fc8e4729e0a91f4d6243f29a11 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 19 Jun 2011 17:51:33 +0000 -Subject: [PATCH 14/27] Fixed parsing of an attachment filename that is +Subject: [PATCH 13/38] Fixed parsing of an attachment filename that is between 66 and 76 characters long (Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@589 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/parameter.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parameter.cpp b/src/parameter.cpp index 91a7e5c..f59d5ab 100644 @@ -766,16 +752,18 @@ switch (value[i]) { -- -1.7.7.3 - - -From 58316dddddbfe8a7c582aa52e9abff8ca3a227b6 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 9735165c57000a6368e91ce8852206a20930c1ca Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 19 Jun 2011 18:08:12 +0000 -Subject: [PATCH 15/27] Correctly generate attachment names which are long and +Subject: [PATCH 14/38] Correctly generate attachment names which are long and have high characters for Outlook Express (Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@590 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/parameter.cpp | 70 ++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/parameter.cpp b/src/parameter.cpp index f59d5ab..d757e1b 100644 @@ -906,15 +894,17 @@ #endif // !VMIME_ALWAYS_GENERATE_7BIT_PARAMETER -- -1.7.7.3 - - -From f7ad17cffea462faf8cbe4f785644da0f3ee812a Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 8d69ad6849d8d6b211674942157f2af8bcd51c26 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 19 Jun 2011 18:16:49 +0000 -Subject: [PATCH 16/27] Alias for UTF-7 charset. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@591 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 15/38] Alias for UTF-7 charset. + +--- + src/charset.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) diff --git a/src/charset.cpp b/src/charset.cpp index e043186..0fda450 100644 @@ -942,17 +932,19 @@ if (newPosition) -- -1.7.7.3 - - -From eac20f47a33a7fdd617f9fd905b8029621259269 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From ccd95daf9cdd7171fc2027afa5d0ad80b0475ded Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 19 Jun 2011 18:39:35 +0000 -Subject: [PATCH 17/27] Fixed messageBuilder to accept an empty mailbox group +Subject: [PATCH 16/38] Fixed messageBuilder to accept an empty mailbox group in 'To:' field, to allow for undisclosed-recipients (Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@592 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/messageBuilder.cpp | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/messageBuilder.cpp b/src/messageBuilder.cpp index 870d59e..3597b3a 100644 @@ -980,17 +972,20 @@ if (!m_to.isEmpty()) msg->getHeader()->To()->setValue(m_to); -- -1.7.7.3 - - -From 1e5dfa80a63b0a7fe90406ce4a3de1593f2e4045 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 583e25bcdee132e53e0792cd8f0d8e535cabb743 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 19 Jun 2011 18:49:55 +0000 -Subject: [PATCH 18/27] Added support for mailboxes that specify an (encoded) +Subject: [PATCH 17/38] Added support for mailboxes that specify an (encoded) full name with an empty email address, set by a <> marker (Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@593 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/mailbox.cpp | 4 +++- + tests/parser/mailboxTest.cpp | 15 +++++++++++++++ + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/mailbox.cpp b/src/mailbox.cpp index 5cb0139..fea7479 100644 @@ -1054,15 +1049,17 @@ VMIME_TEST_SUITE_END -- -1.7.7.3 - - -From 960f2195516eb776eea7b7e4f92612192edfdcd9 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 461b92f84d5c16b297d33610fcd89fc7ca5a161a Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Fri, 24 Jun 2011 15:46:23 +0000 -Subject: [PATCH 19/27] Added missing libs in pkg-config file. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@594 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 18/38] Added missing libs in pkg-config file. + +--- + SConstruct | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 177f5b4..37c0ac6 100644 @@ -1078,16 +1075,19 @@ vmime_pc_in.write("Cflags: -I${includedir}/ @LIBGNUTLS_CFLAGS@\n") vmime_pc_in.close() -- -1.7.7.3 - - -From 9f9084b71b4e3c96edc6513020984ef76fe26e0c Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 2b2c0abd02a17ccff7d49e266b9854f4ea47f8e4 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sat, 25 Jun 2011 17:07:53 +0000 -Subject: [PATCH 20/27] Fixed parsing of empty body parts (thanks to John van +Subject: [PATCH 19/38] Fixed parsing of empty body parts (thanks to John van der Kamp, from Zarafa). -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@595 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/body.cpp | 5 +++++ + tests/parser/bodyPartTest.cpp | 19 +++++++++++++++++++ + 2 files changed, 24 insertions(+) diff --git a/src/body.cpp b/src/body.cpp index 8596833..9d7d57f 100644 @@ -1142,16 +1142,19 @@ VMIME_TEST_SUITE_END -- -1.7.7.3 - - -From 318848aa87761214a6f21c1ea1a9776a7bcbf83c Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 2648d744da0e2e744c7959999ac513c3016072b4 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 26 Jun 2011 08:19:11 +0000 -Subject: [PATCH 21/27] Use gnutls_priority_set_direct() instead of GNUTLS +Subject: [PATCH 20/38] Use gnutls_priority_set_direct() instead of GNUTLS deprecated functions. -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@596 5301114d-f842-0410-bbdd-996ee0417009 +--- + SConstruct | 33 +++++++++++++++++++++++++++++++++ + src/net/tls/TLSSession.cpp | 17 +++++++++++++++++ + 2 files changed, 50 insertions(+) diff --git a/SConstruct b/SConstruct index 37c0ac6..01ad3f3 100644 @@ -1252,15 +1255,18 @@ gnutls_credentials_set(*m_gnutlsSession, GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred); -- -1.7.7.3 - - -From 70a0282a3f96febf973475a298ac95ffaab82c3c Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 1060121ffd4315c3158ffc001040f4f705514e7a Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 26 Jun 2011 12:47:25 +0000 -Subject: [PATCH 22/27] Fixed encoding of whitespace. Fixed old test case. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@597 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 21/38] Fixed encoding of whitespace. Fixed old test case. + +--- + src/text.cpp | 6 ------ + tests/parser/textTest.cpp | 42 +++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/text.cpp b/src/text.cpp index 2454456..66c3b35 100644 @@ -1346,15 +1352,17 @@ VMIME_TEST_SUITE_END -- -1.7.7.3 - - -From 7d399583a458abe5cd16ce0974bd4dc11daba9f6 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From dc6dc039fc0edccf4630894fa6ed8cd4bf3bb3ce Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sat, 20 Aug 2011 06:35:06 +0000 -Subject: [PATCH 23/27] Use gnutls_strerror() for reporting errors. - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@598 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 22/38] Use gnutls_strerror() for reporting errors. + +--- + src/net/tls/TLSSession.cpp | 120 ++++---------------------------------------- + 1 file changed, 9 insertions(+), 111 deletions(-) diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index af73a05..7426a73 100644 @@ -1497,16 +1505,18 @@ -- -1.7.7.3 - - -From aae321dede5e725140534a08a8b2ee997faa30be Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From 7ea6fc3737ef36407e1c90f3aa05f89a39bdefb7 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 21 Aug 2011 08:55:46 +0000 -Subject: [PATCH 24/27] Removed dependency on gcrypt for gnutls version >= +Subject: [PATCH 23/38] Removed dependency on gcrypt for gnutls version >= 2.12. -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@599 5301114d-f842-0410-bbdd-996ee0417009 +--- + src/net/tls/TLSSession.cpp | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index 7426a73..d3f6d49 100644 @@ -1551,16 +1561,18 @@ gnutls_global_init(); -- -1.7.7.3 - - -From af1e5664afb663fb7d26d468adf675fb1b3f8737 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From f21c55be642b166a2f0518ace2b179bed3916b23 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Sun, 21 Aug 2011 09:04:46 +0000 -Subject: [PATCH 25/27] Fixed HAVE_GNUTLS_PRIORITY_FUNCS never defined when +Subject: [PATCH 24/38] Fixed HAVE_GNUTLS_PRIORITY_FUNCS never defined when configured with no TLS support. -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@600 5301114d-f842-0410-bbdd-996ee0417009 +--- + SConstruct | 6 ++++++ + 1 file changed, 6 insertions(+) diff --git a/SConstruct b/SConstruct index 01ad3f3..11e884b 100644 @@ -1584,15 +1596,17 @@ AC_SUBST(LIBGNUTLS_CFLAGS) -- -1.7.7.3 - - -From 41079b2f188bb4a6d8aea9ec1328653faee3e2c9 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From d4e66226a696745adafa1767210580f8fbb7ae00 Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Tue, 15 Nov 2011 11:40:42 +0000 -Subject: [PATCH 26/27] GNU TLS 3 has no 'extra' (thanks to mabrand). - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@601 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 25/38] GNU TLS 3 has no 'extra' (thanks to mabrand). + +--- + src/net/tls/TLSSession.cpp | 2 ++ + 1 file changed, 2 insertions(+) diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index d3f6d49..cb50acc 100644 @@ -1609,15 +1623,17 @@ #include "vmime/config.hpp" -- -1.7.7.3 - - -From eafae52d9b8ec9682c229090b6208092b1d1e6f1 Mon Sep 17 00:00:00 2001 -From: vincent-richard +1.7.10.3 + + +From bacbe512e406d22f6acc83597fcdfc2d624cf82b Mon Sep 17 00:00:00 2001 +From: Vincent Richard Date: Tue, 15 Nov 2011 11:46:07 +0000 -Subject: [PATCH 27/27] Set Diffie-Hellman prime size (bug SF#3434852). - -git-svn-id: https://vmime.svn.sourceforge.net/svnroot/vmime/trunk@602 5301114d-f842-0410-bbdd-996ee0417009 +Subject: [PATCH 26/38] Set Diffie-Hellman prime size (bug SF#3434852). + +--- + src/net/tls/TLSSession.cpp | 1 + + 1 file changed, 1 insertion(+) diff --git a/src/net/tls/TLSSession.cpp b/src/net/tls/TLSSession.cpp index cb50acc..0606808 100644 @@ -1632,5 +1648,8138 @@ if ((res = gnutls_priority_set_direct (*m_gnutlsSession, "NORMAL:%SSL3_RECORD_VERSION", NULL)) != 0) -- -1.7.7.3 - +1.7.10.3 + + +From 6574b60a303c5d864e840aa23959656bb2803485 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 22 Dec 2011 08:51:28 +0000 +Subject: [PATCH 27/38] Updated coding conventions. + +--- + HACKING | 53 +++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 45 insertions(+), 8 deletions(-) + +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.3 + + +From 130e5223dea0af2f8d9d01cca7845be4e1a08d13 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 11:46:39 +0200 +Subject: [PATCH 28/38] Added function to retrieve sequence numbers of + messages whose UID is greater or equal than a + specified UID (thanks to Zahi Mashael). + +--- + src/net/imap/IMAPFolder.cpp | 56 +++++++++++++++++++++++++++++++++++ + src/net/maildir/maildirFolder.cpp | 6 ++++ + src/net/pop3/POP3Folder.cpp | 6 ++++ + vmime/net/folder.hpp | 7 +++++ + vmime/net/imap/IMAPFolder.hpp | 2 ++ + vmime/net/maildir/maildirFolder.hpp | 2 ++ + vmime/net/pop3/POP3Folder.hpp | 2 ++ + 7 files changed, 81 insertions(+) + +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 IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) ++{ ++ std::vector 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 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 & respDataList = resp->continue_req_or_response_data(); ++ ++ for (std::vector ::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 ::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 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 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 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 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 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 getMessageNumbersStartingOnUID(const message::uid& uid); ++ + private: + + void registerMessage(POP3Message* msg); +-- +1.7.10.3 + + +From 3f1a565b8b532f0d11a13d3f6d763b00c8ce625b Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 11:55:07 +0200 +Subject: [PATCH 29/38] Added .gitignore. + +--- + .gitignore | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 .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.3 + + +From 5937bcda0fac9cb80d0cecbaa663ecdfe2839c09 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 12:08:01 +0200 +Subject: [PATCH 30/38] Added check before dereferencing. + +--- + vmime/utility/smartPtr.hpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +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.3 + + +From b0d74ce63ea9563ef4b218bce2497bd668dfad29 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 12:34:51 +0200 +Subject: [PATCH 31/38] Updated README. + +--- + README | 30 +++++++++++++++++++++++++++++- + 1 file changed, 29 insertions(+), 1 deletion(-) + +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.3 + + +From 350fada21a4f11c2f633a3cde1f2195efefe7e32 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 22:10:54 +0200 +Subject: [PATCH 32/38] Added test: Ensure '7bit' encoding is used when body + is 7-bit only. + +--- + tests/parser/bodyPartTest.cpp | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +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 p1 = vmime::create (); ++ p1->setText(vmime::create ("Part1 is US-ASCII only.")); ++ ++ vmime::ref msg = vmime::create (); ++ p1->generateIn(msg, msg); ++ ++ vmime::ref header1 = msg->getBody()->getPartAt(0)->getHeader(); ++ VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); ++ } ++ + VMIME_TEST_SUITE_END + +-- +1.7.10.3 + + +From 6c877ea41a2e408df61ac6f988c3bae7e0821141 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 22:29:32 +0200 +Subject: [PATCH 33/38] Added tests for Quoted-Printable encoding. + +--- + tests/utility/encoderTest.cpp | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +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.3 + + +From e88f062ab58654aee3cf45f94e8a5dd6c1256279 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Thu, 5 Apr 2012 23:15:04 +0200 +Subject: [PATCH 34/38] Fixed wrong encoding of line breaks in QP-encoded text + (issue #7). + +--- + src/encoding.cpp | 52 ++++++++++++++++++++++++++++++++----- + src/utility/encoder/qpEncoder.cpp | 9 ++++--- + tests/parser/bodyPartTest.cpp | 24 +++++++++++++++++ + vmime/encoding.hpp | 16 ++++++++++++ + 4 files changed, 91 insertions(+), 10 deletions(-) + +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 encoding::getEncoder() const + { +- return (utility::encoder::encoderFactory::getInstance()->create(generate())); ++ ref 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 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 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 > encoding::getChildComponents() const + { + return std::vector >(); +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 part = vmime::create (); ++ part->setText(vmime::create ("Part1-line1\r\nPart1-line2\r\n\x89")); ++ ++ vmime::ref msg = vmime::create (); ++ part->generateIn(msg, msg); ++ ++ vmime::ref body = msg->getBody()->getPartAt(0)->getBody(); ++ vmime::ref 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.3 + + +From ea77bdba96588345090e3de81d9d6af116edeeb5 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Fri, 6 Apr 2012 22:26:18 +0200 +Subject: [PATCH 35/38] Fixed memory leak. + +--- + src/net/tls/TLSSocket.cpp | 6 ++++++ + 1 file changed, 6 insertions(+) + +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 session, ref sok) + + TLSSocket::~TLSSocket() + { ++ if (m_ex) ++ { ++ delete m_ex; ++ m_ex = NULL; ++ } ++ + try + { + disconnect(); +-- +1.7.10.3 + + +From 440d491fd6da134fcb5f19416743e8f2044556bf Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Sat, 14 Apr 2012 13:46:05 +0200 +Subject: [PATCH 36/38] Split stream.hpp/.cpp into multiple source files. + +--- + SConstruct | 14 + + src/charsetConverter.cpp | 2 + + src/component.cpp | 1 + + src/encoding.cpp | 1 + + src/fileAttachment.cpp | 1 + + src/generatedMessageAttachment.cpp | 2 + + src/htmlTextPart.cpp | 2 + + src/mdn/MDNHelper.cpp | 2 + + src/mdn/receivedMDNInfos.cpp | 2 + + src/message.cpp | 2 + + src/net/imap/IMAPFolder.cpp | 2 + + src/net/imap/IMAPMessage.cpp | 2 + + src/net/imap/IMAPMessagePartContentHandler.cpp | 3 + + src/net/maildir/maildirFolder.cpp | 3 + + src/net/maildir/maildirMessage.cpp | 2 + + src/net/pop3/POP3Message.cpp | 2 + + src/net/pop3/POP3Store.cpp | 1 + + src/net/sendmail/sendmailTransport.cpp | 2 + + src/net/smtp/SMTPTransport.cpp | 2 + + src/net/transport.cpp | 3 + + src/parameter.cpp | 3 + + src/parsedMessageAttachment.cpp | 2 + + src/security/cert/X509Certificate.cpp | 2 + + src/security/sasl/SASLContext.cpp | 3 + + src/streamContentHandler.cpp | 4 + + src/stringContentHandler.cpp | 4 + + src/utility/encoder/defaultEncoder.cpp | 2 + + src/utility/inputStream.cpp | 33 ++ + src/utility/inputStreamAdapter.cpp | 70 ++++ + src/utility/inputStreamByteBufferAdapter.cpp | 90 +++++ + src/utility/inputStreamPointerAdapter.cpp | 46 +++ + src/utility/inputStreamSocketAdapter.cpp | 82 ++++ + src/utility/inputStreamStringAdapter.cpp | 94 +++++ + src/utility/inputStreamStringProxyAdapter.cpp | 89 +++++ + src/utility/outputStream.cpp | 33 ++ + src/utility/outputStreamAdapter.cpp | 54 +++ + src/utility/outputStreamByteArrayAdapter.cpp | 51 +++ + src/utility/outputStreamSocketAdapter.cpp | 68 ++++ + src/utility/outputStreamStringAdapter.cpp | 51 +++ + src/utility/stream.cpp | 485 ----------------------- + src/utility/streamUtils.cpp | 92 +++++ + src/utility/stringProxy.cpp | 2 + + src/word.cpp | 3 + + src/wordEncoder.cpp | 3 + + vmime/base.hpp | 20 +- + vmime/charset.hpp | 2 + + vmime/component.hpp | 2 + + vmime/net/imap/IMAPParser.hpp | 5 +- + vmime/utility/filteredStream.hpp | 3 +- + vmime/utility/inputStream.hpp | 76 ++++ + vmime/utility/inputStreamAdapter.hpp | 64 +++ + vmime/utility/inputStreamByteBufferAdapter.hpp | 63 +++ + vmime/utility/inputStreamPointerAdapter.hpp | 63 +++ + vmime/utility/inputStreamSocketAdapter.hpp | 77 ++++ + vmime/utility/inputStreamStringAdapter.hpp | 66 +++ + vmime/utility/inputStreamStringProxyAdapter.hpp | 68 ++++ + vmime/utility/outputStream.hpp | 107 +++++ + vmime/utility/outputStreamAdapter.hpp | 62 +++ + vmime/utility/outputStreamByteArrayAdapter.hpp | 58 +++ + vmime/utility/outputStreamSocketAdapter.hpp | 75 ++++ + vmime/utility/outputStreamStringAdapter.hpp | 59 +++ + vmime/utility/stream.hpp | 381 +----------------- + vmime/utility/streamUtils.hpp | 66 +++ + vmime/utility/stringProxy.hpp | 1 + + vmime/vmime.hpp | 16 + + 65 files changed, 1884 insertions(+), 867 deletions(-) + create mode 100644 src/utility/inputStream.cpp + create mode 100644 src/utility/inputStreamAdapter.cpp + create mode 100644 src/utility/inputStreamByteBufferAdapter.cpp + create mode 100644 src/utility/inputStreamPointerAdapter.cpp + create mode 100644 src/utility/inputStreamSocketAdapter.cpp + create mode 100644 src/utility/inputStreamStringAdapter.cpp + create mode 100644 src/utility/inputStreamStringProxyAdapter.cpp + create mode 100644 src/utility/outputStream.cpp + create mode 100644 src/utility/outputStreamAdapter.cpp + create mode 100644 src/utility/outputStreamByteArrayAdapter.cpp + create mode 100644 src/utility/outputStreamSocketAdapter.cpp + create mode 100644 src/utility/outputStreamStringAdapter.cpp + create mode 100644 src/utility/streamUtils.cpp + create mode 100644 vmime/utility/inputStream.hpp + create mode 100644 vmime/utility/inputStreamAdapter.hpp + create mode 100644 vmime/utility/inputStreamByteBufferAdapter.hpp + create mode 100644 vmime/utility/inputStreamPointerAdapter.hpp + create mode 100644 vmime/utility/inputStreamSocketAdapter.hpp + create mode 100644 vmime/utility/inputStreamStringAdapter.hpp + create mode 100644 vmime/utility/inputStreamStringProxyAdapter.hpp + create mode 100644 vmime/utility/outputStream.hpp + create mode 100644 vmime/utility/outputStreamAdapter.hpp + create mode 100644 vmime/utility/outputStreamByteArrayAdapter.hpp + create mode 100644 vmime/utility/outputStreamSocketAdapter.hpp + create mode 100644 vmime/utility/outputStreamStringAdapter.hpp + create mode 100644 vmime/utility/streamUtils.hpp + +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 + +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 +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 + + +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 + #include + +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 + #include + #include +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 + + +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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 // for std::copy +-#include // 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 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 ++// ++// 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 // for std::copy ++#include // 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 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 + #include + +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 (); + } + ++ /** 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 + +-#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 ++// ++// 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 ++// ++// 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 ++ ++ ++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 ++// ++// 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 ++// ++// 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 ++ ++ ++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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++// ++// 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 ++#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 ++outputStream& operator<<(outputStream& os, const char (&str)[N]) ++{ ++ os.write(str, N - 1); ++ return (os); ++} ++ ++#endif // defined(_MSC_VER) && (_MSC_VER <= 1200) ++ ++ ++template ++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 ++// ++// 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 ++ ++ ++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 ++// ++// 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 ++// ++// 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 ++// ++// 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 +-#include + #include + + #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 +-#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 +-outputStream& operator<<(outputStream& os, const char (&str)[N]) +-{ +- os.write(str, N - 1); +- return (os); +-} +- +-#endif // defined(_MSC_VER) && (_MSC_VER <= 1200) +- +- +-template +-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 ++// ++// 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.3 + + +From be30b47f09c5358db2ac8e42fa2bb4a14ec24c51 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Mon, 16 Apr 2012 22:32:33 +0200 +Subject: [PATCH 37/38] 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. + +--- + ChangeLog | 6 + + SConstruct | 3 + + src/addressList.cpp | 8 +- + src/body.cpp | 220 ++++++++++++++------ + src/bodyPart.cpp | 17 +- + src/charset.cpp | 8 +- + src/component.cpp | 137 ++++++++++-- + src/contentDisposition.cpp | 8 +- + src/dateTime.cpp | 8 +- + src/disposition.cpp | 8 +- + src/encoding.cpp | 8 +- + src/header.cpp | 8 +- + src/headerField.cpp | 8 +- + src/mailbox.cpp | 8 +- + src/mailboxGroup.cpp | 8 +- + src/mailboxList.cpp | 6 +- + src/mediaType.cpp | 8 +- + src/message.cpp | 9 +- + src/messageId.cpp | 8 +- + src/messageIdSequence.cpp | 8 +- + src/parameter.cpp | 40 ++-- + src/parameterizedHeaderField.cpp | 12 +- + src/path.cpp | 12 +- + src/platforms/posix/posixFile.cpp | 20 ++ + src/platforms/windows/windowsFile.cpp | 18 ++ + src/relay.cpp | 8 +- + src/streamContentHandler.cpp | 4 + + src/text.cpp | 8 +- + src/utility/inputStreamAdapter.cpp | 12 ++ + src/utility/inputStreamByteBufferAdapter.cpp | 13 ++ + src/utility/inputStreamStringAdapter.cpp | 13 ++ + src/utility/inputStreamStringProxyAdapter.cpp | 13 ++ + src/utility/parserInputStreamAdapter.cpp | 162 ++++++++++++++ + src/utility/seekableInputStreamRegionAdapter.cpp | 95 +++++++++ + src/utility/stream.cpp | 4 + + src/utility/streamUtils.cpp | 29 +++ + src/word.cpp | 8 +- + tests/parser/bodyPartTest.cpp | 89 ++++++++ + vmime/addressList.hpp | 20 +- + vmime/body.hpp | 20 +- + vmime/bodyPart.hpp | 20 +- + vmime/charset.hpp | 20 +- + vmime/component.hpp | 97 +++++++-- + vmime/contentDisposition.hpp | 20 +- + vmime/dateTime.hpp | 20 +- + vmime/disposition.hpp | 20 +- + vmime/encoding.hpp | 20 +- + vmime/header.hpp | 20 +- + vmime/headerField.hpp | 25 ++- + vmime/mailbox.hpp | 15 +- + vmime/mailboxGroup.hpp | 20 +- + vmime/mailboxList.hpp | 20 +- + vmime/mediaType.hpp | 20 +- + vmime/message.hpp | 23 +- + vmime/messageId.hpp | 28 ++- + vmime/messageIdSequence.hpp | 20 +- + vmime/parameter.hpp | 22 +- + vmime/parameterizedHeaderField.hpp | 22 +- + vmime/parserHelpers.hpp | 4 + + vmime/path.hpp | 19 +- + vmime/platforms/posix/posixFile.hpp | 6 +- + vmime/platforms/windows/windowsFile.hpp | 3 + + vmime/relay.hpp | 18 +- + vmime/text.hpp | 19 +- + vmime/utility/inputStreamAdapter.hpp | 6 +- + vmime/utility/inputStreamByteBufferAdapter.hpp | 6 +- + vmime/utility/inputStreamStringAdapter.hpp | 6 +- + vmime/utility/inputStreamStringProxyAdapter.hpp | 6 +- + vmime/utility/parserInputStreamAdapter.hpp | 173 +++++++++++++++ + vmime/utility/seekableInputStream.hpp | 64 ++++++ + vmime/utility/seekableInputStreamRegionAdapter.hpp | 71 +++++++ + vmime/utility/stream.hpp | 4 + + vmime/utility/streamUtils.hpp | 13 ++ + vmime/word.hpp | 49 ++++- + 74 files changed, 1643 insertions(+), 378 deletions(-) + create mode 100644 src/utility/parserInputStreamAdapter.cpp + create mode 100644 src/utility/seekableInputStreamRegionAdapter.cpp + create mode 100644 vmime/utility/parserInputStreamAdapter.hpp + create mode 100644 vmime/utility/seekableInputStream.hpp + create mode 100644 vmime/utility/seekableInputStreamRegionAdapter.hpp + +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 ++ ++ * 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 + + * 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 > addressList::getAddressList() + } + + +-const std::vector > addressList::getChildComponents() const ++const std::vector > addressList::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 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 (); + + // Last part was not found: recover from missing boundary +- if (!lastPart && pos == string::npos) ++ if (!lastPart && pos == utility::stream::npos) + { + ref part = vmime::create (); + + 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 (buffer, position, end, enc); ++ const utility::stream::size_type length = end - position; ++ ++ ref contentStream = ++ vmime::create ++ (parser->getUnderlyingStream(), position, length); ++ ++ m_contents = vmime::create (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 > body::getPartList() + } + + +-const std::vector > body::getChildComponents() const ++const std::vector > body::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 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 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 bodyPart::getParentPart() const + } + + +-const std::vector > bodyPart::getChildComponents() const ++const std::vector > bodyPart::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 > charset::getChildComponents() const ++const std::vector > charset::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 +@@ -43,9 +46,102 @@ component::~component() + } + + ++void component::parse ++ (ref inputStream, const utility::stream::size_type length) ++{ ++ parse(inputStream, 0, length, NULL); ++} ++ ++ ++void component::parse ++ (ref inputStream, const utility::stream::size_type position, ++ const utility::stream::size_type end, utility::stream::size_type* newPosition) ++{ ++ m_parsedOffset = m_parsedLength = 0; ++ ++ ref seekableStream = ++ inputStream.dynamicCast (); ++ ++ 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 parser = ++ vmime::create (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 > children = getChildComponents(); ++ ++ for (unsigned int i = 0, n = children.size() ; i < n ; ++i) ++ children[i]->offsetParsedBounds(offset); ++} ++ ++ ++void component::parseImpl ++ (ref 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 stream = ++ vmime::create (buffer); ++ ++ ref parser = ++ vmime::create (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 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 > component::getChildComponents() +-{ +- const std::vector > constList = +- const_cast (this)->getChildComponents(); +- +- std::vector > list; +- +- const std::vector >::size_type count = constList.size(); ++} // vmime + +- list.resize(count); +- +- for (std::vector >::size_type i = 0 ; i < count ; ++i) +- list[i] = constList[i].constCast (); +- +- 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 > contentDisposition::getChildComponents() const ++const std::vector > contentDisposition::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 datetime::clone() const + } + + +-const std::vector > datetime::getChildComponents() const ++const std::vector > datetime::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 > disposition::getChildComponents() const ++const std::vector > disposition::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +@@ -171,7 +171,7 @@ const std::vector 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 > encoding::getChildComponents() const ++const std::vector > encoding::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 > header::getFieldList() + } + + +-const std::vector > header::getChildComponents() const ++const std::vector > header::getChildComponents() + { +- std::vector > list; ++ std::vector > 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::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 > headerField::getChildComponents() const ++const std::vector > headerField::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 > mailbox::getChildComponents() const ++const std::vector > mailbox::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 > mailboxGroup::getMailboxList() + } + + +-const std::vector > mailboxGroup::getChildComponents() const ++const std::vector > mailboxGroup::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 > mailboxList::getChildComponents() const ++const std::vector > 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 > mediaType::getChildComponents() const ++const std::vector > mediaType::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 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 > messageId::getChildComponents() const ++const std::vector > messageId::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 > messageIdSequence::getChildComponents() const ++const std::vector > messageIdSequence::getChildComponents() + { +- std::vector > res; ++ std::vector > res; + + copy_vector(m_list, res); + +@@ -84,7 +84,7 @@ const std::vector > 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 ()) + { + } + + + parameter::parameter(const string& name, const word& value) +- : m_name(name), m_value(value) ++ : m_name(name), m_value(vmime::create (value)) + { + } + + + parameter::parameter(const string& name, const string& value) +- : m_name(name), m_value(value) ++ : m_name(name), m_value(vmime::create (value)) + { + } + +@@ -73,7 +73,7 @@ void parameter::copyFrom(const component& other) + const parameter& param = dynamic_cast (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 & 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 > parameter::getChildComponents() const ++const std::vector > parameter::getChildComponents() + { +- std::vector > list; ++ std::vector > list; + +- list.push_back(ref ::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 >::const_iterator +@@ -552,11 +552,11 @@ const std::vector > parameterizedHeaderField::getParameterList( + } + + +-const std::vector > parameterizedHeaderField::getChildComponents() const ++const std::vector > parameterizedHeaderField::getChildComponents() + { +- std::vector > list = headerField::getChildComponents(); ++ std::vector > list = headerField::getChildComponents(); + +- for (std::vector >::const_iterator it = m_params.begin() ; ++ for (std::vector >::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 > path::getChildComponents() const ++const std::vector > path::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +-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 (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 (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 & relay::getWithList() + } + + +-const std::vector > relay::getChildComponents() const ++const std::vector > relay::getChildComponents() + { + // TODO: should fields inherit from 'component'? (using typeAdapter) +- return std::vector >(); ++ return std::vector >(); + } + + +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 () != 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 > text::getChildComponents() const ++const std::vector > text::getChildComponents() + { +- std::vector > list; ++ std::vector > 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 ++// ++// 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 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 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 (&begin[1]), ++ static_cast (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 ++// ++// 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 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 (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 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 > 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 > word::getChildComponents() const ++const std::vector > word::getChildComponents() + { +- return std::vector >(); ++ return std::vector >(); + } + + +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 is = ++ vmime::create (oss.str()); ++ ++ vmime::ref msg = vmime::create (); ++ msg->parse(is, oss.str().length()); ++ ++ vmime::ref body1 = msg->getBody()->getPartAt(0)->getBody(); ++ vmime::ref body1Cts = body1->getContents(); ++ ++ vmime::ref body2 = msg->getBody()->getPartAt(1)->getBody(); ++ vmime::ref 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 () != 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 () != 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 > getChildComponents() const; ++ const std::vector > getChildComponents(); + + + /** Add a address at the end of the list. +@@ -163,14 +163,20 @@ private: + + std::vector > 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 > getChildComponents() const; ++ const std::vector > getChildComponents(); + + private: + +@@ -299,14 +299,20 @@ private: + + void initNewPart(ref 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 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 > getChildComponents() const; ++ const std::vector > getChildComponents(); + + private: + +@@ -98,14 +98,20 @@ private: + + weak_ref 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 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 > getChildComponents() const; ++ const std::vector > 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 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 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 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 > getChildComponents(); +- +- /** Return the list of children of this component (const version). +- * +- * @return list of child components +- */ +- virtual const std::vector > getChildComponents() const = 0; ++ virtual const std::vector > 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 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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > getChildComponents(); + + + /** Set the disposition action mode. +@@ -134,14 +134,20 @@ private: + + std::vector 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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); ++ static ref 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 > getChildComponents() const; ++ const std::vector > 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 clone() const; + mailboxGroup& operator=(const component& other); + +- const std::vector > getChildComponents() const; ++ const std::vector > getChildComponents(); + + /** Return the name of the group. + * +@@ -165,14 +165,20 @@ private: + text m_name; + std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 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 > getChildComponents() const; ++ const std::vector > 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 parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition); ++ static ref 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 > getChildComponents() const; ++ const std::vector > getChildComponents(); + + + /** Add a message-id at the end of the list. +@@ -148,14 +148,20 @@ private: + + std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 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 > getParameterList(); + ++ const std::vector > getChildComponents(); ++ + private: + + std::vector > 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 > 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 clone() const; + path& operator=(const path& other); + +- const std::vector > getChildComponents() const; ++ const std::vector > 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 + +@@ -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 > getChildComponents() const; ++ const std::vector > 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 > getChildComponents() const; ++ const std::vector > 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 + +@@ -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 ++// ++// 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 ++ ++ ++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 inputStream); ++ ++ ref 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 ++ 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 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 ++// ++// 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 ++// ++// 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 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 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 > getChildComponents() const; ++public: + +-private: ++ using component::generate; + +- static ref 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 > getChildComponents(); ++ ++private: + +- static const std::vector > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition); ++ static ref 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 > 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.3 + + +From 2e05e574fde890c7ec6dd9f3930d06b1b492ea80 Mon Sep 17 00:00:00 2001 +From: Vincent Richard +Date: Fri, 27 Apr 2012 08:34:26 +0200 +Subject: [PATCH 38/38] Fixed duplicate file reference (thanks to Enes Albay). + +--- + SConstruct | 1 - + 1 file changed, 1 deletion(-) + +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.3 + diff -r 88eccc6528ba -r ebe77bc7e002 src/vmime.mk --- a/src/vmime.mk Sat Jun 09 22:18:13 2012 +0200 +++ b/src/vmime.mk Sun Jun 10 11:26:50 2012 +0200 @@ -16,14 +16,10 @@ endef define $(PKG)_BUILD + $(SED) -i 's/pkg-config/$(TARGET)-pkg-config/g;' '$(1)/SConstruct' + # The configure script will make the real configuration, but # we need scons to generate configure.in, Makefile.am etc. - # ansi and pedantic are too strict for mingw. - # http://sourceforge.net/tracker/index.php?func=detail&aid=2373234&group_id=2435&atid=102435 - $(SED) -i "s/'-ansi', //;" '$(1)/SConstruct' - $(SED) -i "s/'-pedantic', //;" '$(1)/SConstruct' - $(SED) -i 's/pkg-config/$(TARGET)-pkg-config/g;' '$(1)/SConstruct' - cd '$(1)' && scons autotools \ prefix='$(PREFIX)/$(TARGET)' \ target='$(TARGET)' \ @@ -33,6 +29,7 @@ cd '$(1)' && ./configure \ --prefix='$(PREFIX)/$(TARGET)' \ --host='$(TARGET)' \ + --build="`config.guess`" \ --disable-shared \ --enable-platform-windows \ --disable-rpath \