changeset 2573:ebe77bc7e002

package vmime: take upstream fixes
author Mark Brand <mabrand@mabrand.nl>
date Sun, 10 Jun 2012 11:26:50 +0200
parents 88eccc6528ba
children e790818b1d97
files src/vmime-1-fixes.patch src/vmime.mk
diffstat 2 files changed, 8393 insertions(+), 247 deletions(-) [+]
line wrap: on
line diff
--- 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+Commits from master branch of git://github.com/kisli/vmime
+rebased onto version 0.9.1 tarball files.
+
+From 17ff5157ffdc749f60b8285f84e64ac5e06d4283 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Tue, 16 Nov 2010 13:28:05 +0000
-Subject: [PATCH 01/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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From c12ee2b267b9dcfd092a298dfd9a8eec81ab3a0b Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Tue, 30 Nov 2010 14:57:03 +0000
-Subject: [PATCH 02/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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
-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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From fd277afe87485c9d3377964794b76006c6d36a56 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Wed, 8 Dec 2010 08:52:54 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From d64da50e879c0e480d2e65c43e3b903c3e80101f Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 10 Dec 2010 16:24:06 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 130d0aabda2a9988913ad201390796775dc16a65 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 10 Dec 2010 16:54:38 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From c63f37c888798f0e7e99aa03afda16445a72b7b2 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 21 Jan 2011 15:28:06 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 1fafad8f913e700b350e6915de8be710fc2d1ced Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 28 Jan 2011 12:11:08 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 73298423f695d7c4441d44619e4b7f9de75f566e Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Wed, 9 Mar 2011 18:03:31 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 5f5757b9d4bb0febb1e2183578eb91e801a08038 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 27 Mar 2011 11:26:55 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 2b48b4a68ce3e9b9b1a3f485123af5938a568324 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Thu, 31 Mar 2011 19:13:03 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 8d2e039c5201e144ff08e2ff7cf9efe77fe4b3d0 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 10 Jun 2011 19:39:09 +0000
-Subject: [PATCH 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 <gsauthof@techfak.uni-bielefeld.de>
   - Pierre Thierry <nowhere.man@levallois.eu.org> (patches for STL algorithms)
 -- 
-1.7.7.3
-
-
-From 4008955783ef566b98b16762c7bfa28df26e9198 Mon Sep 17 00:00:00 2001
-From: vincent-richard <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From cc6317f28ae0b61fea36e1bc78b09dc8300579f8 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Tue, 14 Jun 2011 18:37:54 +0000
-Subject: [PATCH 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 <vmime::string> props = e->getAvailableProperties();
  
 -- 
-1.7.7.3
-
-
-From e80db1ce802a45b71659d16d77ea47368beeabc1 Mon Sep 17 00:00:00 2001
-From: vincent-richard <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From a916d12d44ac43fc8e4729e0a91f4d6243f29a11 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 19 Jun 2011 17:51:33 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 9735165c57000a6368e91ce8852206a20930c1ca Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 19 Jun 2011 18:08:12 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 8d69ad6849d8d6b211674942157f2af8bcd51c26 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 19 Jun 2011 18:16:49 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From ccd95daf9cdd7171fc2027afa5d0ad80b0475ded Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 19 Jun 2011 18:39:35 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 583e25bcdee132e53e0792cd8f0d8e535cabb743 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 19 Jun 2011 18:49:55 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 461b92f84d5c16b297d33610fcd89fc7ca5a161a Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Fri, 24 Jun 2011 15:46:23 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 2b2c0abd02a17ccff7d49e266b9854f4ea47f8e4 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sat, 25 Jun 2011 17:07:53 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 2648d744da0e2e744c7959999ac513c3016072b4 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 26 Jun 2011 08:19:11 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 1060121ffd4315c3158ffc001040f4f705514e7a Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 26 Jun 2011 12:47:25 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From dc6dc039fc0edccf4630894fa6ed8cd4bf3bb3ce Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sat, 20 Aug 2011 06:35:06 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From 7ea6fc3737ef36407e1c90f3aa05f89a39bdefb7 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 21 Aug 2011 08:55:46 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From f21c55be642b166a2f0518ace2b179bed3916b23 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Sun, 21 Aug 2011 09:04:46 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From d4e66226a696745adafa1767210580f8fbb7ae00 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Tue, 15 Nov 2011 11:40:42 +0000
-Subject: [PATCH 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 <vincent-richard@5301114d-f842-0410-bbdd-996ee0417009>
+1.7.10.3
+
+
+From bacbe512e406d22f6acc83597fcdfc2d624cf82b Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
 Date: Tue, 15 Nov 2011 11:46:07 +0000
-Subject: [PATCH 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 <vincent@vincent-richard.net>
+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 <vincent@vincent-richard.net>
+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 <int> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid)
++{
++	std::vector<int> v;
++
++	std::ostringstream command;
++	command.imbue(std::locale::classic());
++
++	command << "SEARCH UID " << uid;
++
++	// Send the request
++	m_connection->send(true, command.str(), true);
++
++	// Get the response
++	utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
++
++	if (resp->isBad() ||
++	    resp->response_done()->response_tagged()->resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
++	{
++		throw exceptions::command_error("SEARCH",
++			m_connection->getParser()->lastLine(), "bad response");
++	}
++
++	const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList = resp->continue_req_or_response_data();
++
++	for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
++	     it = respDataList.begin() ; it != respDataList.end() ; ++it)
++	{
++		if ((*it)->response_data() == NULL)
++		{
++			throw exceptions::command_error("SEARCH",
++				m_connection->getParser()->lastLine(), "invalid response");
++		}
++
++		const IMAPParser::mailbox_data* mailboxData =
++			(*it)->response_data()->mailbox_data();
++
++		// We are only interested in responses of type "SEARCH"
++		if (mailboxData == NULL ||
++		    mailboxData->type() != IMAPParser::mailbox_data::SEARCH)
++		{
++			continue;
++		}
++
++		for (std::vector <IMAPParser::nz_number*>::const_iterator
++				it = mailboxData->search_nz_number_list().begin() ;
++		     it != mailboxData->search_nz_number_list().end();
++		     ++it)
++		{
++			v.push_back((*it)->value());
++		}
++	}
++
++	return v;
++}
++
++
+ } // imap
+ } // net
+ } // vmime
+diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp
+index dd680c9..d11ae3b 100644
+--- a/src/net/maildir/maildirFolder.cpp
++++ b/src/net/maildir/maildirFolder.cpp
+@@ -1363,6 +1363,12 @@ const utility::file::path maildirFolder::getMessageFSPath(const int number) cons
+ }
+ 
+ 
++std::vector <int> maildirFolder::getMessageNumbersStartingOnUID(const message::uid& /* uid */)
++{
++	throw exceptions::operation_not_supported();
++}
++
++
+ } // maildir
+ } // net
+ } // vmime
+diff --git a/src/net/pop3/POP3Folder.cpp b/src/net/pop3/POP3Folder.cpp
+index d5fc687..e085609 100644
+--- a/src/net/pop3/POP3Folder.cpp
++++ b/src/net/pop3/POP3Folder.cpp
+@@ -843,6 +843,12 @@ void POP3Folder::expunge()
+ }
+ 
+ 
++std::vector <int> POP3Folder::getMessageNumbersStartingOnUID(const message::uid& /* uid */)
++{
++	throw exceptions::operation_not_supported();
++}
++
++
+ } // pop3
+ } // net
+ } // vmime
+diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp
+index b20e9c9..df9cbaf 100644
+--- a/vmime/net/folder.hpp
++++ b/vmime/net/folder.hpp
+@@ -383,6 +383,13 @@ public:
+ 	  */
+ 	virtual int getFetchCapabilities() const = 0;
+ 
++	/** Return the sequence numbers of messages whose UID equal or greater than uid
++ 	  *
++ 	  * @param uid the uid of the first message
++ 	  * @throw net_exception if an error occurs
++ 	  */
++	virtual std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid) = 0;
++
+ 	// Event listeners
+ 	void addMessageChangedListener(events::messageChangedListener* l);
+ 	void removeMessageChangedListener(events::messageChangedListener* l);
+diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp
+index dec3878..cc52596 100644
+--- a/vmime/net/imap/IMAPFolder.hpp
++++ b/vmime/net/imap/IMAPFolder.hpp
+@@ -120,6 +120,8 @@ public:
+ 
+ 	int getFetchCapabilities() const;
+ 
++	std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
++
+ private:
+ 
+ 	void registerMessage(IMAPMessage* msg);
+diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp
+index 7474b1a..68b5b89 100644
+--- a/vmime/net/maildir/maildirFolder.hpp
++++ b/vmime/net/maildir/maildirFolder.hpp
+@@ -121,6 +121,8 @@ public:
+ 
+ 	int getFetchCapabilities() const;
+ 
++	std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
++
+ private:
+ 
+ 	void scanFolder();
+diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp
+index abaa8eb..c482908 100644
+--- a/vmime/net/pop3/POP3Folder.hpp
++++ b/vmime/net/pop3/POP3Folder.hpp
+@@ -119,6 +119,8 @@ public:
+ 
+ 	int getFetchCapabilities() const;
+ 
++	std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid);
++
+ private:
+ 
+ 	void registerMessage(POP3Message* msg);
+-- 
+1.7.10.3
+
+
+From 3f1a565b8b532f0d11a13d3f6d763b00c8ce625b Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
+Date: Thu, 5 Apr 2012 11:55:07 +0200
+Subject: [PATCH 29/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 <vincent@vincent-richard.net>
+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 <vincent@vincent-richard.net>
+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 <vincent@vincent-richard.net>
+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 <vmime::plainTextPart> p1 = vmime::create <vmime::plainTextPart>();
++		p1->setText(vmime::create <vmime::stringContentHandler>("Part1 is US-ASCII only."));
++
++		vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
++		p1->generateIn(msg, msg);
++
++		vmime::ref <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader();
++		VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
++	}
++
+ VMIME_TEST_SUITE_END
+ 
+-- 
+1.7.10.3
+
+
+From 6c877ea41a2e408df61ac6f988c3bae7e0821141 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
+Date: Thu, 5 Apr 2012 22:29:32 +0200
+Subject: [PATCH 33/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 <vincent@vincent-richard.net>
+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 <utility::encoder::encoder> encoding::getEncoder() const
+ {
+-	return (utility::encoder::encoderFactory::getInstance()->create(generate()));
++	ref <utility::encoder::encoder> encoder =
++		utility::encoder::encoderFactory::getInstance()->create(generate());
++
++	// FIXME: this should not be here (move me into QP encoder instead?)
++	if (m_usage == USAGE_TEXT && m_name == encodingTypes::QUOTED_PRINTABLE)
++		encoder->getProperties()["text"] = true;
++
++	return encoder;
+ }
+ 
+ 
+@@ -94,6 +112,7 @@ encoding& encoding::operator=(const encoding& other)
+ encoding& encoding::operator=(const string& name)
+ {
+ 	m_name = utility::stringUtils::toLower(name);
++	m_usage = USAGE_UNKNOWN;
+ 	return (*this);
+ }
+ 
+@@ -167,6 +186,8 @@ const encoding encoding::decideImpl
+ const encoding encoding::decide
+ 	(ref <const contentHandler> data, const EncodingUsage usage)
+ {
++	encoding enc;
++
+ 	if (usage == USAGE_TEXT && data->isBuffered() &&
+ 	    data->getLength() > 0 && data->getLength() < 32768)
+ 	{
+@@ -177,12 +198,16 @@ const encoding encoding::decide
+ 		data->extract(os);
+ 		os.flush();
+ 
+-		return decideImpl(buffer.begin(), buffer.end());
++		enc = decideImpl(buffer.begin(), buffer.end());
+ 	}
+ 	else
+ 	{
+-		return encoding(encodingTypes::BASE64);
++		enc = encoding(encodingTypes::BASE64);
+ 	}
++
++	enc.setUsage(usage);
++
++	return enc;
+ }
+ 
+ 
+@@ -194,7 +219,10 @@ const encoding encoding::decide(ref <const contentHandler> data,
+ 		encoding recEncoding;
+ 
+ 		if (chset.getRecommendedEncoding(recEncoding))
++		{
++			recEncoding.setUsage(usage);
+ 			return recEncoding;
++		}
+ 	}
+ 
+ 	return decide(data, usage);
+@@ -227,6 +255,18 @@ void encoding::setName(const string& name)
+ }
+ 
+ 
++encoding::EncodingUsage encoding::getUsage() const
++{
++	return m_usage;
++}
++
++
++void encoding::setUsage(const EncodingUsage usage)
++{
++	m_usage = usage;
++}
++
++
+ const std::vector <ref <const component> > encoding::getChildComponents() const
+ {
+ 	return std::vector <ref <const component> >();
+diff --git a/src/utility/encoder/qpEncoder.cpp b/src/utility/encoder/qpEncoder.cpp
+index aa95022..ab8db2e 100644
+--- a/src/utility/encoder/qpEncoder.cpp
++++ b/src/utility/encoder/qpEncoder.cpp
+@@ -292,14 +292,15 @@ utility::stream::size_type qpEncoder::encode(utility::inputStream& in,
+ 			case 13:  // CR
+ 			case 10:  // LF
+ 			{
+-				// Text mode (where using CRLF or LF or ... does not
+-				// care for a new line...)
+-				if (text)
++				// RFC-2045/6.7(4)
++
++				// Text data
++				if (text && !rfc2047)
+ 				{
+ 					outBuffer[outBufferPos++] = c;
+ 					++curCol;
+ 				}
+-				// Binary mode (where CR and LF bytes are important!)
++				// Binary data
+ 				else
+ 				{
+ 					QP_ENCODE_HEX(c);
+diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp
+index e1d47a3..9d51262 100644
+--- a/tests/parser/bodyPartTest.cpp
++++ b/tests/parser/bodyPartTest.cpp
+@@ -38,6 +38,7 @@ VMIME_TEST_SUITE_BEGIN
+ 		VMIME_TEST(testPrologEncoding)
+ 		VMIME_TEST(testSuccessiveBoundaries)
+ 		VMIME_TEST(testGenerate7bit)
++		VMIME_TEST(testTextUsageForQPEncoding)
+ 	VMIME_TEST_LIST_END
+ 
+ 
+@@ -214,5 +215,28 @@ VMIME_TEST_SUITE_BEGIN
+ 		VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
+ 	}
+ 
++	void testTextUsageForQPEncoding()
++	{
++		vmime::ref <vmime::plainTextPart> part = vmime::create <vmime::plainTextPart>();
++		part->setText(vmime::create <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89"));
++
++		vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
++		part->generateIn(msg, msg);
++
++		vmime::ref <vmime::body> body = msg->getBody()->getPartAt(0)->getBody();
++		vmime::ref <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader();
++
++		std::ostringstream oss;
++		vmime::utility::outputStreamAdapter os(oss);
++		body->generate(os, 80);
++
++		VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate());
++
++		// This should *NOT* be:
++		//    Part1-line1=0D=0APart1-line2=0D=0A=89
++		VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
++	}
++
++
+ VMIME_TEST_SUITE_END
+ 
+diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp
+index ba78081..42f5246 100644
+--- a/vmime/encoding.hpp
++++ b/vmime/encoding.hpp
+@@ -47,6 +47,7 @@ public:
+ 
+ 	enum EncodingUsage
+ 	{
++		USAGE_UNKNOWN,
+ 		USAGE_TEXT,         /**< Use for body text. */
+ 		USAGE_BINARY_DATA   /**< Use for attachment, image... */
+ 	};
+@@ -54,6 +55,7 @@ public:
+ 
+ 	encoding();
+ 	explicit encoding(const string& name);
++	encoding(const string& name, const EncodingUsage usage);
+ 	encoding(const encoding& enc);
+ 
+ public:
+@@ -72,6 +74,19 @@ public:
+ 	  */
+ 	void setName(const string& name);
+ 
++	/** Return the type of contents this encoding is used for.
++	  * See the EncodingUsage enum.
++	  */
++	EncodingUsage getUsage() const;
++
++	/** Set the type of contents this encoding is used for.
++	  * See the EncodingUsage enum.
++	  *
++	  * @param usage type of contents
++	  */
++	void setUsage(const EncodingUsage usage);
++
++
+ 	encoding& operator=(const encoding& other);
+ 	encoding& operator=(const string& name);
+ 
+@@ -113,6 +128,7 @@ public:
+ private:
+ 
+ 	string m_name;
++	EncodingUsage m_usage;
+ 
+ 	/** Decide which encoding to use based on the specified data.
+ 	  *
+-- 
+1.7.10.3
+
+
+From ea77bdba96588345090e3de81d9d6af116edeeb5 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
+Date: Fri, 6 Apr 2012 22:26:18 +0200
+Subject: [PATCH 35/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 <TLSSession> session, ref <socket> 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 <vincent@vincent-richard.net>
+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 <sstream>
+ 
+diff --git a/src/encoding.cpp b/src/encoding.cpp
+index b4e79db..5d99ab6 100644
+--- a/src/encoding.cpp
++++ b/src/encoding.cpp
+@@ -24,6 +24,7 @@
+ #include "vmime/encoding.hpp"
+ #include "vmime/contentHandler.hpp"
+ 
++#include "vmime/utility/outputStreamStringAdapter.hpp"
+ #include "vmime/utility/encoder/encoderFactory.hpp"
+ 
+ #include <algorithm>
+diff --git a/src/fileAttachment.cpp b/src/fileAttachment.cpp
+index da7c4b7..cb23cd0 100644
+--- a/src/fileAttachment.cpp
++++ b/src/fileAttachment.cpp
+@@ -28,6 +28,7 @@
+ #include "vmime/exception.hpp"
+ 
+ #include "vmime/streamContentHandler.hpp"
++#include "vmime/utility/inputStreamPointerAdapter.hpp"
+ 
+ #include "vmime/contentDispositionField.hpp"
+ 
+diff --git a/src/generatedMessageAttachment.cpp b/src/generatedMessageAttachment.cpp
+index e9bd1a6..443a9d3 100644
+--- a/src/generatedMessageAttachment.cpp
++++ b/src/generatedMessageAttachment.cpp
+@@ -23,6 +23,8 @@
+ 
+ #include "vmime/generatedMessageAttachment.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/htmlTextPart.cpp b/src/htmlTextPart.cpp
+index c845b57..98524af 100644
+--- a/src/htmlTextPart.cpp
++++ b/src/htmlTextPart.cpp
+@@ -31,6 +31,8 @@
+ #include "vmime/emptyContentHandler.hpp"
+ #include "vmime/stringContentHandler.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/mdn/MDNHelper.cpp b/src/mdn/MDNHelper.cpp
+index b419b85..1dd7ff3 100644
+--- a/src/mdn/MDNHelper.cpp
++++ b/src/mdn/MDNHelper.cpp
+@@ -31,6 +31,8 @@
+ #include "vmime/path.hpp"
+ #include "vmime/dateTime.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace mdn {
+diff --git a/src/mdn/receivedMDNInfos.cpp b/src/mdn/receivedMDNInfos.cpp
+index cff211c..f97a58d 100644
+--- a/src/mdn/receivedMDNInfos.cpp
++++ b/src/mdn/receivedMDNInfos.cpp
+@@ -23,6 +23,8 @@
+ 
+ #include "vmime/mdn/receivedMDNInfos.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace mdn {
+diff --git a/src/message.cpp b/src/message.cpp
+index 6f4b046..1b4f086 100644
+--- a/src/message.cpp
++++ b/src/message.cpp
+@@ -24,6 +24,8 @@
+ #include "vmime/message.hpp"
+ #include "vmime/options.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ #include <sstream>
+ 
+ 
+diff --git a/src/net/imap/IMAPFolder.cpp b/src/net/imap/IMAPFolder.cpp
+index 50a2f2b..81bf386 100644
+--- a/src/net/imap/IMAPFolder.cpp
++++ b/src/net/imap/IMAPFolder.cpp
+@@ -34,6 +34,8 @@
+ #include "vmime/exception.hpp"
+ #include "vmime/utility/smartPtr.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ #include <algorithm>
+ #include <sstream>
+ 
+diff --git a/src/net/imap/IMAPMessage.cpp b/src/net/imap/IMAPMessage.cpp
+index bc661ed..702d5f2 100644
+--- a/src/net/imap/IMAPMessage.cpp
++++ b/src/net/imap/IMAPMessage.cpp
+@@ -31,6 +31,8 @@
+ #include "vmime/net/imap/IMAPPart.hpp"
+ #include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ #include <sstream>
+ #include <iterator>
+ #include <typeinfo>
+diff --git a/src/net/imap/IMAPMessagePartContentHandler.cpp b/src/net/imap/IMAPMessagePartContentHandler.cpp
+index 4e6ba97..85c6ec2 100644
+--- a/src/net/imap/IMAPMessagePartContentHandler.cpp
++++ b/src/net/imap/IMAPMessagePartContentHandler.cpp
+@@ -23,6 +23,9 @@
+ 
+ #include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/inputStreamStringProxyAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace net {
+diff --git a/src/net/maildir/maildirFolder.cpp b/src/net/maildir/maildirFolder.cpp
+index d11ae3b..8c4b275 100644
+--- a/src/net/maildir/maildirFolder.cpp
++++ b/src/net/maildir/maildirFolder.cpp
+@@ -35,6 +35,9 @@
+ #include "vmime/exception.hpp"
+ #include "vmime/platform.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace net {
+diff --git a/src/net/maildir/maildirMessage.cpp b/src/net/maildir/maildirMessage.cpp
+index 51cd1ba..4ab75e7 100644
+--- a/src/net/maildir/maildirMessage.cpp
++++ b/src/net/maildir/maildirMessage.cpp
+@@ -31,6 +31,8 @@
+ #include "vmime/exception.hpp"
+ #include "vmime/platform.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace net {
+diff --git a/src/net/pop3/POP3Message.cpp b/src/net/pop3/POP3Message.cpp
+index 50f4f87..69ef004 100644
+--- a/src/net/pop3/POP3Message.cpp
++++ b/src/net/pop3/POP3Message.cpp
+@@ -25,6 +25,8 @@
+ #include "vmime/net/pop3/POP3Folder.hpp"
+ #include "vmime/net/pop3/POP3Store.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ #include <sstream>
+ 
+ 
+diff --git a/src/net/pop3/POP3Store.cpp b/src/net/pop3/POP3Store.cpp
+index 9d554c6..793112a 100644
+--- a/src/net/pop3/POP3Store.cpp
++++ b/src/net/pop3/POP3Store.cpp
+@@ -30,6 +30,7 @@
+ #include "vmime/security/digest/messageDigestFactory.hpp"
+ #include "vmime/utility/filteredStream.hpp"
+ #include "vmime/utility/stringUtils.hpp"
++#include "vmime/utility/inputStreamSocketAdapter.hpp"
+ 
+ #include "vmime/net/defaultConnectionInfos.hpp"
+ 
+diff --git a/src/net/sendmail/sendmailTransport.cpp b/src/net/sendmail/sendmailTransport.cpp
+index 53ff0d1..e7762cc 100644
+--- a/src/net/sendmail/sendmailTransport.cpp
++++ b/src/net/sendmail/sendmailTransport.cpp
+@@ -32,6 +32,8 @@
+ #include "vmime/utility/childProcess.hpp"
+ #include "vmime/utility/smartPtr.hpp"
+ 
++#include "vmime/utility/streamUtils.hpp"
++
+ #include "vmime/net/defaultConnectionInfos.hpp"
+ 
+ #include "vmime/config.hpp"
+diff --git a/src/net/smtp/SMTPTransport.cpp b/src/net/smtp/SMTPTransport.cpp
+index d9fb7b8..bbbea75 100644
+--- a/src/net/smtp/SMTPTransport.cpp
++++ b/src/net/smtp/SMTPTransport.cpp
+@@ -30,6 +30,8 @@
+ 
+ #include "vmime/utility/filteredStream.hpp"
+ #include "vmime/utility/stringUtils.hpp"
++#include "vmime/utility/outputStreamSocketAdapter.hpp"
++#include "vmime/utility/streamUtils.hpp"
+ 
+ #include "vmime/net/defaultConnectionInfos.hpp"
+ 
+diff --git a/src/net/transport.cpp b/src/net/transport.cpp
+index dd4663d..f8ca7b7 100644
+--- a/src/net/transport.cpp
++++ b/src/net/transport.cpp
+@@ -27,6 +27,9 @@
+ #include "vmime/mailboxList.hpp"
+ #include "vmime/message.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace net {
+diff --git a/src/parameter.cpp b/src/parameter.cpp
+index d757e1b..ccbe1a5 100644
+--- a/src/parameter.cpp
++++ b/src/parameter.cpp
+@@ -27,6 +27,9 @@
+ #include "vmime/text.hpp"
+ #include "vmime/encoding.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/parsedMessageAttachment.cpp b/src/parsedMessageAttachment.cpp
+index bde56aa..cb7d71d 100644
+--- a/src/parsedMessageAttachment.cpp
++++ b/src/parsedMessageAttachment.cpp
+@@ -26,6 +26,8 @@
+ #include "vmime/stringContentHandler.hpp"
+ #include "vmime/contentDisposition.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/security/cert/X509Certificate.cpp b/src/security/cert/X509Certificate.cpp
+index 1cd079c..8df4e5e 100644
+--- a/src/security/cert/X509Certificate.cpp
++++ b/src/security/cert/X509Certificate.cpp
+@@ -28,6 +28,8 @@
+ 
+ #include "vmime/security/cert/X509Certificate.hpp"
+ 
++#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
++
+ 
+ namespace vmime {
+ namespace security {
+diff --git a/src/security/sasl/SASLContext.cpp b/src/security/sasl/SASLContext.cpp
+index 51c2bed..4bb33c1 100644
+--- a/src/security/sasl/SASLContext.cpp
++++ b/src/security/sasl/SASLContext.cpp
+@@ -33,6 +33,9 @@
+ #include "vmime/utility/encoder/encoderFactory.hpp"
+ 
+ #include "vmime/utility/stream.hpp"
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamByteBufferAdapter.hpp"
+ 
+ 
+ namespace vmime {
+diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp
+index 2ebd073..89a36b4 100644
+--- a/src/streamContentHandler.cpp
++++ b/src/streamContentHandler.cpp
+@@ -23,6 +23,10 @@
+ 
+ #include "vmime/streamContentHandler.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/streamUtils.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/stringContentHandler.cpp b/src/stringContentHandler.cpp
+index 4e85a6c..5a1e72c 100644
+--- a/src/stringContentHandler.cpp
++++ b/src/stringContentHandler.cpp
+@@ -23,6 +23,10 @@
+ 
+ #include "vmime/stringContentHandler.hpp"
+ 
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamStringProxyAdapter.hpp"
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/src/utility/encoder/defaultEncoder.cpp b/src/utility/encoder/defaultEncoder.cpp
+index 4d0ffb5..e2d226e 100644
+--- a/src/utility/encoder/defaultEncoder.cpp
++++ b/src/utility/encoder/defaultEncoder.cpp
+@@ -23,6 +23,8 @@
+ 
+ #include "vmime/utility/encoder/defaultEncoder.hpp"
+ 
++#include "vmime/utility/streamUtils.hpp"
++
+ 
+ namespace vmime {
+ namespace utility {
+diff --git a/src/utility/inputStream.cpp b/src/utility/inputStream.cpp
+new file mode 100644
+index 0000000..dd0adf4
+--- /dev/null
++++ b/src/utility/inputStream.cpp
+@@ -0,0 +1,33 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/inputStreamAdapter.cpp b/src/utility/inputStreamAdapter.cpp
+new file mode 100644
+index 0000000..b44b084
+--- /dev/null
++++ b/src/utility/inputStreamAdapter.cpp
+@@ -0,0 +1,70 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamAdapter::inputStreamAdapter(std::istream& is)
++	: m_stream(is)
++{
++}
++
++
++bool inputStreamAdapter::eof() const
++{
++	return (m_stream.eof());
++}
++
++
++void inputStreamAdapter::reset()
++{
++	m_stream.exceptions(std::ios_base::badbit);
++	m_stream.seekg(0, std::ios::beg);
++	m_stream.clear();
++}
++
++
++stream::size_type inputStreamAdapter::read
++	(value_type* const data, const size_type count)
++{
++	m_stream.exceptions(std::ios_base::badbit);
++	m_stream.read(data, count);
++	return (m_stream.gcount());
++}
++
++
++stream::size_type inputStreamAdapter::skip(const size_type count)
++{
++	m_stream.exceptions(std::ios_base::badbit);
++	m_stream.ignore(count);
++	return (m_stream.gcount());
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/inputStreamByteBufferAdapter.cpp b/src/utility/inputStreamByteBufferAdapter.cpp
+new file mode 100644
+index 0000000..92e779f
+--- /dev/null
++++ b/src/utility/inputStreamByteBufferAdapter.cpp
+@@ -0,0 +1,90 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamByteBufferAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte_t* buffer, const size_type length)
++	: m_buffer(buffer), m_length(length), m_pos(0)
++{
++}
++
++
++bool inputStreamByteBufferAdapter::eof() const
++{
++	return m_pos >= m_length;
++}
++
++
++void inputStreamByteBufferAdapter::reset()
++{
++	m_pos = 0;
++}
++
++
++stream::size_type inputStreamByteBufferAdapter::read
++	(value_type* const data, const size_type count)
++{
++	const size_type remaining = m_length - m_pos;
++
++	if (remaining < count)
++	{
++		std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data);
++		m_pos += remaining;
++
++		return remaining;
++	}
++	else
++	{
++		std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data);
++		m_pos += count;
++
++		return count;
++	}
++}
++
++
++stream::size_type inputStreamByteBufferAdapter::skip(const size_type count)
++{
++	const size_type remaining = m_length - m_pos;
++
++	if (remaining < count)
++	{
++		m_pos += remaining;
++		return remaining;
++	}
++	else
++	{
++		m_pos += count;
++		return count;
++	}
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/inputStreamPointerAdapter.cpp b/src/utility/inputStreamPointerAdapter.cpp
+new file mode 100644
+index 0000000..4d03e30
+--- /dev/null
++++ b/src/utility/inputStreamPointerAdapter.cpp
+@@ -0,0 +1,46 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamPointerAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own)
++	: inputStreamAdapter(*is), m_stream(is), m_own(own)
++{
++}
++
++
++inputStreamPointerAdapter::~inputStreamPointerAdapter()
++{
++	if (m_own)
++		delete (m_stream);
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/inputStreamSocketAdapter.cpp b/src/utility/inputStreamSocketAdapter.cpp
+new file mode 100644
+index 0000000..b93cc3c
+--- /dev/null
++++ b/src/utility/inputStreamSocketAdapter.cpp
+@@ -0,0 +1,82 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamSocketAdapter.hpp"
++
++
++#if VMIME_HAVE_MESSAGING_FEATURES
++
++
++#include "vmime/net/socket.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok)
++	: m_socket(sok)
++{
++}
++
++
++bool inputStreamSocketAdapter::eof() const
++{
++	// Can't know...
++	return false;
++}
++
++
++void inputStreamSocketAdapter::reset()
++{
++	// Not supported
++}
++
++
++stream::size_type inputStreamSocketAdapter::read
++	(value_type* const data, const size_type count)
++{
++	return m_socket.receiveRaw(data, count);
++}
++
++
++stream::size_type inputStreamSocketAdapter::skip
++	(const size_type /* count */)
++{
++	// Not supported
++	return 0;
++}
++
++
++stream::size_type inputStreamSocketAdapter::getBlockSize()
++{
++	return m_socket.getBlockSize();
++}
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_HAVE_MESSAGING_FEATURES
++
+diff --git a/src/utility/inputStreamStringAdapter.cpp b/src/utility/inputStreamStringAdapter.cpp
+new file mode 100644
+index 0000000..31c9fda
+--- /dev/null
++++ b/src/utility/inputStreamStringAdapter.cpp
+@@ -0,0 +1,94 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer)
++	: m_buffer(buffer), m_begin(0), m_end(buffer.length()), m_pos(0)
++{
++}
++
++
++inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer,
++	const string::size_type begin, const string::size_type end)
++	: m_buffer(buffer), m_begin(begin), m_end(end), m_pos(begin)
++{
++}
++
++
++bool inputStreamStringAdapter::eof() const
++{
++	return (m_pos >= m_end);
++}
++
++
++void inputStreamStringAdapter::reset()
++{
++	m_pos = m_begin;
++}
++
++
++stream::size_type inputStreamStringAdapter::read
++	(value_type* const data, const size_type count)
++{
++	if (m_pos + count >= m_end)
++	{
++		const size_type remaining = m_end - m_pos;
++
++		std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data);
++		m_pos = m_end;
++		return (remaining);
++	}
++	else
++	{
++		std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data);
++		m_pos += count;
++		return (count);
++	}
++}
++
++
++stream::size_type inputStreamStringAdapter::skip(const size_type count)
++{
++	if (m_pos + count >= m_end)
++	{
++		const size_type remaining = m_end - m_pos;
++		m_pos = m_end;
++		return (remaining);
++	}
++	else
++	{
++		m_pos += count;
++		return (count);
++	}
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/inputStreamStringProxyAdapter.cpp b/src/utility/inputStreamStringProxyAdapter.cpp
+new file mode 100644
+index 0000000..5e4b60b
+--- /dev/null
++++ b/src/utility/inputStreamStringProxyAdapter.cpp
+@@ -0,0 +1,89 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/inputStreamStringProxyAdapter.hpp"
++#include "vmime/utility/stringProxy.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++inputStreamStringProxyAdapter::inputStreamStringProxyAdapter(const stringProxy& buffer)
++	: m_buffer(buffer), m_pos(0)
++{
++}
++
++
++bool inputStreamStringProxyAdapter::eof() const
++{
++	return (m_pos >= m_buffer.length());
++}
++
++
++void inputStreamStringProxyAdapter::reset()
++{
++	m_pos = 0;
++}
++
++
++stream::size_type inputStreamStringProxyAdapter::read
++	(value_type* const data, const size_type count)
++{
++	const size_type remaining = m_buffer.length() - m_pos;
++
++	if (count > remaining)
++	{
++		std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_end(), data);
++		m_pos = m_buffer.length();
++		return (remaining);
++	}
++	else
++	{
++		std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_begin() + m_pos + count, data);
++		m_pos += count;
++		return (count);
++	}
++}
++
++
++stream::size_type inputStreamStringProxyAdapter::skip(const size_type count)
++{
++	const size_type remaining = m_buffer.length() - m_pos;
++
++	if (count > remaining)
++	{
++		m_pos = m_buffer.length();
++		return (remaining);
++	}
++	else
++	{
++		m_pos += count;
++		return (count);
++	}
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/outputStream.cpp b/src/utility/outputStream.cpp
+new file mode 100644
+index 0000000..8a65db5
+--- /dev/null
++++ b/src/utility/outputStream.cpp
+@@ -0,0 +1,33 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/outputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/outputStreamAdapter.cpp b/src/utility/outputStreamAdapter.cpp
+new file mode 100644
+index 0000000..2da94f1
+--- /dev/null
++++ b/src/utility/outputStreamAdapter.cpp
+@@ -0,0 +1,54 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/outputStreamAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++outputStreamAdapter::outputStreamAdapter(std::ostream& os)
++	: m_stream(os)
++{
++}
++
++
++void outputStreamAdapter::write
++	(const value_type* const data, const size_type count)
++{
++	m_stream.exceptions(std::ios_base::badbit);
++	m_stream.write(data, count);
++}
++
++
++void outputStreamAdapter::flush()
++{
++	m_stream.exceptions(std::ios_base::badbit);
++	m_stream.flush();
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/outputStreamByteArrayAdapter.cpp b/src/utility/outputStreamByteArrayAdapter.cpp
+new file mode 100644
+index 0000000..97b27d2
+--- /dev/null
++++ b/src/utility/outputStreamByteArrayAdapter.cpp
+@@ -0,0 +1,51 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array)
++	: m_array(array)
++{
++}
++
++
++void outputStreamByteArrayAdapter::write(const value_type* const data, const size_type count)
++{
++	m_array.insert(m_array.end(), data, data + count);
++}
++
++
++void outputStreamByteArrayAdapter::flush()
++{
++	// Do nothing
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/outputStreamSocketAdapter.cpp b/src/utility/outputStreamSocketAdapter.cpp
+new file mode 100644
+index 0000000..d933e73
+--- /dev/null
++++ b/src/utility/outputStreamSocketAdapter.cpp
+@@ -0,0 +1,68 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/outputStreamSocketAdapter.hpp"
++
++
++#if VMIME_HAVE_MESSAGING_FEATURES
++
++
++#include "vmime/net/socket.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok)
++	: m_socket(sok)
++{
++}
++
++
++void outputStreamSocketAdapter::write
++	(const value_type* const data, const size_type count)
++{
++	m_socket.sendRaw(data, count);
++}
++
++
++void outputStreamSocketAdapter::flush()
++{
++	// Do nothing
++}
++
++
++stream::size_type outputStreamSocketAdapter::getBlockSize()
++{
++	return m_socket.getBlockSize();
++}
++
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_HAVE_MESSAGING_FEATURES
++
+diff --git a/src/utility/outputStreamStringAdapter.cpp b/src/utility/outputStreamStringAdapter.cpp
+new file mode 100644
+index 0000000..62b2a72
+--- /dev/null
++++ b/src/utility/outputStreamStringAdapter.cpp
+@@ -0,0 +1,51 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++outputStreamStringAdapter::outputStreamStringAdapter(string& buffer)
++	: m_buffer(buffer)
++{
++}
++
++
++void outputStreamStringAdapter::write(const value_type* const data, const size_type count)
++{
++	m_buffer.append(data, count);
++}
++
++
++void outputStreamStringAdapter::flush()
++{
++	// Do nothing
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp
+index ec30b7d..1c940c2 100644
+--- a/src/utility/stream.cpp
++++ b/src/utility/stream.cpp
+@@ -22,503 +22,18 @@
+ //
+ 
+ #include "vmime/utility/stream.hpp"
+-#include "vmime/utility/stringProxy.hpp"
+ 
+-#include <algorithm>  // for std::copy
+-#include <iterator>   // for std::back_inserter
+-
+-#if VMIME_HAVE_MESSAGING_FEATURES
+-   #include "vmime/net/socket.hpp"
+-#endif
+ 
+ 
+ namespace vmime {
+ namespace utility {
+ 
+ 
+-// stream
+-
+ stream::size_type stream::getBlockSize()
+ {
+ 	return 32768;  // 32 KB
+ }
+ 
+ 
+-// Helpers
+-
+-outputStream& operator<<(outputStream& os, const stream::value_type c)
+-{
+-	os.write(&c, 1);
+-	return (os);
+-}
+-
+-
+-outputStream& operator<<(outputStream& os, const string& str)
+-{
+-	os.write(str.data(), str.length());
+-	return (os);
+-}
+-
+-
+-stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os)
+-{
+-	return bufferedStreamCopy(is, os, 0, NULL);
+-}
+-
+-
+-stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
+-	const stream::size_type length, progressListener* progress)
+-{
+-	const stream::size_type blockSize =
+-		std::min(is.getBlockSize(), os.getBlockSize());
+-
+-	std::vector <stream::value_type> vbuffer(blockSize);
+-
+-	stream::value_type* buffer = &vbuffer.front();
+-	stream::size_type total = 0;
+-
+-	if (progress != NULL)
+-		progress->start(length);
+-
+-	while (!is.eof())
+-	{
+-		const stream::size_type read = is.read(buffer, blockSize);
+-
+-		if (read != 0)
+-		{
+-			os.write(buffer, read);
+-			total += read;
+-
+-			if (progress != NULL)
+-				progress->progress(total, std::max(total, length));
+-		}
+-	}
+-
+-	if (progress != NULL)
+-		progress->stop(total);
+-
+-	return (total);
+-}
+-
+-
+-
+-// outputStreamAdapter
+-
+-outputStreamAdapter::outputStreamAdapter(std::ostream& os)
+-	: m_stream(os)
+-{
+-}
+-
+-
+-void outputStreamAdapter::write
+-	(const value_type* const data, const size_type count)
+-{
+-	m_stream.exceptions(std::ios_base::badbit);
+-	m_stream.write(data, count);
+-}
+-
+-
+-void outputStreamAdapter::flush()
+-{
+-	m_stream.exceptions(std::ios_base::badbit);
+-	m_stream.flush();
+-}
+-
+-
+-
+-// outputStreamStringAdapter
+-
+-outputStreamStringAdapter::outputStreamStringAdapter(string& buffer)
+-	: m_buffer(buffer)
+-{
+-}
+-
+-
+-void outputStreamStringAdapter::write(const value_type* const data, const size_type count)
+-{
+-	m_buffer.append(data, count);
+-}
+-
+-
+-void outputStreamStringAdapter::flush()
+-{
+-	// Do nothing
+-}
+-
+-
+-
+-// outputStreamByteArrayAdapter
+-
+-outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array)
+-	: m_array(array)
+-{
+-}
+-
+-
+-void outputStreamByteArrayAdapter::write(const value_type* const data, const size_type count)
+-{
+-	m_array.insert(m_array.end(), data, data + count);
+-}
+-
+-
+-void outputStreamByteArrayAdapter::flush()
+-{
+-	// Do nothing
+-}
+-
+-
+-
+-// inputStreamAdapter
+-
+-inputStreamAdapter::inputStreamAdapter(std::istream& is)
+-	: m_stream(is)
+-{
+-}
+-
+-
+-bool inputStreamAdapter::eof() const
+-{
+-	return (m_stream.eof());
+-}
+-
+-
+-void inputStreamAdapter::reset()
+-{
+-	m_stream.exceptions(std::ios_base::badbit);
+-	m_stream.seekg(0, std::ios::beg);
+-	m_stream.clear();
+-}
+-
+-
+-stream::size_type inputStreamAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	m_stream.exceptions(std::ios_base::badbit);
+-	m_stream.read(data, count);
+-	return (m_stream.gcount());
+-}
+-
+-
+-stream::size_type inputStreamAdapter::skip(const size_type count)
+-{
+-	m_stream.exceptions(std::ios_base::badbit);
+-	m_stream.ignore(count);
+-	return (m_stream.gcount());
+-}
+-
+-
+-
+-// inputStreamStringAdapter
+-
+-inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer)
+-	: m_buffer(buffer), m_begin(0), m_end(buffer.length()), m_pos(0)
+-{
+-}
+-
+-
+-inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer,
+-	const string::size_type begin, const string::size_type end)
+-	: m_buffer(buffer), m_begin(begin), m_end(end), m_pos(begin)
+-{
+-}
+-
+-
+-bool inputStreamStringAdapter::eof() const
+-{
+-	return (m_pos >= m_end);
+-}
+-
+-
+-void inputStreamStringAdapter::reset()
+-{
+-	m_pos = m_begin;
+-}
+-
+-
+-stream::size_type inputStreamStringAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	if (m_pos + count >= m_end)
+-	{
+-		const size_type remaining = m_end - m_pos;
+-
+-		std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data);
+-		m_pos = m_end;
+-		return (remaining);
+-	}
+-	else
+-	{
+-		std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data);
+-		m_pos += count;
+-		return (count);
+-	}
+-}
+-
+-
+-stream::size_type inputStreamStringAdapter::skip(const size_type count)
+-{
+-	if (m_pos + count >= m_end)
+-	{
+-		const size_type remaining = m_end - m_pos;
+-		m_pos = m_end;
+-		return (remaining);
+-	}
+-	else
+-	{
+-		m_pos += count;
+-		return (count);
+-	}
+-}
+-
+-
+-
+-// inputStreamStringProxyAdapter
+-
+-inputStreamStringProxyAdapter::inputStreamStringProxyAdapter(const stringProxy& buffer)
+-	: m_buffer(buffer), m_pos(0)
+-{
+-}
+-
+-
+-bool inputStreamStringProxyAdapter::eof() const
+-{
+-	return (m_pos >= m_buffer.length());
+-}
+-
+-
+-void inputStreamStringProxyAdapter::reset()
+-{
+-	m_pos = 0;
+-}
+-
+-
+-stream::size_type inputStreamStringProxyAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	const size_type remaining = m_buffer.length() - m_pos;
+-
+-	if (count > remaining)
+-	{
+-		std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_end(), data);
+-		m_pos = m_buffer.length();
+-		return (remaining);
+-	}
+-	else
+-	{
+-		std::copy(m_buffer.it_begin() + m_pos, m_buffer.it_begin() + m_pos + count, data);
+-		m_pos += count;
+-		return (count);
+-	}
+-}
+-
+-
+-stream::size_type inputStreamStringProxyAdapter::skip(const size_type count)
+-{
+-	const size_type remaining = m_buffer.length() - m_pos;
+-
+-	if (count > remaining)
+-	{
+-		m_pos = m_buffer.length();
+-		return (remaining);
+-	}
+-	else
+-	{
+-		m_pos += count;
+-		return (count);
+-	}
+-}
+-
+-
+-
+-// inputStreamPointerAdapter
+-
+-inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own)
+-	: m_stream(is), m_own(own)
+-{
+-}
+-
+-
+-inputStreamPointerAdapter::inputStreamPointerAdapter(const inputStreamPointerAdapter&)
+-	: inputStream(), m_stream(NULL), m_own(false)
+-{
+-	// Not copiable
+-}
+-
+-
+-inputStreamPointerAdapter::~inputStreamPointerAdapter()
+-{
+-	if (m_own)
+-		delete (m_stream);
+-}
+-
+-
+-bool inputStreamPointerAdapter::eof() const
+-{
+-	return (m_stream->eof());
+-}
+-
+-
+-void inputStreamPointerAdapter::reset()
+-{
+-	m_stream->exceptions(std::ios_base::badbit);
+-	m_stream->seekg(0, std::ios::beg);
+-	m_stream->clear();
+-}
+-
+-
+-stream::size_type inputStreamPointerAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	m_stream->exceptions(std::ios_base::badbit);
+-	m_stream->read(data, count);
+-	return (m_stream->gcount());
+-}
+-
+-
+-stream::size_type inputStreamPointerAdapter::skip(const size_type count)
+-{
+-	m_stream->exceptions(std::ios_base::badbit);
+-	m_stream->ignore(count);
+-	return (m_stream->gcount());
+-}
+-
+-
+-
+-// inputStreamByteBufferAdapter
+-
+-inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte_t* buffer, const size_type length)
+-	: m_buffer(buffer), m_length(length), m_pos(0)
+-{
+-}
+-
+-
+-bool inputStreamByteBufferAdapter::eof() const
+-{
+-	return m_pos >= m_length;
+-}
+-
+-
+-void inputStreamByteBufferAdapter::reset()
+-{
+-	m_pos = 0;
+-}
+-
+-
+-stream::size_type inputStreamByteBufferAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	const size_type remaining = m_length - m_pos;
+-
+-	if (remaining < count)
+-	{
+-		std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data);
+-		m_pos += remaining;
+-
+-		return remaining;
+-	}
+-	else
+-	{
+-		std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data);
+-		m_pos += count;
+-
+-		return count;
+-	}
+-}
+-
+-
+-stream::size_type inputStreamByteBufferAdapter::skip(const size_type count)
+-{
+-	const size_type remaining = m_length - m_pos;
+-
+-	if (remaining < count)
+-	{
+-		m_pos += remaining;
+-		return remaining;
+-	}
+-	else
+-	{
+-		m_pos += count;
+-		return count;
+-	}
+-}
+-
+-
+-
+-#ifdef VMIME_HAVE_MESSAGING_FEATURES
+-
+-
+-// outputStreamSocketAdapter
+-
+-outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok)
+-	: m_socket(sok)
+-{
+-}
+-
+-
+-void outputStreamSocketAdapter::write
+-	(const value_type* const data, const size_type count)
+-{
+-	m_socket.sendRaw(data, count);
+-}
+-
+-
+-void outputStreamSocketAdapter::flush()
+-{
+-	// Do nothing
+-}
+-
+-
+-stream::size_type outputStreamSocketAdapter::getBlockSize()
+-{
+-	return m_socket.getBlockSize();
+-}
+-
+-
+-
+-// inputStreamSocketAdapter
+-
+-inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok)
+-	: m_socket(sok)
+-{
+-}
+-
+-
+-bool inputStreamSocketAdapter::eof() const
+-{
+-	// Can't know...
+-	return false;
+-}
+-
+-
+-void inputStreamSocketAdapter::reset()
+-{
+-	// Not supported
+-}
+-
+-
+-stream::size_type inputStreamSocketAdapter::read
+-	(value_type* const data, const size_type count)
+-{
+-	return m_socket.receiveRaw(data, count);
+-}
+-
+-
+-stream::size_type inputStreamSocketAdapter::skip
+-	(const size_type /* count */)
+-{
+-	// Not supported
+-	return 0;
+-}
+-
+-
+-stream::size_type inputStreamSocketAdapter::getBlockSize()
+-{
+-	return m_socket.getBlockSize();
+-}
+-
+-
+-#endif // VMIME_HAVE_MESSAGING_FEATURES
+-
+-
+ } // utility
+ } // vmime
+diff --git a/src/utility/streamUtils.cpp b/src/utility/streamUtils.cpp
+new file mode 100644
+index 0000000..f1d3b9d
+--- /dev/null
++++ b/src/utility/streamUtils.cpp
+@@ -0,0 +1,92 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/streamUtils.hpp"
++
++#include <algorithm>  // for std::copy
++#include <iterator>   // for std::back_inserter
++
++
++
++namespace vmime {
++namespace utility {
++
++
++outputStream& operator<<(outputStream& os, const stream::value_type c)
++{
++	os.write(&c, 1);
++	return (os);
++}
++
++
++outputStream& operator<<(outputStream& os, const string& str)
++{
++	os.write(str.data(), str.length());
++	return (os);
++}
++
++
++stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os)
++{
++	return bufferedStreamCopy(is, os, 0, NULL);
++}
++
++
++stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
++	const stream::size_type length, progressListener* progress)
++{
++	const stream::size_type blockSize =
++		std::min(is.getBlockSize(), os.getBlockSize());
++
++	std::vector <stream::value_type> vbuffer(blockSize);
++
++	stream::value_type* buffer = &vbuffer.front();
++	stream::size_type total = 0;
++
++	if (progress != NULL)
++		progress->start(length);
++
++	while (!is.eof())
++	{
++		const stream::size_type read = is.read(buffer, blockSize);
++
++		if (read != 0)
++		{
++			os.write(buffer, read);
++			total += read;
++
++			if (progress != NULL)
++				progress->progress(total, std::max(total, length));
++		}
++	}
++
++	if (progress != NULL)
++		progress->stop(total);
++
++	return (total);
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/stringProxy.cpp b/src/utility/stringProxy.cpp
+index a4ba6d2..74344b5 100644
+--- a/src/utility/stringProxy.cpp
++++ b/src/utility/stringProxy.cpp
+@@ -23,6 +23,8 @@
+ 
+ #include "vmime/utility/stringProxy.hpp"
+ 
++#include "vmime/utility/outputStreamAdapter.hpp"
++
+ #include <iterator>
+ #include <algorithm>
+ 
+diff --git a/src/word.cpp b/src/word.cpp
+index aeaa737..79060a1 100644
+--- a/src/word.cpp
++++ b/src/word.cpp
+@@ -28,6 +28,9 @@
+ #include "vmime/utility/smartPtr.hpp"
+ #include "vmime/parserHelpers.hpp"
+ 
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++
+ #include "vmime/utility/encoder/encoder.hpp"
+ #include "vmime/utility/encoder/b64Encoder.hpp"
+ #include "vmime/utility/encoder/qpEncoder.hpp"
+diff --git a/src/wordEncoder.cpp b/src/wordEncoder.cpp
+index 67bd7a1..194a189 100644
+--- a/src/wordEncoder.cpp
++++ b/src/wordEncoder.cpp
+@@ -33,6 +33,9 @@
+ 
+ #include "vmime/utility/stringUtils.hpp"
+ 
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++
+ 
+ namespace vmime
+ {
+diff --git a/vmime/base.hpp b/vmime/base.hpp
+index 60e637d..b794031 100644
+--- a/vmime/base.hpp
++++ b/vmime/base.hpp
+@@ -35,7 +35,6 @@
+ #include "vmime/config.hpp"
+ #include "vmime/types.hpp"
+ #include "vmime/constants.hpp"
+-#include "vmime/utility/stream.hpp"
+ #include "vmime/utility/smartPtr.hpp"
+ 
+ 
+@@ -255,7 +254,26 @@ namespace vmime
+ 		return y.dynamicCast <X>();
+ 	}
+ 
++	/** Inherit from this class to indicate the subclass is not copyable,
++	  * ie. you want to prohibit copy construction and copy assignment.
++	  */
++	class noncopyable
++	{
++	protected:
++
++		noncopyable() { }
++		virtual ~noncopyable() { }
++
++	private:
++
++		noncopyable(const noncopyable&);
++		void operator=(const noncopyable&);
++	};
++
+ } // vmime
+ 
+ 
++#include "vmime/utility/stream.hpp"
++
++
+ #endif // VMIME_BASE_HPP_INCLUDED
+diff --git a/vmime/charset.hpp b/vmime/charset.hpp
+index b2e241c..5f5e8e5 100644
+--- a/vmime/charset.hpp
++++ b/vmime/charset.hpp
+@@ -26,6 +26,8 @@
+ 
+ 
+ #include "vmime/base.hpp"
++#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/outputStream.hpp"
+ #include "vmime/component.hpp"
+ 
+ 
+diff --git a/vmime/component.hpp b/vmime/component.hpp
+index b38127f..12b0406 100644
+--- a/vmime/component.hpp
++++ b/vmime/component.hpp
+@@ -26,6 +26,8 @@
+ 
+ 
+ #include "vmime/base.hpp"
++#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/outputStream.hpp"
+ 
+ 
+ namespace vmime
+diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp
+index d71c3ca..f430510 100644
+--- a/vmime/net/imap/IMAPParser.hpp
++++ b/vmime/net/imap/IMAPParser.hpp
+@@ -37,6 +37,9 @@
+ #include "vmime/utility/encoder/b64Encoder.hpp"
+ #include "vmime/utility/encoder/qpEncoder.hpp"
+ 
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++
+ #include "vmime/platform.hpp"
+ 
+ #include "vmime/net/timeoutHandler.hpp"
+@@ -3825,7 +3828,7 @@ public:
+ 			: m_date_time(NULL), m_number(NULL), m_envelope(NULL),
+ 			  m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL),
+ 			  m_section(NULL)
+-              
++
+ 		{
+ 		}
+ 
+diff --git a/vmime/utility/filteredStream.hpp b/vmime/utility/filteredStream.hpp
+index 00be785..2a55edd 100644
+--- a/vmime/utility/filteredStream.hpp
++++ b/vmime/utility/filteredStream.hpp
+@@ -27,7 +27,8 @@
+ 
+ #include <algorithm>
+ 
+-#include "vmime/utility/stream.hpp"
++#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/outputStream.hpp"
+ 
+ 
+ namespace vmime {
+diff --git a/vmime/utility/inputStream.hpp b/vmime/utility/inputStream.hpp
+new file mode 100644
+index 0000000..4a76a7d
+--- /dev/null
++++ b/vmime/utility/inputStream.hpp
+@@ -0,0 +1,76 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
++
++
++#include "vmime/utility/stream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** Simple input stream.
++  */
++
++class inputStream : public stream
++{
++public:
++
++	/** Test for end of stream (no more data to read).
++	  *
++	  * @return true if we have reached the end of stream, false otherwise
++	  */
++	virtual bool eof() const = 0;
++
++	/** Set the read pointer to the beginning of the stream.
++	  *
++	  * @warning WARNING: this may not work for all stream types.
++	  */
++	virtual void reset() = 0;
++
++	/** Read data from the stream.
++	  *
++	  * @param data will receive the data read
++	  * @param count maximum number of bytes to read
++	  * @return number of bytes read
++	  */
++	virtual size_type read(value_type* const data, const size_type count) = 0;
++
++	/** Skip a number of bytes.
++	  *
++	  * @param count maximum number of bytes to ignore
++	  * @return number of bytes skipped
++	  */
++	virtual size_type skip(const size_type count) = 0;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamAdapter.hpp b/vmime/utility/inputStreamAdapter.hpp
+new file mode 100644
+index 0000000..278ab52
+--- /dev/null
++++ b/vmime/utility/inputStreamAdapter.hpp
+@@ -0,0 +1,64 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++#include <istream>
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for C++ standard input streams.
++  */
++
++class inputStreamAdapter : public inputStream
++{
++public:
++
++	/** @param is input stream to wrap
++	  */
++	inputStreamAdapter(std::istream& is);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++
++private:
++
++	std::istream& m_stream;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime/utility/inputStreamByteBufferAdapter.hpp
+new file mode 100644
+index 0000000..0f6a442
+--- /dev/null
++++ b/vmime/utility/inputStreamByteBufferAdapter.hpp
+@@ -0,0 +1,63 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for reading from an array of bytes.
++  */
++
++class inputStreamByteBufferAdapter : public inputStream
++{
++public:
++
++	inputStreamByteBufferAdapter(const byte_t* buffer, size_type length);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++
++private:
++
++	const byte_t* m_buffer;
++	const size_type m_length;
++
++	size_type m_pos;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamPointerAdapter.hpp b/vmime/utility/inputStreamPointerAdapter.hpp
+new file mode 100644
+index 0000000..44e9bad
+--- /dev/null
++++ b/vmime/utility/inputStreamPointerAdapter.hpp
+@@ -0,0 +1,63 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStreamAdapter.hpp"
++
++#include <istream>
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for pointer to C++ standard input stream.
++  */
++
++class inputStreamPointerAdapter : public inputStreamAdapter
++{
++public:
++
++	/** @param is input stream to wrap
++	  * @param own if set to 'true', the pointer will be deleted when
++	  * this object is destroyed
++	  */
++	inputStreamPointerAdapter(std::istream* is, const bool own = true);
++	~inputStreamPointerAdapter();
++
++private:
++
++	std::istream* m_stream;
++	const bool m_own;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamSocketAdapter.hpp b/vmime/utility/inputStreamSocketAdapter.hpp
+new file mode 100644
+index 0000000..0f99c21
+--- /dev/null
++++ b/vmime/utility/inputStreamSocketAdapter.hpp
+@@ -0,0 +1,77 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++
++#if VMIME_HAVE_MESSAGING_FEATURES
++
++
++namespace vmime {
++namespace net {
++	class socket;  // forward reference
++} // net
++} // vmime
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An input stream that is connected to a socket.
++  */
++
++class inputStreamSocketAdapter : public inputStream
++{
++public:
++
++	inputStreamSocketAdapter(net::socket& sok);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++
++	size_type getBlockSize();
++
++private:
++
++	inputStreamSocketAdapter(const inputStreamSocketAdapter&);
++
++	net::socket& m_socket;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_HAVE_MESSAGING_FEATURES
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamStringAdapter.hpp b/vmime/utility/inputStreamStringAdapter.hpp
+new file mode 100644
+index 0000000..a7d986f
+--- /dev/null
++++ b/vmime/utility/inputStreamStringAdapter.hpp
+@@ -0,0 +1,66 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for string input.
++  */
++
++class inputStreamStringAdapter : public inputStream
++{
++public:
++
++	inputStreamStringAdapter(const string& buffer);
++	inputStreamStringAdapter(const string& buffer, const string::size_type begin, const string::size_type end);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++
++private:
++
++	inputStreamStringAdapter(const inputStreamStringAdapter&);
++
++	const string m_buffer;  // do _NOT_ keep a reference...
++	const string::size_type m_begin;
++	const string::size_type m_end;
++	string::size_type m_pos;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/inputStreamStringProxyAdapter.hpp b/vmime/utility/inputStreamStringProxyAdapter.hpp
+new file mode 100644
+index 0000000..74b3f60
+--- /dev/null
++++ b/vmime/utility/inputStreamStringProxyAdapter.hpp
+@@ -0,0 +1,68 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++class stringProxy;
++
++
++/** An adapter class for stringProxy input.
++  */
++
++class inputStreamStringProxyAdapter : public inputStream
++{
++public:
++
++	/** @param buffer stringProxy object to wrap
++	  */
++	inputStreamStringProxyAdapter(const stringProxy& buffer);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++
++private:
++
++	inputStreamStringProxyAdapter(const inputStreamStringProxyAdapter&);
++
++	const stringProxy& m_buffer;
++	string::size_type m_pos;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/outputStream.hpp b/vmime/utility/outputStream.hpp
+new file mode 100644
+index 0000000..7372d20
+--- /dev/null
++++ b/vmime/utility/outputStream.hpp
+@@ -0,0 +1,107 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
++#define VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
++
++
++#include "vmime/utility/stream.hpp"
++
++
++#if defined(_MSC_VER) && (_MSC_VER <= 1200)  // VC++6
++#	include <cstring>
++#endif
++
++
++namespace vmime {
++namespace utility {
++
++
++/** Simple output stream.
++  */
++
++class outputStream : public stream
++{
++public:
++
++	/** Write data to the stream.
++	  *
++	  * @param data buffer containing data to write
++	  * @param count number of bytes to write
++	  */
++	virtual void write(const value_type* const data, const size_type count) = 0;
++
++	/** Flush this output stream and forces any buffered output
++	  * bytes to be written out to the stream.
++	  */
++	virtual void flush() = 0;
++};
++
++
++// Helpers functions
++
++outputStream& operator<<(outputStream& os, const string& str);
++outputStream& operator<<(outputStream& os, const stream::value_type c);
++
++
++#if defined(_MSC_VER) && (_MSC_VER <= 1200)  // Internal compiler error with VC++6
++
++inline outputStream& operator<<(outputStream& os, const char* str)
++{
++	os.write(str, ::strlen(str));
++	return (os);
++}
++
++#else
++
++template <int N>
++outputStream& operator<<(outputStream& os, const char (&str)[N])
++{
++	os.write(str, N - 1);
++	return (os);
++}
++
++#endif // defined(_MSC_VER) && (_MSC_VER <= 1200)
++
++
++template <typename T>
++outputStream& operator<<(outputStream& os, const T& t)
++{
++	std::ostringstream oss;
++	oss.imbue(std::locale::classic());  // no formatting
++
++	oss << t;
++
++	os << oss.str();
++
++	return (os);
++}
++
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
++
+diff --git a/vmime/utility/outputStreamAdapter.hpp b/vmime/utility/outputStreamAdapter.hpp
+new file mode 100644
+index 0000000..be55d8d
+--- /dev/null
++++ b/vmime/utility/outputStreamAdapter.hpp
+@@ -0,0 +1,62 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/outputStream.hpp"
++
++#include <ostream>
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for C++ standard output streams.
++  */
++
++class outputStreamAdapter : public outputStream
++{
++public:
++
++	/** @param os output stream to wrap
++	  */
++	outputStreamAdapter(std::ostream& os);
++
++	void write(const value_type* const data, const size_type count);
++	void flush();
++
++private:
++
++	std::ostream& m_stream;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/outputStreamByteArrayAdapter.hpp b/vmime/utility/outputStreamByteArrayAdapter.hpp
+new file mode 100644
+index 0000000..bf7d839
+--- /dev/null
++++ b/vmime/utility/outputStreamByteArrayAdapter.hpp
+@@ -0,0 +1,58 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/outputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for byte array output.
++  */
++
++class outputStreamByteArrayAdapter : public outputStream
++{
++public:
++
++	outputStreamByteArrayAdapter(byteArray& array);
++
++	void write(const value_type* const data, const size_type count);
++	void flush();
++
++private:
++
++	byteArray& m_array;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/outputStreamSocketAdapter.hpp b/vmime/utility/outputStreamSocketAdapter.hpp
+new file mode 100644
+index 0000000..e3d3eb0
+--- /dev/null
++++ b/vmime/utility/outputStreamSocketAdapter.hpp
+@@ -0,0 +1,75 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/outputStream.hpp"
++
++
++#if VMIME_HAVE_MESSAGING_FEATURES
++
++
++namespace vmime {
++namespace net {
++	class socket;  // forward reference
++} // net
++} // vmime
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An output stream that is connected to a socket.
++  */
++
++class outputStreamSocketAdapter : public outputStream
++{
++public:
++
++	outputStreamSocketAdapter(net::socket& sok);
++
++	void write(const value_type* const data, const size_type count);
++	void flush();
++
++	size_type getBlockSize();
++
++private:
++
++	outputStreamSocketAdapter(const outputStreamSocketAdapter&);
++
++	net::socket& m_socket;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_HAVE_MESSAGING_FEATURES
++
++
++#endif // VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/outputStreamStringAdapter.hpp b/vmime/utility/outputStreamStringAdapter.hpp
+new file mode 100644
+index 0000000..8c8b304
+--- /dev/null
++++ b/vmime/utility/outputStreamStringAdapter.hpp
+@@ -0,0 +1,59 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/outputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class for string output.
++  */
++
++class outputStreamStringAdapter : public outputStream
++{
++public:
++
++	outputStreamStringAdapter(string& buffer);
++
++	void write(const value_type* const data, const size_type count);
++	void flush();
++
++size_type getBlockSize(){return 8192;}
++private:
++
++	string& m_buffer;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/stream.hpp b/vmime/utility/stream.hpp
+index 1faab55..566ab9d 100644
+--- a/vmime/utility/stream.hpp
++++ b/vmime/utility/stream.hpp
+@@ -25,40 +25,22 @@
+ #define VMIME_UTILITY_STREAM_HPP_INCLUDED
+ 
+ 
+-#include <istream>
+-#include <ostream>
+ #include <sstream>
+ 
+ #include "vmime/config.hpp"
+ #include "vmime/types.hpp"
+-
+-#include "vmime/utility/progressListener.hpp"
+-
+-
+-#if VMIME_HAVE_MESSAGING_FEATURES
+-	namespace vmime {
+-	namespace net {
+-		class socket;  // forward reference
+-	} // net
+-	} // vmime
+-#endif
+-
+-#if defined(_MSC_VER) && (_MSC_VER <= 1200)  // VC++6
+-#   include <cstring>
+-#endif
++#include "vmime/base.hpp"
+ 
+ 
+ namespace vmime {
+ namespace utility {
+ 
+ 
+-class stringProxy;
+-
+ 
+ /** Base class for input/output stream.
+   */
+ 
+-class stream : public object
++class stream : public object, private noncopyable
+ {
+ public:
+ 
+@@ -81,365 +63,6 @@ public:
+ };
+ 
+ 
+-
+-/** Simple output stream.
+-  */
+-
+-class outputStream : public stream
+-{
+-public:
+-
+-	/** Write data to the stream.
+-	  *
+-	  * @param data buffer containing data to write
+-	  * @param count number of bytes to write
+-	  */
+-	virtual void write(const value_type* const data, const size_type count) = 0;
+-
+-	/** Flush this output stream and forces any buffered output
+-	  * bytes to be written out to the stream.
+-	  */
+-	virtual void flush() = 0;
+-};
+-
+-
+-
+-/** Simple input stream.
+-  */
+-
+-class inputStream : public stream
+-{
+-public:
+-
+-	/** Test for end of stream (no more data to read).
+-	  *
+-	  * @return true if we have reached the end of stream, false otherwise
+-	  */
+-	virtual bool eof() const = 0;
+-
+-	/** Set the read pointer to the beginning of the stream.
+-	  *
+-	  * @warning WARNING: this may not work for all stream types.
+-	  */
+-	virtual void reset() = 0;
+-
+-	/** Read data from the stream.
+-	  *
+-	  * @param data will receive the data read
+-	  * @param count maximum number of bytes to read
+-	  * @return number of bytes read
+-	  */
+-	virtual size_type read(value_type* const data, const size_type count) = 0;
+-
+-	/** Skip a number of bytes.
+-	  *
+-	  * @param count maximum number of bytes to ignore
+-	  * @return number of bytes skipped
+-	  */
+-	virtual size_type skip(const size_type count) = 0;
+-};
+-
+-
+-
+-// Helpers functions
+-
+-outputStream& operator<<(outputStream& os, const string& str);
+-outputStream& operator<<(outputStream& os, const stream::value_type c);
+-
+-
+-#if defined(_MSC_VER) && (_MSC_VER <= 1200)  // Internal compiler error with VC++6
+-
+-inline outputStream& operator<<(outputStream& os, const char* str)
+-{
+-	os.write(str, ::strlen(str));
+-	return (os);
+-}
+-
+-#else
+-
+-template <int N>
+-outputStream& operator<<(outputStream& os, const char (&str)[N])
+-{
+-	os.write(str, N - 1);
+-	return (os);
+-}
+-
+-#endif // defined(_MSC_VER) && (_MSC_VER <= 1200)
+-
+-
+-template <typename T>
+-outputStream& operator<<(outputStream& os, const T& t)
+-{
+-	std::ostringstream oss;
+-	oss.imbue(std::locale::classic());  // no formatting
+-
+-	oss << t;
+-
+-	os << oss.str();
+-
+-	return (os);
+-}
+-
+-
+-/** Copy data from one stream into another stream using a buffered method.
+-  *
+-  * @param is input stream (source data)
+-  * @param os output stream (destination for data)
+-  * @return number of bytes copied
+-  */
+-
+-stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os);
+-
+-/** Copy data from one stream into another stream using a buffered method
+-  * and notify progress state of the operation.
+-  *
+-  * @param is input stream (source data)
+-  * @param os output stream (destination for data)
+-  * @param length predicted number of bytes to copy
+-  * @param progress listener to notify
+-  * @return number of bytes copied
+-  */
+-
+-stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
+-	const stream::size_type length, progressListener* progress);
+-
+-
+-// Adapters
+-
+-
+-/** An adapter class for C++ standard output streams.
+-  */
+-
+-class outputStreamAdapter : public outputStream
+-{
+-public:
+-
+-	/** @param os output stream to wrap
+-	  */
+-	outputStreamAdapter(std::ostream& os);
+-
+-	void write(const value_type* const data, const size_type count);
+-	void flush();
+-
+-private:
+-
+-	std::ostream& m_stream;
+-};
+-
+-
+-/** An adapter class for string output.
+-  */
+-
+-class outputStreamStringAdapter : public outputStream
+-{
+-public:
+-
+-	outputStreamStringAdapter(string& buffer);
+-
+-	void write(const value_type* const data, const size_type count);
+-	void flush();
+-
+-size_type getBlockSize(){return 8192;}
+-private:
+-
+-	string& m_buffer;
+-};
+-
+-
+-/** An adapter class for byte array output.
+-  */
+-
+-class outputStreamByteArrayAdapter : public outputStream
+-{
+-public:
+-
+-	outputStreamByteArrayAdapter(byteArray& array);
+-
+-	void write(const value_type* const data, const size_type count);
+-	void flush();
+-
+-private:
+-
+-	byteArray& m_array;
+-};
+-
+-
+-/** An adapter class for C++ standard input streams.
+-  */
+-
+-class inputStreamAdapter : public inputStream
+-{
+-public:
+-
+-	/** @param is input stream to wrap
+-	  */
+-	inputStreamAdapter(std::istream& is);
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-private:
+-
+-	std::istream& m_stream;
+-};
+-
+-
+-/** An adapter class for string input.
+-  */
+-
+-class inputStreamStringAdapter : public inputStream
+-{
+-public:
+-
+-	inputStreamStringAdapter(const string& buffer);
+-	inputStreamStringAdapter(const string& buffer, const string::size_type begin, const string::size_type end);
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-private:
+-
+-	inputStreamStringAdapter(const inputStreamStringAdapter&);
+-
+-	const string m_buffer;  // do _NOT_ keep a reference...
+-	const string::size_type m_begin;
+-	const string::size_type m_end;
+-	string::size_type m_pos;
+-};
+-
+-
+-/** An adapter class for stringProxy input.
+-  */
+-
+-class inputStreamStringProxyAdapter : public inputStream
+-{
+-public:
+-
+-	/** @param buffer stringProxy object to wrap
+-	  */
+-	inputStreamStringProxyAdapter(const stringProxy& buffer);
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-private:
+-
+-	inputStreamStringProxyAdapter(const inputStreamStringProxyAdapter&);
+-
+-	const stringProxy& m_buffer;
+-	string::size_type m_pos;
+-};
+-
+-
+-/** An adapter class for pointer to C++ standard input stream.
+-  */
+-
+-class inputStreamPointerAdapter : public inputStream
+-{
+-public:
+-
+-	/** @param is input stream to wrap
+-	  * @param own if set to 'true', the pointer will be deleted when
+-	  * this object is destroyed
+-	  */
+-	inputStreamPointerAdapter(std::istream* is, const bool own = true);
+-	~inputStreamPointerAdapter();
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-private:
+-
+-	inputStreamPointerAdapter(const inputStreamPointerAdapter&);
+-
+-	std::istream* m_stream;
+-	const bool m_own;
+-};
+-
+-
+-/** An adapter class for reading from an array of bytes.
+-  */
+-
+-class inputStreamByteBufferAdapter : public inputStream
+-{
+-public:
+-
+-	inputStreamByteBufferAdapter(const byte_t* buffer, size_type length);
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-private:
+-
+-	const byte_t* m_buffer;
+-	const size_type m_length;
+-
+-	size_type m_pos;
+-};
+-
+-
+-#if VMIME_HAVE_MESSAGING_FEATURES
+-
+-
+-/** An output stream that is connected to a socket.
+-  */
+-
+-class outputStreamSocketAdapter : public outputStream
+-{
+-public:
+-
+-	outputStreamSocketAdapter(net::socket& sok);
+-
+-	void write(const value_type* const data, const size_type count);
+-	void flush();
+-
+-	size_type getBlockSize();
+-
+-private:
+-
+-	outputStreamSocketAdapter(const outputStreamSocketAdapter&);
+-
+-	net::socket& m_socket;
+-};
+-
+-
+-/** An input stream that is connected to a socket.
+-  */
+-
+-class inputStreamSocketAdapter : public inputStream
+-{
+-public:
+-
+-	inputStreamSocketAdapter(net::socket& sok);
+-
+-	bool eof() const;
+-	void reset();
+-	size_type read(value_type* const data, const size_type count);
+-	size_type skip(const size_type count);
+-
+-	size_type getBlockSize();
+-
+-private:
+-
+-	inputStreamSocketAdapter(const inputStreamSocketAdapter&);
+-
+-	net::socket& m_socket;
+-};
+-
+-
+-#endif // VMIME_HAVE_MESSAGING_FEATURES
+-
+-
+ } // utility
+ } // vmime
+ 
+diff --git a/vmime/utility/streamUtils.hpp b/vmime/utility/streamUtils.hpp
+new file mode 100644
+index 0000000..cdf70aa
+--- /dev/null
++++ b/vmime/utility/streamUtils.hpp
+@@ -0,0 +1,66 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
++#define VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/outputStream.hpp"
++
++#include "vmime/utility/progressListener.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** Copy data from one stream into another stream using a buffered method.
++  *
++  * @param is input stream (source data)
++  * @param os output stream (destination for data)
++  * @return number of bytes copied
++  */
++
++stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os);
++
++/** Copy data from one stream into another stream using a buffered method
++  * and notify progress state of the operation.
++  *
++  * @param is input stream (source data)
++  * @param os output stream (destination for data)
++  * @param length predicted number of bytes to copy
++  * @param progress listener to notify
++  * @return number of bytes copied
++  */
++
++stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
++	const stream::size_type length, progressListener* progress);
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
++
+diff --git a/vmime/utility/stringProxy.hpp b/vmime/utility/stringProxy.hpp
+index 21c65ea..66a6dfd 100644
+--- a/vmime/utility/stringProxy.hpp
++++ b/vmime/utility/stringProxy.hpp
+@@ -29,6 +29,7 @@
+ 
+ #include "vmime/types.hpp"
+ #include "vmime/utility/stream.hpp"
++#include "vmime/utility/outputStream.hpp"
+ #include "vmime/utility/progressListener.hpp"
+ 
+ 
+diff --git a/vmime/vmime.hpp b/vmime/vmime.hpp
+index f187b9e..fd04853 100644
+--- a/vmime/vmime.hpp
++++ b/vmime/vmime.hpp
+@@ -68,6 +68,22 @@
+ // Encoders
+ #include "vmime/utility/encoder/encoderFactory.hpp"
+ 
++// Streams
++#include "vmime/utility/filteredStream.hpp"
++#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/inputStreamAdapter.hpp"
++#include "vmime/utility/inputStreamByteBufferAdapter.hpp"
++#include "vmime/utility/inputStreamPointerAdapter.hpp"
++#include "vmime/utility/inputStreamSocketAdapter.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/inputStreamStringProxyAdapter.hpp"
++#include "vmime/utility/outputStream.hpp"
++#include "vmime/utility/outputStreamAdapter.hpp"
++#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
++#include "vmime/utility/outputStreamSocketAdapter.hpp"
++#include "vmime/utility/outputStreamStringAdapter.hpp"
++#include "vmime/utility/streamUtils.hpp"
++
+ // Message builder/parser
+ #include "vmime/messageBuilder.hpp"
+ #include "vmime/messageParser.hpp"
+-- 
+1.7.10.3
+
+
+From be30b47f09c5358db2ac8e42fa2bb4a14ec24c51 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
+Date: Mon, 16 Apr 2012 22:32:33 +0200
+Subject: [PATCH 37/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  <vincent@vincent-richard.net>
++
++ * MIME Parser can now operate directly on an input stream (eg. file).
++   This allows very big messages to be parsed without loading the whole
++   message data into memory.
++
+ 2010-11-16  Vincent Richard  <vincent@vincent-richard.net>
+ 
+  * Started version 0.9.2.
+diff --git a/SConstruct b/SConstruct
+index ea5c4eb..2690172 100644
+--- a/SConstruct
++++ b/SConstruct
+@@ -153,11 +153,14 @@ libvmime_sources = [
+ 	'utility/inputStreamSocketAdapter.cpp', 'utility/inputStreamSocketAdapter.hpp',
+ 	'utility/inputStreamStringAdapter.cpp', 'utility/inputStreamStringAdapter.hpp',
+ 	'utility/inputStreamStringProxyAdapter.cpp', 'utility/inputStreamStringProxyAdapter.hpp',
++	'utility/seekableInputStream.hpp',
++	'utility/seekableInputStreamRegionAdapter.cpp', 'utility/seekableInputStreamRegionAdapter.hpp',
+ 	'utility/outputStream.cpp', 'utility/outputStream.hpp',
+ 	'utility/outputStreamAdapter.cpp', 'utility/outputStreamAdapter.hpp',
+ 	'utility/outputStreamByteArrayAdapter.cpp', 'utility/outputStreamByteArrayAdapter.hpp',
+ 	'utility/outputStreamSocketAdapter.cpp', 'utility/outputStreamSocketAdapter.hpp',
+ 	'utility/outputStreamStringAdapter.cpp', 'utility/outputStreamStringAdapter.hpp',
++	'utility/parserInputStreamAdapter.cpp', 'utility/parserInputStreamAdapter.hpp',
+ 	'utility/stringProxy.cpp', 'utility/stringProxy.hpp',
+ 	'utility/stringUtils.cpp', 'utility/stringUtils.hpp',
+ 	'utility/url.cpp', 'utility/url.hpp',
+diff --git a/src/addressList.cpp b/src/addressList.cpp
+index 31a2a3d..f06460d 100644
+--- a/src/addressList.cpp
++++ b/src/addressList.cpp
+@@ -50,7 +50,7 @@ addressList::~addressList()
+ }
+ 
+ 
+-void addressList::parse(const string& buffer, const string::size_type position,
++void addressList::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	removeAllAddresses();
+@@ -72,7 +72,7 @@ void addressList::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void addressList::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void addressList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	string::size_type pos = curLinePos;
+@@ -248,9 +248,9 @@ const std::vector <ref <address> > addressList::getAddressList()
+ }
+ 
+ 
+-const std::vector <ref <const component> > addressList::getChildComponents() const
++const std::vector <ref <component> > addressList::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	copy_vector(m_list, list);
+ 
+diff --git a/src/body.cpp b/src/body.cpp
+index 9d7d57f..732fa8b 100644
+--- a/src/body.cpp
++++ b/src/body.cpp
+@@ -31,10 +31,13 @@
+ 
+ #include "vmime/utility/random.hpp"
+ 
++#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
++
+ #include "vmime/parserHelpers.hpp"
+ 
+ #include "vmime/emptyContentHandler.hpp"
+ #include "vmime/stringContentHandler.hpp"
++#include "vmime/streamContentHandler.hpp"
+ 
+ 
+ namespace vmime
+@@ -52,11 +55,28 @@ body::~body()
+ }
+ 
+ 
+-void body::parse(const string& buffer, const string::size_type position,
+-	const string::size_type end, string::size_type* newPosition)
++void body::parseImpl
++	(ref <utility::parserInputStreamAdapter> parser,
++	 const utility::stream::size_type position,
++	 const utility::stream::size_type end,
++	 utility::stream::size_type* newPosition)
+ {
+ 	removeAllParts();
+ 
++	m_prologText.clear();
++	m_epilogText.clear();
++
++	if (end == position)
++	{
++
++		setParsedBounds(position, end);
++
++		if (newPosition)
++			*newPosition = end;
++
++		return;
++	}
++
+ 	// Check whether the body is a MIME-multipart
+ 	bool isMultipart = false;
+ 	string boundary;
+@@ -80,37 +100,61 @@ void body::parse(const string& buffer, const string::size_type position,
+ 			{
+ 				// No "boundary" parameter specified: we can try to
+ 				// guess it by scanning the body contents...
+-				string::size_type pos = buffer.find("\n--", position);
++				utility::stream::size_type pos = position;
++
++				parser->seek(pos);
++
++				if (pos + 2 < end && parser->matchBytes("--", 2))
++				{
++					pos += 2;
++				}
++				else
++				{
++					pos = parser->findNext("\n--", position);
+ 
+-				if ((pos != string::npos) && (pos < end))
++					if ((pos != utility::stream::npos) && (pos + 3 < end))
++						pos += 3;  // skip \n--
++				}
++
++				if ((pos != utility::stream::npos) && (pos < end))
+ 				{
+-					pos += 3;
++					parser->seek(pos);
+ 
+-					const string::size_type start = pos;
++					// Read some bytes after boundary separator
++					utility::stream::value_type buffer[256];
++					const utility::stream::size_type bufferLen =
++						parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0])));
+ 
+-					char_t c = buffer[pos];
+-					string::size_type length = 0;
++					buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';
+ 
++					// Extract boundary from buffer (stop at first CR or LF).
+ 					// We have to stop after a reasonnably long boundary length (100)
+ 					// not to take the whole body contents for a boundary...
+-					while (pos < end && length < 100 && !(c == '\r' || c == '\n'))
++					string::value_type boundaryBytes[100];
++					string::size_type boundaryLen = 0;
++
++					for (string::value_type c = buffer[0] ;
++					     boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ;
++					     c = buffer[++boundaryLen])
+ 					{
+-						++length;
+-						c = buffer[pos++];
++						boundaryBytes[boundaryLen] = buffer[boundaryLen];
+ 					}
+ 
+-					if (pos < end && length < 100)
++					if (boundaryLen >= 1 && boundaryLen < 100)
+ 					{
+ 						// RFC #1521, Page 31:
+ 						// "...the boundary parameter, which consists of 1 to 70
+ 						//  characters from a set of characters known to be very
+ 						//  robust through email gateways, and NOT ending with
+ 						//  white space..."
+-						while (pos != start && parserHelpers::isSpace(buffer[pos - 1]))
+-							--pos;
+-
+-						boundary = string(buffer.begin() + start,
+-						                  buffer.begin() + pos);
++						while (boundaryLen != 0 &&
++						       parserHelpers::isSpace(boundaryBytes[boundaryLen - 1]))
++						{
++							boundaryLen--;
++						}
++
++						if (boundaryLen >= 1)
++							boundary = string(boundaryBytes, boundaryBytes + boundaryLen);
+ 					}
+ 				}
+ 			}
+@@ -126,51 +170,79 @@ void body::parse(const string& buffer, const string::size_type position,
+ 	{
+ 		const string boundarySep("--" + boundary);
+ 
+-		string::size_type partStart = position;
+-		string::size_type pos = position;
++		utility::stream::size_type partStart = position;
++		utility::stream::size_type pos = position;
+ 
+ 		bool lastPart = false;
+ 
+-		while (pos != string::npos && pos < end)
++		while (pos != utility::stream::npos && pos < end)
+ 		{
+-			pos = buffer.find(boundarySep, pos);
+-
+-			if (pos == string::npos ||
+-			    ((pos == 0 || buffer[pos - 1] == '\n') &&
+-			     (buffer[pos + boundarySep.length()] == '\r' ||
+-			      buffer[pos + boundarySep.length()] == '\n' ||
+-			      buffer[pos + boundarySep.length()] == '-'
+-			     )
+-			    )
+-			   )
++			pos = parser->findNext(boundarySep, pos);
++
++			if (pos == utility::stream::npos)
++				break;  // not found
++
++			if (pos != 0)
+ 			{
+-				break;
++				parser->seek(pos - 1);
++
++				if (parser->peekByte() != '\n')
++				{
++					// Boundary is not at a beginning of a line
++					pos++;
++					continue;
++				}
++
++				parser->skip(1 + boundarySep.length());
++			}
++			else
++			{
++				parser->seek(pos + boundarySep.length());
+ 			}
+ 
+-			// boundary not a beginning of line, or just a prefix of another, continue the search.
++			const utility::stream::value_type next = parser->peekByte();
++
++			if (next == '\r' || next == '\n' || next == '-')
++				break;
++
++			// Boundary is a prefix of another, continue the search
+ 			pos++;
+ 		}
+ 
+-		if (pos != string::npos && pos < end)
++		if (pos != utility::stream::npos && pos < end)
+ 		{
+ 			vmime::text text;
+-			text.parse(buffer, position, pos);
++			text.parse(parser, position, pos);
+ 
+ 			m_prologText = text.getWholeBuffer();
+ 		}
+ 
+-		for (int index = 0 ; !lastPart && (pos != string::npos) && (pos < end) ; ++index)
++		for (int index = 0 ; !lastPart && (pos != utility::stream::npos) && (pos < end) ; ++index)
+ 		{
+-			string::size_type partEnd = pos;
++			utility::stream::size_type partEnd = pos;
+ 
+ 			// Get rid of the [CR]LF just before the boundary string
+-			if (pos >= (position + 1) && buffer[pos - 1] == '\n') --partEnd;
+-			if (pos >= (position + 2) && buffer[pos - 2] == '\r') --partEnd;
++			if (pos >= (position + 1))
++			{
++				parser->seek(pos - 1);
++
++				if (parser->peekByte() == '\n')
++					--partEnd;
++			}
++
++			if (pos >= (position + 2))
++			{
++				parser->seek(pos - 2);
++
++				if (parser->peekByte() == '\r')
++					--partEnd;
++			}
+ 
+ 			// Check whether it is the last part (boundary terminated by "--")
+ 			pos += boundarySep.length();
++			parser->seek(pos);
+ 
+-			if (pos + 1 < end && buffer[pos] == '-' && buffer[pos + 1] == '-')
++			if (pos + 1 < end && parser->matchBytes("--", 2))
+ 			{
+ 				lastPart = true;
+ 				pos += 2;
+@@ -180,15 +252,15 @@ void body::parse(const string& buffer, const string::size_type position,
+ 			// "...(If a boundary appears to end with white space, the
+ 			//  white space must be presumed to have been added by a
+ 			//  gateway, and must be deleted.)..."
+-			while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t'))
+-				++pos;
++			parser->seek(pos);
++			pos += parser->skipIf(parserHelpers::isSpaceOrTab, end);
+ 
+ 			// End of boundary line
+-			if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] =='\n')
++			if (pos + 1 < end && parser->matchBytes("\r\n", 2))
+ 			{
+ 				pos += 2;
+ 			}
+-			else if (pos < end && buffer[pos] == '\n')
++			else if (pos < end && parser->peekByte() == '\n')
+ 			{
+ 				++pos;
+ 			}
+@@ -202,7 +274,7 @@ void body::parse(const string& buffer, const string::size_type position,
+ 				if (partEnd < partStart)
+ 					std::swap(partStart, partEnd);
+ 
+-				part->parse(buffer, partStart, partEnd, NULL);
++				part->parse(parser, partStart, partEnd, NULL);
+ 				part->m_parent = m_part;
+ 
+ 				m_parts.push_back(part);
+@@ -210,23 +282,37 @@ void body::parse(const string& buffer, const string::size_type position,
+ 
+ 			partStart = pos;
+ 
+-			while (pos != string::npos && pos < end)
++			while (pos != utility::stream::npos && pos < end)
+ 			{
+-				pos = buffer.find(boundarySep, pos);
+-
+-				if (pos == string::npos ||
+-				    ((pos == 0 || buffer[pos - 1] == '\n') &&
+-				     (buffer[pos + boundarySep.length()] == '\r' ||
+-				      buffer[pos + boundarySep.length()] == '\n' ||
+-					buffer[pos + boundarySep.length()] == '-'
+-				     )
+-				    )
+-				   )
++				pos = parser->findNext(boundarySep, pos);
++
++				if (pos == utility::stream::npos)
++					break;  // not found
++
++				if (pos != 0)
+ 				{
+-					break;
++					parser->seek(pos - 1);
++
++					if (parser->peekByte() != '\n')
++					{
++						// Boundary is not at a beginning of a line
++						pos++;
++						continue;
++					}
++
++					parser->skip(1 + boundarySep.length());
++				}
++				else
++				{
++					parser->seek(pos + boundarySep.length());
+ 				}
+ 
+-				// boundary not a beginning of line, or just a prefix of another, continue the search.
++				const utility::stream::value_type next = parser->peekByte();
++
++				if (next == '\r' || next == '\n' || next == '-')
++					break;
++
++				// Boundary is a prefix of another, continue the search
+ 				pos++;
+ 			}
+ 		}
+@@ -234,13 +320,13 @@ void body::parse(const string& buffer, const string::size_type position,
+ 		m_contents = vmime::create <emptyContentHandler>();
+ 
+ 		// Last part was not found: recover from missing boundary
+-		if (!lastPart && pos == string::npos)
++		if (!lastPart && pos == utility::stream::npos)
+ 		{
+ 			ref <bodyPart> part = vmime::create <bodyPart>();
+ 
+ 			try
+ 			{
+-				part->parse(buffer, partStart, end);
++				part->parse(parser, partStart, end);
+ 			}
+ 			catch (std::exception&)
+ 			{
+@@ -255,7 +341,7 @@ void body::parse(const string& buffer, const string::size_type position,
+ 		else if (partStart < end)
+ 		{
+ 			vmime::text text;
+-			text.parse(buffer, partStart, end);
++			text.parse(parser, partStart, end);
+ 
+ 			m_epilogText = text.getWholeBuffer();
+ 		}
+@@ -282,7 +368,13 @@ void body::parse(const string& buffer, const string::size_type position,
+ 		}
+ 
+ 		// Extract the (encoded) contents
+-		m_contents = vmime::create <stringContentHandler>(buffer, position, end, enc);
++		const utility::stream::size_type length = end - position;
++
++		ref <utility::inputStream> contentStream =
++			vmime::create <utility::seekableInputStreamRegionAdapter>
++				(parser->getUnderlyingStream(), position, length);
++
++		m_contents = vmime::create <streamContentHandler>(contentStream, length, enc);
+ 	}
+ 
+ 	setParsedBounds(position, end);
+@@ -292,7 +384,7 @@ void body::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void body::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void body::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+ {
+ 	// MIME-Multipart
+@@ -862,9 +954,9 @@ const std::vector <ref <bodyPart> > body::getPartList()
+ }
+ 
+ 
+-const std::vector <ref <const component> > body::getChildComponents() const
++const std::vector <ref <component> > body::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	copy_vector(m_parts, list);
+ 
+diff --git a/src/bodyPart.cpp b/src/bodyPart.cpp
+index 7d60461..522cbb2 100644
+--- a/src/bodyPart.cpp
++++ b/src/bodyPart.cpp
+@@ -46,15 +46,18 @@ bodyPart::bodyPart(weak_ref <vmime::bodyPart> parentPart)
+ }
+ 
+ 
+-void bodyPart::parse(const string& buffer, const string::size_type position,
+-	const string::size_type end, string::size_type* newPosition)
++void bodyPart::parseImpl
++	(ref <utility::parserInputStreamAdapter> parser,
++	 const utility::stream::size_type position,
++	 const utility::stream::size_type end,
++	 utility::stream::size_type* newPosition)
+ {
+ 	// Parse the headers
+ 	string::size_type pos = position;
+-	m_header->parse(buffer, pos, end, &pos);
++	m_header->parse(parser, pos, end, &pos);
+ 
+ 	// Parse the body contents
+-	m_body->parse(buffer, pos, end, NULL);
++	m_body->parse(parser, pos, end, NULL);
+ 
+ 	setParsedBounds(position, end);
+ 
+@@ -63,7 +66,7 @@ void bodyPart::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void bodyPart::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void bodyPart::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+ {
+ 	m_header->generate(os, maxLineLength);
+@@ -142,9 +145,9 @@ ref <const bodyPart> bodyPart::getParentPart() const
+ }
+ 
+ 
+-const std::vector <ref <const component> > bodyPart::getChildComponents() const
++const std::vector <ref <component> > bodyPart::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	list.push_back(m_header);
+ 	list.push_back(m_body);
+diff --git a/src/charset.cpp b/src/charset.cpp
+index 0fda450..705664f 100644
+--- a/src/charset.cpp
++++ b/src/charset.cpp
+@@ -57,7 +57,7 @@ charset::charset(const char* name)
+ }
+ 
+ 
+-void charset::parse(const string& buffer, const string::size_type position,
++void charset::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	m_name = utility::stringUtils::trim
+@@ -74,7 +74,7 @@ void charset::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void charset::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
++void charset::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	os << m_name;
+@@ -142,9 +142,9 @@ void charset::copyFrom(const component& other)
+ }
+ 
+ 
+-const std::vector <ref <const component> > charset::getChildComponents() const
++const std::vector <ref <component> > charset::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/component.cpp b/src/component.cpp
+index 139cf66..e93aacf 100644
+--- a/src/component.cpp
++++ b/src/component.cpp
+@@ -23,6 +23,9 @@
+ 
+ #include "vmime/component.hpp"
+ #include "vmime/base.hpp"
++
++#include "vmime/utility/streamUtils.hpp"
++#include "vmime/utility/inputStreamStringAdapter.hpp"
+ #include "vmime/utility/outputStreamAdapter.hpp"
+ 
+ #include <sstream>
+@@ -43,9 +46,102 @@ component::~component()
+ }
+ 
+ 
++void component::parse
++	(ref <utility::inputStream> inputStream, const utility::stream::size_type length)
++{
++	parse(inputStream, 0, length, NULL);
++}
++
++
++void component::parse
++	(ref <utility::inputStream> inputStream, const utility::stream::size_type position,
++	 const utility::stream::size_type end, utility::stream::size_type* newPosition)
++{
++	m_parsedOffset = m_parsedLength = 0;
++
++	ref <utility::seekableInputStream> seekableStream =
++		inputStream.dynamicCast <utility::seekableInputStream>();
++
++	if (seekableStream == NULL || end == 0)
++	{
++		// Read the whole stream into a buffer
++		std::ostringstream oss;
++		utility::outputStreamAdapter ossAdapter(oss);
++
++		utility::bufferedStreamCopyRange(*inputStream, ossAdapter, position, end - position);
++
++		const string buffer = oss.str();
++		parseImpl(buffer, 0, buffer.length(), NULL);
++	}
++	else
++	{
++		ref <utility::parserInputStreamAdapter> parser =
++			vmime::create <utility::parserInputStreamAdapter>(seekableStream);
++
++		parseImpl(parser, position, end, newPosition);
++	}
++}
++
++
+ void component::parse(const string& buffer)
+ {
+-	parse(buffer, 0, buffer.length(), NULL);
++	m_parsedOffset = m_parsedLength = 0;
++
++	parseImpl(buffer, 0, buffer.length(), NULL);
++}
++
++
++void component::parse
++	(const string& buffer, const string::size_type position,
++	 const string::size_type end, string::size_type* newPosition)
++{
++	m_parsedOffset = m_parsedLength = 0;
++
++	parseImpl(buffer, position, end, newPosition);
++}
++
++
++void component::offsetParsedBounds(const utility::stream::size_type offset)
++{
++	// Offset parsed bounds of this component
++	if (m_parsedLength != 0)
++		m_parsedOffset += offset;
++
++	// Offset parsed bounds of our children
++	std::vector <ref <component> > children = getChildComponents();
++
++	for (unsigned int i = 0, n = children.size() ; i < n ; ++i)
++		children[i]->offsetParsedBounds(offset);
++}
++
++
++void component::parseImpl
++	(ref <utility::parserInputStreamAdapter> parser, const utility::stream::size_type position,
++	 const utility::stream::size_type end, utility::stream::size_type* newPosition)
++{
++	const std::string buffer = parser->extract(position, end);
++	parseImpl(buffer, 0, buffer.length(), newPosition);
++
++	// Recursivey offset parsed bounds on children
++	if (position != 0)
++		offsetParsedBounds(position);
++
++	if (newPosition != NULL)
++		*newPosition += position;
++}
++
++
++void component::parseImpl
++	(const string& buffer, const string::size_type position,
++	 const string::size_type end, string::size_type* newPosition)
++{
++	ref <utility::seekableInputStream> stream =
++		vmime::create <utility::inputStreamStringAdapter>(buffer);
++
++	ref <utility::parserInputStreamAdapter> parser =
++		vmime::create <utility::parserInputStreamAdapter>(stream);
++
++	parseImpl(parser, position, end, newPosition);
+ }
+ 
+ 
+@@ -61,6 +157,26 @@ const string component::generate(const string::size_type maxLineLength,
+ }
+ 
+ 
++void component::generate
++	(utility::outputStream& os,
++	 const string::size_type maxLineLength,
++	 const string::size_type curLinePos,
++	 string::size_type* newLinePos) const
++{
++	generateImpl(os, maxLineLength, curLinePos, newLinePos);
++}
++
++
++void component::generate
++	(ref <utility::outputStream> os,
++	 const string::size_type maxLineLength,
++	 const string::size_type curLinePos,
++	 string::size_type* newLinePos) const
++{
++	generateImpl(*os, maxLineLength, curLinePos, newLinePos);
++}
++
++
+ string::size_type component::getParsedOffset() const
+ {
+ 	return (m_parsedOffset);
+@@ -80,22 +196,5 @@ void component::setParsedBounds(const string::size_type start, const string::siz
+ }
+ 
+ 
+-const std::vector <ref <component> > component::getChildComponents()
+-{
+-	const std::vector <ref <const component> > constList =
+-		const_cast <const component*>(this)->getChildComponents();
+-
+-	std::vector <ref <component> > list;
+-
+-	const std::vector <ref <const component> >::size_type count = constList.size();
++} // vmime
+ 
+-	list.resize(count);
+-
+-	for (std::vector <ref <const component> >::size_type i = 0 ; i < count ; ++i)
+-		list[i] = constList[i].constCast <component>();
+-
+-	return (list);
+-}
+-
+-
+-}
+diff --git a/src/contentDisposition.cpp b/src/contentDisposition.cpp
+index 0ab7c45..253dbba 100644
+--- a/src/contentDisposition.cpp
++++ b/src/contentDisposition.cpp
+@@ -47,7 +47,7 @@ contentDisposition::contentDisposition(const contentDisposition& type)
+ }
+ 
+ 
+-void contentDisposition::parse(const string& buffer, const string::size_type position,
++void contentDisposition::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	m_name = utility::stringUtils::trim(utility::stringUtils::toLower
+@@ -60,7 +60,7 @@ void contentDisposition::parse(const string& buffer, const string::size_type pos
+ }
+ 
+ 
+-void contentDisposition::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
++void contentDisposition::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	os << m_name;
+@@ -122,9 +122,9 @@ void contentDisposition::setName(const string& name)
+ }
+ 
+ 
+-const std::vector <ref <const component> > contentDisposition::getChildComponents() const
++const std::vector <ref <component> > contentDisposition::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/dateTime.cpp b/src/dateTime.cpp
+index 089a900..0d97b2f 100644
+--- a/src/dateTime.cpp
++++ b/src/dateTime.cpp
+@@ -67,7 +67,7 @@ zone = "UT" / "GMT"                               ; Universal Time
+ */
+ 
+ 
+-void datetime::parse(const string& buffer, const string::size_type position,
++void datetime::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -588,7 +588,7 @@ void datetime::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void datetime::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
++void datetime::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	static const string::value_type* dayNames[] =
+@@ -784,9 +784,9 @@ ref <component> datetime::clone() const
+ }
+ 
+ 
+-const std::vector <ref <const component> > datetime::getChildComponents() const
++const std::vector <ref <component> > datetime::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/disposition.cpp b/src/disposition.cpp
+index b8059a7..24a4579 100644
+--- a/src/disposition.cpp
++++ b/src/disposition.cpp
+@@ -79,9 +79,9 @@ disposition& disposition::operator=(const disposition& other)
+ }
+ 
+ 
+-const std::vector <ref <const component> > disposition::getChildComponents() const
++const std::vector <ref <component> > disposition::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+@@ -171,7 +171,7 @@ const std::vector <string> disposition::getModifierList() const
+ }
+ 
+ 
+-void disposition::parse(const string& buffer, const string::size_type position,
++void disposition::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	// disposition-mode ";" disposition-type
+@@ -276,7 +276,7 @@ void disposition::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void disposition::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void disposition::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	string::size_type pos = curLinePos;
+diff --git a/src/encoding.cpp b/src/encoding.cpp
+index 5d99ab6..343a822 100644
+--- a/src/encoding.cpp
++++ b/src/encoding.cpp
+@@ -61,7 +61,7 @@ encoding::encoding(const encoding& enc)
+ }
+ 
+ 
+-void encoding::parse(const string& buffer, const string::size_type position,
++void encoding::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	m_usage = USAGE_UNKNOWN;
+@@ -80,7 +80,7 @@ void encoding::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void encoding::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
++void encoding::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	os << m_name;
+@@ -268,9 +268,9 @@ void encoding::setUsage(const EncodingUsage usage)
+ }
+ 
+ 
+-const std::vector <ref <const component> > encoding::getChildComponents() const
++const std::vector <ref <component> > encoding::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/header.cpp b/src/header.cpp
+index 443aab8..fcdca2c 100644
+--- a/src/header.cpp
++++ b/src/header.cpp
+@@ -61,7 +61,7 @@ field-body-contents =
+ 		 specials tokens, or else consisting of texts>
+ */
+ 
+-void header::parse(const string& buffer, const string::size_type position,
++void header::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	string::size_type pos = position;
+@@ -83,7 +83,7 @@ void header::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void header::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void header::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type /* curLinePos */, string::size_type* newLinePos) const
+ {
+ 	// Generate the fields
+@@ -337,9 +337,9 @@ const std::vector <ref <headerField> > header::getFieldList()
+ }
+ 
+ 
+-const std::vector <ref <const component> > header::getChildComponents() const
++const std::vector <ref <component> > header::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	copy_vector(m_fields, list);
+ 
+diff --git a/src/headerField.cpp b/src/headerField.cpp
+index d1d4236..a8460aa 100644
+--- a/src/headerField.cpp
++++ b/src/headerField.cpp
+@@ -262,14 +262,14 @@ ref <headerField> headerField::parseNext(const string& buffer, const string::siz
+ }
+ 
+ 
+-void headerField::parse(const string& buffer, const string::size_type position, const string::size_type end,
++void headerField::parseImpl(const string& buffer, const string::size_type position, const string::size_type end,
+ 	string::size_type* newPosition)
+ {
+ 	m_value->parse(buffer, position, end, newPosition);
+ }
+ 
+ 
+-void headerField::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void headerField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	os << m_name + ": ";
+@@ -296,9 +296,9 @@ bool headerField::isCustom() const
+ }
+ 
+ 
+-const std::vector <ref <const component> > headerField::getChildComponents() const
++const std::vector <ref <component> > headerField::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	if (m_value)
+ 		list.push_back(m_value);
+diff --git a/src/mailbox.cpp b/src/mailbox.cpp
+index fea7479..dfdccad 100644
+--- a/src/mailbox.cpp
++++ b/src/mailbox.cpp
+@@ -65,7 +65,7 @@ angle-addr      =       [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+ 
+ */
+ 
+-void mailbox::parse(const string& buffer, const string::size_type position,
++void mailbox::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -343,7 +343,7 @@ void mailbox::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void mailbox::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void mailbox::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	if (m_name.isEmpty())
+@@ -514,9 +514,9 @@ void mailbox::setEmail(const string& email)
+ }
+ 
+ 
+-const std::vector <ref <const component> > mailbox::getChildComponents() const
++const std::vector <ref <component> > mailbox::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/mailboxGroup.cpp b/src/mailboxGroup.cpp
+index 94f7ba6..c37444a 100644
+--- a/src/mailboxGroup.cpp
++++ b/src/mailboxGroup.cpp
+@@ -54,7 +54,7 @@ mailboxGroup::~mailboxGroup()
+ }
+ 
+ 
+-void mailboxGroup::parse(const string& buffer, const string::size_type position,
++void mailboxGroup::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -111,7 +111,7 @@ void mailboxGroup::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void mailboxGroup::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void mailboxGroup::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	// We have to encode the name:
+@@ -348,9 +348,9 @@ const std::vector <ref <mailbox> > mailboxGroup::getMailboxList()
+ }
+ 
+ 
+-const std::vector <ref <const component> > mailboxGroup::getChildComponents() const
++const std::vector <ref <component> > mailboxGroup::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	copy_vector(m_list, list);
+ 
+diff --git a/src/mailboxList.cpp b/src/mailboxList.cpp
+index 0023d9d..f87fb48 100644
+--- a/src/mailboxList.cpp
++++ b/src/mailboxList.cpp
+@@ -190,20 +190,20 @@ mailboxList& mailboxList::operator=(const mailboxList& other)
+ }
+ 
+ 
+-const std::vector <ref <const component> > mailboxList::getChildComponents() const
++const std::vector <ref <component> > mailboxList::getChildComponents()
+ {
+ 	return (m_list.getChildComponents());
+ }
+ 
+ 
+-void mailboxList::parse(const string& buffer, const string::size_type position,
++void mailboxList::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	m_list.parse(buffer, position, end, newPosition);
+ }
+ 
+ 
+-void mailboxList::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void mailboxList::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	m_list.generate(os, maxLineLength, curLinePos, newLinePos);
+diff --git a/src/mediaType.cpp b/src/mediaType.cpp
+index 725f933..627b276 100644
+--- a/src/mediaType.cpp
++++ b/src/mediaType.cpp
+@@ -48,7 +48,7 @@ mediaType::mediaType(const string& type, const string& subType)
+ }
+ 
+ 
+-void mediaType::parse(const string& buffer, const string::size_type position,
++void mediaType::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -82,7 +82,7 @@ void mediaType::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void mediaType::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void mediaType::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	const string value = m_type + "/" + m_subType;
+@@ -176,9 +176,9 @@ void mediaType::setFromString(const string& type)
+ }
+ 
+ 
+-const std::vector <ref <const component> > mediaType::getChildComponents() const
++const std::vector <ref <component> > mediaType::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/message.cpp b/src/message.cpp
+index 1b4f086..3fa9b6a 100644
+--- a/src/message.cpp
++++ b/src/message.cpp
+@@ -61,9 +61,14 @@ const string message::generate(const string::size_type maxLineLength,
+ }
+ 
+ 
+-void message::parse(const string& buffer)
++
++void message::generate
++	(ref <utility::outputStream> os,
++	 const string::size_type maxLineLength,
++	 const string::size_type curLinePos,
++	 string::size_type* newLinePos) const
+ {
+-	bodyPart::parse(buffer);
++	bodyPart::generate(os, maxLineLength, curLinePos, newLinePos);
+ }
+ 
+ 
+diff --git a/src/messageId.cpp b/src/messageId.cpp
+index 961fb63..1f4b186 100644
+--- a/src/messageId.cpp
++++ b/src/messageId.cpp
+@@ -61,7 +61,7 @@ messageId::messageId(const string& left, const string& right)
+ 	msg-id          =       [CFWS] "<" id-left "@" id-right ">" [CFWS]
+ */
+ 
+-void messageId::parse(const string& buffer, const string::size_type position,
++void messageId::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -185,7 +185,7 @@ const string messageId::getId() const
+ }
+ 
+ 
+-void messageId::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void messageId::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	string::size_type pos = curLinePos;
+@@ -288,9 +288,9 @@ void messageId::setRight(const string& right)
+ }
+ 
+ 
+-const std::vector <ref <const component> > messageId::getChildComponents() const
++const std::vector <ref <component> > messageId::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/messageIdSequence.cpp b/src/messageIdSequence.cpp
+index 08103d0..0a5c9a0 100644
+--- a/src/messageIdSequence.cpp
++++ b/src/messageIdSequence.cpp
+@@ -74,9 +74,9 @@ messageIdSequence& messageIdSequence::operator=(const messageIdSequence& other)
+ }
+ 
+ 
+-const std::vector <ref <const component> > messageIdSequence::getChildComponents() const
++const std::vector <ref <component> > messageIdSequence::getChildComponents()
+ {
+-	std::vector <ref <const component> > res;
++	std::vector <ref <component> > res;
+ 
+ 	copy_vector(m_list, res);
+ 
+@@ -84,7 +84,7 @@ const std::vector <ref <const component> > messageIdSequence::getChildComponents
+ }
+ 
+ 
+-void messageIdSequence::parse(const string& buffer, const string::size_type position,
++void messageIdSequence::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	removeAllMessageIds();
+@@ -106,7 +106,7 @@ void messageIdSequence::parse(const string& buffer, const string::size_type posi
+ }
+ 
+ 
+-void messageIdSequence::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void messageIdSequence::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	string::size_type pos = curLinePos;
+diff --git a/src/parameter.cpp b/src/parameter.cpp
+index ccbe1a5..58d9a3e 100644
+--- a/src/parameter.cpp
++++ b/src/parameter.cpp
+@@ -36,19 +36,19 @@ namespace vmime
+ 
+ 
+ parameter::parameter(const string& name)
+-	: m_name(name)
++	: m_name(name), m_value(vmime::create <word>())
+ {
+ }
+ 
+ 
+ parameter::parameter(const string& name, const word& value)
+-	: m_name(name), m_value(value)
++	: m_name(name), m_value(vmime::create <word>(value))
+ {
+ }
+ 
+ 
+ parameter::parameter(const string& name, const string& value)
+-	: m_name(name), m_value(value)
++	: m_name(name), m_value(vmime::create <word>(value))
+ {
+ }
+ 
+@@ -73,7 +73,7 @@ void parameter::copyFrom(const component& other)
+ 	const parameter& param = dynamic_cast <const parameter&>(other);
+ 
+ 	m_name = param.m_name;
+-	m_value.copyFrom(param.m_value);
++	m_value->copyFrom(*param.m_value);
+ }
+ 
+ 
+@@ -92,7 +92,7 @@ const string& parameter::getName() const
+ 
+ const word& parameter::getValue() const
+ {
+-	return m_value;
++	return *m_value;
+ }
+ 
+ 
+@@ -109,15 +109,15 @@ void parameter::setValue(const component& value)
+ 
+ void parameter::setValue(const word& value)
+ {
+-	m_value = value;
++	*m_value = value;
+ }
+ 
+ 
+-void parameter::parse(const string& buffer, const string::size_type position,
++void parameter::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+-	m_value.setBuffer(string(buffer.begin() + position, buffer.begin() + end));
+-	m_value.setCharset(charset(charsets::US_ASCII));
++	m_value->setBuffer(string(buffer.begin() + position, buffer.begin() + end));
++	m_value->setCharset(charset(charsets::US_ASCII));
+ 
+ 	if (newPosition)
+ 		*newPosition = end;
+@@ -248,16 +248,16 @@ void parameter::parse(const std::vector <valueChunk>& chunks)
+ 		}
+ 	}
+ 
+-	m_value.setBuffer(value.str());
+-	m_value.setCharset(ch);
++	m_value->setBuffer(value.str());
++	m_value->setCharset(ch);
+ }
+ 
+ 
+-void parameter::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void parameter::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	const string& name = m_name;
+-	const string& value = m_value.getBuffer();
++	const string& value = m_value->getBuffer();
+ 
+ 	// For compatibility with implementations that do not understand RFC-2231,
+ 	// also generate a normal "7bit/us-ascii" parameter
+@@ -344,7 +344,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
+ 	// 7-bit (ASCII) bytes in the input will be used to determine if
+ 	// we need to encode the whole buffer.
+ 	encoding recommendedEnc;
+-	const bool alwaysEncode = m_value.getCharset().getRecommendedEncoding(recommendedEnc);
++	const bool alwaysEncode = m_value->getCharset().getRecommendedEncoding(recommendedEnc);
+ 	bool extended = alwaysEncode;
+ 
+ 	if (needQuotedPrintable)
+@@ -352,7 +352,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
+ 		// Send the name in quoted-printable, so outlook express et.al.
+ 		// will understand the real filename
+ 		size_t oldLen = sevenBitBuffer.length();
+-		m_value.generate(sevenBitStream);
++		m_value->generate(sevenBitStream);
+ 		pos += sevenBitBuffer.length() - oldLen;
+ 		extended = true;		// also send with RFC-2231 encoding
+ 	}
+@@ -429,7 +429,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
+ 		// + at least 5 characters for the value
+ 		const string::size_type firstSectionLength =
+ 			  name.length() + 4 /* *0*= */ + 2 /* '' */
+-			+ m_value.getCharset().getName().length();
++			+ m_value->getCharset().getName().length();
+ 
+ 		if (pos + firstSectionLength + 5 >= maxLineLength)
+ 		{
+@@ -539,7 +539,7 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
+ 
+ 			if (sectionNumber == 0)
+ 			{
+-				os << m_value.getCharset().getName();
++				os << m_value->getCharset().getName();
+ 				os << '\'' << /* No language */ '\'';
+ 			}
+ 
+@@ -570,11 +570,11 @@ void parameter::generate(utility::outputStream& os, const string::size_type maxL
+ }
+ 
+ 
+-const std::vector <ref <const component> > parameter::getChildComponents() const
++const std::vector <ref <component> > parameter::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+-	list.push_back(ref <const component>::fromPtr(&m_value));
++	list.push_back(m_value);
+ 
+ 	return list;
+ }
+diff --git a/src/parameterizedHeaderField.cpp b/src/parameterizedHeaderField.cpp
+index 464990e..756d02f 100644
+--- a/src/parameterizedHeaderField.cpp
++++ b/src/parameterizedHeaderField.cpp
+@@ -78,7 +78,7 @@ struct paramInfo
+ #endif // VMIME_BUILDING_DOC
+ 
+ 
+-void parameterizedHeaderField::parse(const string& buffer, const string::size_type position,
++void parameterizedHeaderField::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -328,13 +328,13 @@ void parameterizedHeaderField::parse(const string& buffer, const string::size_ty
+ }
+ 
+ 
+-void parameterizedHeaderField::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void parameterizedHeaderField::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	string::size_type pos = curLinePos;
+ 
+ 	// Parent header field
+-	headerField::generate(os, maxLineLength, pos, &pos);
++	headerField::generateImpl(os, maxLineLength, pos, &pos);
+ 
+ 	// Parameters
+ 	for (std::vector <ref <parameter> >::const_iterator
+@@ -552,11 +552,11 @@ const std::vector <ref <parameter> > parameterizedHeaderField::getParameterList(
+ }
+ 
+ 
+-const std::vector <ref <const component> > parameterizedHeaderField::getChildComponents() const
++const std::vector <ref <component> > parameterizedHeaderField::getChildComponents()
+ {
+-	std::vector <ref <const component> > list = headerField::getChildComponents();
++	std::vector <ref <component> > list = headerField::getChildComponents();
+ 
+-	for (std::vector <ref <parameter> >::const_iterator it = m_params.begin() ;
++	for (std::vector <ref <parameter> >::iterator it = m_params.begin() ;
+ 	     it != m_params.end() ; ++it)
+ 	{
+ 		list.push_back(*it);
+diff --git a/src/path.cpp b/src/path.cpp
+index 37a4090..d92bb0a 100644
+--- a/src/path.cpp
++++ b/src/path.cpp
+@@ -106,14 +106,14 @@ path& path::operator=(const path& other)
+ }
+ 
+ 
+-const std::vector <ref <const component> > path::getChildComponents() const
++const std::vector <ref <component> > path::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+-void path::parse(const string& buffer, const string::size_type position,
+-                 const string::size_type end, string::size_type* newPosition)
++void path::parseImpl(const string& buffer, const string::size_type position,
++	const string::size_type end, string::size_type* newPosition)
+ {
+ 	string::size_type pos = position;
+ 
+@@ -165,8 +165,8 @@ void path::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void path::generate(utility::outputStream& os, const string::size_type /* maxLineLength */,
+-                    const string::size_type curLinePos, string::size_type* newLinePos) const
++void path::generateImpl(utility::outputStream& os, const string::size_type /* maxLineLength */,
++	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	if (m_localPart.empty() && m_domain.empty())
+ 	{
+diff --git a/src/platforms/posix/posixFile.cpp b/src/platforms/posix/posixFile.cpp
+index ec529eb..4087a21 100644
+--- a/src/platforms/posix/posixFile.cpp
++++ b/src/platforms/posix/posixFile.cpp
+@@ -224,6 +224,26 @@ vmime::utility::stream::size_type posixFileReaderInputStream::skip(const size_ty
+ }
+ 
+ 
++vmime::utility::stream::size_type posixFileReaderInputStream::getPosition() const
++{
++	const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR);
++
++	if (curPos == off_t(-1))
++		posixFileSystemFactory::reportError(m_path, errno);
++
++	return static_cast <size_type>(curPos);
++}
++
++
++void posixFileReaderInputStream::seek(const size_type pos)
++{
++	const off_t newPos = ::lseek(m_fd, pos, SEEK_SET);
++
++	if (newPos == off_t(-1))
++		posixFileSystemFactory::reportError(m_path, errno);
++}
++
++
+ 
+ //
+ // posixFileWriter
+diff --git a/src/platforms/windows/windowsFile.cpp b/src/platforms/windows/windowsFile.cpp
+index 624612a..5da786e 100644
+--- a/src/platforms/windows/windowsFile.cpp
++++ b/src/platforms/windows/windowsFile.cpp
+@@ -479,6 +479,24 @@ vmime::utility::stream::size_type windowsFileReaderInputStream::skip(const size_
+ 	return (dwNewPos - dwCurPos);
+ }
+ 
++vmime::utility::stream::size_type windowsFileReaderInputStream::getPosition() const
++{
++	DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
++
++	if (dwCurPos == INVALID_SET_FILE_POINTER)
++		windowsFileSystemFactory::reportError(m_path, GetLastError());
++
++	return static_cast <size_type>(dwCurPos);
++}
++
++void windowsFileReaderInputStream::seek(const size_type pos)
++{
++	DWORD dwNewPos = SetFilePointer(m_hFile, (LONG)pos, NULL, FILE_BEGIN);
++
++	if (dwNewPos == INVALID_SET_FILE_POINTER)
++		windowsFileSystemFactory::reportError(m_path, GetLastError());
++}
++
+ windowsFileWriter::windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath)
+ : m_path(path), m_nativePath(nativePath)
+ {
+diff --git a/src/relay.cpp b/src/relay.cpp
+index 5cd454f..97f793d 100644
+--- a/src/relay.cpp
++++ b/src/relay.cpp
+@@ -57,7 +57,7 @@ relay::relay(const relay& r)
+                        ["for"  addr-spec]        ; initial form
+ */
+ 
+-void relay::parse(const string& buffer, const string::size_type position,
++void relay::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	const string::value_type* const pend = buffer.data() + end;
+@@ -198,7 +198,7 @@ void relay::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void relay::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void relay::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	std::ostringstream oss;
+@@ -338,10 +338,10 @@ std::vector <string>& relay::getWithList()
+ }
+ 
+ 
+-const std::vector <ref <const component> > relay::getChildComponents() const
++const std::vector <ref <component> > relay::getChildComponents()
+ {
+ 	// TODO: should fields inherit from 'component'? (using typeAdapter)
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/src/streamContentHandler.cpp b/src/streamContentHandler.cpp
+index 89a36b4..14837d2 100644
+--- a/src/streamContentHandler.cpp
++++ b/src/streamContentHandler.cpp
+@@ -25,6 +25,7 @@
+ 
+ #include "vmime/utility/outputStreamAdapter.hpp"
+ #include "vmime/utility/inputStreamStringAdapter.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ #include "vmime/utility/streamUtils.hpp"
+ 
+ 
+@@ -207,6 +208,9 @@ const vmime::encoding& streamContentHandler::getEncoding() const
+ 
+ bool streamContentHandler::isBuffered() const
+ {
++	if (m_stream.dynamicCast <utility::seekableInputStream>() != NULL)
++		return true;
++
+ 	// FIXME: some streams can be resetted
+ 	return false;
+ }
+diff --git a/src/text.cpp b/src/text.cpp
+index 66c3b35..91b81e1 100644
+--- a/src/text.cpp
++++ b/src/text.cpp
+@@ -67,7 +67,7 @@ text::~text()
+ }
+ 
+ 
+-void text::parse(const string& buffer, const string::size_type position,
++void text::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	removeAllWords();
+@@ -85,7 +85,7 @@ void text::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void text::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void text::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	encodeAndFold(os, maxLineLength, curLinePos, newLinePos, 0);
+@@ -389,9 +389,9 @@ text* text::decodeAndUnfold(const string& in, text* generateInExisting)
+ }
+ 
+ 
+-const std::vector <ref <const component> > text::getChildComponents() const
++const std::vector <ref <component> > text::getChildComponents()
+ {
+-	std::vector <ref <const component> > list;
++	std::vector <ref <component> > list;
+ 
+ 	copy_vector(m_words, list);
+ 
+diff --git a/src/utility/inputStreamAdapter.cpp b/src/utility/inputStreamAdapter.cpp
+index b44b084..441307b 100644
+--- a/src/utility/inputStreamAdapter.cpp
++++ b/src/utility/inputStreamAdapter.cpp
+@@ -65,6 +65,18 @@ stream::size_type inputStreamAdapter::skip(const size_type count)
+ }
+ 
+ 
++stream::size_type inputStreamAdapter::getPosition() const
++{
++	return m_stream.tellg();
++}
++
++
++void inputStreamAdapter::seek(const size_type pos)
++{
++	m_stream.seekg(pos, std::ios_base::beg);
++}
++
++
+ } // utility
+ } // vmime
+ 
+diff --git a/src/utility/inputStreamByteBufferAdapter.cpp b/src/utility/inputStreamByteBufferAdapter.cpp
+index 92e779f..907f1ee 100644
+--- a/src/utility/inputStreamByteBufferAdapter.cpp
++++ b/src/utility/inputStreamByteBufferAdapter.cpp
+@@ -85,6 +85,19 @@ stream::size_type inputStreamByteBufferAdapter::skip(const size_type count)
+ }
+ 
+ 
++stream::size_type inputStreamByteBufferAdapter::getPosition() const
++{
++	return m_pos;
++}
++
++
++void inputStreamByteBufferAdapter::seek(const size_type pos)
++{
++	if (pos <= m_length)
++		m_pos = pos;
++}
++
++
+ } // utility
+ } // vmime
+ 
+diff --git a/src/utility/inputStreamStringAdapter.cpp b/src/utility/inputStreamStringAdapter.cpp
+index 31c9fda..9b8fb0c 100644
+--- a/src/utility/inputStreamStringAdapter.cpp
++++ b/src/utility/inputStreamStringAdapter.cpp
+@@ -89,6 +89,19 @@ stream::size_type inputStreamStringAdapter::skip(const size_type count)
+ }
+ 
+ 
++stream::size_type inputStreamStringAdapter::getPosition() const
++{
++	return m_pos - m_begin;
++}
++
++
++void inputStreamStringAdapter::seek(const size_type pos)
++{
++	if (m_begin + pos <= m_end)
++		m_pos = m_begin + pos;
++}
++
++
+ } // utility
+ } // vmime
+ 
+diff --git a/src/utility/inputStreamStringProxyAdapter.cpp b/src/utility/inputStreamStringProxyAdapter.cpp
+index 5e4b60b..feecddd 100644
+--- a/src/utility/inputStreamStringProxyAdapter.cpp
++++ b/src/utility/inputStreamStringProxyAdapter.cpp
+@@ -84,6 +84,19 @@ stream::size_type inputStreamStringProxyAdapter::skip(const size_type count)
+ }
+ 
+ 
++stream::size_type inputStreamStringProxyAdapter::getPosition() const
++{
++	return m_pos;
++}
++
++
++void inputStreamStringProxyAdapter::seek(const size_type pos)
++{
++	if (pos <= m_buffer.length())
++		m_pos = pos;
++}
++
++
+ } // utility
+ } // vmime
+ 
+diff --git a/src/utility/parserInputStreamAdapter.cpp b/src/utility/parserInputStreamAdapter.cpp
+new file mode 100644
+index 0000000..7a38ef1
+--- /dev/null
++++ b/src/utility/parserInputStreamAdapter.cpp
+@@ -0,0 +1,162 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/parserInputStreamAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++parserInputStreamAdapter::parserInputStreamAdapter(ref <seekableInputStream> stream)
++	: m_stream(stream)
++{
++}
++
++
++bool parserInputStreamAdapter::eof() const
++{
++	return m_stream->eof();
++}
++
++
++void parserInputStreamAdapter::reset()
++{
++	m_stream->reset();
++}
++
++
++stream::size_type parserInputStreamAdapter::read
++	(value_type* const data, const size_type count)
++{
++	return m_stream->read(data, count);
++}
++
++
++ref <seekableInputStream> parserInputStreamAdapter::getUnderlyingStream()
++{
++	return m_stream;
++}
++
++
++const string parserInputStreamAdapter::extract(const size_type begin, const size_type end) const
++{
++	const size_type initialPos = m_stream->getPosition();
++
++	try
++	{
++		value_type *buffer = new value_type[end - begin + 1];
++
++		m_stream->seek(begin);
++
++		const size_type readBytes = m_stream->read(buffer, end - begin);
++		buffer[readBytes] = '\0';
++
++		m_stream->seek(initialPos);
++
++		string str(buffer, buffer + readBytes);
++		delete [] buffer;
++
++		return str;
++	}
++	catch (...)
++	{
++		m_stream->seek(initialPos);
++		throw;
++	}
++}
++
++
++stream::size_type parserInputStreamAdapter::findNext
++	(const std::string& token, const size_type startPosition)
++{
++	static const unsigned int BUFFER_SIZE = 4096;
++
++	// Token must not be longer than BUFFER_SIZE/2
++	if (token.empty() || token.length() > BUFFER_SIZE / 2)
++		return npos;
++
++	const size_type initialPos = getPosition();
++
++	seek(startPosition);
++
++	try
++	{
++		value_type findBuffer[BUFFER_SIZE];
++		value_type* findBuffer1 = findBuffer;
++		value_type* findBuffer2 = findBuffer + (BUFFER_SIZE / 2) * sizeof(value_type);
++
++		size_type findBufferLen = 0;
++		size_type findBufferOffset = 0;
++
++		// Fill in initial buffer
++		findBufferLen = read(findBuffer, BUFFER_SIZE * sizeof(value_type));
++
++		for (;;)
++		{
++			// Find token
++			for (value_type *begin = findBuffer, *end = findBuffer + findBufferLen - token.length() ;
++			     begin <= end ; ++begin)
++			{
++				if (begin[0] == token[0] &&
++				    (token.length() == 1 ||
++				     memcmp(static_cast <const void *>(&begin[1]),
++				            static_cast <const void *>(token.data() + 1),
++				            token.length() - 1) == 0))
++				{
++					seek(initialPos);
++					return startPosition + findBufferOffset + (begin - findBuffer);
++				}
++			}
++
++			// Rotate buffer
++			memcpy(findBuffer1, findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type));
++
++			// Read more bytes
++			if (findBufferLen < BUFFER_SIZE && eof())
++			{
++				break;
++			}
++			else
++			{
++				const size_type bytesRead = read(findBuffer2, (BUFFER_SIZE / 2) * sizeof(value_type));
++				findBufferLen = (BUFFER_SIZE / 2) + bytesRead;
++				findBufferOffset += (BUFFER_SIZE / 2);
++			}
++		}
++
++		seek(initialPos);
++	}
++	catch (...)
++	{
++		seek(initialPos);
++		throw;
++	}
++
++	return npos;
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/seekableInputStreamRegionAdapter.cpp b/src/utility/seekableInputStreamRegionAdapter.cpp
+new file mode 100644
+index 0000000..348618c
+--- /dev/null
++++ b/src/utility/seekableInputStreamRegionAdapter.cpp
+@@ -0,0 +1,95 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++seekableInputStreamRegionAdapter::seekableInputStreamRegionAdapter
++	(ref <seekableInputStream> stream, const size_type begin, const size_type length)
++	: m_stream(stream), m_begin(begin), m_length(length)
++{
++}
++
++
++bool seekableInputStreamRegionAdapter::eof() const
++{
++	return getPosition() >= m_length;
++}
++
++
++void seekableInputStreamRegionAdapter::reset()
++{
++	m_stream->seek(m_begin);
++}
++
++
++stream::size_type seekableInputStreamRegionAdapter::read
++	(value_type* const data, const size_type count)
++{
++	if (getPosition() + count >= m_length)
++	{
++		const size_type remaining = m_length - getPosition();
++		return m_stream->read(data, remaining);
++	}
++	else
++	{
++		return m_stream->read(data, count);
++	}
++}
++
++
++stream::size_type seekableInputStreamRegionAdapter::skip(const size_type count)
++{
++	if (getPosition() + count >= m_length)
++	{
++		const size_type remaining = m_length - getPosition();
++		m_stream->skip(remaining);
++		return remaining;
++	}
++	else
++	{
++		m_stream->skip(count);
++		return count;
++	}
++}
++
++
++stream::size_type seekableInputStreamRegionAdapter::getPosition() const
++{
++	return m_stream->getPosition() - m_begin;
++}
++
++
++void seekableInputStreamRegionAdapter::seek(const size_type pos)
++{
++	m_stream->seek(m_begin + pos);
++}
++
++
++} // utility
++} // vmime
++
+diff --git a/src/utility/stream.cpp b/src/utility/stream.cpp
+index 1c940c2..67c1f33 100644
+--- a/src/utility/stream.cpp
++++ b/src/utility/stream.cpp
+@@ -29,6 +29,9 @@ namespace vmime {
+ namespace utility {
+ 
+ 
++const stream::size_type stream::npos = static_cast <size_type>(vmime::string::npos);
++
++
+ stream::size_type stream::getBlockSize()
+ {
+ 	return 32768;  // 32 KB
+@@ -37,3 +40,4 @@ stream::size_type stream::getBlockSize()
+ 
+ } // utility
+ } // vmime
++
+diff --git a/src/utility/streamUtils.cpp b/src/utility/streamUtils.cpp
+index f1d3b9d..f7ea62f 100644
+--- a/src/utility/streamUtils.cpp
++++ b/src/utility/streamUtils.cpp
+@@ -52,6 +52,35 @@ stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os)
+ }
+ 
+ 
++stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os,
++	const stream::size_type start, const stream::size_type length)
++{
++	const stream::size_type blockSize =
++		std::min(is.getBlockSize(), os.getBlockSize());
++
++	is.skip(start);
++
++	std::vector <stream::value_type> vbuffer(blockSize);
++
++	stream::value_type* buffer = &vbuffer.front();
++	stream::size_type total = 0;
++
++	while (!is.eof() && total < length)
++	{
++		const stream::size_type remaining = std::min(length - total, blockSize);
++		const stream::size_type read = is.read(buffer, blockSize);
++
++		if (read != 0)
++		{
++			os.write(buffer, read);
++			total += read;
++		}
++	}
++
++	return total;
++}
++
++
+ stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os,
+ 	const stream::size_type length, progressListener* progress)
+ {
+diff --git a/src/word.cpp b/src/word.cpp
+index 79060a1..2876ddf 100644
+--- a/src/word.cpp
++++ b/src/word.cpp
+@@ -241,7 +241,7 @@ const std::vector <ref <word> > word::parseMultiple(const string& buffer, const
+ }
+ 
+ 
+-void word::parse(const string& buffer, const string::size_type position,
++void word::parseImpl(const string& buffer, const string::size_type position,
+ 	const string::size_type end, string::size_type* newPosition)
+ {
+ 	if (position + 6 < end && // 6 = "=?(.+)?(.*)?="
+@@ -324,7 +324,7 @@ void word::parse(const string& buffer, const string::size_type position,
+ }
+ 
+ 
+-void word::generate(utility::outputStream& os, const string::size_type maxLineLength,
++void word::generateImpl(utility::outputStream& os, const string::size_type maxLineLength,
+ 	const string::size_type curLinePos, string::size_type* newLinePos) const
+ {
+ 	generate(os, maxLineLength, curLinePos, newLinePos, 0, NULL);
+@@ -743,9 +743,9 @@ void word::setBuffer(const string& buffer)
+ }
+ 
+ 
+-const std::vector <ref <const component> > word::getChildComponents() const
++const std::vector <ref <component> > word::getChildComponents()
+ {
+-	return std::vector <ref <const component> >();
++	return std::vector <ref <component> >();
+ }
+ 
+ 
+diff --git a/tests/parser/bodyPartTest.cpp b/tests/parser/bodyPartTest.cpp
+index 9d51262..deb4b9c 100644
+--- a/tests/parser/bodyPartTest.cpp
++++ b/tests/parser/bodyPartTest.cpp
+@@ -33,12 +33,14 @@ VMIME_TEST_SUITE_BEGIN
+ 	VMIME_TEST_LIST_BEGIN
+ 		VMIME_TEST(testParse)
+ 		VMIME_TEST(testGenerate)
++		VMIME_TEST(testParseGuessBoundary)
+ 		VMIME_TEST(testParseMissingLastBoundary)
+ 		VMIME_TEST(testPrologEpilog)
+ 		VMIME_TEST(testPrologEncoding)
+ 		VMIME_TEST(testSuccessiveBoundaries)
+ 		VMIME_TEST(testGenerate7bit)
+ 		VMIME_TEST(testTextUsageForQPEncoding)
++		VMIME_TEST(testParseVeryBigMessage)
+ 	VMIME_TEST_LIST_END
+ 
+ 
+@@ -237,6 +239,93 @@ VMIME_TEST_SUITE_BEGIN
+ 		VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
+ 	}
+ 
++	void testParseGuessBoundary()
++	{
++		// Boundary is not specified in "Content-Type" field
++		// Parser will try to guess it from message contents.
++
++		vmime::string str =
++			"Content-Type: multipart/mixed"
++			"\r\n\r\n"
++			"--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
++			"--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
++			"--UNKNOWN-BOUNDARY--";
++
++		vmime::bodyPart p;
++		p.parse(str);
++
++		VASSERT_EQ("count", 2, p.getBody()->getPartCount());
++
++		VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
++		VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
++	}
++
++	void testParseVeryBigMessage()
++	{
++		// When parsing from a seekable input stream, body contents should not
++		// be kept in memory in a "stringContentHandler" object. Instead, content
++		// should be accessible via a "streamContentHandler" object.
++
++		static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1";
++		static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1";
++		static const std::string BODY1_END = "END1END1";
++		static const unsigned int BODY1_REPEAT = 35000;
++		static const unsigned int BODY1_LENGTH =
++			BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length();
++
++		static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2";
++		static const unsigned int BODY2_REPEAT = 20000;
++
++		std::ostringstream oss;
++		oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
++		    << "\r\n\r\n"
++		    << "--MY-BOUNDARY\r\n"
++		    << "HEADER1\r\n"
++		    << "\r\n";
++
++		oss << BODY1_BEGIN;
++
++		for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i)
++			oss << BODY1_LINE;
++
++		oss << BODY1_END;
++
++		oss << "\r\n"
++		    << "--MY-BOUNDARY\r\n"
++		    << "HEADER2\r\n"
++		    << "\r\n";
++
++		for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i)
++			oss << BODY2_LINE;
++
++		oss << "\r\n"
++		    << "--MY-BOUNDARY--\r\n";
++
++		vmime::ref <vmime::utility::inputStreamStringAdapter> is =
++			vmime::create <vmime::utility::inputStreamStringAdapter>(oss.str());
++
++		vmime::ref <vmime::message> msg = vmime::create <vmime::message>();
++		msg->parse(is, oss.str().length());
++
++		vmime::ref <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody();
++		vmime::ref <const vmime::contentHandler> body1Cts = body1->getContents();
++
++		vmime::ref <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody();
++		vmime::ref <const vmime::contentHandler> body2Cts = body2->getContents();
++
++		vmime::string body1CtsExtracted;
++		vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted);
++		body1Cts->extract(body1CtsExtractStream);
++
++		VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength());
++		VASSERT("1.2", body1Cts.dynamicCast <const vmime::streamContentHandler>() != NULL);
++		VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length());
++		VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length()));
++		VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length()));
++
++		VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength());
++		VASSERT("2.2", body2Cts.dynamicCast <const vmime::streamContentHandler>() != NULL);
++	}
+ 
+ VMIME_TEST_SUITE_END
+ 
+diff --git a/vmime/addressList.hpp b/vmime/addressList.hpp
+index 2e537c0..9dc283c 100644
+--- a/vmime/addressList.hpp
++++ b/vmime/addressList.hpp
+@@ -56,7 +56,7 @@ public:
+ 	addressList& operator=(const addressList& other);
+ 	addressList& operator=(const mailboxList& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 
+ 	/** Add a address at the end of the list.
+@@ -163,14 +163,20 @@ private:
+ 
+ 	std::vector <ref <address> > m_list;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/body.hpp b/vmime/body.hpp
+index 9e83d6b..bd5bbb9 100644
+--- a/vmime/body.hpp
++++ b/vmime/body.hpp
+@@ -278,7 +278,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	body& operator=(const body& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ private:
+ 
+@@ -299,14 +299,20 @@ private:
+ 
+ 	void initNewPart(ref <bodyPart> part);
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(ref <utility::parserInputStreamAdapter> parser,
++		 const utility::stream::size_type position,
++		 const utility::stream::size_type end,
++		 utility::stream::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/bodyPart.hpp b/vmime/bodyPart.hpp
+index aa0f040..5f36d90 100644
+--- a/vmime/bodyPart.hpp
++++ b/vmime/bodyPart.hpp
+@@ -89,7 +89,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	bodyPart& operator=(const bodyPart& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ private:
+ 
+@@ -98,14 +98,20 @@ private:
+ 
+ 	weak_ref <bodyPart> m_parent;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(ref <utility::parserInputStreamAdapter> parser,
++		 const utility::stream::size_type position,
++		 const utility::stream::size_type end,
++		 utility::stream::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/charset.hpp b/vmime/charset.hpp
+index 5f5e8e5..26abb4f 100644
+--- a/vmime/charset.hpp
++++ b/vmime/charset.hpp
+@@ -62,7 +62,7 @@ public:
+ 	bool operator==(const charset& value) const;
+ 	bool operator!=(const charset& value) const;
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Gets the recommended encoding for this charset.
+ 	  * Note: there may be no recommended encoding.
+@@ -117,14 +117,20 @@ private:
+ 
+ 	string m_name;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/component.hpp b/vmime/component.hpp
+index 12b0406..5e6f393 100644
+--- a/vmime/component.hpp
++++ b/vmime/component.hpp
+@@ -27,6 +27,8 @@
+ 
+ #include "vmime/base.hpp"
+ #include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
++#include "vmime/utility/parserInputStreamAdapter.hpp"
+ #include "vmime/utility/outputStream.hpp"
+ 
+ 
+@@ -51,6 +53,12 @@ public:
+ 	  */
+ 	void parse(const string& buffer);
+ 
++	/** Parse RFC-822/MIME data for this component. If stream is not seekable,
++	  * or if length is not specified, entire contents of the stream will
++	  * be loaded into memory before parsing.
++	  */
++	void parse(ref <utility::inputStream> inputStream, const utility::stream::size_type length);
++
+ 	/** Parse RFC-822/MIME data for this component.
+ 	  *
+ 	  * @param buffer input buffer
+@@ -58,7 +66,26 @@ public:
+ 	  * @param end end position in the input buffer
+ 	  * @param newPosition will receive the new position in the input buffer
+ 	  */
+-	virtual void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL) = 0;
++	void parse
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	/** Parse RFC-822/MIME data for this component. If stream is not seekable,
++	  * or if end position is not specified, entire contents of the stream will
++	  * be loaded into memory before parsing.
++	  *
++	  * @param inputStream stream from which to read data
++	  * @param position current position in the input stream
++	  * @param end end position in the input stream
++	  * @param newPosition will receive the new position in the input stream
++	  */
++	void parse
++		(ref <utility::inputStream> inputStream,
++		 const utility::stream::size_type position,
++		 const utility::stream::size_type end,
++		 utility::stream::size_type* newPosition = NULL);
+ 
+ 	/** Generate RFC-2822/MIME data for this component.
+ 	  *
+@@ -68,16 +95,35 @@ public:
+ 	  * @param curLinePos length of the current line in the output buffer
+ 	  * @return generated data
+ 	  */
+-	const string generate(const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0) const;
++	virtual const string generate
++		(const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0) const;
+ 
+ 	/** Generate RFC-2822/MIME data for this component.
+ 	  *
+-	  * @param os output stream
++	  * @param outputStream output stream
+ 	  * @param maxLineLength maximum line length for output
+ 	  * @param curLinePos length of the current line in the output buffer
+ 	  * @param newLinePos will receive the new line position (length of the last line written)
+ 	  */
+-	virtual void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const = 0;
++	virtual void generate
++		(utility::outputStream& outputStream,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
++
++	/** Generate RFC-2822/MIME data for this component.
++	  *
++	  * @param outputStream output stream
++	  * @param maxLineLength maximum line length for output
++	  * @param curLinePos length of the current line in the output buffer
++	  * @param newLinePos will receive the new line position (length of the last line written)
++	  */
++	virtual void generate
++		(ref <utility::outputStream> outputStream,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+ 	/** Clone this component.
+ 	  *
+@@ -95,41 +141,56 @@ public:
+ 	virtual void copyFrom(const component& other) = 0;
+ 
+ 	/** Return the start position of this component in the
+-	  * parsed message contents.
++	  * parsed message contents. Use for debugging only.
+ 	  *
+ 	  * @return start position in parsed buffer
+ 	  * or 0 if this component has not been parsed
+ 	  */
+-	string::size_type getParsedOffset() const;
++	utility::stream::size_type getParsedOffset() const;
+ 
+ 	/** Return the length of this component in the
+-	  * parsed message contents.
++	  * parsed message contents. Use for debugging only.
+ 	  *
+ 	  * @return length of the component in parsed buffer
+ 	  * or 0 if this component has not been parsed
+ 	  */
+-	string::size_type getParsedLength() const;
++	utility::stream::size_type getParsedLength() const;
+ 
+ 	/** Return the list of children of this component.
+ 	  *
+ 	  * @return list of child components
+ 	  */
+-	const std::vector <ref <component> > getChildComponents();
+-
+-	/** Return the list of children of this component (const version).
+-	  *
+-	  * @return list of child components
+-	  */
+-	virtual const std::vector <ref <const component> > getChildComponents() const = 0;
++	virtual const std::vector <ref <component> > getChildComponents() = 0;
+ 
+ protected:
+ 
+-	void setParsedBounds(const string::size_type start, const string::size_type end);
++	void setParsedBounds(const utility::stream::size_type start, const utility::stream::size_type end);
++
++	// AT LEAST ONE of these parseImpl() functions MUST be implemented in derived class
++	virtual void parseImpl
++		(ref <utility::parserInputStreamAdapter> parser,
++		 const utility::stream::size_type position,
++		 const utility::stream::size_type end,
++		 utility::stream::size_type* newPosition = NULL);
++
++	virtual void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	virtual void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const = 0;
+ 
+ private:
+ 
+-	string::size_type m_parsedOffset;
+-	string::size_type m_parsedLength;
++	void offsetParsedBounds(const utility::stream::size_type offset);
++
++	utility::stream::size_type m_parsedOffset;
++	utility::stream::size_type m_parsedLength;
+ };
+ 
+ 
+diff --git a/vmime/contentDisposition.hpp b/vmime/contentDisposition.hpp
+index 9d1749b..abd2e1a 100644
+--- a/vmime/contentDisposition.hpp
++++ b/vmime/contentDisposition.hpp
+@@ -63,7 +63,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	contentDisposition& operator=(const contentDisposition& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 
+ 	contentDisposition& operator=(const string& name);
+@@ -75,14 +75,20 @@ private:
+ 
+ 	string m_name;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/dateTime.hpp b/vmime/dateTime.hpp
+index 8e99640..053f4a6 100644
+--- a/vmime/dateTime.hpp
++++ b/vmime/dateTime.hpp
+@@ -237,16 +237,22 @@ public:
+ 	// Current date and time
+ 	static const datetime now();
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/disposition.hpp b/vmime/disposition.hpp
+index 05bfca2..7bdc832 100644
+--- a/vmime/disposition.hpp
++++ b/vmime/disposition.hpp
+@@ -50,7 +50,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	disposition& operator=(const disposition& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 
+ 	/** Set the disposition action mode.
+@@ -134,14 +134,20 @@ private:
+ 
+ 	std::vector <string> m_modifiers;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/encoding.hpp b/vmime/encoding.hpp
+index 42f5246..4322b29 100644
+--- a/vmime/encoding.hpp
++++ b/vmime/encoding.hpp
+@@ -93,7 +93,7 @@ public:
+ 	bool operator==(const encoding& value) const;
+ 	bool operator!=(const encoding& value) const;
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Decide which encoding to use based on the specified data.
+ 	  *
+@@ -141,14 +141,20 @@ private:
+ 	  */
+ 	static const encoding decideImpl(const string::const_iterator begin, const string::const_iterator end);
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/header.hpp b/vmime/header.hpp
+index 95a9326..ed555b0 100644
+--- a/vmime/header.hpp
++++ b/vmime/header.hpp
+@@ -220,7 +220,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	header& operator=(const header& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ private:
+ 
+@@ -251,14 +251,20 @@ private:
+ 		string m_name;
+ 	};
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/headerField.hpp b/vmime/headerField.hpp
+index 50494c9..61e01ee 100644
+--- a/vmime/headerField.hpp
++++ b/vmime/headerField.hpp
+@@ -59,7 +59,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	headerField& operator=(const headerField& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Sets the name of this field.
+ 	  *
+@@ -118,15 +118,26 @@ public:
+ 	void setValue(const string& value);
+ 
+ 
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+-protected:
+ 
+-	static ref <headerField> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
++	static ref <headerField> parseNext
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
+ 
+ 
+ 	string m_name;
+diff --git a/vmime/mailbox.hpp b/vmime/mailbox.hpp
+index 2072be8..2099355 100644
+--- a/vmime/mailbox.hpp
++++ b/vmime/mailbox.hpp
+@@ -85,7 +85,7 @@ public:
+ 
+ 	void clear();
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 
+ 	bool isGroup() const;
+@@ -101,8 +101,17 @@ public:
+ 	using address::generate;
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/mailboxGroup.hpp b/vmime/mailboxGroup.hpp
+index 0061d5b..1433141 100644
+--- a/vmime/mailboxGroup.hpp
++++ b/vmime/mailboxGroup.hpp
+@@ -52,7 +52,7 @@ public:
+ 	ref <component> clone() const;
+ 	mailboxGroup& operator=(const component& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Return the name of the group.
+ 	  *
+@@ -165,14 +165,20 @@ private:
+ 	text m_name;
+ 	std::vector <ref <mailbox> > m_list;
+ 
+-public:
+-
+-	using address::parse;
+-	using address::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/mailboxList.hpp b/vmime/mailboxList.hpp
+index 11e4e79..1b480c1 100644
+--- a/vmime/mailboxList.hpp
++++ b/vmime/mailboxList.hpp
+@@ -51,7 +51,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	mailboxList& operator=(const mailboxList& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Add a mailbox at the end of the list.
+ 	  *
+@@ -155,14 +155,20 @@ private:
+ 
+ 	addressList m_list;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/mediaType.hpp b/vmime/mediaType.hpp
+index 658b21f..18182f0 100644
+--- a/vmime/mediaType.hpp
++++ b/vmime/mediaType.hpp
+@@ -55,7 +55,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	mediaType& operator=(const mediaType& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Return the media type.
+ 	  * See the constants in vmime::mediaTypes.
+@@ -97,14 +97,18 @@ protected:
+ 	string m_type;
+ 	string m_subType;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
+-
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/message.hpp b/vmime/message.hpp
+index f3be229..9767564 100644
+--- a/vmime/message.hpp
++++ b/vmime/message.hpp
+@@ -43,12 +43,25 @@ public:
+ 	message();
+ 
+ 
+-	// Component parsing & assembling
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
+-
+-	const string generate(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(), const string::size_type curLinePos = 0) const;
++public:
+ 
+-	void parse(const string& buffer);
++	// Override default generate() functions so that we can change
++	// the default 'maxLineLength' value
++	void generate
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(),
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
++
++	const string generate
++		(const string::size_type maxLineLength = options::getInstance()->message.maxLineLength(),
++		 const string::size_type curLinePos = 0) const;
++
++	void generate
++		(ref <utility::outputStream> os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/messageId.hpp b/vmime/messageId.hpp
+index 3686b11..ac408e6 100644
+--- a/vmime/messageId.hpp
++++ b/vmime/messageId.hpp
+@@ -97,23 +97,27 @@ public:
+ 	void copyFrom(const component& other);
+ 	messageId& operator=(const messageId& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ private:
+ 
+ 	string m_left;
+ 	string m_right;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
+-
+-protected:
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+ 	/** Parse a message-id from an input buffer.
+ 	  *
+@@ -123,7 +127,11 @@ protected:
+ 	  * @param newPosition will receive the new position in the input buffer
+ 	  * @return a new message-id object, or null if no more message-id can be parsed from the input buffer
+ 	  */
+-	static ref <messageId> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
++	static ref <messageId> parseNext
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition);
+ };
+ 
+ 
+diff --git a/vmime/messageIdSequence.hpp b/vmime/messageIdSequence.hpp
+index 5dfb840..6736d0a 100644
+--- a/vmime/messageIdSequence.hpp
++++ b/vmime/messageIdSequence.hpp
+@@ -49,7 +49,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	messageIdSequence& operator=(const messageIdSequence& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 
+ 	/** Add a message-id at the end of the list.
+@@ -148,14 +148,20 @@ private:
+ 
+ 	std::vector <ref <messageId> > m_list;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/parameter.hpp b/vmime/parameter.hpp
+index e1b13a1..0773ea6 100644
+--- a/vmime/parameter.hpp
++++ b/vmime/parameter.hpp
+@@ -67,7 +67,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	parameter& operator=(const parameter& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Return the name of this parameter.
+ 	  *
+@@ -104,7 +104,7 @@ public:
+ 	const T getValueAs() const
+ 	{
+ 		T ret;
+-		ret.parse(m_value.getBuffer());
++		ret.parse(m_value->getBuffer());
+ 
+ 		return ret;
+ 	}
+@@ -122,11 +122,19 @@ public:
+ 	void setValue(const word& value);
+ 
+ 
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+ private:
+ 
+@@ -134,7 +142,7 @@ private:
+ 
+ 
+ 	string m_name;
+-	word m_value;
++	ref <word> m_value;
+ };
+ 
+ 
+diff --git a/vmime/parameterizedHeaderField.hpp b/vmime/parameterizedHeaderField.hpp
+index 2940ca3..d2c934f 100644
+--- a/vmime/parameterizedHeaderField.hpp
++++ b/vmime/parameterizedHeaderField.hpp
+@@ -172,19 +172,25 @@ public:
+ 	  */
+ 	const std::vector <ref <parameter> > getParameterList();
+ 
++	const std::vector <ref <component> > getChildComponents();
++
+ private:
+ 
+ 	std::vector <ref <parameter> > m_params;
+ 
+-public:
+-
+-	using headerField::parse;
+-	using headerField::generate;
+-
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++protected:
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/parserHelpers.hpp b/vmime/parserHelpers.hpp
+index 9b075f7..d4f1246 100644
+--- a/vmime/parserHelpers.hpp
++++ b/vmime/parserHelpers.hpp
+@@ -45,6 +45,10 @@ public:
+ 		return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
+ 	}
+ 
++	static bool isSpaceOrTab(const char_t c)
++	{
++		return (c == ' ' || c == '\t');
++	}
+ 
+ 	static bool isDigit(const char_t c)
+ 	{
+diff --git a/vmime/path.hpp b/vmime/path.hpp
+index beaa72b..eec8dfc 100644
+--- a/vmime/path.hpp
++++ b/vmime/path.hpp
+@@ -76,21 +76,26 @@ public:
+ 	ref <component> clone() const;
+ 	path& operator=(const path& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ protected:
+ 
+ 	string m_localPart;
+ 	string m_domain;
+ 
+-public:
+-
+-	using component::parse;
+-	using component::generate;
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/platforms/posix/posixFile.hpp b/vmime/platforms/posix/posixFile.hpp
+index 70986df..704b7b0 100644
+--- a/vmime/platforms/posix/posixFile.hpp
++++ b/vmime/platforms/posix/posixFile.hpp
+@@ -26,6 +26,7 @@
+ 
+ 
+ #include "vmime/utility/file.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ 
+ #if VMIME_HAVE_FILESYSTEM_FEATURES
+@@ -57,7 +58,7 @@ private:
+ 
+ 
+ 
+-class posixFileReaderInputStream : public vmime::utility::inputStream
++class posixFileReaderInputStream : public vmime::utility::seekableInputStream
+ {
+ public:
+ 
+@@ -72,6 +73,9 @@ public:
+ 
+ 	size_type skip(const size_type count);
+ 
++	size_type getPosition() const;
++	void seek(const size_type pos);
++
+ private:
+ 
+ 	const vmime::utility::file::path m_path;
+diff --git a/vmime/platforms/windows/windowsFile.hpp b/vmime/platforms/windows/windowsFile.hpp
+index 6e1c8fb..f417032 100644
+--- a/vmime/platforms/windows/windowsFile.hpp
++++ b/vmime/platforms/windows/windowsFile.hpp
+@@ -26,6 +26,7 @@
+ 
+ 
+ #include "vmime/utility/file.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ #include <windows.h>
+ 
+@@ -157,6 +158,8 @@ public:
+ 	void reset();
+ 	size_type read(value_type* const data, const size_type count);
+ 	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
+ 
+ private:
+ 
+diff --git a/vmime/relay.hpp b/vmime/relay.hpp
+index 583ad80..dbaedf2 100644
+--- a/vmime/relay.hpp
++++ b/vmime/relay.hpp
+@@ -51,7 +51,7 @@ public:
+ 	void copyFrom(const component& other);
+ 	relay& operator=(const relay& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	const string& getFrom() const;
+ 	void setFrom(const string& from);
+@@ -85,13 +85,19 @@ private:
+ 
+ 	datetime m_date;
+ 
+-public:
++protected:
+ 
+-	using component::parse;
+-	using component::generate;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
+ 
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ };
+ 
+ 
+diff --git a/vmime/text.hpp b/vmime/text.hpp
+index 15e11ae..778ce86 100644
+--- a/vmime/text.hpp
++++ b/vmime/text.hpp
+@@ -58,7 +58,7 @@ public:
+ 	text& operator=(const component& other);
+ 	text& operator=(const text& other);
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++	const std::vector <ref <component> > getChildComponents();
+ 
+ 	/** Add a word at the end of the list.
+ 	  *
+@@ -226,13 +226,20 @@ public:
+ 	  */
+ 	static text* decodeAndUnfold(const string& in, text* generateInExisting);
+ 
+-
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+ 	// Component parsing & assembling
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
++
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+ private:
+ 
+diff --git a/vmime/utility/inputStreamAdapter.hpp b/vmime/utility/inputStreamAdapter.hpp
+index 278ab52..bd4d21e 100644
+--- a/vmime/utility/inputStreamAdapter.hpp
++++ b/vmime/utility/inputStreamAdapter.hpp
+@@ -25,7 +25,7 @@
+ #define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
+ 
+ 
+-#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ #include <istream>
+ 
+@@ -37,7 +37,7 @@ namespace utility {
+ /** An adapter class for C++ standard input streams.
+   */
+ 
+-class inputStreamAdapter : public inputStream
++class inputStreamAdapter : public seekableInputStream
+ {
+ public:
+ 
+@@ -49,6 +49,8 @@ public:
+ 	void reset();
+ 	size_type read(value_type* const data, const size_type count);
+ 	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
+ 
+ private:
+ 
+diff --git a/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime/utility/inputStreamByteBufferAdapter.hpp
+index 0f6a442..b3dafd9 100644
+--- a/vmime/utility/inputStreamByteBufferAdapter.hpp
++++ b/vmime/utility/inputStreamByteBufferAdapter.hpp
+@@ -25,7 +25,7 @@
+ #define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
+ 
+ 
+-#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ 
+ namespace vmime {
+@@ -35,7 +35,7 @@ namespace utility {
+ /** An adapter class for reading from an array of bytes.
+   */
+ 
+-class inputStreamByteBufferAdapter : public inputStream
++class inputStreamByteBufferAdapter : public seekableInputStream
+ {
+ public:
+ 
+@@ -45,6 +45,8 @@ public:
+ 	void reset();
+ 	size_type read(value_type* const data, const size_type count);
+ 	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
+ 
+ private:
+ 
+diff --git a/vmime/utility/inputStreamStringAdapter.hpp b/vmime/utility/inputStreamStringAdapter.hpp
+index a7d986f..18a9083 100644
+--- a/vmime/utility/inputStreamStringAdapter.hpp
++++ b/vmime/utility/inputStreamStringAdapter.hpp
+@@ -25,7 +25,7 @@
+ #define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
+ 
+ 
+-#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ 
+ namespace vmime {
+@@ -35,7 +35,7 @@ namespace utility {
+ /** An adapter class for string input.
+   */
+ 
+-class inputStreamStringAdapter : public inputStream
++class inputStreamStringAdapter : public seekableInputStream
+ {
+ public:
+ 
+@@ -46,6 +46,8 @@ public:
+ 	void reset();
+ 	size_type read(value_type* const data, const size_type count);
+ 	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
+ 
+ private:
+ 
+diff --git a/vmime/utility/inputStreamStringProxyAdapter.hpp b/vmime/utility/inputStreamStringProxyAdapter.hpp
+index 74b3f60..dc52637 100644
+--- a/vmime/utility/inputStreamStringProxyAdapter.hpp
++++ b/vmime/utility/inputStreamStringProxyAdapter.hpp
+@@ -25,7 +25,7 @@
+ #define VMIME_UTILITY_INPUTSTREAMSTRINGPROXYADAPTER_HPP_INCLUDED
+ 
+ 
+-#include "vmime/utility/inputStream.hpp"
++#include "vmime/utility/seekableInputStream.hpp"
+ 
+ 
+ namespace vmime {
+@@ -38,7 +38,7 @@ class stringProxy;
+ /** An adapter class for stringProxy input.
+   */
+ 
+-class inputStreamStringProxyAdapter : public inputStream
++class inputStreamStringProxyAdapter : public seekableInputStream
+ {
+ public:
+ 
+@@ -50,6 +50,8 @@ public:
+ 	void reset();
+ 	size_type read(value_type* const data, const size_type count);
+ 	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
+ 
+ private:
+ 
+diff --git a/vmime/utility/parserInputStreamAdapter.hpp b/vmime/utility/parserInputStreamAdapter.hpp
+new file mode 100644
+index 0000000..c24fa44
+--- /dev/null
++++ b/vmime/utility/parserInputStreamAdapter.hpp
+@@ -0,0 +1,173 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/seekableInputStream.hpp"
++
++#include <cstring>
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter class used for parsing from an input stream.
++  */
++
++class parserInputStreamAdapter : public seekableInputStream
++{
++public:
++
++	/** @param is input stream to wrap
++	  */
++	parserInputStreamAdapter(ref <seekableInputStream> inputStream);
++
++	ref <seekableInputStream> getUnderlyingStream();
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++
++	void seek(const size_type pos)
++	{
++		m_stream->seek(pos);
++	}
++
++	size_type skip(const size_type count)
++	{
++		return m_stream->skip(count);
++	}
++
++	size_type getPosition() const
++	{
++		return m_stream->getPosition();
++	}
++
++	/** Get the byte at the current position without updating the
++	  * current position.
++	  *
++	  * @return byte at the current position
++	  */
++	value_type peekByte() const
++	{
++		const size_type initialPos = m_stream->getPosition();
++
++		try
++		{
++			value_type buffer[1];
++			const size_type readBytes = m_stream->read(buffer, 1);
++
++			m_stream->seek(initialPos);
++
++			return (readBytes == 1 ? buffer[0] : 0);
++		}
++		catch (...)
++		{
++			m_stream->seek(initialPos);
++			throw;
++		}
++	}
++
++	/** Get the byte at the current position and advance current
++	  * position by one byte.
++	  *
++	  * @return byte at the current position
++	  */
++	value_type getByte()
++	{
++		value_type buffer[1];
++		const size_type readBytes = m_stream->read(buffer, 1);
++
++		return (readBytes == 1 ? buffer[0] : 0);
++	}
++
++	/** Check whether the bytes following the current position match
++	  * the specified bytes. Position is not updated.
++	  *
++	  * @param bytes bytes to compare
++	  * @param length number of bytes
++	  * @return true if the next bytes match the pattern, false otherwise
++	  */
++	bool matchBytes(const value_type* bytes, const size_type length) const
++	{
++		const size_type initialPos = m_stream->getPosition();
++
++		try
++		{
++			value_type buffer[32];
++			const size_type readBytes = m_stream->read(buffer, length);
++
++			m_stream->seek(initialPos);
++
++			return readBytes == length &&
++			       ::memcmp(bytes, buffer, length) == 0;
++		}
++		catch (...)
++		{
++			m_stream->seek(initialPos);
++			throw;
++		}
++	}
++
++	const string extract(const size_type begin, const size_type end) const;
++
++	/** Skips bytes matching a predicate from the current position.
++	  * The current position is updated to the next following byte
++	  * which does not match the predicate.
++	  *
++	  * @param pred predicate
++	  * @param endPosition stop at this position (or at end of the stream,
++	  * whichever comes first)
++	  * @return number of bytes skipped
++	  */
++	template <typename PREDICATE>
++	size_type skipIf(PREDICATE pred, const size_type endPosition)
++	{
++		const size_type initialPos = getPosition();
++		size_type pos = initialPos;
++
++		while (!m_stream->eof() && pos < endPosition && pred(getByte()))
++			++pos;
++
++		m_stream->seek(pos);
++
++		return pos - initialPos;
++	}
++
++	size_type findNext(const std::string& token, const size_type startPosition = 0);
++
++private:
++
++	mutable ref <seekableInputStream> m_stream;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/seekableInputStream.hpp b/vmime/utility/seekableInputStream.hpp
+new file mode 100644
+index 0000000..c2ab1bb
+--- /dev/null
++++ b/vmime/utility/seekableInputStream.hpp
+@@ -0,0 +1,64 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
++#define VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
++
++
++#include "vmime/utility/inputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An input stream that allows seeking within the input.
++  */
++
++class seekableInputStream : public inputStream
++{
++public:
++
++	/** Returns the current position in this stream.
++	  *
++	  * @return the offset from the beginning of the stream, in bytes,
++	  * at which the next read occurs
++	  */
++	virtual size_type getPosition() const = 0;
++
++	/** Sets the position, measured from the beginning of this stream,
++	  * at which the next read occurs.
++	  *
++	  * @param pos the offset position, measured in bytes from the
++	  * beginning of the stream, at which to set the stream pointer.
++	  */
++	virtual void seek(const size_type pos) = 0;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
++
+diff --git a/vmime/utility/seekableInputStreamRegionAdapter.hpp b/vmime/utility/seekableInputStreamRegionAdapter.hpp
+new file mode 100644
+index 0000000..5ebccc6
+--- /dev/null
++++ b/vmime/utility/seekableInputStreamRegionAdapter.hpp
+@@ -0,0 +1,71 @@
++//
++// VMime library (http://www.vmime.org)
++// Copyright (C) 2002-2012 Vincent Richard <vincent@vincent-richard.net>
++//
++// This program is free software; you can redistribute it and/or
++// modify it under the terms of the GNU General Public License as
++// published by the Free Software Foundation; either version 3 of
++// the License, or (at your option) any later version.
++//
++// This program is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// General Public License for more details.
++//
++// You should have received a copy of the GNU General Public License along
++// with this program; if not, write to the Free Software Foundation, Inc.,
++// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++//
++// Linking this library statically or dynamically with other modules is making
++// a combined work based on this library.  Thus, the terms and conditions of
++// the GNU General Public License cover the whole combination.
++//
++
++#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
++#define VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
++
++
++#include "vmime/utility/seekableInputStream.hpp"
++
++
++namespace vmime {
++namespace utility {
++
++
++/** An adapter for reading a limited region of a seekable input stream.
++  */
++
++class seekableInputStreamRegionAdapter : public seekableInputStream
++{
++public:
++
++	/** Creates a new adapter for a seekableInputStream.
++	  *
++	  * @param stream source stream
++	  * @param begin start position in source stream
++	  * @param length region length in source stream
++	  */
++	seekableInputStreamRegionAdapter(ref <seekableInputStream> stream,
++		const size_type begin, const size_type length);
++
++	bool eof() const;
++	void reset();
++	size_type read(value_type* const data, const size_type count);
++	size_type skip(const size_type count);
++	size_type getPosition() const;
++	void seek(const size_type pos);
++
++private:
++
++	ref <seekableInputStream> m_stream;
++	size_type m_begin;
++	size_type m_length;
++};
++
++
++} // utility
++} // vmime
++
++
++#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
++
+diff --git a/vmime/utility/stream.hpp b/vmime/utility/stream.hpp
+index 566ab9d..78be827 100644
+--- a/vmime/utility/stream.hpp
++++ b/vmime/utility/stream.hpp
+@@ -54,6 +54,10 @@ public:
+ 	  */
+ 	typedef string::size_type size_type;
+ 
++	/** Constant value with the greatest possible value for an element of type size_type.
++	  */
++	static const size_type npos;
++
+ 	/** Return the preferred maximum block size when reading
+ 	  * from or writing to this stream.
+ 	  *
+diff --git a/vmime/utility/streamUtils.hpp b/vmime/utility/streamUtils.hpp
+index cdf70aa..87c8fc5 100644
+--- a/vmime/utility/streamUtils.hpp
++++ b/vmime/utility/streamUtils.hpp
+@@ -45,6 +45,19 @@ namespace utility {
+ stream::size_type bufferedStreamCopy(inputStream& is, outputStream& os);
+ 
+ /** Copy data from one stream into another stream using a buffered method
++  * and copying only a specified range of data.
++  *
++  * @param is input stream (source data)
++  * @param os output stream (destination for data)
++  * @param start number of bytes to ignore before starting copying
++  * @param length maximum number of bytes to copy
++  * @return number of bytes copied
++  */
++
++stream::size_type bufferedStreamCopyRange(inputStream& is, outputStream& os,
++	const stream::size_type start, const stream::size_type length);
++
++/** Copy data from one stream into another stream using a buffered method
+   * and notify progress state of the operation.
+   *
+   * @param is input stream (source data)
+diff --git a/vmime/word.hpp b/vmime/word.hpp
+index ad848ec..492aab5 100644
+--- a/vmime/word.hpp
++++ b/vmime/word.hpp
+@@ -128,21 +128,52 @@ public:
+ #endif
+ 
+ 
+-	using component::parse;
+-	using component::generate;
++protected:
+ 
+-	void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL);
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const;
++	void parseImpl
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition = NULL);
+ 
+-	void generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, generatorState* state) const;
++	void generateImpl
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength = lineLengthLimits::infinite,
++		 const string::size_type curLinePos = 0,
++		 string::size_type* newLinePos = NULL) const;
+ 
+-	const std::vector <ref <const component> > getChildComponents() const;
++public:
+ 
+-private:
++	using component::generate;
+ 
+-	static ref <word> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, bool prevIsEncoded, bool* isEncoded, bool isFirst);
++#ifndef VMIME_BUILDING_DOC
++	void generate
++		(utility::outputStream& os,
++		 const string::size_type maxLineLength,
++		 const string::size_type curLinePos,
++		 string::size_type* newLinePos,
++		 const int flags,
++		 generatorState* state) const;
++#endif
++
++	const std::vector <ref <component> > getChildComponents();
++
++private:
+ 
+-	static const std::vector <ref <word> > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);
++	static ref <word> parseNext
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition,
++		 bool prevIsEncoded,
++		 bool* isEncoded,
++		 bool isFirst);
++
++	static const std::vector <ref <word> > parseMultiple
++		(const string& buffer,
++		 const string::size_type position,
++		 const string::size_type end,
++		 string::size_type* newPosition);
+ 
+ 
+ 	// The "m_buffer" of this word holds the data, and this data is encoded
+-- 
+1.7.10.3
+
+
+From 2e05e574fde890c7ec6dd9f3930d06b1b492ea80 Mon Sep 17 00:00:00 2001
+From: Vincent Richard <vincent@vincent-richard.net>
+Date: Fri, 27 Apr 2012 08:34:26 +0200
+Subject: [PATCH 38/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
+
--- 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 \